import { expect , skipIf } from '@loopback/testlab' ; import { ChildProcess , fork } from 'child_process' ; const app = require . resolve ( './application-with-shutdown' ) ; const isWindows = process . platform === 'win32' ; describe ( 'Application shutdown hooks' , ( ) => { skipIf ( isWindows , it , 'traps registered signals - SIGTERM' , ( ) => { return testSignal ( 'SIGTERM' ) ; } ) ; skipIf ( isWindows , it , 'traps registered signals with grace period - SIGTERM' , ( ) => { return testSignal ( 'SIGTERM' , 5 , [ 'start\n' , 'stop\n' ] ) ; } ) ; skipIf ( isWindows , it , 'traps registered signals - SIGINT' , ( ) => { return testSignal ( 'SIGINT' ) ; } ) ; skipIf ( isWindows , it , 'does not trap unregistered signals - SIGHUP' , ( ) => { return testSignal ( 'SIGHUP' , undefined , [ 'start\n' ] ) ; } ) ; function normalizeStdoutData ( output ) { return output . join ( '' ) ; } function createAppWithShutdown ( expectedSignal , gracePeriod , expectedEvents ) { let args = [ ] ; if ( typeof gracePeriod === 'number' ) { args = [ gracePeriod . toString ( ) ] ; } const child = fork ( app , args , { stdio : 'pipe' , } ) ; const events = [ ] ; const childStart = new Promise < ChildProcess > ( resolve => { child . stdout ! . on ( 'data' , ( buf ) => { events . push ( buf . toString ( 'utf-8' ) ) ; resolve ( child ) ; } ) ; } ) ; const childExit = new Promise ( ( resolve , reject ) => { child . on ( 'exit' , ( code , sig ) => { if ( typeof sig === 'string' ) { expect ( sig ) . to . eql ( expectedSignal ) ; } expect ( normalizeStdoutData ( events ) ) . to . eql ( normalizeStdoutData ( expectedEvents ) ) ; resolve ( code ) ; } ) ; child . on ( 'error' , err => { reject ( err ) ; } ) ; } ) ; return { childStart , childExit } ; } async function testSignal ( expectedSignal , gracePeriod = undefined , expectedEvents = [ 'start\n' , 'stop\n' , 'stopped\n' ] ) { const { childStart , childExit } = createAppWithShutdown ( expectedSignal , gracePeriod , expectedEvents ) ; const child = await childStart ; child . kill ( expectedSignal ) ; return childExit ; } } ) ;