mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-19 09:15:19 +03:00
fix(machine): a taken endpoint id is a conflict, not a server fault
A host reporting an endpoint id another machine already holds hit the unique index, and the raw refusal reached the global handler as a 500 -- telling a host its beat broke the server rather than that the id is taken. It is now the 409 every other conflict here gives, and the route documents it. Checked-then-written would be worse rather than better: two hosts reporting the same id in the same instant both read "nobody holds it" and both write, which is precisely what the index is for. The read would add a query and remove nothing. Before: expect(res.status).toBe(409) Received: 500
This commit is contained in:
@@ -157,6 +157,31 @@ describe('POST /machine/heartbeat', () => {
|
||||
expect((await Machine.fromID(host.id))?.lastSeen).not.toBeNull();
|
||||
});
|
||||
|
||||
test('claiming another host’s endpoint id is a conflict, not a fault', async () => {
|
||||
const first = await registeredHost('beat-endpoint-taken-a');
|
||||
const second = await registeredHost('beat-endpoint-taken-b');
|
||||
const endpointId = 'f'.repeat(64);
|
||||
|
||||
await app.request('/machine/heartbeat', {
|
||||
method: 'POST',
|
||||
headers: { ...first.headers, 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ endpointId })
|
||||
});
|
||||
|
||||
const res = await app.request('/machine/heartbeat', {
|
||||
method: 'POST',
|
||||
headers: { ...second.headers, 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ endpointId })
|
||||
});
|
||||
|
||||
// The unique index is the invariant, so the database refusing is the
|
||||
// expected way to find out — and an expected refusal reaching a host as
|
||||
// a 500 tells it the server broke rather than that the id is taken.
|
||||
expect(res.status).toBe(409);
|
||||
expect((await res.json()) as any).toMatchObject({ type: 'already_exists' });
|
||||
expect((await Machine.fromID(second.id))?.endpointId).toBeNull();
|
||||
});
|
||||
|
||||
test('a user session cannot beat on a host’s behalf', async () => {
|
||||
// A box holds credentials but is not its owner, and the reverse holds
|
||||
// too: `machineOnly` exists so a route written for a host cannot be
|
||||
|
||||
Reference in New Issue
Block a user