Add resilient dual-radio network failover

This commit is contained in:
2026-07-31 20:24:34 +02:00
parent 0a0dae144c
commit 6940cfb3a8
19 changed files with 857 additions and 11 deletions
+32
View File
@@ -17,6 +17,11 @@ function testConfig(): AppConfig {
allowedOrigins: new Set(["http://mg4pi.local:8787"]),
updateStatusPath: `/tmp/pi-car-companion-test-${process.pid}-missing-update.json`,
versionFile: `/tmp/pi-car-companion-test-${process.pid}-missing-revision`,
network: {
enabled: false,
statusPath: `/tmp/pi-car-companion-test-${process.pid}-missing-network-status.json`,
commandPath: `/tmp/pi-car-companion-test-${process.pid}-network-command.json`
},
adb: { enabled: false, executable: "adb", serial: null, timeoutMs: 3_000 }
};
}
@@ -180,6 +185,33 @@ describe("authentication boundary", () => {
expect(response.statusCode).toBe(401);
});
it("keeps network status and controls behind authentication and explicit configuration", async () => {
const app = await createApp();
expect((await app.inject({ method: "GET", url: "/api/network" })).statusCode).toBe(401);
const token = await csrf(app);
await setup(app, token);
const login = await app.inject({
method: "POST",
url: "/api/auth/login",
headers: mutationHeaders(token),
payload: { username: "owner", password: "Correct-horse1" }
});
const session = login.cookies.find((item) => item.name === SESSION_COOKIE)?.value ?? "";
const cookie = `${CSRF_COOKIE}=${token}; ${SESSION_COOKIE}=${session}`;
const status = await app.inject({ method: "GET", url: "/api/network", headers: { cookie } });
expect(status.statusCode).toBe(200);
expect(status.json()).toMatchObject({ supported: false, enabled: false, mode: "disabled" });
const action = await app.inject({
method: "POST",
url: "/api/network/actions",
headers: { ...mutationHeaders(token), cookie },
payload: { action: "retry-upstream" }
});
expect(action.statusCode).toBe(503);
});
it("exposes only allowlisted jobs and authenticated run history", async () => {
const app = await createApp();
const token = await csrf(app);