mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 08:29:42 +02:00
fix(remote): stop the flush losing a chunk, and reset the host form's wake fields
Own review pass over the PR:
- `_flush` took the chunk out of the buffer only AFTER awaiting the write. Input
arriving during that await is enqueued (`waking` is still set, so it takes the
buffer path), and the 4 KB cap then drops the OLDEST chunk — which is the one
already on its way to the pane. The `shift()` that followed removed the NEXT
chunk instead, so the drop-oldest bookkeeping silently lost a chunk that was
never written, while the log line blamed the one that was. The chunk is now
removed before the await and re-inserted at the FRONT on a failed write, so the
order of the queue behind it is preserved. Regression test: a chunk enqueued
during the first write of a full buffer must still reach the pane (red against
the old order).
- `showCreateCaseModal()` reset the remote-host form fields but not the two new
wake inputs, so one host's MAC/command carried over into the next host that
form saved.
- The banner's pre-poll `wakeConfigured` labelled a command-only host as 'mac'.
Nothing reads the distinction, but the field is documented as which path is
configured, so it says the truth until the first poll corrects it.
- Stale `resolveRemote` comment ("only for sessions that have no usable target of
their own"): after the host config became authoritative in both directions it is
consulted on the TTL regardless.
This commit is contained in:
@@ -372,6 +372,38 @@ describe('RemoteWakeRegistry', () => {
|
||||
expect(h.registry.pendingBytes('sess-1')).toBe(3);
|
||||
});
|
||||
|
||||
it('flushes the chunk it is writing out of the buffer first, so a concurrent enqueue cannot drop a different one', async () => {
|
||||
// Input arriving DURING the flush is enqueued (`waking` is still set), and the cap
|
||||
// then drops the OLDEST chunk — the one already on its way to the pane. Shifting the
|
||||
// buffer after the write removed the NEXT chunk instead, so the drop-oldest
|
||||
// bookkeeping lost a chunk that was never written.
|
||||
const h = harness();
|
||||
h.probe.mockResolvedValue(false);
|
||||
let release: (() => void) | undefined;
|
||||
h.waitUntilReady.mockImplementation(
|
||||
() =>
|
||||
new Promise<boolean>((resolve) => {
|
||||
release = () => resolve(true);
|
||||
})
|
||||
);
|
||||
|
||||
const big = 'a'.repeat(REMOTE_WAKE_PENDING_MAX_BYTES - 10);
|
||||
await h.registry.handleInput(h.session, big);
|
||||
await h.registry.handleInput(h.session, 'bbbbbbbbbb'); // fills the cap exactly
|
||||
// The third chunk arrives while the FIRST write is in flight, which is what pushes
|
||||
// the buffer over the cap mid-flush.
|
||||
h.writeViaMux.mockImplementationOnce(async () => {
|
||||
await h.registry.handleInput(h.session, 'c');
|
||||
return true;
|
||||
});
|
||||
|
||||
release?.();
|
||||
await h.registry.wake(h.session);
|
||||
|
||||
expect(h.writeViaMux.mock.calls.map((c) => c[0])).toEqual([big, 'bbbbbbbbbb', 'c']);
|
||||
expect(h.registry.pendingBytes('sess-1')).toBe(0);
|
||||
});
|
||||
|
||||
it('ensureAwake blocks only for the wait path and returns true without a wake command', async () => {
|
||||
const h = harness({ remote: { hostId: 'x', label: 'X', host: '10.0.0.9' } });
|
||||
await expect(h.registry.ensureAwake(h.session)).resolves.toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user