Add test-all.sh runner; fix bootstrap idempotency flake and test isolation
- test-all.sh: single entry point running all four test suites (51 checks), non-zero exit on any failure, --verbose shows failing suite output. - repo-bootstrap.sh: write_meta now compares stable fields excluding the second-resolution generated_at timestamp, so two runs straddling a second boundary no longer rewrite .bootstrap-meta (T02 idempotency flake fixed). - test-integration.sh: pre-clean memory residue before I01/I02 so checks are independent of prior interrupted-run state. - README.md: document test-all.sh as the top-level test entry point.
This commit is contained in:
@@ -95,9 +95,11 @@ dev_agent_team/
|
||||
│ ├── install.sh # one-command installer
|
||||
│ ├── repo-bootstrap.sh # repository intelligence bootstrap tool
|
||||
│ ├── memory-lifecycle.sh # memory CRUD operations
|
||||
│ ├── test-all.sh # single entry point that runs all test suites
|
||||
│ ├── test-repo-bootstrap.sh # test suite for the bootstrap
|
||||
│ ├── test-agent-architecture.sh # structural tests for the agent architecture
|
||||
│ ├── test-memory-system.sh # structural tests for memory/skills/improvements
|
||||
│ ├── test-integration.sh # end-to-end memory/skills/lifecycle integration tests
|
||||
│ └── verify-permission-patterns.sh # permission engine verifier
|
||||
└── docs/
|
||||
├── PROMPT_INSTALL.md # paste-ready prompt for installing from inside opencode
|
||||
@@ -136,15 +138,25 @@ repo-bootstrap.sh bootstrap
|
||||
repo-bootstrap.sh refresh
|
||||
```
|
||||
|
||||
Run `bash scripts/test-repo-bootstrap.sh` to verify bootstrap behavior
|
||||
(11 tests covering all 10 acceptance criteria).
|
||||
Run all test suites with a single command (aggregates the four suites below):
|
||||
|
||||
Run `bash scripts/test-agent-architecture.sh` to verify the agent architecture
|
||||
contains the required adaptive/evidence-driven elements
|
||||
(16 structural tests).
|
||||
```bash
|
||||
bash scripts/test-all.sh
|
||||
```
|
||||
|
||||
Run `bash scripts/test-memory-system.sh` to verify the memory, skills, and
|
||||
improvement systems are structurally sound (12 tests).
|
||||
51 individual checks across 4 suites (16 architecture + 12 memory + 11 bootstrap
|
||||
+ 12 integration). Any suite failing makes the overall exit code non-zero.
|
||||
|
||||
Individual suites:
|
||||
|
||||
- `test-agent-architecture.sh` — architecture contains the required
|
||||
adaptive/evidence-driven elements (16 structural tests).
|
||||
- `test-memory-system.sh` — memory, skills, and improvement systems are
|
||||
structurally sound (12 tests).
|
||||
- `test-repo-bootstrap.sh` — bootstrap behavior and idempotency
|
||||
(11 tests covering all 10 acceptance criteria).
|
||||
- `test-integration.sh` — end-to-end memory/skills/improvements integration
|
||||
(12 tests).
|
||||
|
||||
## Manual install alternative
|
||||
|
||||
|
||||
@@ -421,22 +421,28 @@ write_meta() { # write_meta <root>
|
||||
local root="$1"
|
||||
mkdir -p "$root/.opencode"
|
||||
current_fingerprint "$root"
|
||||
local new_meta
|
||||
new_meta="$(printf '%s\n' \
|
||||
# Compare only the stable fields (excluding generated_at) so a second run in an
|
||||
# unchanged repo is a true no-op — even across a second boundary — and the
|
||||
# original timestamp is preserved. Without this, idempotency flakes whenever
|
||||
# two runs straddle a second boundary (generated_at would otherwise differ).
|
||||
local stable
|
||||
stable="$(printf '%s\n' \
|
||||
"schema=1" \
|
||||
"tool=dev_agent_team-repo-bootstrap" \
|
||||
"version=$VERSION" \
|
||||
"generated_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
"git_head=$GIT_HEAD" \
|
||||
"manifest_fingerprint=$MANIFEST_FP" \
|
||||
"top_level_fingerprint=$TOPLEVEL_FP" \
|
||||
"signals=$SIGNAL_TXT")"
|
||||
# Idempotent: skip rewrite if content is identical (preserves timestamp).
|
||||
local existing=""
|
||||
local existing="" existing_stable=""
|
||||
[ -f "$root/.opencode/$META_FILE" ] && existing="$(cat "$root/.opencode/$META_FILE")"
|
||||
if [ "$existing" = "$new_meta" ]; then
|
||||
[ -n "$existing" ] && existing_stable="$(printf '%s\n' "$existing" | grep -v '^generated_at=' || true)"
|
||||
if [ "$existing_stable" = "$stable" ]; then
|
||||
return 0
|
||||
fi
|
||||
local new_meta
|
||||
new_meta="$(printf '%s\n' "$stable" \
|
||||
"generated_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)")"
|
||||
printf '%s\n' "$new_meta" > "$root/.opencode/$META_FILE"
|
||||
}
|
||||
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# test-all.sh — Run every test suite in the repo and report a combined result.
|
||||
#
|
||||
# bash scripts/test-all.sh
|
||||
#
|
||||
# Exit code: 0 if all suites pass, non-zero if any suite fails.
|
||||
# Optional: pass --verbose to show each suite's full output on failure.
|
||||
|
||||
set -uo pipefail
|
||||
TEAM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
VERBOSE=0
|
||||
[ "${1:-}" = "--verbose" ] && VERBOSE=1
|
||||
|
||||
SUITES=(test-agent-architecture test-memory-system test-repo-bootstrap test-integration)
|
||||
|
||||
BOLD=""
|
||||
RESET=""
|
||||
if [ -t 1 ]; then
|
||||
BOLD="\033[1m"
|
||||
RESET="\033[0m"
|
||||
fi
|
||||
|
||||
pass=0; fail=0
|
||||
printf "${BOLD}=== Agent Team: full test run ===${RESET}\n\n"
|
||||
|
||||
for s in "${SUITES[@]}"; do
|
||||
script="$TEAM_ROOT/scripts/$s.sh"
|
||||
if [ ! -f "$script" ]; then
|
||||
printf " %-28s ${BOLD}MISSING${RESET}\n" "$s"
|
||||
fail=$((fail + 1))
|
||||
continue
|
||||
fi
|
||||
out="$(bash "$script" 2>&1)"
|
||||
rc=$?
|
||||
|
||||
# Count individual PASS/FAIL lines (uniform format: "PASS T01 ..." / "PASS I01 ...";
|
||||
# excludes the summary lines that also start with "PASS:"/"FAIL:").
|
||||
npass="$(printf '%s\n' "$out" | grep -cE '^PASS [TI]' || true)"
|
||||
nfail="$(printf '%s\n' "$out" | grep -cE '^FAIL [TI]' || true)"
|
||||
|
||||
if [ "$rc" = "0" ]; then
|
||||
printf " %-28s ${BOLD}PASS${RESET} (%s checks)\n" "$s" "$npass"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
printf " %-28s ${BOLD}FAIL${RESET} (%s check(s) failed)\n" "$s" "$nfail"
|
||||
fail=$((fail + 1))
|
||||
if [ "$VERBOSE" = "1" ]; then
|
||||
printf '\n--- %s output ---\n%s\n--------------------------\n' "$s" "$out"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
printf '\n%s=== RESULT ===%s\n' "$BOLD" "$RESET"
|
||||
printf 'suites passed: %d suites failed: %d (total %d suites)\n' \
|
||||
"$pass" "$fail" "${#SUITES[@]}"
|
||||
|
||||
if [ "$fail" = "0" ]; then
|
||||
printf 'ALL SUITES PASS\n'
|
||||
exit 0
|
||||
else
|
||||
printf 'FAILURES PRESENT\n'
|
||||
exit 1
|
||||
fi
|
||||
@@ -56,6 +56,10 @@ SC_OK=0
|
||||
# into `grep -q`. grep -q closes the pipe early (SIGPIPE, rc=141), which fails
|
||||
# the pipeline under `pipefail`.
|
||||
STORE_OK=0
|
||||
# Test isolation: remove any residue a previous interrupted/crashed run may have
|
||||
# left behind before storing. Writing a fresh entry makes the check independent
|
||||
# of the memory directory's pre-existing state.
|
||||
rm -f "$MEMORY/lessons/"*integration-test* 2>/dev/null || true
|
||||
if bash "$LS" store lessons "$LESSON_FILE" >/dev/null 2>&1; then
|
||||
STORE_OK=1
|
||||
fi
|
||||
@@ -80,6 +84,8 @@ fi
|
||||
# TEST I02: Session lifecycle — create, list, cleanup
|
||||
# ======================================================================== #
|
||||
Sess="$MEMORY/sessions/2026-09-08_integration-session-test.md"
|
||||
# Test isolation: remove any residue a previous interrupted/crashed run left.
|
||||
rm -f "$Sess" 2>/dev/null || true
|
||||
printf -- '%s\n' "Status: active" "# Integration session test" "## State" "in progress" > "$Sess"
|
||||
SESS_OUT="$(bash "$LS" sessions 2>&1 || true)"
|
||||
SESS_OK=0
|
||||
|
||||
Reference in New Issue
Block a user