-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy pathmain.test.ts
More file actions
139 lines (111 loc) · 3.43 KB
/
main.test.ts
File metadata and controls
139 lines (111 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { beforeEach, describe, expect, it, vi } from 'bun:test';
import { createNoOpLogger } from '@repo/shared';
import { createSupervisorController } from '../src/main';
const mockLogger = createNoOpLogger();
describe('createSupervisorController', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('forwards shutdown signal to a running child, cleans up, and exits', async () => {
const cleanup = vi.fn().mockResolvedValue(undefined);
const exit = vi.fn();
const kill = vi.fn().mockReturnValue(true);
const child = {
exitCode: null,
kill
};
const controller = createSupervisorController({
cleanup,
getChild: () => child,
exit,
logger: mockLogger
});
await controller.onSignal('SIGTERM');
expect(kill).toHaveBeenCalledWith('SIGTERM');
expect(cleanup).toHaveBeenCalledTimes(1);
expect(exit).toHaveBeenCalledWith(0);
});
it('still shuts down when the child already exited', async () => {
const cleanup = vi.fn().mockResolvedValue(undefined);
const exit = vi.fn();
const kill = vi.fn().mockReturnValue(true);
const child = {
exitCode: 0,
kill
};
const controller = createSupervisorController({
cleanup,
getChild: () => child,
exit,
logger: mockLogger
});
await controller.onSignal('SIGTERM');
expect(kill).not.toHaveBeenCalled();
expect(cleanup).toHaveBeenCalledTimes(1);
expect(exit).toHaveBeenCalledWith(0);
});
it('does not exit from child signal events once shutdown has started', async () => {
let resolveCleanup!: () => void;
const cleanup = vi.fn().mockImplementation(
() =>
new Promise<void>((resolve) => {
resolveCleanup = resolve;
})
);
const exit = vi.fn();
const kill = vi.fn().mockReturnValue(true);
const child = {
exitCode: null,
kill
};
const controller = createSupervisorController({
cleanup,
getChild: () => child,
exit,
logger: mockLogger
});
const shutdown = controller.onSignal('SIGTERM');
controller.onChildExit(null, 'SIGTERM');
expect(exit).not.toHaveBeenCalled();
resolveCleanup();
await shutdown;
expect(exit).toHaveBeenCalledTimes(1);
expect(exit).toHaveBeenCalledWith(0);
});
it('preserves existing child exit behaviour outside shutdown', () => {
const cleanup = vi.fn().mockResolvedValue(undefined);
const exit = vi.fn();
const controller = createSupervisorController({
cleanup,
getChild: () => null,
exit,
logger: mockLogger
});
controller.onChildExit(null, 'SIGTERM');
expect(exit).toHaveBeenCalledWith(143);
});
it('does not exit when child exits with code 0 outside shutdown', () => {
const cleanup = vi.fn().mockResolvedValue(undefined);
const exit = vi.fn();
const controller = createSupervisorController({
cleanup,
getChild: () => null,
exit,
logger: mockLogger
});
controller.onChildExit(0, null);
expect(exit).not.toHaveBeenCalled();
});
it('exits with child exit code on non-zero exit outside shutdown', () => {
const cleanup = vi.fn().mockResolvedValue(undefined);
const exit = vi.fn();
const controller = createSupervisorController({
cleanup,
getChild: () => null,
exit,
logger: mockLogger
});
controller.onChildExit(1, null);
expect(exit).toHaveBeenCalledWith(1);
});
});