feat(api): complete phase 2.4 control plane

This commit is contained in:
chick
2026-07-17 00:37:11 +08:00
parent c2702b5fc6
commit 7b91dbbad1
40 changed files with 4526 additions and 74 deletions
+48
View File
@@ -11,6 +11,7 @@ describe('API startup boundary', () => {
calls.push(options);
return 'http://127.0.0.1:8790';
},
close: async () => undefined,
},
});
expect(calls).toEqual([{ host: API_DEFAULT_HOST, port: API_DEFAULT_PORT }]);
@@ -26,9 +27,56 @@ describe('API startup boundary', () => {
called = true;
return '';
},
close: async () => undefined,
},
}),
).rejects.toThrow(/reserved|legacy/i);
expect(called).toBe(false);
});
it('validates listen options before composing production resources', async () => {
await expect(startApi({ environment: { API_PORT: '8788' } })).rejects.toThrow(/8788.*legacy/i);
});
it('closes an injected app when listen fails and preserves the listen error', async () => {
const listenError = new Error('address already in use');
let closed = false;
await expect(
startApi({
app: {
listen: async () => {
throw listenError;
},
close: async () => {
closed = true;
throw new Error('close also failed');
},
},
}),
).rejects.toBe(listenError);
expect(closed).toBe(true);
});
it('schedules cleanup only after a successful listen without waiting for it', async () => {
const events: string[] = [];
let release!: () => void;
const cleanup = new Promise<void>((resolve) => {
release = resolve;
});
await startApi({
app: {
listen: async () => {
events.push('listen');
return '';
},
close: async () => undefined,
retryPendingSecretCleanup: async () => {
events.push('cleanup');
await cleanup;
},
},
});
expect(events).toEqual(['listen', 'cleanup']);
release();
});
});