mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 22:25:24 +00:00
109 lines
3.6 KiB
TypeScript
109 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
diffContainerStates,
|
|
parseContainerStates,
|
|
} from "../../src/backend/docker-watcher.js";
|
|
|
|
/**
|
|
* The polling side needs SSH, so what is tested here is the pure part: turning
|
|
* `docker ps` output into states, and turning two snapshots into events.
|
|
*/
|
|
|
|
describe("parseContainerStates", () => {
|
|
it("reads name, state and health out of the ps output", () => {
|
|
const output = [
|
|
'{"name":"web","state":"running","status":"Up 2 hours"}',
|
|
'{"name":"db","state":"exited","status":"Exited (0) 5 minutes ago"}',
|
|
'{"name":"api","state":"running","status":"Up 1 hour (unhealthy)"}',
|
|
].join("\n");
|
|
|
|
const states = parseContainerStates(output);
|
|
|
|
expect(states.get("web")).toEqual({ state: "running", unhealthy: false });
|
|
expect(states.get("db")).toEqual({ state: "exited", unhealthy: false });
|
|
expect(states.get("api")).toEqual({ state: "running", unhealthy: true });
|
|
});
|
|
|
|
it("skips blank and malformed lines rather than failing the poll", () => {
|
|
const output = [
|
|
'{"name":"web","state":"running","status":"Up"}',
|
|
"",
|
|
"not json at all",
|
|
'{"state":"running"}',
|
|
].join("\n");
|
|
|
|
const states = parseContainerStates(output);
|
|
expect([...states.keys()]).toEqual(["web"]);
|
|
});
|
|
|
|
it("returns nothing for empty output", () => {
|
|
expect(parseContainerStates("").size).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("diffContainerStates", () => {
|
|
const running = { state: "running", unhealthy: false };
|
|
const exited = { state: "exited", unhealthy: false };
|
|
|
|
it("reports a container that stopped", () => {
|
|
const events = diffContainerStates(
|
|
new Map([["web", running]]),
|
|
new Map([["web", exited]]),
|
|
);
|
|
expect(events).toEqual([{ container: "web", event: "exited" }]);
|
|
});
|
|
|
|
it("reports a container that started", () => {
|
|
const events = diffContainerStates(
|
|
new Map([["web", exited]]),
|
|
new Map([["web", running]]),
|
|
);
|
|
expect(events).toEqual([{ container: "web", event: "started" }]);
|
|
});
|
|
|
|
it("reports a container that began restarting", () => {
|
|
const events = diffContainerStates(
|
|
new Map([["web", running]]),
|
|
new Map([["web", { state: "restarting", unhealthy: false }]]),
|
|
);
|
|
expect(events).toEqual([{ container: "web", event: "restarting" }]);
|
|
});
|
|
|
|
it("reports a container that went unhealthy while still running", () => {
|
|
const events = diffContainerStates(
|
|
new Map([["web", running]]),
|
|
new Map([["web", { state: "running", unhealthy: true }]]),
|
|
);
|
|
expect(events).toEqual([{ container: "web", event: "unhealthy" }]);
|
|
});
|
|
|
|
it("stays quiet when nothing changed", () => {
|
|
const events = diffContainerStates(
|
|
new Map([["web", running]]),
|
|
new Map([["web", running]]),
|
|
);
|
|
expect(events).toEqual([]);
|
|
});
|
|
|
|
it("does not re-announce a container that is still unhealthy", () => {
|
|
const unhealthy = { state: "running", unhealthy: true };
|
|
const events = diffContainerStates(
|
|
new Map([["web", unhealthy]]),
|
|
new Map([["web", unhealthy]]),
|
|
);
|
|
expect(events).toEqual([]);
|
|
});
|
|
|
|
// A first sighting is a baseline, not an event: otherwise every container
|
|
// running at boot would report itself as freshly started.
|
|
it("treats a newly seen container as a baseline", () => {
|
|
const events = diffContainerStates(new Map(), new Map([["web", running]]));
|
|
expect(events).toEqual([]);
|
|
});
|
|
|
|
it("ignores a container that disappeared", () => {
|
|
const events = diffContainerStates(new Map([["web", running]]), new Map());
|
|
expect(events).toEqual([]);
|
|
});
|
|
});
|