mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-20 12:11:28 -07:00
feat: add background stats server daemon lifecycle
Implement `subminer stats -b` to start a background stats daemon and `subminer stats -s` to stop it, with PID-based process lifecycle management, single-instance lock bypass for daemon mode, and automatic reuse of running daemon instances.
This commit is contained in:
@@ -27,6 +27,11 @@ function makeHandler(
|
||||
calls.push('ensureStatsServerStarted');
|
||||
return 'http://127.0.0.1:6969';
|
||||
},
|
||||
ensureBackgroundStatsServerStarted: () => ({
|
||||
url: 'http://127.0.0.1:6969',
|
||||
runningInCurrentProcess: true,
|
||||
}),
|
||||
stopBackgroundStatsServer: async () => ({ ok: true, stale: false }),
|
||||
openExternal: async (url) => {
|
||||
calls.push(`openExternal:${url}`);
|
||||
},
|
||||
@@ -70,6 +75,88 @@ test('stats cli command starts tracker, server, browser, and writes success resp
|
||||
]);
|
||||
});
|
||||
|
||||
test('stats cli command starts background daemon without opening browser', async () => {
|
||||
const { handler, calls, responses } = makeHandler({
|
||||
ensureBackgroundStatsServerStarted: () => {
|
||||
calls.push('ensureBackgroundStatsServerStarted');
|
||||
return { url: 'http://127.0.0.1:6969', runningInCurrentProcess: true };
|
||||
},
|
||||
} as never);
|
||||
|
||||
await handler(
|
||||
{
|
||||
statsResponsePath: '/tmp/subminer-stats-response.json',
|
||||
statsBackground: true,
|
||||
} as never,
|
||||
'initial',
|
||||
);
|
||||
|
||||
assert.deepEqual(calls, [
|
||||
'ensureBackgroundStatsServerStarted',
|
||||
'info:Stats dashboard available at http://127.0.0.1:6969',
|
||||
]);
|
||||
assert.deepEqual(responses, [
|
||||
{
|
||||
responsePath: '/tmp/subminer-stats-response.json',
|
||||
payload: { ok: true, url: 'http://127.0.0.1:6969' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('stats cli command exits helper app when background daemon is already running elsewhere', async () => {
|
||||
const { handler, calls, responses } = makeHandler({
|
||||
ensureBackgroundStatsServerStarted: () => {
|
||||
calls.push('ensureBackgroundStatsServerStarted');
|
||||
return { url: 'http://127.0.0.1:6969', runningInCurrentProcess: false };
|
||||
},
|
||||
} as never);
|
||||
|
||||
await handler(
|
||||
{
|
||||
statsResponsePath: '/tmp/subminer-stats-response.json',
|
||||
statsBackground: true,
|
||||
} as never,
|
||||
'initial',
|
||||
);
|
||||
|
||||
assert.ok(calls.includes('exitAppWithCode:0'));
|
||||
assert.deepEqual(responses, [
|
||||
{
|
||||
responsePath: '/tmp/subminer-stats-response.json',
|
||||
payload: { ok: true, url: 'http://127.0.0.1:6969' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('stats cli command stops background daemon and treats stale state as success', async () => {
|
||||
const { handler, calls, responses } = makeHandler({
|
||||
stopBackgroundStatsServer: async () => {
|
||||
calls.push('stopBackgroundStatsServer');
|
||||
return { ok: true, stale: true };
|
||||
},
|
||||
} as never);
|
||||
|
||||
await handler(
|
||||
{
|
||||
statsResponsePath: '/tmp/subminer-stats-response.json',
|
||||
statsStop: true,
|
||||
} as never,
|
||||
'initial',
|
||||
);
|
||||
|
||||
assert.deepEqual(calls, [
|
||||
'stopBackgroundStatsServer',
|
||||
'info:Background stats server is not running; cleaned stale state.',
|
||||
'exitAppWithCode:0',
|
||||
]);
|
||||
assert.deepEqual(responses, [
|
||||
{
|
||||
responsePath: '/tmp/subminer-stats-response.json',
|
||||
payload: { ok: true },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('stats cli command fails when immersion tracking is disabled', async () => {
|
||||
const { handler, calls, responses } = makeHandler({
|
||||
getResolvedConfig: () => ({
|
||||
|
||||
Reference in New Issue
Block a user