test(server): fix the pre-bind race in the byte-ledger ceiling test
The test opened a duplex channel with data scripted to arrive right after the open reply. Under load, the host could process that data notification before the open reply's own continuation bound the route. The ceiling rejection then raced the bind, and the open call itself failed with DUPLEX_CHANNEL_OPEN_FAILED instead of the intended post-bind rejection. Open the channel with no scripted data, then write one byte after the open call resolves. The write is strictly post-bind, so the rejection is always a genuine post-bind event. Also name the reservation that rejects. The host makes two reservations for the write. The raw payload byte fits the ceiling. The serialized host-to-worker frame does not. The test name and the comments now describe that path. Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
eb86fcd498
commit
b64fbcd5b2
|
|
@ -161,18 +161,24 @@ describe("plugin worker manager duplex aggregate byte ledger", () => {
|
|||
expect(telemetry.underflows).toBe(0);
|
||||
});
|
||||
|
||||
it("fails closed and retains nothing when a buffered reservation would pass the ceiling", async () => {
|
||||
it("fails closed and retains nothing when a write reservation would pass the ceiling", async () => {
|
||||
const telemetry = countingTelemetry();
|
||||
// A four-byte ceiling. One five-byte chunk cannot fit.
|
||||
// A four-byte ceiling. A serialized host-to-worker write frame cannot fit.
|
||||
const ledger = new DuplexAggregateByteLedger({ ceilingBytes: 4, telemetry });
|
||||
const handle = makeDuplexHandle({ duplexAggregateByteLedger: ledger });
|
||||
try {
|
||||
await handle.start();
|
||||
await handle.openDuplexChannel(
|
||||
// No listener attaches, so "hello" tries to buffer. Its five raw bytes pass
|
||||
// the four-byte ceiling, so the reservation rejects and the route ends.
|
||||
duplexOpenInput({ data: [{ chunk: "hello" }] }),
|
||||
);
|
||||
// Open with no scripted data, so the fixture sends only the open reply.
|
||||
// The route is bound and live by the time this line resolves.
|
||||
const session = await handle.openDuplexChannel(duplexOpenInput({}));
|
||||
// The write happens strictly after the bind, so the rejection is a genuine
|
||||
// post-bind event, never a frame that races the open reply. The host makes
|
||||
// two reservations for this write. The one raw payload byte fits the
|
||||
// ceiling, so the pending-write reservation succeeds. The host then meters
|
||||
// the serialized frame just before the stdin write. That frame is much
|
||||
// larger than four bytes, so the transport reservation rejects, the host
|
||||
// writes nothing, and the route ends fail-closed.
|
||||
session.write(new TextEncoder().encode("a"));
|
||||
await vi.waitFor(() => {
|
||||
expect(telemetry.rejections).toBeGreaterThanOrEqual(1);
|
||||
expect(ledger.bytesInUse).toBe(0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue