Row 138 round 2, Rocko's candidate e3f9a400 (43 paths) on26a0b0fab. Dewey approved (comment 28754) after round 1 changes (comment 28752): D1-D5 mutants killed, the 17 touched test files run singly passed 124/124. Rocko's own run: 753 tests and 59/59 mutants killed. The bus gains the project adapter through runtime.mjs, the way it already injects the organization, so broker.mjs takes no new imports and refuses with project-not-configured when no adapter is set. The project socket timeout is 120s. Roles gain record.write. The schema moves from 3e to 3f; the live migration follows MIGRATION.md and needs Mos's window. Sage's landing gate ran onc842686d5plus the candidate: 25 steps, all rc 0 (15 packages, 10 script suites), network sage-r138_default removed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
97 lines
5.1 KiB
JavaScript
97 lines
5.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { connect } from 'node:net';
|
|
import { join } from 'node:path';
|
|
import { fixture } from './spec-fixtures.mjs';
|
|
import { serve } from '../src/server.mjs';
|
|
import { Client } from '../src/client.mjs';
|
|
async function socketFixture(t, options = {}) {
|
|
const f = await fixture(t), path = join(f.root, 'bus.sock');
|
|
const server = await serve({ broker: f.broker, path, ...options });
|
|
t.after(() => server.close());
|
|
return { ...f, path, client: new Client({ path, cap: f.coder }) };
|
|
}
|
|
|
|
test('real socket awaits spec reads, record writes and cited raises; other requests still return normally', async t => {
|
|
const f = await socketFixture(t);
|
|
const spec = await f.client.call('spec.read', { project: 'stack' });
|
|
assert.equal(spec.commit, f.commit); assert.match(spec.content, /North.star/i);
|
|
const result = await f.client.call('record.write', { project: 'stack', path: 'docs/socket.md', record: '# Socket\n' });
|
|
assert.match(result.commit, /^[0-9a-f]{40}$/);
|
|
const d = await f.client.call('decision.raise', { action: 'deploy', question: 'Ship?',
|
|
options: [{ key: 'yes', text: 'Yes' }, { key: 'no', text: 'No' }], recommendation: 'yes', blocking: false,
|
|
project: 'stack', spec_path: spec.path, spec_commit: spec.commit });
|
|
assert.equal(f.store.get('SELECT spec_commit FROM decisions WHERE id=?', d.id).spec_commit, spec.commit);
|
|
assert.ok(Array.isArray(await f.client.call('agents')));
|
|
});
|
|
|
|
test('real socket preserves asynchronous refusal codes and disconnects its transient proof', async t => {
|
|
let transient;
|
|
const f = await fixture(t), path = join(f.root, 'bus.sock');
|
|
const server = await serve({ broker: f.broker, path, authenticateHuman: () => {
|
|
transient = f.broker.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true });
|
|
return transient;
|
|
} });
|
|
t.after(() => server.close());
|
|
const client = new Client({ path, cap: f.coder });
|
|
await assert.rejects(client.call('spec.read', { project: 'missing' }), { code: 'project-not-declared' });
|
|
await assert.rejects(new Client({ path, human: { fixture: true } }).call('spec.read', { project: 'stack' }), { code: 'agent-required' });
|
|
assert.throws(() => f.broker.identity(transient), /unauthenticated/);
|
|
assert.ok(Array.isArray(await client.call('agents')));
|
|
});
|
|
|
|
test('two real socket writes to one repository yield one commit and one project-busy refusal', async t => {
|
|
const f = await socketFixture(t);
|
|
const results = await Promise.allSettled(['one', 'two'].map(name =>
|
|
new Client({ path: f.path, cap: f.coder }).call('record.write', {
|
|
project: 'stack', path: `docs/${name}.md`, record: `# ${name}\n`,
|
|
})));
|
|
assert.equal(results.filter(r => r.status === 'fulfilled').length, 1);
|
|
const refused = results.find(r => r.status === 'rejected');
|
|
assert.equal(refused.reason.code, 'project-busy');
|
|
assert.equal(f.store.all("SELECT body FROM events WHERE json_extract(body,'$.action')='record.write'").length, 1);
|
|
});
|
|
|
|
for (const rejects of [false, true]) test(`client disconnect during await tolerates late ${rejects ? 'refusal' : 'reply'}`, async t => {
|
|
const f = await fixture(t), path = join(f.root, 'bus.sock');
|
|
let release, admitted, finished;
|
|
const holding = new Promise(resolve => { release = resolve; });
|
|
const started = new Promise(resolve => { admitted = resolve; });
|
|
const completed = new Promise(resolve => { finished = resolve; });
|
|
const broker = { request(cap, request) {
|
|
if (request.verb !== 'spec.read') return f.broker.request(cap, request);
|
|
admitted();
|
|
return holding.then(() => f.broker.request(cap, { verb: 'spec.read',
|
|
args: { project: rejects ? 'missing' : 'stack' } })).finally(finished);
|
|
} };
|
|
const server = await serve({ broker, path });
|
|
t.after(() => server.close());
|
|
const socket = connect(path);
|
|
socket.on('error', () => {});
|
|
socket.write(JSON.stringify({ cap: f.coder, verb: 'spec.read', args: { project: 'stack' } }) + '\n');
|
|
await started;
|
|
const closed = new Promise(resolve => socket.once('close', resolve));
|
|
socket.destroy(); await closed;
|
|
release(); await completed;
|
|
// A further socket round-trip proves the server remains usable after the late completion.
|
|
assert.ok(Array.isArray(await new Client({ path, cap: f.coder }).call('agents')));
|
|
});
|
|
|
|
|
|
test('N-a: slow admitted record.write returns its committed result after the idle deadline', async t => {
|
|
const f = await fixture(t), path = join(f.root, 'bus.sock');
|
|
const broker = { async request(cap, request) {
|
|
if (request.verb === 'record.write') await new Promise(resolve => setTimeout(resolve, 150));
|
|
return f.broker.request(cap, request);
|
|
} };
|
|
const server = await serve({ broker, path, timeout: 40 });
|
|
t.after(() => server.close());
|
|
const written = await new Client({ path, cap: f.coder }).call('record.write', {
|
|
project: 'stack', path: 'docs/slow.md', record: '# Slow write\n',
|
|
});
|
|
assert.match(written.commit, /^[0-9a-f]{40}$/);
|
|
const receipts = f.store.all("SELECT body FROM events WHERE kind='action.allowed' AND json_extract(body,'$.action')='record.write'");
|
|
assert.equal(receipts.length, 1);
|
|
assert.equal(JSON.parse(receipts[0].body).commit, written.commit);
|
|
});
|