mirror of
https://github.com/Pandipipas/scoreko-electron-dev.git
synced 2026-06-06 05:32:06 +00:00
feat: complete pending roadmap items with doctor, hardening, and code quality
This commit is contained in:
@@ -31,7 +31,7 @@ function getBaseConfig(): AppRuntimeConfig {
|
||||
};
|
||||
}
|
||||
|
||||
test("startNodeCG valida instalación de NodeCG antes de arrancar", () => {
|
||||
test("startNodeCG valida instalación de NodeCG antes de arrancar", async () => {
|
||||
const manager = createNodecgProcessManager({
|
||||
isDev: true,
|
||||
nodecgRootPath: "/fake/nodecg",
|
||||
@@ -46,11 +46,29 @@ test("startNodeCG valida instalación de NodeCG antes de arrancar", () => {
|
||||
},
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
manager.startNodecgProcess();
|
||||
await assert.rejects(async () => {
|
||||
await manager.startNodecgProcess();
|
||||
}, /No existe la carpeta NodeCG/);
|
||||
});
|
||||
|
||||
test("startNodeCG falla si no hay permisos de lectura/escritura", async () => {
|
||||
const manager = createNodecgProcessManager({
|
||||
isDev: true,
|
||||
nodecgRootPath: "/fake/nodecg",
|
||||
nodecgBaseUrl: "http://127.0.0.1:9090",
|
||||
appConfig: getBaseConfig(),
|
||||
log: () => undefined,
|
||||
deps: {
|
||||
pathExists: () => true,
|
||||
hasReadWriteAccess: () => false,
|
||||
},
|
||||
});
|
||||
|
||||
await assert.rejects(async () => {
|
||||
await manager.startNodecgProcess();
|
||||
}, /Sin permisos de lectura\/escritura/);
|
||||
});
|
||||
|
||||
test("waitForNodeCGReady resuelve cuando el endpoint responde 404", async () => {
|
||||
const child = new MockChildProcess(4321);
|
||||
const manager = createNodecgProcessManager({
|
||||
@@ -62,17 +80,19 @@ test("waitForNodeCGReady resuelve cuando el endpoint responde 404", async () =>
|
||||
deps: {
|
||||
pathExists: () => true,
|
||||
spawnProcess: () => child as unknown as import("node:child_process").ChildProcess,
|
||||
fetchUrl: async () => ({ ok: false, status: 404 } as Response),
|
||||
setTimer: ((handler: (...args: unknown[]) => void, _timeoutMs: number) => {
|
||||
fetchUrl: async () => ({ ok: false, status: 404 }) as Response,
|
||||
setTimer: (handler: (...args: unknown[]) => void, _timeoutMs: number) => {
|
||||
handler();
|
||||
return 0 as never;
|
||||
}),
|
||||
},
|
||||
stdoutWrite: () => undefined,
|
||||
stderrWrite: () => undefined,
|
||||
probePortAvailable: async () => true,
|
||||
hasReadWriteAccess: () => true,
|
||||
},
|
||||
});
|
||||
|
||||
manager.startNodecgProcess();
|
||||
await manager.startNodecgProcess();
|
||||
await assert.doesNotReject(async () => {
|
||||
await manager.waitForNodecgReady(Date.now());
|
||||
});
|
||||
@@ -92,20 +112,22 @@ test("stopNodeCG envía SIGTERM y luego SIGKILL si el proceso no sale", async ()
|
||||
deps: {
|
||||
pathExists: () => true,
|
||||
spawnProcess: () => child as unknown as import("node:child_process").ChildProcess,
|
||||
fetchUrl: async () => ({ ok: false, status: 404 } as Response),
|
||||
fetchUrl: async () => ({ ok: false, status: 404 }) as Response,
|
||||
killProcess: (pid, signal) => {
|
||||
killSignals.push({ pid, signal });
|
||||
},
|
||||
setTimer: ((handler: (...args: unknown[]) => void, _timeoutMs: number) => {
|
||||
setTimer: (handler: (...args: unknown[]) => void, _timeoutMs: number) => {
|
||||
timers.push(() => handler());
|
||||
return 0 as never;
|
||||
}),
|
||||
},
|
||||
stdoutWrite: () => undefined,
|
||||
stderrWrite: () => undefined,
|
||||
probePortAvailable: async () => true,
|
||||
hasReadWriteAccess: () => true,
|
||||
},
|
||||
});
|
||||
|
||||
manager.startNodecgProcess();
|
||||
await manager.startNodecgProcess();
|
||||
const stopPromise = manager.stopNodecgProcessGracefully();
|
||||
|
||||
assert.deepEqual(killSignals, [{ pid: -9999, signal: "SIGTERM" }]);
|
||||
@@ -123,7 +145,6 @@ test("stopNodeCG envía SIGTERM y luego SIGKILL si el proceso no sale", async ()
|
||||
await stopPromise;
|
||||
});
|
||||
|
||||
|
||||
test("stopNodeCG reutiliza la misma promesa cuando se invoca en paralelo", async () => {
|
||||
const child = new MockChildProcess(5555);
|
||||
|
||||
@@ -136,15 +157,17 @@ test("stopNodeCG reutiliza la misma promesa cuando se invoca en paralelo", async
|
||||
deps: {
|
||||
pathExists: () => true,
|
||||
spawnProcess: () => child as unknown as import("node:child_process").ChildProcess,
|
||||
fetchUrl: async () => ({ ok: false, status: 404 } as Response),
|
||||
fetchUrl: async () => ({ ok: false, status: 404 }) as Response,
|
||||
killProcess: () => undefined,
|
||||
setTimer: () => 0,
|
||||
stdoutWrite: () => undefined,
|
||||
stderrWrite: () => undefined,
|
||||
probePortAvailable: async () => true,
|
||||
hasReadWriteAccess: () => true,
|
||||
},
|
||||
});
|
||||
|
||||
manager.startNodecgProcess();
|
||||
await manager.startNodecgProcess();
|
||||
const firstStop = manager.stopNodecgProcessGracefully();
|
||||
const secondStop = manager.stopNodecgProcessGracefully();
|
||||
|
||||
@@ -170,7 +193,7 @@ test("stopNodeCG normaliza timeout negativo a cero", async () => {
|
||||
deps: {
|
||||
pathExists: () => true,
|
||||
spawnProcess: () => child as unknown as import("node:child_process").ChildProcess,
|
||||
fetchUrl: async () => ({ ok: false, status: 404 } as Response),
|
||||
fetchUrl: async () => ({ ok: false, status: 404 }) as Response,
|
||||
killProcess: () => undefined,
|
||||
setTimer: (handler, timeoutMs) => {
|
||||
timeouts.push(timeoutMs);
|
||||
@@ -179,10 +202,12 @@ test("stopNodeCG normaliza timeout negativo a cero", async () => {
|
||||
},
|
||||
stdoutWrite: () => undefined,
|
||||
stderrWrite: () => undefined,
|
||||
probePortAvailable: async () => true,
|
||||
hasReadWriteAccess: () => true,
|
||||
},
|
||||
});
|
||||
|
||||
manager.startNodecgProcess();
|
||||
await manager.startNodecgProcess();
|
||||
const stopPromise = manager.stopNodecgProcessGracefully();
|
||||
|
||||
assert.ok(timeouts.includes(0));
|
||||
@@ -190,3 +215,22 @@ test("stopNodeCG normaliza timeout negativo a cero", async () => {
|
||||
child.emit("exit", 0, null);
|
||||
await stopPromise;
|
||||
});
|
||||
|
||||
test("startNodeCG falla si el puerto ya está ocupado", async () => {
|
||||
const manager = createNodecgProcessManager({
|
||||
isDev: true,
|
||||
nodecgRootPath: "/fake/nodecg",
|
||||
nodecgBaseUrl: "http://127.0.0.1:9090",
|
||||
appConfig: getBaseConfig(),
|
||||
log: () => undefined,
|
||||
deps: {
|
||||
pathExists: () => true,
|
||||
hasReadWriteAccess: () => true,
|
||||
probePortAvailable: async () => false,
|
||||
},
|
||||
});
|
||||
|
||||
await assert.rejects(async () => {
|
||||
await manager.startNodecgProcess();
|
||||
}, /ya está en uso/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user