Files
curriculum-project-hub/hub/test/integration/silo-bootstrap.test.ts
T

99 lines
4.2 KiB
TypeScript

import { afterAll, beforeEach, describe, expect, it } from "vitest";
import { bootstrapAlphaSilo } from "../../src/deployment/bootstrap-silo.js";
import { requireSiloOrganization } from "../../src/deployment/silo.js";
import { prisma, testSecretEnvelope } from "./helpers.js";
const input = {
organization: { id: "org_alpha", slug: "alpha", name: "Alpha School" },
owner: { openId: "ou_owner", displayName: "Owner" },
feishu: { appId: "cli_alpha", appSecret: "feishu-secret", botOpenId: "ou_bot" },
provider: {
providerId: "openrouter",
baseUrl: "https://openrouter.ai/api",
authToken: "provider-secret",
},
teams: [{ slug: "teachers", name: "Teachers" }],
} as const;
describe("Alpha Silo bootstrap", () => {
beforeEach(async () => {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE "Organization" RESTART IDENTITY CASCADE`);
await prisma.organization.create({
data: {
id: "org_default",
slug: "legacy-default",
name: "Legacy Default Organization",
agentRoles: { create: { roleId: "draft", label: "草稿", isDefault: true } },
projectSettings: { create: { membersCanCreateProjects: true } },
folders: {
create: {
id: "folder_inbox_2b99350e0db97ad0cbcb55c20ee8bafa",
name: "Inbox",
sortKey: "000000",
},
},
},
});
});
afterAll(async () => {
await prisma.$disconnect();
});
it("creates one scoped Organization and is idempotent", async () => {
const probes = { feishu: async () => {}, provider: async () => {} };
const first = await bootstrapAlphaSilo(prisma, testSecretEnvelope, input, probes);
const second = await bootstrapAlphaSilo(prisma, testSecretEnvelope, input, probes);
expect(first).toMatchObject({ organizationId: "org_alpha", initialized: true, providerConfigured: true });
expect(second).toMatchObject({ organizationId: "org_alpha", initialized: false, providerConfigured: true });
await expect(requireSiloOrganization(prisma, "org_alpha")).resolves.toMatchObject({ slug: "alpha" });
expect(await prisma.organization.count()).toBe(1);
expect(await prisma.organizationMembership.count({ where: { role: "OWNER", revokedAt: null } })).toBe(1);
expect(await prisma.feishuUserIdentity.count()).toBe(1);
expect(await prisma.team.count({ where: { slug: "teachers", archivedAt: null } })).toBe(1);
expect(await prisma.teamMembership.count({ where: { revokedAt: null } })).toBe(1);
expect(await prisma.organizationProviderConnection.count({ where: { status: "ACTIVE" } })).toBe(1);
await expect(prisma.organizationAgentRole.findMany({
where: { organizationId: "org_alpha", disabledAt: null },
orderBy: { sortOrder: "asc" },
select: { roleId: true, label: true, isDefault: true },
})).resolves.toEqual([
{ roleId: "draft", label: "草稿", isDefault: true },
{ roleId: "review", label: "审校", isDefault: false },
]);
const persisted = JSON.stringify({
feishu: await prisma.feishuApplicationCredentialVersion.findMany(),
provider: await prisma.providerCredentialVersion.findMany(),
});
expect(persisted).not.toContain("feishu-secret");
expect(persisted).not.toContain("provider-secret");
});
it("rejects a configured Organization that does not match the database", async () => {
await bootstrapAlphaSilo(prisma, testSecretEnvelope, input, {
feishu: async () => {},
provider: async () => {},
});
await expect(requireSiloOrganization(prisma, "org_other")).rejects.toThrow("Silo Organization mismatch");
});
it("does not delete a legacy migration Organization that contains tenant data", async () => {
await prisma.project.create({
data: {
organizationId: "org_default",
folderId: "folder_inbox_2b99350e0db97ad0cbcb55c20ee8bafa",
name: "Legacy Project",
workspaceDir: "legacy-project",
},
});
await expect(bootstrapAlphaSilo(prisma, testSecretEnvelope, input, {
feishu: async () => {},
provider: async () => {},
})).rejects.toThrow("bootstrap database is not the configured single-Organization Silo");
await expect(prisma.organization.findUnique({ where: { id: "org_default" } })).resolves.not.toBeNull();
});
});