fix(agents): use NotFoundError for missing resources, add deprecate+published tests
- routes.ts: use NotFoundError (404) instead of BadRequestError (400) for missing agent by key and missing published version - routes.test.ts: fix expectation for unknown key (400→404), add 4 new tests: deprecate success, deprecate already-deprecated guard, GET published success, GET published 404 when none - Total: 13 agent tests (was 8)
This commit is contained in:
parent
5f294b30b0
commit
036d17d8f0
@ -111,12 +111,12 @@ describe('agentRoutes', () => {
|
|||||||
expect(JSON.parse(res.body).key).toBe('incident-responder');
|
expect(JSON.parse(res.body).key).toBe('incident-responder');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GET /agents/by-key/:key returns 400 for unknown key', async () => {
|
it('GET /agents/by-key/:key returns 404 for unknown key', async () => {
|
||||||
repoMock.getAgentByKey.mockResolvedValue(null);
|
repoMock.getAgentByKey.mockResolvedValue(null);
|
||||||
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
||||||
|
|
||||||
const res = await app.inject({ method: 'GET', url: '/api/agents/by-key/nonexistent' });
|
const res = await app.inject({ method: 'GET', url: '/api/agents/by-key/nonexistent' });
|
||||||
expect(res.statusCode).toBe(400);
|
expect(res.statusCode).toBe(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('POST /agents/:id/versions/:versionId/publish publishes and deprecates previous', async () => {
|
it('POST /agents/:id/versions/:versionId/publish publishes and deprecates previous', async () => {
|
||||||
@ -154,6 +154,61 @@ describe('agentRoutes', () => {
|
|||||||
expect(res.statusCode).toBe(400);
|
expect(res.statusCode).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('POST /agents/:id/versions/:versionId/deprecate marks version deprecated', async () => {
|
||||||
|
repoMock.getAgent.mockResolvedValue({ id: 'agt_1', productId: 'lysnrai' });
|
||||||
|
repoMock.getAgentVersion.mockResolvedValue({ id: 'agt_1:v1', status: 'published' });
|
||||||
|
repoMock.updateAgentVersion.mockResolvedValue({ id: 'agt_1:v1', status: 'deprecated' });
|
||||||
|
|
||||||
|
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
||||||
|
const res = await app.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/agents/agt_1/versions/agt_1:v1/deprecate',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
expect(repoMock.updateAgentVersion).toHaveBeenCalledWith('agt_1:v1', 'agt_1', {
|
||||||
|
status: 'deprecated',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('POST /agents/:id/versions/:versionId/deprecate rejects already deprecated', async () => {
|
||||||
|
repoMock.getAgent.mockResolvedValue({ id: 'agt_1', productId: 'lysnrai' });
|
||||||
|
repoMock.getAgentVersion.mockResolvedValue({ id: 'agt_1:v1', status: 'deprecated' });
|
||||||
|
|
||||||
|
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
||||||
|
const res = await app.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/agents/agt_1/versions/agt_1:v1/deprecate',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(400);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('GET /agents/:id/published returns the published version', async () => {
|
||||||
|
repoMock.getAgent.mockResolvedValue({ id: 'agt_1', productId: 'lysnrai' });
|
||||||
|
repoMock.getPublishedVersion.mockResolvedValue({
|
||||||
|
id: 'agt_1:v2',
|
||||||
|
status: 'published',
|
||||||
|
version: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
||||||
|
const res = await app.inject({ method: 'GET', url: '/api/agents/agt_1/published' });
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
expect(JSON.parse(res.body).id).toBe('agt_1:v2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('GET /agents/:id/published returns 404 when none published', async () => {
|
||||||
|
repoMock.getAgent.mockResolvedValue({ id: 'agt_1', productId: 'lysnrai' });
|
||||||
|
repoMock.getPublishedVersion.mockResolvedValue(null);
|
||||||
|
|
||||||
|
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
||||||
|
const res = await app.inject({ method: 'GET', url: '/api/agents/agt_1/published' });
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(404);
|
||||||
|
});
|
||||||
|
|
||||||
it('DELETE /agents/:id only allows deleting draft agents', async () => {
|
it('DELETE /agents/:id only allows deleting draft agents', async () => {
|
||||||
repoMock.getAgent.mockResolvedValue({ id: 'agt_1', productId: 'lysnrai', status: 'active' });
|
repoMock.getAgent.mockResolvedValue({ id: 'agt_1', productId: 'lysnrai', status: 'active' });
|
||||||
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
import type { FastifyInstance } from 'fastify';
|
import type { FastifyInstance } from 'fastify';
|
||||||
import { BadRequestError, ForbiddenError } from '../../lib/errors.js';
|
import { BadRequestError, ForbiddenError, NotFoundError } from '../../lib/errors.js';
|
||||||
import {
|
import {
|
||||||
AgentDefinitionDoc,
|
AgentDefinitionDoc,
|
||||||
AgentVersionDoc,
|
AgentVersionDoc,
|
||||||
@ -148,7 +148,7 @@ export async function agentRoutes(app: FastifyInstance) {
|
|||||||
const access = requireAdmin(req);
|
const access = requireAdmin(req);
|
||||||
const { key } = req.params as { key: string };
|
const { key } = req.params as { key: string };
|
||||||
const agent = await repo.getAgentByKey(access.productId, key);
|
const agent = await repo.getAgentByKey(access.productId, key);
|
||||||
if (!agent) throw new BadRequestError(`Agent with key '${key}' not found`);
|
if (!agent) throw new NotFoundError(`Agent with key '${key}' not found`);
|
||||||
return agent;
|
return agent;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ export async function agentRoutes(app: FastifyInstance) {
|
|||||||
const { id } = req.params as { id: string };
|
const { id } = req.params as { id: string };
|
||||||
await repo.getAgent(id, access.productId);
|
await repo.getAgent(id, access.productId);
|
||||||
const published = await repo.getPublishedVersion(id);
|
const published = await repo.getPublishedVersion(id);
|
||||||
if (!published) throw new BadRequestError('No published version found');
|
if (!published) throw new NotFoundError('No published version found');
|
||||||
return published;
|
return published;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user