evOo-local/packages/db/src/bootstrap-user.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

186 lines
6.9 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { bootstrapUserSpace } from "./bootstrap-user.js";
import type { PrismaClient } from "./client.js";
function makePrisma(settings: { id: string; ownerUserId: string | null } | null) {
const create = () => vi.fn(async (_input: { data: Record<string, unknown> }) => ({}));
const prisma = {
organization: {
create: create(),
findUniqueOrThrow: vi.fn(async () => {
throw new Error("not found");
}),
},
member: { create: create() },
space: { create: create() },
spaceMember: { create: create() },
deploymentSettings: {
findUnique: vi.fn(async () => settings),
create: create(),
update: create(),
upsert: vi.fn(
async (_input: { create: Record<string, unknown>; update: Record<string, unknown> }) =>
settings ?? { id: "default" },
),
updateMany: vi.fn(async () => ({ count: settings && !settings.ownerUserId ? 1 : 0 })),
},
memoryDocument: { findFirst: vi.fn(async () => null), create: create() },
notificationPreference: { create: create() },
};
return prisma;
}
const env = { signupsEnabled: "false", signupAllowlist: "a@example.com, b@example.com" };
describe("bootstrapUserSpace", () => {
it("creates a personal organization with a default workspace", async () => {
const prisma = makePrisma({ id: "default", ownerUserId: "user-1" });
const result = await bootstrapUserSpace(
prisma as unknown as PrismaClient,
{ id: "user-1" },
env,
);
expect(prisma.organization.create).toHaveBeenCalledTimes(1);
const orgData = prisma.organization.create.mock.calls[0]![0].data;
expect(orgData.name).toBe("Personal");
expect(orgData.slug).toBe("user-user-1".slice(0, 16));
expect(result.spaceId).toBe(orgData.id);
const memberData = prisma.member.create.mock.calls[0]![0].data;
expect(memberData.organizationId).toBe(orgData.id);
expect(memberData.userId).toBe("user-1");
expect(memberData.role).toBe("owner");
const spaceData = prisma.space.create.mock.calls[0]![0].data;
expect(spaceData).toEqual(
expect.objectContaining({
id: orgData.id,
organizationId: orgData.id,
name: "Personal",
}),
);
const spaceMemberData = prisma.spaceMember.create.mock.calls[0]![0].data;
expect(spaceMemberData).toEqual(
expect.objectContaining({
spaceId: orgData.id,
organizationId: orgData.id,
userId: "user-1",
}),
);
});
it("seeds deployment settings from the env policy when none exist", async () => {
const prisma = makePrisma(null);
await bootstrapUserSpace(prisma as unknown as PrismaClient, { id: "user-1" }, env);
const { create, update } = prisma.deploymentSettings.upsert.mock.calls[0]![0];
expect(create.id).toBe("default");
expect(create.ownerUserId).toBe("user-1");
expect(create.signupsEnabled).toBe(false);
expect(create.signupAllowlist).toBe("a@example.com,b@example.com");
expect(create.signupPolicyInitialized).toBe(true);
expect(update).toEqual({});
});
it("claims the deployment owner when settings exist without one", async () => {
const prisma = makePrisma({ id: "default", ownerUserId: null });
await bootstrapUserSpace(prisma as unknown as PrismaClient, { id: "user-1" }, env);
// Conditional claim: the database predicate decides, so a concurrent
// claimant that already holds the seat is never overwritten.
expect(prisma.deploymentSettings.updateMany).toHaveBeenCalledWith({
where: { id: "default", ownerUserId: null },
data: { ownerUserId: "user-1" },
});
});
it("leaves existing owned settings untouched", async () => {
const prisma = makePrisma({ id: "default", ownerUserId: "user-0" });
await bootstrapUserSpace(prisma as unknown as PrismaClient, { id: "user-1" }, env);
const { update } = prisma.deploymentSettings.upsert.mock.calls[0]![0];
expect(update).toEqual({});
// The only owner write is the conditional claim, which excludes rows
// that already have an owner.
expect(prisma.deploymentSettings.updateMany).toHaveBeenCalledWith({
where: { id: "default", ownerUserId: null },
data: { ownerUserId: "user-1" },
});
});
it("never claims deployment ownership when claimDeploymentOwner is false", async () => {
const prisma = makePrisma({ id: "default", ownerUserId: null });
await bootstrapUserSpace(prisma as unknown as PrismaClient, { id: "user-1" }, env, {
claimDeploymentOwner: false,
});
expect(prisma.deploymentSettings.updateMany).not.toHaveBeenCalled();
});
it("seeds settings without an owner when claimDeploymentOwner is false", async () => {
const prisma = makePrisma(null);
await bootstrapUserSpace(prisma as unknown as PrismaClient, { id: "user-1" }, env, {
claimDeploymentOwner: false,
});
const { create } = prisma.deploymentSettings.upsert.mock.calls[0]![0];
expect(create.ownerUserId).toBeNull();
});
it("creates the user memory document and notification preference in the new workspace", async () => {
const prisma = makePrisma({ id: "default", ownerUserId: "user-1" });
const { spaceId } = await bootstrapUserSpace(
prisma as unknown as PrismaClient,
{ id: "user-1" },
env,
);
const memoryData = prisma.memoryDocument.create.mock.calls[0]![0].data;
expect(memoryData.spaceId).toBe(spaceId);
expect(memoryData.userId).toBe("user-1");
expect(memoryData.scope).toBe("user");
expect(memoryData.path).toBe("MEMORY.md");
const prefData = prisma.notificationPreference.create.mock.calls[0]![0].data;
expect(prefData.spaceId).toBe(spaceId);
expect(prefData.userId).toBe("user-1");
});
});
describe("bootstrapUserSpace concurrency", () => {
it("recovers when a concurrent bootstrap wins the org, member, and settings races", async () => {
const uniqueViolation = async () => {
throw Object.assign(new Error("Unique constraint failed"), { code: "P2002" });
};
const prisma = {
organization: {
create: vi.fn(uniqueViolation),
findUniqueOrThrow: vi.fn(async () => ({ id: "org-winner" })),
},
member: { create: vi.fn(uniqueViolation) },
space: { create: vi.fn(uniqueViolation) },
spaceMember: { create: vi.fn(uniqueViolation) },
deploymentSettings: {
findUnique: vi.fn(async () => null),
create: vi.fn(uniqueViolation),
upsert: vi.fn(async () => ({ id: "default" })),
update: vi.fn(async () => ({})),
updateMany: vi.fn(async () => ({ count: 0 })),
},
memoryDocument: {
findFirst: vi.fn(async () => ({ id: "mem-1" })),
create: vi.fn(async () => ({})),
},
notificationPreference: { create: vi.fn(uniqueViolation) },
};
const result = await bootstrapUserSpace(
prisma as unknown as PrismaClient,
{ id: "user-1" },
env,
);
expect(result.spaceId).toBe("org-winner");
});
});