120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
|
|
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
|
||
|
|
import type { PrismaClient } from '@prisma/client';
|
||
|
|
import { setupTestDb, cleanupTestDb, clearAllTables } from './helpers.js';
|
||
|
|
|
||
|
|
describe('ResourceRevision schema', () => {
|
||
|
|
let prisma: PrismaClient;
|
||
|
|
|
||
|
|
beforeAll(async () => {
|
||
|
|
prisma = await setupTestDb();
|
||
|
|
}, 30_000);
|
||
|
|
|
||
|
|
afterAll(async () => {
|
||
|
|
await cleanupTestDb();
|
||
|
|
});
|
||
|
|
|
||
|
|
beforeEach(async () => {
|
||
|
|
await clearAllTables(prisma);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('creates a revision with required fields and defaults', async () => {
|
||
|
|
const rev = await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'prompt',
|
||
|
|
resourceId: 'fake-prompt-id',
|
||
|
|
contentHash: 'sha256:abc',
|
||
|
|
body: { content: 'hello' },
|
||
|
|
},
|
||
|
|
});
|
||
|
|
expect(rev.id).toBeDefined();
|
||
|
|
expect(rev.semver).toBe('0.1.0');
|
||
|
|
expect(rev.note).toBe('');
|
||
|
|
expect(rev.authorUserId).toBeNull();
|
||
|
|
expect(rev.authorSessionId).toBeNull();
|
||
|
|
expect(rev.body).toEqual({ content: 'hello' });
|
||
|
|
expect(rev.createdAt).toBeInstanceOf(Date);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('survives resource deletion (soft FK)', async () => {
|
||
|
|
// No actual prompt exists with this id — the soft FK design lets
|
||
|
|
// revisions outlive their resources.
|
||
|
|
const rev = await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'skill',
|
||
|
|
resourceId: 'never-existed',
|
||
|
|
contentHash: 'sha256:def',
|
||
|
|
body: { content: 'ghost' },
|
||
|
|
},
|
||
|
|
});
|
||
|
|
expect(rev.resourceId).toBe('never-existed');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('orders revisions latest-first within a resource', async () => {
|
||
|
|
const resourceId = 'r1';
|
||
|
|
const a = await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'prompt', resourceId,
|
||
|
|
semver: '0.1.0', contentHash: 'h1', body: {},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
await new Promise((r) => setTimeout(r, 10));
|
||
|
|
const b = await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'prompt', resourceId,
|
||
|
|
semver: '0.1.1', contentHash: 'h2', body: {},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
await new Promise((r) => setTimeout(r, 10));
|
||
|
|
const c = await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'prompt', resourceId,
|
||
|
|
semver: '0.2.0', contentHash: 'h3', body: {},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
const rows = await prisma.resourceRevision.findMany({
|
||
|
|
where: { resourceType: 'prompt', resourceId },
|
||
|
|
orderBy: { createdAt: 'desc' },
|
||
|
|
});
|
||
|
|
expect(rows.map((r) => r.id)).toEqual([c.id, b.id, a.id]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('allows multiple revisions with the same contentHash (rollback)', async () => {
|
||
|
|
const resourceId = 'r2';
|
||
|
|
await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'prompt', resourceId,
|
||
|
|
semver: '0.1.0', contentHash: 'identical', body: {},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
const second = await prisma.resourceRevision.create({
|
||
|
|
data: {
|
||
|
|
resourceType: 'prompt', resourceId,
|
||
|
|
semver: '0.2.0', contentHash: 'identical', body: {},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
expect(second.id).toBeDefined();
|
||
|
|
const rows = await prisma.resourceRevision.findMany({
|
||
|
|
where: { contentHash: 'identical' },
|
||
|
|
});
|
||
|
|
expect(rows.length).toBe(2);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('discriminates between prompt and skill revisions', async () => {
|
||
|
|
await prisma.resourceRevision.create({
|
||
|
|
data: { resourceType: 'prompt', resourceId: 'x', contentHash: 'a', body: {} },
|
||
|
|
});
|
||
|
|
await prisma.resourceRevision.create({
|
||
|
|
data: { resourceType: 'skill', resourceId: 'x', contentHash: 'a', body: {} },
|
||
|
|
});
|
||
|
|
const prompts = await prisma.resourceRevision.findMany({
|
||
|
|
where: { resourceType: 'prompt', resourceId: 'x' },
|
||
|
|
});
|
||
|
|
const skills = await prisma.resourceRevision.findMany({
|
||
|
|
where: { resourceType: 'skill', resourceId: 'x' },
|
||
|
|
});
|
||
|
|
expect(prompts.length).toBe(1);
|
||
|
|
expect(skills.length).toBe(1);
|
||
|
|
});
|
||
|
|
});
|