Skip to content

Commit 3d68f26

Browse files
piotrskiclaude
andcommitted
test: add e2e tests for daemon auto-restart on rebuild
Verifies that: - daemon restarts with the same port when daemon.js mtime is newer - daemon does NOT restart when daemon.js has not changed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 96806ae commit 3d68f26

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2+
import fs from 'node:fs';
3+
import path from 'node:path';
4+
import {
5+
createTempStateDir,
6+
getTestPort,
7+
startDaemon,
8+
waitForDaemon,
9+
stopDaemon,
10+
runCli,
11+
} from './helpers.js';
12+
import type { ChildProcess } from 'node:child_process';
13+
14+
describe('Daemon auto-restart on rebuild', () => {
15+
let stateDir: string;
16+
let port: number;
17+
let daemon: ChildProcess | null = null;
18+
19+
beforeEach(async () => {
20+
stateDir = createTempStateDir();
21+
port = getTestPort();
22+
daemon = startDaemon(port, stateDir);
23+
await waitForDaemon(stateDir);
24+
});
25+
26+
afterEach(async () => {
27+
await stopDaemon(daemon, stateDir);
28+
daemon = null;
29+
});
30+
31+
it('should restart daemon when startedAt is older than daemon.js', async () => {
32+
const infoPath = path.join(stateDir, 'daemon.json');
33+
const infoBefore = JSON.parse(fs.readFileSync(infoPath, 'utf-8'));
34+
const pidBefore = infoBefore.pid;
35+
36+
// Simulate a daemon that was started long before the last build
37+
// by backdating startedAt in daemon.json
38+
infoBefore.startedAt = 1000;
39+
fs.writeFileSync(infoPath, JSON.stringify(infoBefore, null, 2));
40+
41+
const result = await runCli(['get', 'tree'], stateDir);
42+
expect(result.exitCode).toBe(0);
43+
44+
const infoAfter = JSON.parse(fs.readFileSync(infoPath, 'utf-8'));
45+
expect(infoAfter.pid).not.toBe(pidBefore);
46+
expect(infoAfter.port).toBe(port);
47+
48+
// Clean up the new daemon process
49+
daemon = null;
50+
try {
51+
process.kill(infoAfter.pid, 'SIGTERM');
52+
} catch {
53+
// already dead
54+
}
55+
});
56+
57+
it('should not restart when daemon.js has not changed', async () => {
58+
const infoPath = path.join(stateDir, 'daemon.json');
59+
const infoBefore = JSON.parse(fs.readFileSync(infoPath, 'utf-8'));
60+
61+
const result = await runCli(['get', 'tree'], stateDir);
62+
expect(result.exitCode).toBe(0);
63+
64+
const infoAfter = JSON.parse(fs.readFileSync(infoPath, 'utf-8'));
65+
expect(infoAfter.pid).toBe(infoBefore.pid);
66+
});
67+
});

0 commit comments

Comments
 (0)