Ctrl K
ComunidadGuías…

test/claude-transport-lifecycle.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var test = require("node:test");
var assert = require("node:assert/strict");
var fs = require("node:fs");
var os = require("node:os");
var path = require("node:path");
var home = fs.mkdtempSync(path.join(os.tmpdir(), "clay-transport-"));
process.env.HOME = home;
process.env.CLAY_HOME = path.join(home, ".clay");
var attach = require("../lib/yoke/claude-worker-startup").attachWorkerStartup;
var kit = require("../lib/yoke/adapters/claude").contractTestKit;
test.after(function() { fs.rmSync(home, { recursive: true, force: true }); });

function startup() {
  var timeout;
  var cancelled = 0;
  var killed = 0;
  var worker = { kill: function() { killed++; } };
  attach(worker, { setTimeout: function(fn, ms) { assert.equal(ms, 180000); timeout = fn; return 1; }, clearTimeout: function() { cancelled++; } });
  return { worker: worker, timeout: function() { timeout(); }, cancelled: function() { return cancelled; }, killed: function() { return killed; } };
}

test("worker startup settles on readiness and cancels its deadline", async function() {
  var fixture = startup();
  fixture.worker._readyResolve();
  await fixture.worker.readyPromise;
  assert.equal(fixture.cancelled(), 1);
  assert.equal(fixture.worker._readyReject, null);
});
test("worker startup exit/error rejects rather than leaving createQuery pending", async function() {
  var fixture = startup();
  fixture.worker._readyReject(new Error("Worker exited before ready"));
  await assert.rejects(fixture.worker.readyPromise, /exited before ready/);
  assert.equal(fixture.cancelled(), 1);
});
test("silent startup has a bounded deadline and terminates its worker", async function() {
  var fixture = startup();
  fixture.timeout();
  await assert.rejects(fixture.worker.readyPromise, /startup deadline/);
  assert.equal(fixture.killed(), 1);
});

test("in-process recovery waits for SDK termination, not close or cancellation request", async function() {
  var finish;
  var controller = new AbortController();
  var raw = { close: function() {}, [Symbol.asyncIterator]: function() { return { next: function() { return new Promise(function(resolve) { finish = resolve; }); } }; } };
  var handle = kit.createQueryHandle(raw, kit.createMessageQueue(), controller);
  var next = handle[Symbol.asyncIterator]().next();
  var settled = false;
  var stopped = handle.stopAndWait().then(function() { settled = true; });
  handle.close();
  await Promise.resolve();
  assert.equal(controller.signal.aborted, true);
  assert.equal(settled, false);
  finish({ done: true });
  await next;
  await stopped;
  assert.equal(settled, true);
});

test("worker recovery waits for termination acknowledgement, ignoring local iterator closure", async function() {
  var receive;
  var resolveExit;
  var timer;
  var worker = { process: { killed: false, exitCode: null }, send: function() { return true; }, onMessage: function(fn) { receive = fn; }, exitPromise: new Promise(function(resolve) { resolveExit = resolve; }) };
  var handle = kit.createWorkerQueryHandle(worker);
  var settled = false;
  var stopped = handle.stopAndWait().then(function() { settled = true; });
  timer = worker._abortTimeout;
  handle.close();
  await Promise.resolve();
  assert.equal(settled, false);
  receive({ type: "query_error", error: "socket lost", _fallback: true });
  await Promise.resolve();
  assert.equal(settled, false);
  resolveExit();
  await stopped;
  clearTimeout(timer);
  assert.equal(settled, true);
});

test("worker query completion acknowledges safe stop without waiting for reusable process exit", async function() {
  var receive;
  var worker = { process: { killed: false, exitCode: null }, send: function() { return true; }, onMessage: function(fn) { receive = fn; }, exitPromise: new Promise(function() {}) };
  var handle = kit.createWorkerQueryHandle(worker);
  var stopped = handle.stopAndWait();
  receive({ type: "query_done" });
  await stopped;
  assert.equal(worker._abortTimeout, null, "completed abort must not kill a reused worker later");
});

test("in-process rejected SDK iteration also confirms execution termination", async function() {
  var fail;
  var raw = { [Symbol.asyncIterator]: function() { return { next: function() { return new Promise(function(resolve, reject) { fail = reject; }); } }; } };
  var handle = kit.createQueryHandle(raw, kit.createMessageQueue(), new AbortController());
  var next = handle[Symbol.asyncIterator]().next();
  var rejected = assert.rejects(next, /SDK stopped/);
  var stopped = handle.stopAndWait();
  fail(new Error("SDK stopped"));
  await rejected;
  await stopped;
});