1
1
import { describe , test , expect , vi , beforeEach } from "vitest" ;
2
- import { shutdownManager } from "./shutdownManager.js" ;
3
-
4
- // Type assertion to access private members for testing
5
- type PrivateShutdownManager = {
6
- handlers : Map < string , { handler : NodeJS . SignalsListener ; signals : Array < "SIGTERM" | "SIGINT" > } > ;
7
- shutdown : ( signal : "SIGTERM" | "SIGINT" ) => Promise < void > ;
8
- _reset : ( ) => void ;
9
- } ;
2
+ import { ShutdownManager } from "./shutdownManager.js" ;
10
3
11
4
describe ( "ShutdownManager" , { concurrent : false } , ( ) => {
12
- const manager = shutdownManager as unknown as PrivateShutdownManager ;
13
5
// Mock process.exit to prevent actual exit
14
6
const mockExit = vi . spyOn ( process , "exit" ) . mockImplementation ( ( ) => undefined as never ) ;
15
7
16
8
beforeEach ( ( ) => {
17
- // Clear all mocks and reset the manager before each test
18
9
vi . clearAllMocks ( ) ;
19
- manager . _reset ( ) ;
20
10
} ) ;
21
11
22
12
test ( "should successfully register a new handler" , ( ) => {
13
+ const manager = new ShutdownManager ( false ) ;
14
+
23
15
const handler = vi . fn ( ) ;
24
- shutdownManager . register ( "test-handler" , handler ) ;
16
+ manager . register ( "test-handler" , handler ) ;
25
17
26
- expect ( manager . handlers . has ( "test-handler" ) ) . toBe ( true ) ;
27
- const registeredHandler = manager . handlers . get ( "test-handler" ) ;
18
+ expect ( manager . _getHandlersForTesting ( ) . has ( "test-handler" ) ) . toBe ( true ) ;
19
+ const registeredHandler = manager . _getHandlersForTesting ( ) . get ( "test-handler" ) ;
28
20
expect ( registeredHandler ?. handler ) . toBe ( handler ) ;
29
21
expect ( registeredHandler ?. signals ) . toEqual ( [ "SIGTERM" , "SIGINT" ] ) ;
30
22
} ) ;
31
23
32
24
test ( "should throw error when registering duplicate handler name" , ( ) => {
25
+ const manager = new ShutdownManager ( false ) ;
26
+
33
27
const handler = vi . fn ( ) ;
34
- shutdownManager . register ( "duplicate-handler" , handler ) ;
28
+ manager . register ( "duplicate-handler" , handler ) ;
35
29
36
30
expect ( ( ) => {
37
- shutdownManager . register ( "duplicate-handler" , handler ) ;
31
+ manager . register ( "duplicate-handler" , handler ) ;
38
32
} ) . toThrow ( 'Shutdown handler "duplicate-handler" already registered' ) ;
39
33
} ) ;
40
34
41
35
test ( "should register handler with custom signals" , ( ) => {
36
+ const manager = new ShutdownManager ( false ) ;
37
+
42
38
const handler = vi . fn ( ) ;
43
- shutdownManager . register ( "custom-signals" , handler , [ "SIGTERM" ] ) ;
39
+ manager . register ( "custom-signals" , handler , [ "SIGTERM" ] ) ;
44
40
45
- const registeredHandler = manager . handlers . get ( "custom-signals" ) ;
41
+ const registeredHandler = manager . _getHandlersForTesting ( ) . get ( "custom-signals" ) ;
46
42
expect ( registeredHandler ?. signals ) . toEqual ( [ "SIGTERM" ] ) ;
47
43
} ) ;
48
44
49
45
test ( "should call registered handlers when shutdown is triggered" , async ( ) => {
46
+ const manager = new ShutdownManager ( false ) ;
47
+
50
48
const handler1 = vi . fn ( ) ;
51
49
const handler2 = vi . fn ( ) ;
52
50
53
- shutdownManager . register ( "handler1" , handler1 ) ;
54
- shutdownManager . register ( "handler2" , handler2 ) ;
51
+ manager . register ( "handler1" , handler1 ) ;
52
+ manager . register ( "handler2" , handler2 ) ;
55
53
56
54
await manager . shutdown ( "SIGTERM" ) ;
57
55
@@ -61,11 +59,13 @@ describe("ShutdownManager", { concurrent: false }, () => {
61
59
} ) ;
62
60
63
61
test ( "should only call handlers registered for specific signal" , async ( ) => {
62
+ const manager = new ShutdownManager ( false ) ;
63
+
64
64
const handler1 = vi . fn ( ) ;
65
65
const handler2 = vi . fn ( ) ;
66
66
67
- shutdownManager . register ( "handler1" , handler1 , [ "SIGTERM" ] ) ;
68
- shutdownManager . register ( "handler2" , handler2 , [ "SIGINT" ] ) ;
67
+ manager . register ( "handler1" , handler1 , [ "SIGTERM" ] ) ;
68
+ manager . register ( "handler2" , handler2 , [ "SIGINT" ] ) ;
69
69
70
70
await manager . shutdown ( "SIGTERM" ) ;
71
71
@@ -75,11 +75,13 @@ describe("ShutdownManager", { concurrent: false }, () => {
75
75
} ) ;
76
76
77
77
test ( "should handle errors in shutdown handlers gracefully" , async ( ) => {
78
+ const manager = new ShutdownManager ( false ) ;
79
+
78
80
const successHandler = vi . fn ( ) ;
79
81
const errorHandler = vi . fn ( ) . mockRejectedValue ( new Error ( "Handler failed" ) ) ;
80
82
81
- shutdownManager . register ( "success-handler" , successHandler ) ;
82
- shutdownManager . register ( "error-handler" , errorHandler ) ;
83
+ manager . register ( "success-handler" , successHandler ) ;
84
+ manager . register ( "error-handler" , errorHandler ) ;
83
85
84
86
await manager . shutdown ( "SIGTERM" ) ;
85
87
@@ -89,8 +91,10 @@ describe("ShutdownManager", { concurrent: false }, () => {
89
91
} ) ;
90
92
91
93
test ( "should only run shutdown sequence once even if called multiple times" , async ( ) => {
94
+ const manager = new ShutdownManager ( false ) ;
95
+
92
96
const handler = vi . fn ( ) ;
93
- shutdownManager . register ( "test-handler" , handler ) ;
97
+ manager . register ( "test-handler" , handler ) ;
94
98
95
99
await Promise . all ( [ manager . shutdown ( "SIGTERM" ) , manager . shutdown ( "SIGTERM" ) ] ) ;
96
100
@@ -99,23 +103,27 @@ describe("ShutdownManager", { concurrent: false }, () => {
99
103
expect ( mockExit ) . toHaveBeenCalledWith ( 128 + 15 ) ;
100
104
} ) ;
101
105
102
- test ( "should exit with correct signal number" , async ( ) => {
103
- const handler = vi . fn ( ) ;
104
- shutdownManager . register ( "test-handler" , handler ) ;
106
+ test ( "should exit with correct signal number on SIGINT" , async ( ) => {
107
+ const manager = new ShutdownManager ( false ) ;
108
+
109
+ manager . register ( "test-handler" , vi . fn ( ) ) ;
105
110
106
111
await manager . shutdown ( "SIGINT" ) ;
107
112
expect ( mockExit ) . toHaveBeenCalledWith ( 128 + 2 ) ; // SIGINT number
113
+ } ) ;
108
114
109
- vi . clearAllMocks ( ) ;
110
- manager . _reset ( ) ;
111
- shutdownManager . register ( "test-handler" , handler ) ;
115
+ test ( "should exit with correct signal number on SIGTERM" , async ( ) => {
116
+ const manager = new ShutdownManager ( false ) ;
117
+
118
+ manager . register ( "test-handler" , vi . fn ( ) ) ;
112
119
113
120
await manager . shutdown ( "SIGTERM" ) ;
114
121
expect ( mockExit ) . toHaveBeenCalledWith ( 128 + 15 ) ; // SIGTERM number
115
122
} ) ;
116
123
117
124
test ( "should only exit after all handlers have finished" , async ( ) => {
118
125
const sequence : string [ ] = [ ] ;
126
+ const manager = new ShutdownManager ( false ) ;
119
127
120
128
const handler1 = vi . fn ( ) . mockImplementation ( async ( ) => {
121
129
sequence . push ( "handler1 start" ) ;
@@ -144,9 +152,9 @@ describe("ShutdownManager", { concurrent: false }, () => {
144
152
return undefined as never ;
145
153
} ) ;
146
154
147
- shutdownManager . register ( "handler1" , handler1 ) ;
148
- shutdownManager . register ( "handler2" , handler2 ) ;
149
- shutdownManager . register ( "handler3" , handler3 ) ;
155
+ manager . register ( "handler1" , handler1 ) ;
156
+ manager . register ( "handler2" , handler2 ) ;
157
+ manager . register ( "handler3" , handler3 ) ;
150
158
151
159
await manager . shutdown ( "SIGTERM" ) ;
152
160
0 commit comments