Files
9router/tests/unit/provider-connection-admin-access.test.js
T

119 lines
4.2 KiB
JavaScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const getProviderConnectionById = vi.fn();
const getProxyPoolById = vi.fn();
const updateProviderConnection = vi.fn();
const deleteProviderConnection = vi.fn();
const getProviderConnectionAccess = vi.fn();
vi.mock("@/models", () => ({
getProviderConnectionById,
getProxyPoolById,
updateProviderConnection,
deleteProviderConnection,
}));
vi.mock("@/lib/providers/connectionAccess", () => ({ getProviderConnectionAccess }));
vi.mock("@/shared/constants/providers", () => ({
isOpenAICompatibleProvider: (provider) => provider.startsWith("openai-compatible-"),
isAnthropicCompatibleProvider: (provider) => provider.startsWith("anthropic-compatible-"),
isCustomEmbeddingProvider: (provider) => provider.startsWith("custom-embedding-"),
}));
const { PUT, DELETE } = await import("../../src/app/api/providers/[id]/route.js");
const memberAccess = {
user: { id: "member", role: "user" },
ownerId: "member",
};
const adminAccess = {
user: { id: "admin", role: "admin" },
ownerId: null,
};
describe("provider connection administrator-managed access", () => {
beforeEach(() => {
getProviderConnectionById.mockReset();
getProxyPoolById.mockReset();
updateProviderConnection.mockReset();
deleteProviderConnection.mockReset();
getProviderConnectionAccess.mockReset();
});
it("prevents a member from updating their legacy compatible connection", async () => {
getProviderConnectionAccess.mockResolvedValue(memberAccess);
getProviderConnectionById.mockResolvedValue({
id: "legacy-compatible",
provider: "openai-compatible-chat-node",
ownerId: "member",
});
const response = await PUT(new Request("http://localhost/api/providers/legacy-compatible", {
method: "PUT",
body: JSON.stringify({ name: "Changed" }),
}), { params: Promise.resolve({ id: "legacy-compatible" }) });
expect(response.status).toBe(403);
expect(updateProviderConnection).not.toHaveBeenCalled();
});
it("prevents a member from deleting their legacy compatible connection", async () => {
getProviderConnectionAccess.mockResolvedValue(memberAccess);
getProviderConnectionById.mockResolvedValue({
id: "legacy-compatible",
provider: "anthropic-compatible-node",
ownerId: "member",
});
const response = await DELETE(new Request("http://localhost/api/providers/legacy-compatible", {
method: "DELETE",
}), { params: Promise.resolve({ id: "legacy-compatible" }) });
expect(response.status).toBe(403);
expect(deleteProviderConnection).not.toHaveBeenCalled();
});
it("allows an administrator to delete a compatible connection", async () => {
getProviderConnectionAccess.mockResolvedValue(adminAccess);
getProviderConnectionById.mockResolvedValue({
id: "compatible",
provider: "custom-embedding-node",
ownerId: "admin",
});
deleteProviderConnection.mockResolvedValue(true);
const response = await DELETE(new Request("http://localhost/api/providers/compatible", {
method: "DELETE",
}), { params: Promise.resolve({ id: "compatible" }) });
expect(response.status).toBe(200);
expect(deleteProviderConnection).toHaveBeenCalledWith("compatible");
});
it("preserves member control over their non-compatible connection", async () => {
getProviderConnectionAccess.mockResolvedValue(memberAccess);
getProviderConnectionById.mockResolvedValue({
id: "openai-connection",
provider: "openai",
ownerId: "member",
providerSpecificData: {},
authType: "apikey",
});
updateProviderConnection.mockResolvedValue({
id: "openai-connection",
provider: "openai",
name: "Changed",
});
const response = await PUT(new Request("http://localhost/api/providers/openai-connection", {
method: "PUT",
body: JSON.stringify({ name: "Changed" }),
}), { params: Promise.resolve({ id: "openai-connection" }) });
expect(response.status).toBe(200);
expect(updateProviderConnection).toHaveBeenCalledWith("openai-connection", {
name: "Changed",
providerSpecificData: {},
});
});
});