1+ import { join } from 'node:path' ;
2+ import { mkdir } from 'node:fs/promises' ;
13import { findAvailablePort } from '../test-helpers/findAvailablePort.mts' ;
4+ import { makeTestTempDir } from '../test-helpers/makeFileStructure.mts' ;
25import type { ConfigServer } from './config/types.mts' ;
36import type { AddColour } from './log.mts' ;
47import { ServerManager } from './ServerManager.mts' ;
@@ -11,7 +14,7 @@ describe('ServerManager', () => {
1114 const logs : string [ ] = [ ] ;
1215 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
1316 try {
14- await manager . set ( [ fixtureServer ( port , 'content' ) ] , [ ] ) ;
17+ await manager . set ( [ fixtureServer ( port , 'content' ) ] , [ ] , ( ) => fail ( ) ) ;
1518 expect ( logs ) . equals ( [
1619 `http://localhost:${ port } starting` ,
1720 `http://localhost:${ port } ready` ,
@@ -34,7 +37,11 @@ describe('ServerManager', () => {
3437 const logs : string [ ] = [ ] ;
3538 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
3639 try {
37- await manager . set ( [ fixtureServer ( port1 , 'content 1' ) , fixtureServer ( port2 , 'content 2' ) ] , [ ] ) ;
40+ await manager . set (
41+ [ fixtureServer ( port1 , 'content 1' ) , fixtureServer ( port2 , 'content 2' ) ] ,
42+ [ ] ,
43+ ( ) => fail ( ) ,
44+ ) ;
3845 expect ( logs [ logs . length - 1 ] ) . equals ( 'all servers ready' ) ;
3946
4047 const res1 = await fetch ( `http://localhost:${ port1 } ` ) ;
@@ -53,7 +60,11 @@ describe('ServerManager', () => {
5360 const logs : string [ ] = [ ] ;
5461 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
5562 try {
56- await manager . set ( [ fixtureServer ( port , 'content 1' ) , fixtureServer ( port , 'content 2' ) ] , [ ] ) ;
63+ await manager . set (
64+ [ fixtureServer ( port , 'content 1' ) , fixtureServer ( port , 'content 2' ) ] ,
65+ [ ] ,
66+ ( ) => fail ( ) ,
67+ ) ;
5768 expect ( logs ) . equals ( [
5869 `skipping servers[1] because port ${ port } has already been defined` ,
5970 `http://localhost:${ port } starting` ,
@@ -72,7 +83,11 @@ describe('ServerManager', () => {
7283 const logs : string [ ] = [ ] ;
7384 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
7485 try {
75- await manager . set ( [ fixtureServer ( 0 , 'content 1' ) , fixtureServer ( 65536 , 'content 2' ) ] , [ ] ) ;
86+ await manager . set (
87+ [ fixtureServer ( 0 , 'content 1' ) , fixtureServer ( 65536 , 'content 2' ) ] ,
88+ [ ] ,
89+ ( ) => fail ( ) ,
90+ ) ;
7691 expect ( logs ) . equals ( [
7792 'servers[0] must have a specific port from 1 to 65535' ,
7893 'servers[1] must have a specific port from 1 to 65535' ,
@@ -89,7 +104,7 @@ describe('ServerManager', () => {
89104 const logs : string [ ] = [ ] ;
90105 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
91106 try {
92- await manager . set ( [ fixtureServer ( port , 'content' ) ] , [ ] ) ;
107+ await manager . set ( [ fixtureServer ( port , 'content' ) ] , [ ] , ( ) => fail ( ) ) ;
93108 expect ( logs ) . equals ( [
94109 `http://localhost:${ port } starting` ,
95110 `http://localhost:${ port } ready` ,
@@ -100,7 +115,7 @@ describe('ServerManager', () => {
100115 expect ( await res1 . text ( ) ) . equals ( 'content' ) ;
101116
102117 logs . length = 0 ;
103- await manager . set ( [ fixtureServer ( port , 'updated content' ) ] , [ ] ) ;
118+ await manager . set ( [ fixtureServer ( port , 'updated content' ) ] , [ ] , ( ) => fail ( ) ) ;
104119 expect ( logs ) . equals ( [ `http://localhost:${ port } updated` , 'all servers ready' ] ) ;
105120
106121 const res2 = await fetch ( `http://localhost:${ port } ` ) ;
@@ -116,7 +131,7 @@ describe('ServerManager', () => {
116131 const logs : string [ ] = [ ] ;
117132 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
118133 try {
119- await manager . set ( [ fixtureServer ( port , 'content' ) ] , [ ] ) ;
134+ await manager . set ( [ fixtureServer ( port , 'content' ) ] , [ ] , ( ) => fail ( ) ) ;
120135 expect ( logs ) . equals ( [
121136 `http://localhost:${ port } starting` ,
122137 `http://localhost:${ port } ready` ,
@@ -135,6 +150,7 @@ describe('ServerManager', () => {
135150 } ,
136151 ] ,
137152 [ ] ,
153+ ( ) => fail ( ) ,
138154 ) ;
139155 expect ( logs ) . equals ( [
140156 `http://localhost:${ port } restarting (step 1: shutdown)` ,
@@ -161,6 +177,7 @@ describe('ServerManager', () => {
161177 await manager . set (
162178 [ fixtureServer ( port1 , 'content 1' ) , fixtureServer ( port2 , 'content 2' ) ] ,
163179 [ ] ,
180+ ( ) => fail ( ) ,
164181 ) ;
165182 manager . shutdown ( ) ;
166183 await expect . poll ( ( ) => logs [ logs . length - 1 ] , equals ( 'shutdown complete' ) , {
@@ -180,7 +197,11 @@ describe('ServerManager', () => {
180197 const logs : string [ ] = [ ] ;
181198 const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
182199 try {
183- manager . set ( [ fixtureServer ( port1 , 'content 1' ) , fixtureServer ( port2 , 'content 2' ) ] , [ ] ) ;
200+ manager . set (
201+ [ fixtureServer ( port1 , 'content 1' ) , fixtureServer ( port2 , 'content 2' ) ] ,
202+ [ ] ,
203+ ( ) => fail ( ) ,
204+ ) ;
184205 manager . shutdown ( ) ;
185206 await expect . poll ( ( ) => logs [ logs . length - 1 ] , equals ( 'shutdown complete' ) , {
186207 timeout : 500 ,
@@ -193,6 +214,100 @@ describe('ServerManager', () => {
193214 }
194215 } ) ;
195216 } ) ;
217+
218+ const TEST_DIR = makeTestTempDir ( 'sm-' ) ;
219+
220+ it (
221+ 'retries transient errors if an executable is running' ,
222+ { timeout : 3000 } ,
223+ async ( { getTyped } ) => {
224+ const port = await findAvailablePort ( ) ;
225+
226+ const logs : string [ ] = [ ] ;
227+ const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
228+ try {
229+ await manager . set (
230+ [
231+ {
232+ port,
233+ host : 'localhost' ,
234+ mount : [
235+ { type : 'files' , path : '/' , dir : join ( getTyped ( TEST_DIR ) , 'sub' ) , options : { } } ,
236+ ] ,
237+ options : DEFAULT_SERVER_OPTIONS ,
238+ } ,
239+ ] ,
240+ [
241+ {
242+ command : 'true' ,
243+ arguments : [ ] ,
244+ cwd : '.' ,
245+ environment : { } ,
246+ options : { killSignal : 'SIGTERM' , displayStdout : true , displayStderr : true } ,
247+ } ,
248+ ] ,
249+ ( ) => fail ( ) ,
250+ ) ;
251+ expect ( logs ) . contains ( matches ( / d i r e c t o r y t o s e r v e n o t f o u n d / ) ) ;
252+ expect ( logs ) . not ( contains ( `http://localhost:${ port } ready` ) ) ;
253+ expect ( logs ) . not ( contains ( 'all servers ready' ) ) ;
254+
255+ await mkdir ( join ( getTyped ( TEST_DIR ) , 'sub' ) ) ;
256+
257+ await expect . poll ( ( ) => logs , contains ( 'all servers ready' ) ) ;
258+ expect ( logs ) . contains ( `http://localhost:${ port } ready` ) ;
259+ } finally {
260+ manager . shutdown ( ) ;
261+ }
262+ } ,
263+ ) ;
264+
265+ it (
266+ 'does not retry transient errors if no executables are running' ,
267+ { timeout : 3000 } ,
268+ async ( { getTyped } ) => {
269+ const port = await findAvailablePort ( ) ;
270+
271+ const logs : string [ ] = [ ] ;
272+ const manager = new ServerManager ( ( _ , msg ) => logs . push ( msg ) , NO_COLOUR ) ;
273+ try {
274+ let errorCaptor = ( _ : unknown ) => { } ;
275+ const awaitError = new Promise < unknown > ( ( resolve ) => {
276+ errorCaptor = resolve ;
277+ } ) ;
278+ await manager . set (
279+ [
280+ {
281+ port,
282+ host : 'localhost' ,
283+ mount : [
284+ { type : 'files' , path : '/' , dir : join ( getTyped ( TEST_DIR ) , 'nope' ) , options : { } } ,
285+ ] ,
286+ options : DEFAULT_SERVER_OPTIONS ,
287+ } ,
288+ ] ,
289+ [
290+ {
291+ command : 'true' ,
292+ arguments : [ ] ,
293+ cwd : '.' ,
294+ environment : { } ,
295+ options : { killSignal : 'SIGTERM' , displayStdout : true , displayStderr : true } ,
296+ } ,
297+ ] ,
298+ errorCaptor ,
299+ ) ;
300+ const capturedError = await awaitError ;
301+ expect ( capturedError ) . isInstanceOf ( Error ) ;
302+ expect ( ( capturedError as Error ) . message ) . contains ( 'directory to serve not found' ) ;
303+ expect ( logs ) . contains ( matches ( / d i r e c t o r y t o s e r v e n o t f o u n d / ) ) ;
304+ expect ( logs ) . not ( contains ( `http://localhost:${ port } ready` ) ) ;
305+ expect ( logs ) . not ( contains ( 'all servers ready' ) ) ;
306+ } finally {
307+ manager . shutdown ( ) ;
308+ }
309+ } ,
310+ ) ;
196311} ) ;
197312
198313const NO_COLOUR : AddColour = ( _ , message ) => message ;
0 commit comments