all repos — sz-chrome-remote-extension @ master

pi-chrome, patched to drive a signed-in browser on another host through a broker, with an MCP server

test-suite/unit/session-cleanup.test.mjs (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
// Exercise the shipped cleanup helper and shutdown listener, without opening a bridge or Chrome.
import assert from "node:assert/strict";
import fs from "node:fs";
import vm from "node:vm";
import { stripTypeScriptTypes } from "node:module";

const source = fs.readFileSync(new URL("../../extensions/chrome-profile-bridge/index.ts", import.meta.url), "utf8");
function section(start, end) {
  const from = source.indexOf(start);
  const to = source.indexOf(end, from);
  assert.ok(from >= 0 && to > from, `Missing source section: ${start}`);
  return source.slice(from, to);
}
const helper = stripTypeScriptTypes(section("const cleanupAutomationTargetBestEffort =", "const lockChromeControl ="));
const listener = section('pi.on("session_shutdown",', 'pi.on("before_agent_start",');

function harness(send, sessionKey = "session:test") {
  const timers = new Map();
  const events = [];
  let shutdown;
  const token = Symbol();
  const globalState = { loaded: { token }, auth: { until: "indefinite" } };
  const context = {
    AbortController, Promise,
    setTimeout(fn, ms) { const key = Symbol(); timers.set(key, { fn, ms }); return key; },
    clearTimeout(key) { timers.delete(key); },
    bridge: { send(...args) { events.push("send"); return send(...args); }, stop() { events.push("stop"); } },
    sessionCtx: {}, sessionKeyFor: () => sessionKey ?? undefined,
    clearAuthExpiryTimer() {}, clearCountdownInterval() {},
    globalState, PI_CHROME_GLOBAL_KEY: "loaded", PI_CHROME_AUTH_KEY: "auth", instanceToken: token,
    pi: { on(name, handler) { assert.equal(name, "session_shutdown"); shutdown = handler; } },
  };
  vm.runInNewContext(`${helper}\n${listener}`, context);
  return { shutdown, timers, events, globalState };
}

// Delivery must settle before bridge.stop; reload does not issue cleanup at all.
{
  let complete;
  let request;
  const h = harness((...args) => {
    request = args;
    return new Promise((resolve) => { complete = resolve; });
  });
  const done = h.shutdown({ reason: "quit" });
  assert.deepEqual(h.events, ["send"]);
  assert.equal(request[0], "automation.cleanup");
  assert.equal(request[1].sessionKey, "session:test");
  assert.equal(request[2], 2000);
  assert.equal(request[3].aborted, false);
  complete();
  await done;
  assert.deepEqual(h.events, ["send", "stop"]);
  assert.equal(h.timers.size, 0);
  assert.equal(h.globalState.loaded, undefined);
}
{
  const h = harness(() => { throw new Error("reload must not send"); });
  await h.shutdown({ reason: "reload" });
  assert.deepEqual(h.events, ["stop"]);
  assert.equal(h.timers.size, 0);
}

// Even an owner request that never settles cannot hold up shutdown past its budget.
{
  let signal;
  const h = harness((_action, _params, _timeout, s) => { signal = s; return new Promise(() => {}); });
  const done = h.shutdown({});
  const [timer] = h.timers.values();
  assert.equal(timer.ms, 2000);
  timer.fn();
  await done;
  assert.equal(signal.aborted, true);
  assert.deepEqual(h.events, ["send", "stop"]);
  assert.equal(h.timers.size, 0);
}
for (const reason of ["quit", "new", "resume", "fork"]) {
  const h = harness(() => Promise.resolve({}));
  await h.shutdown({ reason });
  assert.deepEqual(h.events, ["send", "stop"]);
  // A /chrome authorize grant stays with its session: a session switch drops it, quit leaves it
  // for a parent session sharing this process.
  assert.equal("auth" in h.globalState, reason === "quit", `grant after ${reason}`);
}
{
  const h = harness(() => Promise.resolve({}));
  await h.shutdown({ reason: "reload" });
  assert.deepEqual(h.globalState.auth, { until: "indefinite" }, "grant after reload");
}
for (const send of [() => Promise.reject(new Error("offline")), () => { throw new Error("offline"); }]) {
  const h = harness(send);
  await h.shutdown({ reason: "exit" });
  assert.deepEqual(h.events, ["send", "stop"]);
  assert.equal(h.timers.size, 0);
}
{
  const h = harness(() => { throw new Error("unscoped cleanup must not send"); }, null);
  await h.shutdown({ reason: "exit" });
  assert.deepEqual(h.events, ["stop"]);
}
console.log("session-cleanup: shutdown ordering, reload, deadline, failures, missing identity, and grant scope passed");