Files
rea/src/process/ProcessOwnership.part3.test.ts
T
morlutoandGitHub 3c84080aab refactor(app): split Setup and ProcessOwnership modules (#628)
* refactor(domain): consolidate canonical ordering and digest helpers (#624)

* refactor(domain): consolidate canonical ordering and digest helpers

Single owner for code-point ordering (domain/canonicalOrdering.ts)
and canonical JSON digests (domain/comparisonSemantics.ts). Delete
all local compareCodePoints/compareText/digestCanonical duplicates
and migrate every importer. No re-export shims.

* fix(ci): allow slower real browser startup

* chore(config): remove dead eslint, dedupe scripts, cacheable turbo tasks

Delete eslint.config.js (oxlint is the linter), drop lint:dead alias,
pin smol-toml, fold jscpd/scan:todos into check:pr, make test:run
cacheable, align oxlint ignores.

* fix(config): hash all test inputs for cached runs

* docs: fix architecture diagram and pretty-print tool catalog

Drop dangling REPLAY edges, add dotnet/reference/error/evaluation
nodes. Emit 2-space JSON from the catalog generator and regenerate.

* test: extract shared fixtures, drop knip carve-outs

Dedupe android/apple session tests, bundler adapter headers, and
reconstruction helpers into tests/support fixtures. Delete unused
type aliases and the knip ignoreIssues block. Lower jscpd threshold
2.7 to 2.5.

* refactor(app): split Setup and ProcessOwnership modules

Extract SetupTypes/SetupHost from Setup.ts and move observation
helpers into ProcessOwnershipObservation/ProcessTree. Migrate all
importers including CLI commands. No re-export shims.
2026-10-06 05:00:32 +08:00

136 lines
3.7 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { type ProcessOwnershipHost } from "./ProcessOwnership.js";
import { observeOwnedProcessLineage } from "./ProcessOwnershipObservation.js";
const ownership = {
runId: "run-token",
leaderPid: 100,
processGroupId: 100,
};
describe("owned process-group cleanup discovery", () => {
it("walks the PPID tree across process-group boundaries", async () => {
const environment = vi.fn((pid: number) =>
Promise.resolve({
REA_PROCESS_RUN_ID: pid === 103 ? "unrelated-run" : "run-token",
}),
);
const adapter: ProcessOwnershipHost = {
listProcesses: () =>
Promise.resolve([
{
pid: 103,
parentPid: 999,
processGroupId: 100,
state: "S",
command: "unrelated-same-group",
},
{
pid: 102,
parentPid: 101,
processGroupId: 102,
state: "S",
command: "grandchild-session",
},
{
pid: 100,
parentPid: 1,
processGroupId: 100,
state: "S",
command: "fixture",
},
{
pid: 101,
parentPid: 100,
processGroupId: 101,
state: "S",
command: "child-group",
},
]),
environment,
signalGroup: vi.fn(),
};
await expect(
observeOwnedProcessLineage(ownership, adapter),
).resolves.toEqual({
status: "verified",
observedAt: expect.any(String),
lineage: {
runId: "run-token",
launcherPid: 100,
launcherParentPid: 1,
processGroupId: 100,
descendants: [
{ pid: 101, parentPid: 100, processGroupId: 101 },
{ pid: 102, parentPid: 101, processGroupId: 102 },
],
},
});
});
it("omits a descendant that exits while lineage is validated", async () => {
const launcher = {
pid: 100,
parentPid: 1,
processGroupId: 100,
state: "S",
command: "root",
};
const child = {
pid: 101,
parentPid: 100,
processGroupId: 101,
state: "S",
command: "child",
};
const processes = [launcher, child];
const listProcesses = vi
.fn<ProcessOwnershipHost["listProcesses"]>()
.mockResolvedValueOnce(processes)
.mockResolvedValueOnce([launcher]);
const host: ProcessOwnershipHost = {
listProcesses,
environment: (pid) =>
pid === 101
? Promise.reject(new Error("process exited during environment read"))
: Promise.resolve({ REA_PROCESS_RUN_ID: "run-token" }),
signalGroup: vi.fn(),
};
await expect(observeOwnedProcessLineage(ownership, host)).resolves.toEqual({
status: "verified",
observedAt: expect.any(String),
lineage: {
runId: "run-token",
launcherPid: 100,
launcherParentPid: 1,
processGroupId: 100,
descendants: [],
},
});
});
it("does not publish lineage when the launcher exits during validation", async () => {
const launcher = {
pid: 100,
parentPid: 1,
processGroupId: 100,
state: "S",
command: "root",
};
const listProcesses = vi
.fn<ProcessOwnershipHost["listProcesses"]>()
.mockResolvedValueOnce([launcher])
.mockResolvedValueOnce([]);
const host: ProcessOwnershipHost = {
listProcesses,
environment: () => Promise.reject(new Error("launcher exited")),
signalGroup: vi.fn(),
};
await expect(
observeOwnedProcessLineage(ownership, host),
).resolves.toMatchObject({
status: "unavailable",
reason: "owned launcher exited during lineage validation",
});
});
});