Files
mcpctl/src/mcpd/tests/bootstrap-system-project.test.ts

151 lines
4.9 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { bootstrapSystemProject, SYSTEM_PROJECT_NAME, getSystemPromptNames } from '../src/bootstrap/system-project.js';
import type { PrismaClient } from '@prisma/client';
function mockPrisma(): PrismaClient {
const prompts = new Map<string, { id: string; name: string; projectId: string }>();
let promptIdCounter = 1;
return {
user: {
upsert: vi.fn(async () => ({
id: 'sys-user-id',
email: 'system@mcpctl.local',
name: 'System',
})),
},
project: {
upsert: vi.fn(async (args: { where: { name: string }; create: Record<string, unknown>; update: Record<string, unknown> }) => ({
id: 'sys-proj-id',
name: args.where.name,
...args.create,
})),
},
prompt: {
findFirst: vi.fn(async (args: { where: { name: string; projectId: string } }) => {
return prompts.get(`${args.where.projectId}:${args.where.name}`) ?? null;
}),
create: vi.fn(async (args: { data: { name: string; content: string; priority: number; projectId: string } }) => {
const id = `prompt-${promptIdCounter++}`;
const prompt = { id, ...args.data };
prompts.set(`${args.data.projectId}:${args.data.name}`, prompt);
return prompt;
}),
},
} as unknown as PrismaClient;
}
describe('bootstrapSystemProject', () => {
let prisma: PrismaClient;
beforeEach(() => {
prisma = mockPrisma();
});
it('creates a system user via upsert', async () => {
await bootstrapSystemProject(prisma);
expect(prisma.user.upsert).toHaveBeenCalledWith(
expect.objectContaining({
where: { email: 'system@mcpctl.local' },
create: expect.objectContaining({
email: 'system@mcpctl.local',
name: 'System',
}),
}),
);
});
it('creates the mcpctl-system project via upsert', async () => {
await bootstrapSystemProject(prisma);
expect(prisma.project.upsert).toHaveBeenCalledWith(
expect.objectContaining({
where: { name: SYSTEM_PROJECT_NAME },
create: expect.objectContaining({
name: SYSTEM_PROJECT_NAME,
ownerId: 'sys-user-id',
gated: false,
}),
update: {},
}),
);
});
it('creates all system prompts', async () => {
await bootstrapSystemProject(prisma);
const expectedNames = getSystemPromptNames();
expect(expectedNames.length).toBeGreaterThanOrEqual(4);
for (const name of expectedNames) {
expect(prisma.prompt.findFirst).toHaveBeenCalledWith(
expect.objectContaining({
where: { name, projectId: 'sys-proj-id' },
}),
);
}
expect(prisma.prompt.create).toHaveBeenCalledTimes(expectedNames.length);
});
it('creates system prompts with expected priorities', async () => {
await bootstrapSystemProject(prisma);
const createCalls = vi.mocked(prisma.prompt.create).mock.calls;
for (const call of createCalls) {
const data = (call[0] as { data: { name: string; priority: number } }).data;
// Gate prompts have priority 10, LLM pipeline prompts have priority 5
if (data.name.startsWith('gate-') || data.name === 'session-greeting') {
expect(data.priority).toBe(10);
} else {
expect(data.priority).toBe(5);
}
}
});
it('does not re-create existing prompts (idempotent)', async () => {
// First call creates everything
await bootstrapSystemProject(prisma);
const firstCallCount = vi.mocked(prisma.prompt.create).mock.calls.length;
// Second call — prompts already exist in mock, should not create again
await bootstrapSystemProject(prisma);
// create should not have been called additional times
expect(vi.mocked(prisma.prompt.create).mock.calls.length).toBe(firstCallCount);
});
it('re-creates deleted prompts on subsequent startup', async () => {
// First run creates everything
await bootstrapSystemProject(prisma);
// Simulate deletion: clear the map so findFirst returns null
vi.mocked(prisma.prompt.findFirst).mockResolvedValue(null);
vi.mocked(prisma.prompt.create).mockClear();
// Second run should recreate
await bootstrapSystemProject(prisma);
const expectedNames = getSystemPromptNames();
expect(vi.mocked(prisma.prompt.create).mock.calls.length).toBe(expectedNames.length);
});
it('system project has gated=false', async () => {
await bootstrapSystemProject(prisma);
const upsertCall = vi.mocked(prisma.project.upsert).mock.calls[0]![0];
expect((upsertCall as { create: { gated: boolean } }).create.gated).toBe(false);
});
});
describe('getSystemPromptNames', () => {
it('returns all system prompt names', () => {
const names = getSystemPromptNames();
expect(names).toContain('gate-instructions');
expect(names).toContain('gate-encouragement');
expect(names).toContain('gate-intercept-preamble');
expect(names).toContain('session-greeting');
});
});