11import axios from 'axios' ;
2- import { spawn , spawnSync } from 'node:child_process' ;
2+ import { spawnSync } from 'node:child_process' ;
33import { randomUUID } from 'node:crypto' ;
4- import { readFileSync , writeFileSync } from 'node:fs ' ;
4+ import { resolve as pathResolve } from 'node:path ' ;
55import { Agent } from 'node:https' ;
66import * as semver from 'semver' ;
77
@@ -31,49 +31,65 @@ httpClient.interceptors.request.use(
3131 ( error ) => Promise . reject ( error ) ,
3232) ;
3333
34- const setupAPI7 = async ( ) => {
35- return new Promise < void > ( ( resolve , reject ) => {
36- const download = spawnSync (
37- 'sh' ,
38- [
39- '-c' ,
40- `curl -O ${ process . env . BACKEND_API7_DOWNLOAD_URL } && tar xf api7-ee-*.tar.gz` ,
41- ] ,
42- { cwd : `/tmp` } ,
43- ) ;
34+ const assetsDir = pathResolve ( __dirname , '../../e2e/assets' ) ;
35+
36+ const waitForDashboard = async (
37+ maxRetries = 60 ,
38+ intervalMs = 2000 ,
39+ ) : Promise < void > => {
40+ console . log ( 'Waiting for Dashboard to be ready...' ) ;
41+ for ( let i = 0 ; i < maxRetries ; i ++ ) {
42+ try {
43+ await httpClient . get ( '/api/status' , { timeout : 2000 } ) ;
44+ console . log ( 'Dashboard is ready' ) ;
45+ return ;
46+ } catch {
47+ // Also try login endpoint as a fallback health check
48+ try {
49+ await httpClient . post (
50+ '/api/login' ,
51+ { username : '' , password : '' } ,
52+ { timeout : 2000 , validateStatus : ( ) => true } ,
53+ ) ;
54+ console . log ( 'Dashboard is ready' ) ;
55+ return ;
56+ } catch {
57+ // not ready yet
58+ }
59+ }
60+ await new Promise ( ( r ) => setTimeout ( r , intervalMs ) ) ;
61+ }
62+ throw new Error (
63+ `Dashboard not ready after ${ maxRetries * intervalMs / 1000 } s` ,
64+ ) ;
65+ } ;
4466
45- console . log ( 'stdout: ' + download . stdout . toString ( 'utf-8' ) ) ;
46- console . log ( 'stderr: ' + download . stderr . toString ( 'utf-8' ) ) ;
67+ const runCompose = ( ...args : string [ ] ) => {
68+ const result = spawnSync ( 'docker' , [ 'compose' , ...args ] , {
69+ cwd : assetsDir ,
70+ stdio : 'inherit' ,
71+ } ) ;
4772
48- const dockerComposePath = `/tmp/api7-ee/docker-compose.yaml` ;
49- const dockerCompose = readFileSync ( dockerComposePath , 'utf-8' ) . replaceAll (
50- ': bitnami/' ,
51- ': bitnamilegacy/' ,
73+ if ( result . error ) throw result . error ;
74+ if ( result . signal )
75+ throw new Error (
76+ `docker compose ${ args . join ( ' ' ) } terminated by signal ${ result . signal } ` ,
5277 ) ;
53- writeFileSync ( dockerComposePath , dockerCompose , 'utf-8' ) ;
54-
55- const setup = spawn ( 'sh' , [ '-c' , `cd api7-ee && bash run.sh start` ] , {
56- cwd : `/tmp` ,
57- } ) ;
58-
59- console . log ( '\nSetup API7 Instance\n' ) ;
60-
61- setup . stdout . on ( 'data' , function ( data ) {
62- console . log ( 'stdout: ' + data . toString ( ) ) ;
63- } ) ;
64-
65- setup . stderr . on ( 'data' , function ( data ) {
66- console . log ( 'stderr: ' + data . toString ( ) ) ;
67- } ) ;
78+ if ( result . status !== 0 )
79+ throw new Error (
80+ `docker compose ${ args . join ( ' ' ) } failed with code ${ result . status } ` ,
81+ ) ;
82+ } ;
6883
69- setup . on ( 'exit' , function ( code ) {
70- if ( code )
71- reject ( `child process exited with non-zero code: ${ code ?. toString ( ) } ` ) ;
84+ const setupAPI7 = async ( ) => {
85+ console . log ( '\nSetup API7 Instance via Docker Compose\n' ) ;
86+ if ( process . env . API7_IMAGE_TAG === 'dev' ) {
87+ runCompose ( 'pull' ) ;
88+ }
89+ runCompose ( 'up' , '-d' ) ;
7290
73- console . log ( 'Successful deployment' ) ;
74- resolve ( ) ;
75- } ) ;
76- } ) ;
91+ console . log ( 'Docker Compose started' ) ;
92+ await waitForDashboard ( ) ;
7793} ;
7894
7995const initUser = async (
@@ -162,7 +178,7 @@ const generateToken = async () => {
162178 process . env . TOKEN = resp . data . value . token ;
163179} ;
164180
165- export default async ( ) => {
181+ export async function setup ( ) {
166182 if ( process . env [ 'SKIP_API7_SETUP' ] !== 'true' ) await setupAPI7 ( ) ;
167183 try {
168184 await initUser ( ) ;
@@ -181,4 +197,14 @@ export default async () => {
181197 process.env.GATEWAY_GROUP = 'adc';
182198 process.env.BACKEND_API7_VERSION = '0.0.0'; */
183199 // ONLY FOR LOCAL TEST //
184- } ;
200+ }
201+
202+ export async function teardown ( ) {
203+ if ( process . env [ 'SKIP_API7_SETUP' ] === 'true' ) return ;
204+ console . log ( 'Tearing down API7 via Docker Compose' ) ;
205+ try {
206+ runCompose ( 'down' , '-v' ) ;
207+ } catch ( err ) {
208+ console . error ( 'Teardown failed:' , err ) ;
209+ }
210+ }
0 commit comments