@@ -522,31 +522,60 @@ test.group('Application | providers', (group) => {
522522 constructor(private app) {}
523523
524524 register() {
525- this.app.container.singleton('route ', () => {
525+ this.app.container.singleton('lifecycle ', () => {
526526 return {
527527 stack: []
528528 }
529529 })
530530 }
531531
532532 async boot() {
533- const route = await this.app.container.make('route ')
534- route .stack.push('booted')
533+ const lifecycle = await this.app.container.make('lifecycle ')
534+ lifecycle .stack.push('router booted')
535535 }
536536
537537 async start() {
538- const route = await this.app.container.make('route ')
539- route .stack.push('setup start')
538+ const lifecycle = await this.app.container.make('lifecycle ')
539+ lifecycle .stack.push('router setup start')
540540 }
541541
542542 async ready() {
543- const route = await this.app.container.make('route ')
544- route .stack.push('ready')
543+ const lifecycle = await this.app.container.make('lifecycle ')
544+ lifecycle .stack.push('router ready')
545545 }
546546
547547 async shutdown() {
548- const route = await this.app.container.make('route')
549- route.stack.push('shutdown')
548+ const lifecycle = await this.app.container.make('lifecycle')
549+ lifecycle.stack.push('router shutdown')
550+ }
551+ }
552+ `
553+ )
554+
555+ await outputFile (
556+ join ( BASE_PATH , './app_provider.ts' ) ,
557+ `
558+ export default class AppProvider {
559+ constructor(private app) {}
560+
561+ async boot() {
562+ const lifecycle = await this.app.container.make('lifecycle')
563+ lifecycle.stack.push('app booted')
564+ }
565+
566+ async start() {
567+ const lifecycle = await this.app.container.make('lifecycle')
568+ lifecycle.stack.push('app setup start')
569+ }
570+
571+ async ready() {
572+ const lifecycle = await this.app.container.make('lifecycle')
573+ lifecycle.stack.push('app ready')
574+ }
575+
576+ async shutdown() {
577+ const lifecycle = await this.app.container.make('lifecycle')
578+ lifecycle.stack.push('app shutdown')
550579 }
551580 }
552581 `
@@ -562,19 +591,143 @@ test.group('Application | providers', (group) => {
562591 file : ( ) => import ( new URL ( './route_provider.js?v=12' , BASE_URL ) . href ) ,
563592 environment : [ 'web' ] ,
564593 } ,
594+ {
595+ file : ( ) => import ( new URL ( './app_provider.js?v=12' , BASE_URL ) . href ) ,
596+ environment : [ 'web' ] ,
597+ } ,
565598 ] ,
566599 } )
567600
568601 await app . init ( )
569602 await app . boot ( )
570603 await app . start ( async ( ) => {
571- const route = await app . container . make ( 'route ' )
572- route . stack . push ( 'starting' )
604+ const lifecycle = await app . container . make ( 'lifecycle ' )
605+ lifecycle . stack . push ( 'starting' )
573606 } )
574607 await app . terminate ( )
575608
576- assert . deepEqual ( await app . container . make ( 'route' ) , {
577- stack : [ 'booted' , 'setup start' , 'starting' , 'ready' , 'shutdown' ] ,
609+ assert . deepEqual ( await app . container . make ( 'lifecycle' ) , {
610+ stack : [
611+ 'router booted' ,
612+ 'app booted' ,
613+ 'router setup start' ,
614+ 'app setup start' ,
615+ 'starting' ,
616+ 'router ready' ,
617+ 'app ready' ,
618+ 'router shutdown' ,
619+ 'app shutdown' ,
620+ ] ,
621+ } )
622+ } )
623+
624+ test ( 'invoke shutdown hooks in reverse order' , async ( { assert } ) => {
625+ await outputFile (
626+ join ( BASE_PATH , './route_provider.ts' ) ,
627+ `
628+ export default class RouteProvider {
629+ constructor(private app) {}
630+
631+ register() {
632+ this.app.container.singleton('lifecycle', () => {
633+ return {
634+ stack: []
635+ }
636+ })
637+ }
638+
639+ async boot() {
640+ const lifecycle = await this.app.container.make('lifecycle')
641+ lifecycle.stack.push('router booted')
642+ }
643+
644+ async start() {
645+ const lifecycle = await this.app.container.make('lifecycle')
646+ lifecycle.stack.push('router setup start')
647+ }
648+
649+ async ready() {
650+ const lifecycle = await this.app.container.make('lifecycle')
651+ lifecycle.stack.push('router ready')
652+ }
653+
654+ async shutdown() {
655+ const lifecycle = await this.app.container.make('lifecycle')
656+ lifecycle.stack.push('router shutdown')
657+ }
658+ }
659+ `
660+ )
661+
662+ await outputFile (
663+ join ( BASE_PATH , './app_provider.ts' ) ,
664+ `
665+ export default class AppProvider {
666+ constructor(private app) {}
667+
668+ async boot() {
669+ const lifecycle = await this.app.container.make('lifecycle')
670+ lifecycle.stack.push('app booted')
671+ }
672+
673+ async start() {
674+ const lifecycle = await this.app.container.make('lifecycle')
675+ lifecycle.stack.push('app setup start')
676+ }
677+
678+ async ready() {
679+ const lifecycle = await this.app.container.make('lifecycle')
680+ lifecycle.stack.push('app ready')
681+ }
682+
683+ async shutdown() {
684+ const lifecycle = await this.app.container.make('lifecycle')
685+ lifecycle.stack.push('app shutdown')
686+ }
687+ }
688+ `
689+ )
690+
691+ const app = new Application ( BASE_URL , {
692+ environment : 'web' ,
693+ } )
694+
695+ app . rcContents ( {
696+ experimental : {
697+ shutdownInReverseOrder : true ,
698+ } ,
699+ providers : [
700+ {
701+ file : ( ) => import ( new URL ( './route_provider.js?v=13' , BASE_URL ) . href ) ,
702+ environment : [ 'web' ] ,
703+ } ,
704+ {
705+ file : ( ) => import ( new URL ( './app_provider.js?v=13' , BASE_URL ) . href ) ,
706+ environment : [ 'web' ] ,
707+ } ,
708+ ] ,
709+ } )
710+
711+ await app . init ( )
712+ await app . boot ( )
713+ await app . start ( async ( ) => {
714+ const lifecycle = await app . container . make ( 'lifecycle' )
715+ lifecycle . stack . push ( 'starting' )
716+ } )
717+ await app . terminate ( )
718+
719+ assert . deepEqual ( await app . container . make ( 'lifecycle' ) , {
720+ stack : [
721+ 'router booted' ,
722+ 'app booted' ,
723+ 'router setup start' ,
724+ 'app setup start' ,
725+ 'starting' ,
726+ 'router ready' ,
727+ 'app ready' ,
728+ 'app shutdown' ,
729+ 'router shutdown' ,
730+ ] ,
578731 } )
579732 } )
580733
@@ -623,7 +776,7 @@ test.group('Application | providers', (group) => {
623776 app . rcContents ( {
624777 providers : [
625778 {
626- file : ( ) => import ( new URL ( './route_provider.js?v=13 ' , BASE_URL ) . href ) ,
779+ file : ( ) => import ( new URL ( './route_provider.js?v=14 ' , BASE_URL ) . href ) ,
627780 environment : [ 'web' ] ,
628781 } ,
629782 ] ,
@@ -683,7 +836,7 @@ test.group('Application | providers', (group) => {
683836 app . rcContents ( {
684837 providers : [
685838 {
686- file : ( ) => import ( new URL ( './route_provider.js?v=14 ' , BASE_URL ) . href ) ,
839+ file : ( ) => import ( new URL ( './route_provider.js?v=15 ' , BASE_URL ) . href ) ,
687840 environment : [ 'web' ] ,
688841 } ,
689842 ] ,
@@ -740,7 +893,7 @@ test.group('Application | providers', (group) => {
740893 app . rcContents ( {
741894 providers : [
742895 {
743- file : ( ) => import ( new URL ( './route_provider.js?v=15 ' , BASE_URL ) . href ) ,
896+ file : ( ) => import ( new URL ( './route_provider.js?v=16 ' , BASE_URL ) . href ) ,
744897 environment : [ 'web' ] ,
745898 } ,
746899 ] ,
@@ -767,6 +920,95 @@ test.group('Application | providers', (group) => {
767920 assert . isTrue ( app . isTerminated )
768921 } )
769922
923+ test ( 'invoke terminating hooks in reverse order' , async ( { assert } ) => {
924+ await outputFile (
925+ join ( BASE_PATH , './route_provider.ts' ) ,
926+ `
927+ export default class RouteProvider {
928+ constructor(private app) {}
929+
930+ register() {
931+ this.app.container.singleton('route', () => {
932+ return {
933+ stack: []
934+ }
935+ })
936+ }
937+
938+ async boot() {
939+ const route = await this.app.container.make('route')
940+ route.stack.push('booted')
941+ }
942+
943+ async start() {
944+ const route = await this.app.container.make('route')
945+ route.stack.push('setup start')
946+ }
947+
948+ async ready() {
949+ const route = await this.app.container.make('route')
950+ route.stack.push('ready')
951+ }
952+
953+ async shutdown() {
954+ const route = await this.app.container.make('route')
955+ route.stack.push('shutdown')
956+ }
957+ }
958+ `
959+ )
960+
961+ const app = new Application ( BASE_URL , {
962+ environment : 'web' ,
963+ } )
964+
965+ app . rcContents ( {
966+ experimental : {
967+ shutdownInReverseOrder : true ,
968+ } ,
969+ providers : [
970+ {
971+ file : ( ) => import ( new URL ( './route_provider.js?v=17' , BASE_URL ) . href ) ,
972+ environment : [ 'web' ] ,
973+ } ,
974+ ] ,
975+ } )
976+
977+ await app . init ( )
978+ await app . boot ( )
979+ await app . start ( async ( ) => {
980+ const route = await app . container . make ( 'route' )
981+ route . stack . push ( 'starting' )
982+ } )
983+
984+ app . terminating ( async ( ) => {
985+ const route = await app . container . make ( 'route' )
986+ assert . isTrue ( app . isTerminating )
987+ route . stack . push ( 'terminating 1' )
988+ } )
989+ app . terminating ( async ( ) => {
990+ const route = await app . container . make ( 'route' )
991+ assert . isTrue ( app . isTerminating )
992+ route . stack . push ( 'terminating 2' )
993+ } )
994+
995+ await app . terminate ( )
996+
997+ assert . deepEqual ( await app . container . make ( 'route' ) , {
998+ stack : [
999+ 'booted' ,
1000+ 'setup start' ,
1001+ 'starting' ,
1002+ 'ready' ,
1003+ 'terminating 2' ,
1004+ 'terminating 1' ,
1005+ 'shutdown' ,
1006+ ] ,
1007+ } )
1008+
1009+ assert . isTrue ( app . isTerminated )
1010+ } )
1011+
7701012 test ( 'terminate after from initiated state' , async ( { assert } ) => {
7711013 await outputFile (
7721014 join ( BASE_PATH , './route_provider.ts' ) ,
@@ -806,7 +1048,7 @@ test.group('Application | providers', (group) => {
8061048 app . rcContents ( {
8071049 providers : [
8081050 {
809- file : ( ) => import ( new URL ( './route_provider.js?v=16 ' , BASE_URL ) . href ) ,
1051+ file : ( ) => import ( new URL ( './route_provider.js?v=18 ' , BASE_URL ) . href ) ,
8101052 environment : [ 'web' ] ,
8111053 } ,
8121054 ] ,
0 commit comments