11/**
2- * Test runner — executes all phases in order and prints combined summary .
2+ * Test runner — fully autonomous, starts/stops servers as needed .
33 *
44 * Usage:
5- * npx tsx tests/run-all.ts # run all phases
6- * npx tsx tests/run-all.ts --phase 1 3 # run specific phases
7- * npx tsx tests/run-all.ts --phase 10 11 # run auth + oauth only
5+ * npx tsx tests/run-all.ts # run all 18 phases
6+ * npx tsx tests/run-all.ts --phase 1 3 # run specific phases
7+ * npx tsx tests/run-all.ts --phase 10 # run auth only
88 *
9- * Phases 1-9 require a running server on port 3737 (default sandbox).
10- * Phases 10-18 start/stop their own servers with different configs.
9+ * Lifecycle:
10+ * Phases 1-9: share one sandbox server (port 3737) — started once, stopped after phase 9
11+ * Phases 10-18: each starts/stops its own server with a dedicated config
1112 */
1213
13- import { PhaseResult , printSummary } from './utils' ;
14+ import { PhaseResult , printSummary , startServer , stopServer } from './utils' ;
15+
16+ // ─── Phase registry ──────────────────────────────────────────────
17+
18+ interface PhaseEntry {
19+ id : number ;
20+ file : string ;
21+ group : 'sandbox' | 'self' ; // sandbox = needs shared server, self = manages own
22+ }
23+
24+ const PHASES : PhaseEntry [ ] = [
25+ { id : 1 , file : './01-server-indexing' , group : 'sandbox' } ,
26+ { id : 2 , file : './02-knowledge' , group : 'sandbox' } ,
27+ { id : 3 , file : './03-tasks' , group : 'sandbox' } ,
28+ { id : 4 , file : './04-epics' , group : 'sandbox' } ,
29+ { id : 5 , file : './05-skills' , group : 'sandbox' } ,
30+ { id : 6 , file : './06-auth-oauth' , group : 'sandbox' } ,
31+ { id : 7 , file : './07-embedding' , group : 'sandbox' } ,
32+ { id : 8 , file : './08-edge-cases' , group : 'sandbox' } ,
33+ { id : 9 , file : './09-db-filesystem' , group : 'sandbox' } ,
34+ { id : 10 , file : './10-auth' , group : 'self' } ,
35+ { id : 11 , file : './11-oauth' , group : 'self' } ,
36+ { id : 12 , file : './12-embedding-api' , group : 'self' } ,
37+ { id : 13 , file : './13-websocket' , group : 'self' } ,
38+ { id : 14 , file : './14-watcher' , group : 'self' } ,
39+ { id : 15 , file : './15-workspace' , group : 'self' } ,
40+ { id : 16 , file : './16-ratelimit' , group : 'self' } ,
41+ { id : 17 , file : './17-concurrent' , group : 'self' } ,
42+ { id : 18 , file : './18-mirror-import' , group : 'self' } ,
43+ ] ;
44+
45+ // ─── Main ────────────────────────────────────────────────────────
1446
1547async function main ( ) {
1648 const args = process . argv . slice ( 2 ) ;
@@ -27,100 +59,35 @@ async function main() {
2759
2860 const shouldRun = ( n : number ) => phaseFilter . size === 0 || phaseFilter . has ( n ) ;
2961 const results : PhaseResult [ ] = [ ] ;
62+ const startTime = Date . now ( ) ;
63+
64+ // ── Sandbox phases (1-9): shared server ──────────────────────
65+ const sandboxPhases = PHASES . filter ( p => p . group === 'sandbox' && shouldRun ( p . id ) ) ;
66+ if ( sandboxPhases . length > 0 ) {
67+ console . log ( '\n Starting sandbox server (port 3737)...' ) ;
68+ await startServer ( { config : 'graph-memory.yaml' , port : 3737 } ) ;
69+ console . log ( ' Server ready.\n' ) ;
70+
71+ for ( const phase of sandboxPhases ) {
72+ const { run } = require ( phase . file ) ;
73+ results . push ( await run ( ) ) ;
74+ }
3075
31- // Phases 1-9: require external server on port 3737
32- if ( shouldRun ( 1 ) ) {
33- const { run } = require ( './01-server-indexing' ) ;
34- results . push ( await run ( ) ) ;
35- }
36-
37- if ( shouldRun ( 2 ) ) {
38- const { run } = require ( './02-knowledge' ) ;
39- results . push ( await run ( ) ) ;
40- }
41-
42- if ( shouldRun ( 3 ) ) {
43- const { run } = require ( './03-tasks' ) ;
44- results . push ( await run ( ) ) ;
45- }
46-
47- if ( shouldRun ( 4 ) ) {
48- const { run } = require ( './04-epics' ) ;
49- results . push ( await run ( ) ) ;
50- }
51-
52- if ( shouldRun ( 5 ) ) {
53- const { run } = require ( './05-skills' ) ;
54- results . push ( await run ( ) ) ;
55- }
56-
57- if ( shouldRun ( 6 ) ) {
58- const { run } = require ( './06-auth-oauth' ) ;
59- results . push ( await run ( ) ) ;
60- }
61-
62- if ( shouldRun ( 7 ) ) {
63- const { run } = require ( './07-embedding' ) ;
64- results . push ( await run ( ) ) ;
65- }
66-
67- if ( shouldRun ( 8 ) ) {
68- const { run } = require ( './08-edge-cases' ) ;
69- results . push ( await run ( ) ) ;
70- }
71-
72- if ( shouldRun ( 9 ) ) {
73- const { run } = require ( './09-db-filesystem' ) ;
74- results . push ( await run ( ) ) ;
75- }
76-
77- // Phases 10-18: self-contained (start/stop own servers)
78- if ( shouldRun ( 10 ) ) {
79- const { run } = require ( './10-auth' ) ;
80- results . push ( await run ( ) ) ;
81- }
82-
83- if ( shouldRun ( 11 ) ) {
84- const { run } = require ( './11-oauth' ) ;
85- results . push ( await run ( ) ) ;
86- }
87-
88- if ( shouldRun ( 12 ) ) {
89- const { run } = require ( './12-embedding-api' ) ;
90- results . push ( await run ( ) ) ;
91- }
92-
93- if ( shouldRun ( 13 ) ) {
94- const { run } = require ( './13-websocket' ) ;
95- results . push ( await run ( ) ) ;
96- }
97-
98- if ( shouldRun ( 14 ) ) {
99- const { run } = require ( './14-watcher' ) ;
100- results . push ( await run ( ) ) ;
101- }
102-
103- if ( shouldRun ( 15 ) ) {
104- const { run } = require ( './15-workspace' ) ;
105- results . push ( await run ( ) ) ;
106- }
107-
108- if ( shouldRun ( 16 ) ) {
109- const { run } = require ( './16-ratelimit' ) ;
110- results . push ( await run ( ) ) ;
111- }
112-
113- if ( shouldRun ( 17 ) ) {
114- const { run } = require ( './17-concurrent' ) ;
115- results . push ( await run ( ) ) ;
76+ stopServer ( ) ;
77+ console . log ( '\n Sandbox server stopped.\n' ) ;
11678 }
11779
118- if ( shouldRun ( 18 ) ) {
119- const { run } = require ( './18-mirror-import' ) ;
80+ // ── Self-contained phases (10-18): each manages own server ───
81+ const selfPhases = PHASES . filter ( p => p . group === 'self' && shouldRun ( p . id ) ) ;
82+ for ( const phase of selfPhases ) {
83+ const { run } = require ( phase . file ) ;
12084 results . push ( await run ( ) ) ;
12185 }
12286
87+ // ── Summary ──────────────────────────────────────────────────
88+ const elapsed = ( ( Date . now ( ) - startTime ) / 1000 ) . toFixed ( 1 ) ;
12389 printSummary ( results ) ;
90+ console . log ( ` Duration: ${ elapsed } s\n` ) ;
12491
12592 const hasFails = results . some ( r =>
12693 r . groups . some ( g => g . tests . some ( t => ! t . passed ) ) ,
0 commit comments