godcrm/backend/services/agent-tools/__tests__/query-inflight-paused.test.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

216 lines
6.8 KiB
JavaScript

// @vitest-environment node
/**
* ADR-0063-A §P3 — query_inflight_paused MCP wrapper tests.
*
* Mocks dbAll() and asserts the wrapper builds the right scope filter,
* shapes the response, and degrades gracefully when no rows match.
* Source-of-truth for the SQL stays in SystemTableService.queryInflightRuns;
* tests here cover the handler-level contract:
* - admin=true is honoured ONLY when context.spaceId === 1 (otherwise dropped)
* - non-admin callers stay scoped to their context.spaceId via metadata.space_id
* - agent_slug + conversation_id filters propagate to the SQL WHERE clause
* - limit capped at 200, default 50
* - empty result + DB error shapes
*/
import { describe, it, expect, beforeEach, vi } from 'vitest';
const dbAll = vi.fn();
const dbGet = vi.fn();
const dbRun = vi.fn();
const isPostgres = vi.fn(() => true);
const sqlNow = vi.fn(() => 'NOW()');
vi.mock('../../../database/connection.js', () => ({
dbAll: (...args) => dbAll(...args),
dbGet: (...args) => dbGet(...args),
dbRun: (...args) => dbRun(...args),
isPostgres: (...args) => isPostgres(...args),
sqlNow: (...args) => sqlNow(...args),
}));
vi.mock('../../../utils/logger.js', () => ({
aiLogger: { error: vi.fn(), info: vi.fn(), warn: vi.fn(), debug: vi.fn() },
apiLogger: { error: vi.fn(), info: vi.fn(), warn: vi.fn(), debug: vi.fn() },
}));
const { ticketToolHandlers } = await import('../ticket-tools.js');
beforeEach(() => {
dbAll.mockReset();
});
function paused(id, overrides = {}) {
return {
id,
ticket_id: null,
agent_slug: 'developer-ralph',
conversation_id: 3214,
started_at: new Date(`2026-05-15T12:00:0${id}Z`),
last_step_id: null,
status: 'paused',
reason: 'paused-rate-limit',
resume_at: new Date(`2026-05-15T12:15:0${id}Z`),
resume_attempts: 0,
metadata: { space_id: 11, retry_after_s: 900 },
updated_at: new Date(`2026-05-15T12:00:0${id}Z`),
...overrides,
};
}
describe('query_inflight_paused — scope resolution', () => {
it('admin=true is honoured from space-1 context → no metadata.space_id filter', async () => {
dbAll.mockResolvedValueOnce([paused(1), paused(2, { metadata: { space_id: 35 } })]);
const res = await ticketToolHandlers.query_inflight_paused(
{ admin: true },
1,
{ spaceId: 1 }
);
expect(res.success).toBe(true);
expect(res.admin_view).toBe(true);
expect(res.space_id).toBe(1);
expect(res.count).toBe(2);
const [sql, params] = dbAll.mock.calls[0];
expect(sql).toContain("status = ?");
expect(sql).not.toContain("(metadata->>'space_id')::int");
expect(params).toEqual(['paused', 50]);
});
it('admin=true is silently DROPPED when caller is not in space-1', async () => {
dbAll.mockResolvedValueOnce([paused(1)]);
const res = await ticketToolHandlers.query_inflight_paused(
{ admin: true },
1,
{ spaceId: 11 }
);
expect(res.admin_view).toBe(false);
expect(res.space_id).toBe(11);
const [sql, params] = dbAll.mock.calls[0];
expect(sql).toContain("(metadata->>'space_id')::int = ?");
expect(params).toEqual([11, 'paused', 50]);
});
it('non-admin caller is scoped to context.spaceId via metadata.space_id', async () => {
dbAll.mockResolvedValueOnce([paused(1)]);
await ticketToolHandlers.query_inflight_paused({}, 1, { spaceId: 11 });
const [sql, params] = dbAll.mock.calls[0];
expect(sql).toContain("(metadata->>'space_id')::int = ?");
expect(params).toEqual([11, 'paused', 50]);
});
it('no context.spaceId + no admin → unfiltered query (system/internal caller)', async () => {
dbAll.mockResolvedValueOnce([paused(1)]);
const res = await ticketToolHandlers.query_inflight_paused({}, 1);
// admin_view stays false because admin !== true
expect(res.admin_view).toBe(false);
expect(res.space_id).toBe(null);
const [sql, params] = dbAll.mock.calls[0];
expect(sql).not.toContain("metadata->>'space_id'");
expect(params).toEqual(['paused', 50]);
});
});
describe('query_inflight_paused — agent_slug / conversation_id / limit', () => {
it('passes agent_slug into the WHERE clause', async () => {
dbAll.mockResolvedValueOnce([paused(1, { agent_slug: 'architect' })]);
await ticketToolHandlers.query_inflight_paused(
{ admin: true, agent_slug: 'architect' },
1,
{ spaceId: 1 }
);
const [sql, params] = dbAll.mock.calls[0];
expect(sql).toContain('agent_slug = ?');
expect(params).toEqual(['paused', 'architect', 50]);
});
it('passes conversation_id into the WHERE clause', async () => {
dbAll.mockResolvedValueOnce([paused(1, { conversation_id: 3214 })]);
await ticketToolHandlers.query_inflight_paused(
{ admin: true, conversation_id: 3214 },
1,
{ spaceId: 1 }
);
const [sql, params] = dbAll.mock.calls[0];
expect(sql).toContain('conversation_id = ?');
expect(params).toEqual(['paused', 3214, 50]);
});
it('caps limit at 200', async () => {
dbAll.mockResolvedValueOnce([]);
await ticketToolHandlers.query_inflight_paused({ admin: true, limit: 9999 }, 1, { spaceId: 1 });
const [, params] = dbAll.mock.calls[0];
expect(params[params.length - 1]).toBe(200);
});
it('uses default limit 50 when omitted', async () => {
dbAll.mockResolvedValueOnce([]);
await ticketToolHandlers.query_inflight_paused({ admin: true }, 1, { spaceId: 1 });
const [, params] = dbAll.mock.calls[0];
expect(params[params.length - 1]).toBe(50);
});
});
describe('query_inflight_paused — empty result edge', () => {
it('returns success with count=0 + empty runs when no rows match', async () => {
dbAll.mockResolvedValueOnce([]);
const res = await ticketToolHandlers.query_inflight_paused({}, 1, { spaceId: 11 });
expect(res).toMatchObject({
success: true,
space_id: 11,
admin_view: false,
count: 0,
runs: [],
});
});
it('surfaces DB errors as { error } shape, not a throw', async () => {
dbAll.mockRejectedValueOnce(new Error('connection refused'));
const res = await ticketToolHandlers.query_inflight_paused({ admin: true }, 1, { spaceId: 1 });
expect(res).toEqual({ error: 'connection refused' });
});
});
describe('query_inflight_paused — row shape', () => {
it('returns id/ticket_id/agent_slug/conversation_id/status/reason/resume_at/metadata', async () => {
dbAll.mockResolvedValueOnce([
paused(7, { metadata: { space_id: 11, retry_after_s: 60 } }),
]);
const res = await ticketToolHandlers.query_inflight_paused(
{ admin: true },
1,
{ spaceId: 1 }
);
expect(res.runs[0]).toMatchObject({
id: 7,
agent_slug: 'developer-ralph',
conversation_id: 3214,
status: 'paused',
reason: 'paused-rate-limit',
metadata: { space_id: 11, retry_after_s: 60 },
});
expect(res.runs[0].started_at).toBeInstanceOf(Date);
});
});