test: add 85 comprehensive tests and Gitea CI/CD workflow
CI / build-and-test (push) Failing after 56s
CI / build-and-test (push) Failing after 56s
- test-full.sh: 85 tests covering CLI, DSL parsing (all keywords), config parsing, users/groups, assertions, imports, doctor diagnostics, repos/remotes, index generation, add/remove operations, install DB, resolver (conflicts + missing), scheduler (deptree ordering), build execution + error handling, env operators, init systems, bootloaders, variable interpolation, --root override, rollback config, system env, feature flags, rebuild dry-run - .gitea/workflows/ci.yml: builds on Ubuntu with clang+cmake+ninja, runs all three test suites on push/PR to main Total test count: 31 (DSL) + 23 (init-switch) + 85 (comprehensive) = 139
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq clang cmake ninja-build
|
||||
|
||||
- name: Build kappa
|
||||
run: |
|
||||
cmake -B build -G Ninja \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++
|
||||
cmake --build build
|
||||
|
||||
- name: DSL and CLI tests
|
||||
run: ./test.sh
|
||||
|
||||
- name: Init-switching tests
|
||||
run: ./test-init-switch.sh
|
||||
|
||||
- name: Comprehensive tests
|
||||
run: ./test-full.sh
|
||||
Executable
+992
@@ -0,0 +1,992 @@
|
||||
#!/bin/sh
|
||||
# kappa comprehensive test suite — DSL, ops, error handling, edge cases
|
||||
set -e
|
||||
|
||||
KAPPA="${KAPPA_BIN:-./build/kappa}"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
check() {
|
||||
local desc="$1" cmd="$2" expect="$3"
|
||||
local out
|
||||
out=$(eval "$cmd" 2>&1) || true
|
||||
if echo "$out" | grep -q "$expect"; then
|
||||
echo " ✓ $desc"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo " ✗ $desc"
|
||||
echo " expected: $expect"
|
||||
echo " got: $(echo "$out" | head -3 | tr '\n' ' ')"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
check_fail() {
|
||||
local desc="$1" cmd="$2" expect="$3"
|
||||
local out rc=0
|
||||
out=$(eval "$cmd" 2>&1) || rc=$?
|
||||
if [ "$rc" -ne 0 ] && echo "$out" | grep -q "$expect"; then
|
||||
echo " ✓ $desc"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo " ✗ $desc"
|
||||
echo " expected exit≠0 with: $expect"
|
||||
echo " exit: $rc, got: $(echo "$out" | head -3 | tr '\n' ' ')"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
TMPDIR=$(mktemp -d /tmp/kappa-full-test-XXXXX)
|
||||
trap 'rm -rf $TMPDIR' EXIT
|
||||
export KAPPA_ROOT="$TMPDIR/root"
|
||||
mkdir -p "$KAPPA_ROOT"/{bin,temp,db,system,builds,cache/{packages,indexes}}
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== CLI: help, version, error handling ==="
|
||||
echo ""
|
||||
|
||||
check "kappa --help" \
|
||||
"$KAPPA --help" \
|
||||
'Usage'
|
||||
|
||||
check "kappa -h" \
|
||||
"$KAPPA -h" \
|
||||
'Subcommands'
|
||||
|
||||
check "kappa -V" \
|
||||
"$KAPPA -V" \
|
||||
'kappa 0.1.0'
|
||||
|
||||
check_fail "missing subcommand" \
|
||||
"$KAPPA" \
|
||||
'missing subcommand'
|
||||
|
||||
check_fail "unknown subcommand" \
|
||||
"$KAPPA fakething" \
|
||||
"unknown subcommand 'fakething'"
|
||||
|
||||
check_fail "missing file arg" \
|
||||
"$KAPPA parse-package" \
|
||||
'no input file'
|
||||
|
||||
check_fail "nonexistent file" \
|
||||
"$KAPPA parse-package /nonexistent/file.kap" \
|
||||
'cannot open'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== DSL: parse-package and validate ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/basic.kap" << 'KAPEOF'
|
||||
package "testpkg" {
|
||||
version = "1.0"
|
||||
source = "https://example.com/test-1.0.tar.gz"
|
||||
sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
license = "MIT"
|
||||
provides = ["libtest.so.1"]
|
||||
build { make -j${jobs} }
|
||||
install { make DESTDIR=${destdir} install }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "basic package parse" \
|
||||
"$KAPPA parse-package $TMPDIR/basic.kap" \
|
||||
'package "testpkg" 1.0 — valid'
|
||||
|
||||
check "validate package" \
|
||||
"$KAPPA validate $TMPDIR/basic.kap" \
|
||||
'valid package'
|
||||
|
||||
|
||||
check_fail "unclosed brace" \
|
||||
"printf 'package \"bad\" {\n version = \"1\"\n' | $KAPPA parse-package /dev/stdin" \
|
||||
'unclosed'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== DSL: all keywords parse and format ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/full.kap" << 'KAPEOF'
|
||||
package "fullpkg" {
|
||||
const version = "2.0"
|
||||
const source = "https://example.com/full-v2.0.tar.gz"
|
||||
sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
sha512 = "abc"
|
||||
md5 = "def"
|
||||
license = "BSD-2"
|
||||
provides = ["full", "libfull.so"]
|
||||
outputs = ["bin", "lib"]
|
||||
conflicts = ["incompatible"]
|
||||
depends = [{ name = "zlib", version = ">=1.2" }, "openssl"]
|
||||
features {
|
||||
ssl = { enabled = true, flag = "--with-ssl" }
|
||||
debug = false
|
||||
}
|
||||
config {
|
||||
file "etc/full.conf" mode = "default" {
|
||||
port = "8080"
|
||||
}
|
||||
}
|
||||
env {
|
||||
CFLAGS = "-O2"
|
||||
CFLAGS += "-pipe"
|
||||
LDFLAGS ?= "-s"
|
||||
}
|
||||
patches = [{ url = "https://example.com/fix.patch", sha256 = "abc", level = 1 }]
|
||||
service {
|
||||
exec = "/usr/bin/full"
|
||||
type = "forking"
|
||||
ports = [80, 443]
|
||||
}
|
||||
assert {
|
||||
"ssl required" : features.ssl == "true"
|
||||
}
|
||||
prepare { echo prepare }
|
||||
build { make -j4 }
|
||||
check { make check }
|
||||
install { make DESTDIR=/tmp/dest install }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "full keyword parse" \
|
||||
"$KAPPA parse-package $TMPDIR/full.kap" \
|
||||
'package "fullpkg"'
|
||||
|
||||
check "format full roundtrip" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'package "fullpkg"'
|
||||
|
||||
check "format preserves provides" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'libfull.so'
|
||||
|
||||
check "format preserves features" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'features {'
|
||||
|
||||
check "format preserves env +=" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'CFLAGS +='
|
||||
|
||||
check "format preserves env ?=" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'LDFLAGS ?='
|
||||
|
||||
check "format preserves service" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'/usr/bin/full'
|
||||
|
||||
check "format preserves asserts" \
|
||||
"$KAPPA format $TMPDIR/full.kap" \
|
||||
'assert {'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Config: parse-config and format ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/simple-config.kap" << 'KAPEOF'
|
||||
system {
|
||||
hostname = "test"
|
||||
}
|
||||
packages {
|
||||
testpkg {}
|
||||
}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "parse-config basic" \
|
||||
"$KAPPA parse-config $TMPDIR/simple-config.kap" \
|
||||
'valid'
|
||||
|
||||
check "parse-config shows init" \
|
||||
"$KAPPA parse-config $TMPDIR/simple-config.kap" \
|
||||
's6'
|
||||
|
||||
check "validate config" \
|
||||
"$KAPPA validate $TMPDIR/simple-config.kap" \
|
||||
'valid system configuration'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Config: users and groups ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/users-config.kap" << 'KAPEOF'
|
||||
system {
|
||||
hostname = "test"
|
||||
}
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
groups {
|
||||
wheel { gid = 998 }
|
||||
audio {}
|
||||
}
|
||||
users {
|
||||
root {
|
||||
shell = "/bin/zsh"
|
||||
groups = ["wheel", "audio"]
|
||||
}
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "parse-config with users" \
|
||||
"$KAPPA parse-config $TMPDIR/users-config.kap" \
|
||||
'1 users'
|
||||
|
||||
check "format users roundtrip" \
|
||||
"$KAPPA format $TMPDIR/users-config.kap" \
|
||||
'/bin/zsh'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Config: assertions ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/assert-pass.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
packages { testpkg {} }
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
assert {
|
||||
"root required" : boot.root != ""
|
||||
"init must be s6" : boot.init == "s6"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "validate passes assertions" \
|
||||
"$KAPPA validate $TMPDIR/assert-pass.kap" \
|
||||
'valid system configuration'
|
||||
|
||||
cat > "$TMPDIR/assert-fail.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "openrc"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
assert {
|
||||
"must be s6" : boot.init == "s6"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check_fail "validate fails assertion" \
|
||||
"$KAPPA validate $TMPDIR/assert-fail.kap" \
|
||||
'assertion failures'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Config: imports ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/imported.kap" << 'KAPEOF'
|
||||
system { hostname = "imported.local" }
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
cat > "$TMPDIR/importer.kap" << 'KAPEOF'
|
||||
imports = ["imported.kap"]
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "imports merges hostname" \
|
||||
"$KAPPA parse-config $TMPDIR/importer.kap" \
|
||||
'valid'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Doctor diagnostics ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/doctor-bad.kap" << 'KAPEOF'
|
||||
package "bad" {
|
||||
version = ""
|
||||
source = ""
|
||||
build { echo ok }
|
||||
install { echo ok }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check_fail "doctor catches empty version" \
|
||||
"$KAPPA doctor $TMPDIR/doctor-bad.kap" \
|
||||
'version is not set'
|
||||
|
||||
check_fail "doctor catches empty source" \
|
||||
"$KAPPA doctor $TMPDIR/doctor-bad.kap" \
|
||||
'source URL is not set'
|
||||
|
||||
check_fail "doctor warns missing license" \
|
||||
"$KAPPA doctor $TMPDIR/doctor-bad.kap" \
|
||||
'license is not specified'
|
||||
|
||||
cat > "$TMPDIR/doctor-badcfg.kap" << 'KAPEOF'
|
||||
system {}
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "fakenit"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "lilo"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check_fail "doctor warns missing hostname" \
|
||||
"$KAPPA doctor $TMPDIR/doctor-badcfg.kap" \
|
||||
'hostname is not set'
|
||||
|
||||
check_fail "doctor warns unknown init" \
|
||||
"$KAPPA doctor $TMPDIR/doctor-badcfg.kap" \
|
||||
'not a recognized init system'
|
||||
|
||||
check_fail "doctor warns unknown bootloader" \
|
||||
"$KAPPA doctor $TMPDIR/doctor-badcfg.kap" \
|
||||
'not a recognized bootloader'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Repos: parsing and formatting ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/repos-config.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
repos {
|
||||
upstream {
|
||||
url = "https://packages.example.com/"
|
||||
channels = ["stable", "testing"]
|
||||
mirrors = [
|
||||
"https://cdn.example.com/",
|
||||
"https://eu.example.com/",
|
||||
]
|
||||
priority = 100
|
||||
}
|
||||
local {
|
||||
url = "file:///usr/local/kappa/repo/"
|
||||
channels = ["default"]
|
||||
}
|
||||
}
|
||||
packages { testpkg {} }
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "parse-config with repos" \
|
||||
"$KAPPA parse-config $TMPDIR/repos-config.kap" \
|
||||
'repos: 2'
|
||||
|
||||
check "format repos roundtrip" \
|
||||
"$KAPPA format $TMPDIR/repos-config.kap" \
|
||||
'upstream {'
|
||||
|
||||
check "format repos preserves channels" \
|
||||
"$KAPPA format $TMPDIR/repos-config.kap" \
|
||||
'channels = \['
|
||||
|
||||
check "format repos preserves mirrors" \
|
||||
"$KAPPA format $TMPDIR/repos-config.kap" \
|
||||
'cdn.example.com'
|
||||
|
||||
check "format repos preserves priority" \
|
||||
"$KAPPA format $TMPDIR/repos-config.kap" \
|
||||
'priority = 100'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Backward compat: remotes flat list ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/remotes-config.kap" << 'KAPEOF'
|
||||
remotes = [
|
||||
"https://old.example.com/",
|
||||
"https://old2.example.com/",
|
||||
]
|
||||
system { hostname = "test" }
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "flat remotes still parse" \
|
||||
"$KAPPA parse-config $TMPDIR/remotes-config.kap" \
|
||||
'valid'
|
||||
|
||||
check "format remotes roundtrip" \
|
||||
"$KAPPA format $TMPDIR/remotes-config.kap" \
|
||||
'remotes = \['
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Index: generation and validation ==="
|
||||
echo ""
|
||||
|
||||
check "kappa index generates index.kap" \
|
||||
"$KAPPA index $TMPDIR" \
|
||||
'packages indexed'
|
||||
|
||||
check "validate index.kap" \
|
||||
"$KAPPA validate $TMPDIR/index.kap" \
|
||||
'valid index'
|
||||
|
||||
check "format index roundtrip" \
|
||||
"$KAPPA format $TMPDIR/index.kap" \
|
||||
'index "'
|
||||
|
||||
check_fail "index needs directory arg" \
|
||||
"$KAPPA index" \
|
||||
'no directory'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Package operations: add and remove ==="
|
||||
echo ""
|
||||
|
||||
rm -f "$KAPPA_ROOT/system/config.kap"
|
||||
|
||||
check "add creates config" \
|
||||
"$KAPPA add newpkg" \
|
||||
'added newpkg'
|
||||
|
||||
check "add with version" \
|
||||
"$KAPPA add verpkg 2.0" \
|
||||
'added verpkg 2.0'
|
||||
|
||||
check "add existing updates version" \
|
||||
"$KAPPA add newpkg 3.0" \
|
||||
'updated newpkg'
|
||||
|
||||
check "add existing idempotent" \
|
||||
"$KAPPA add verpkg" \
|
||||
'already in packages'
|
||||
|
||||
check "remove package" \
|
||||
"$KAPPA remove verpkg" \
|
||||
'removed verpkg'
|
||||
|
||||
check "remove nonexistent idempotent" \
|
||||
"$KAPPA remove nonexistent" \
|
||||
'not in packages'
|
||||
|
||||
check_fail "add needs name" \
|
||||
"$KAPPA add" \
|
||||
'no package name'
|
||||
|
||||
check_fail "remove needs name" \
|
||||
"$KAPPA remove" \
|
||||
'no package name'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Install: list and rollback ==="
|
||||
echo ""
|
||||
|
||||
check "list empty" \
|
||||
"$KAPPA list" \
|
||||
'no packages installed'
|
||||
|
||||
mkdir -p "$KAPPA_ROOT/db"
|
||||
cat > "$KAPPA_ROOT/db/installed" << 'EOF'
|
||||
testpkg 1.0 a1b2c3d4e5f6a7b8
|
||||
otherpkg 2.0 b2c3d4e5f6a7b8c9 libother.so
|
||||
EOF
|
||||
|
||||
check "list shows installed" \
|
||||
"$KAPPA list" \
|
||||
'2 packages installed'
|
||||
|
||||
check "list shows provides" \
|
||||
"$KAPPA list" \
|
||||
'libother.so'
|
||||
|
||||
mkdir -p "$KAPPA_ROOT/db/generations"
|
||||
echo "a1b2c3d4e5f6a7b8" > "$KAPPA_ROOT/db/generations/gen-0001"
|
||||
echo "b2c3d4e5f6a7b8c9" > "$KAPPA_ROOT/db/generations/gen-0002"
|
||||
|
||||
check "rollback shows generations" \
|
||||
"$KAPPA rollback" \
|
||||
'2 generations'
|
||||
|
||||
check "rollback shows gen IDs" \
|
||||
"$KAPPA rollback" \
|
||||
'gen-0001'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Resolver: conflicts ==="
|
||||
echo ""
|
||||
|
||||
mkdir -p "$KAPPA_ROOT/cache/packages"
|
||||
|
||||
cat > "$KAPPA_ROOT/cache/packages/a.kap" << 'KAPEOF'
|
||||
package "a" {
|
||||
version = "1.0"
|
||||
source = "a.tar.gz"
|
||||
conflicts = ["b"]
|
||||
build { echo a }
|
||||
install { echo a > ${destdir}/tmp/a }
|
||||
}
|
||||
KAPEOF
|
||||
cat > "$KAPPA_ROOT/cache/packages/b.kap" << 'KAPEOF'
|
||||
package "b" {
|
||||
version = "1.0"
|
||||
source = "b.tar.gz"
|
||||
conflicts = ["a"]
|
||||
build { echo b }
|
||||
install { echo b > ${destdir}/tmp/b }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
cat > "$TMPDIR/conflict-config.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
packages { a {} b {} }
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check_fail "resolve catches conflicts" \
|
||||
"$KAPPA resolve $TMPDIR/conflict-config.kap" \
|
||||
'conflicts detected'
|
||||
|
||||
check_fail "rebuild catches conflicts" \
|
||||
"$KAPPA rebuild $TMPDIR/conflict-config.kap" \
|
||||
'conflicts detected'
|
||||
|
||||
cat > "$TMPDIR/missing-config.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
packages { nonexistent {} }
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "resolve warns on missing" \
|
||||
"$KAPPA resolve $TMPDIR/missing-config.kap 2>&1" \
|
||||
'not found in registry'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Scheduler: deptree ordering ==="
|
||||
echo ""
|
||||
|
||||
cat > "$KAPPA_ROOT/cache/packages/dep-a.kap" << 'KAPEOF'
|
||||
package "dep-a" {
|
||||
version = "1.0"
|
||||
source = "a.tar.gz"
|
||||
build { echo a }
|
||||
install { echo a > ${destdir}/tmp/a }
|
||||
}
|
||||
KAPEOF
|
||||
cat > "$KAPPA_ROOT/cache/packages/dep-b.kap" << 'KAPEOF'
|
||||
package "dep-b" {
|
||||
version = "1.0"
|
||||
source = "b.tar.gz"
|
||||
depends = [{ name = "dep-a" }]
|
||||
build { echo b }
|
||||
install { echo b > ${destdir}/tmp/b }
|
||||
}
|
||||
KAPEOF
|
||||
cat > "$KAPPA_ROOT/cache/packages/dep-c.kap" << 'KAPEOF'
|
||||
package "dep-c" {
|
||||
version = "1.0"
|
||||
source = "c.tar.gz"
|
||||
depends = [{ name = "dep-b" }]
|
||||
build { echo c }
|
||||
install { echo c > ${destdir}/tmp/c }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
cat > "$TMPDIR/deptree-config.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
packages { dep-a {} dep-b {} dep-c {} }
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "resolve deptree (a=0 deps)" \
|
||||
"$KAPPA resolve $TMPDIR/deptree-config.kap 2>&1" \
|
||||
'dep-a (0 deps)'
|
||||
|
||||
check "resolve deptree (c has dep)" \
|
||||
"$KAPPA resolve $TMPDIR/deptree-config.kap 2>&1" \
|
||||
'dep-c (1 deps)'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Build: simple execution ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/simple-build.kap" << 'KAPEOF'
|
||||
package "simple" {
|
||||
version = "1.0"
|
||||
source = "simple-1.0.tar.gz"
|
||||
sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
license = "MIT"
|
||||
build { echo built }
|
||||
check { echo checked }
|
||||
install {
|
||||
mkdir -p ${destdir}/tmp
|
||||
echo done > ${destdir}/tmp/simple
|
||||
}
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "build simple package" \
|
||||
"$KAPPA build $TMPDIR/simple-build.kap" \
|
||||
'build successful'
|
||||
|
||||
check "installed after build" \
|
||||
"$KAPPA list" \
|
||||
'simple'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Build: error handling ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/fail-build.kap" << 'KAPEOF'
|
||||
package "failpkg" {
|
||||
version = "1.0"
|
||||
source = "fail.tar.gz"
|
||||
sha256 = "abc"
|
||||
license = "MIT"
|
||||
build { exit 42 }
|
||||
install { echo ok }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check_fail "build reports exit code" \
|
||||
"$KAPPA build $TMPDIR/fail-build.kap" \
|
||||
'exited with code 42'
|
||||
|
||||
check_fail "build reports failed phase" \
|
||||
"$KAPPA build $TMPDIR/fail-build.kap" \
|
||||
'build'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Build: env operators ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/env-ops.kap" << 'KAPEOF'
|
||||
package "envops" {
|
||||
version = "1.0"
|
||||
source = "envops.tar.gz"
|
||||
sha256 = "abc"
|
||||
license = "MIT"
|
||||
env {
|
||||
FLAGS = "base"
|
||||
FLAGS += "extra"
|
||||
FLAGS ?= "soft"
|
||||
}
|
||||
build { echo ok }
|
||||
install { mkdir -p ${destdir}/tmp }
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "format shows env =" \
|
||||
"$KAPPA format $TMPDIR/env-ops.kap" \
|
||||
'FLAGS = "base"'
|
||||
|
||||
check "format shows env +=" \
|
||||
"$KAPPA format $TMPDIR/env-ops.kap" \
|
||||
'FLAGS += "extra"'
|
||||
|
||||
check "format shows env ?=" \
|
||||
"$KAPPA format $TMPDIR/env-ops.kap" \
|
||||
'FLAGS ?= "soft"'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Init systems: all 5 recognized ==="
|
||||
echo ""
|
||||
|
||||
for init in systemd openrc s6 runit dinit; do
|
||||
cat > "$TMPDIR/init-$init.kap" << KAPEOF
|
||||
system { hostname = "test" }
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "$init"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
users {
|
||||
root { shell = "/bin/sh" }
|
||||
}
|
||||
KAPEOF
|
||||
check "parse-config recognizes $init" \
|
||||
"$KAPPA parse-config $TMPDIR/init-$init.kap" \
|
||||
'valid'
|
||||
done
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Bootloaders: both recognized ==="
|
||||
echo ""
|
||||
|
||||
for bl in grub limine; do
|
||||
cat > "$TMPDIR/bl-$bl.kap" << KAPEOF
|
||||
system { hostname = "test" }
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "$bl"
|
||||
}
|
||||
users {
|
||||
root { shell = "/bin/sh" }
|
||||
}
|
||||
KAPEOF
|
||||
check "parse-config recognizes $bl" \
|
||||
"$KAPPA parse-config $TMPDIR/bl-$bl.kap" \
|
||||
'valid'
|
||||
done
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Variable interpolation: format preserves ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/vars.kap" << 'KAPEOF'
|
||||
package "vars" {
|
||||
version = "1.0"
|
||||
source = "https://example.com/vars-1.0.tar.gz"
|
||||
sha256 = "abc"
|
||||
license = "MIT"
|
||||
build {
|
||||
./configure --prefix=${prefix}
|
||||
make -j${jobs}
|
||||
}
|
||||
install {
|
||||
make DESTDIR=${destdir} install
|
||||
}
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "format preserves prefix var" \
|
||||
"$KAPPA format $TMPDIR/vars.kap" \
|
||||
'prefix=${prefix}'
|
||||
|
||||
check "format preserves jobs var" \
|
||||
"$KAPPA format $TMPDIR/vars.kap" \
|
||||
'j${jobs}'
|
||||
|
||||
check "format preserves destdir var" \
|
||||
"$KAPPA format $TMPDIR/vars.kap" \
|
||||
'DESTDIR=${destdir}'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Paths: --root override ==="
|
||||
echo ""
|
||||
|
||||
ALTROOT="$TMPDIR/altroot"
|
||||
mkdir -p "$ALTROOT/system"
|
||||
|
||||
cat > "$ALTROOT/system/config.kap" << 'KAPEOF'
|
||||
system { hostname = "alt" }
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "--root flag works" \
|
||||
"$KAPPA --root $ALTROOT parse-config $ALTROOT/system/config.kap" \
|
||||
'valid'
|
||||
|
||||
$KAPPA --root "$ALTROOT" add rootpkg 2>/dev/null
|
||||
check "verify add wrote to alt root" \
|
||||
"grep -c rootpkg $ALTROOT/system/config.kap" \
|
||||
'1'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Config: rollback config ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/rollback-cfg.kap" << 'KAPEOF'
|
||||
system {
|
||||
hostname = "test"
|
||||
rollback {
|
||||
keep = 3
|
||||
}
|
||||
}
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "format preserves rollback keep" \
|
||||
"$KAPPA format $TMPDIR/rollback-cfg.kap" \
|
||||
'keep = 3'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Config: system env block ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/sysenv-config.kap" << 'KAPEOF'
|
||||
system {
|
||||
hostname = "test"
|
||||
env {
|
||||
CFLAGS = "-O2"
|
||||
CFLAGS += "-pipe"
|
||||
}
|
||||
}
|
||||
packages {}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "parse-config with system env" \
|
||||
"$KAPPA parse-config $TMPDIR/sysenv-config.kap" \
|
||||
'valid'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== DSL: feature flags ==="
|
||||
echo ""
|
||||
|
||||
cat > "$TMPDIR/features-config.kap" << 'KAPEOF'
|
||||
system {
|
||||
hostname = "test"
|
||||
features {
|
||||
ssl = true
|
||||
wayland = false
|
||||
}
|
||||
}
|
||||
packages {
|
||||
testpkg {
|
||||
features {
|
||||
debug = true
|
||||
}
|
||||
}
|
||||
}
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "parse-config with features" \
|
||||
"$KAPPA parse-config $TMPDIR/features-config.kap" \
|
||||
'valid'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=== Rebuild: dry-run detection ==="
|
||||
echo ""
|
||||
|
||||
# Package must be in registry + installed DB for rebuild
|
||||
cp "$TMPDIR/basic.kap" "$KAPPA_ROOT/cache/packages/testpkg.kap"
|
||||
mkdir -p "$KAPPA_ROOT/db"
|
||||
echo "testpkg 1.0 0000000000000000" > "$KAPPA_ROOT/db/installed"
|
||||
|
||||
cat > "$TMPDIR/rebuild-config.kap" << 'KAPEOF'
|
||||
system { hostname = "test" }
|
||||
packages { testpkg {} }
|
||||
services {}
|
||||
boot {
|
||||
kernel = "linux"
|
||||
init = "s6"
|
||||
root = "/dev/sda1"
|
||||
bootloader = "limine"
|
||||
}
|
||||
KAPEOF
|
||||
|
||||
check "rebuild dry-run detects changes" \
|
||||
"$KAPPA rebuild --dry-run $TMPDIR/rebuild-config.kap 2>&1" \
|
||||
'nothing to rebuild'
|
||||
|
||||
check "resolve shows build plan" \
|
||||
"$KAPPA resolve $TMPDIR/rebuild-config.kap 2>&1" \
|
||||
'packages in build order'
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " Results: $PASS passed, $FAIL failed"
|
||||
echo "=========================================="
|
||||
|
||||
[ "$FAIL" -eq 0 ] || exit 1
|
||||
Reference in New Issue
Block a user