All checks were successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
216 lines
5.6 KiB
TypeScript
216 lines
5.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { AgentConfigService } from "./agent-config.service";
|
|
import { PrismaService } from "../prisma/prisma.service";
|
|
import { CryptoService } from "../crypto/crypto.service";
|
|
|
|
describe("AgentConfigService", () => {
|
|
let service: AgentConfigService;
|
|
|
|
const mockPrismaService = {
|
|
userAgentConfig: {
|
|
findUnique: vi.fn(),
|
|
},
|
|
llmProvider: {
|
|
findMany: vi.fn(),
|
|
},
|
|
userContainer: {
|
|
findUnique: vi.fn(),
|
|
findMany: vi.fn(),
|
|
},
|
|
systemContainer: {
|
|
findUnique: vi.fn(),
|
|
findMany: vi.fn(),
|
|
},
|
|
};
|
|
|
|
const mockCryptoService = {
|
|
isEncrypted: vi.fn((value: string) => value.startsWith("enc:")),
|
|
decrypt: vi.fn((value: string) => value.replace(/^enc:/, "")),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
|
|
service = new AgentConfigService(
|
|
mockPrismaService as unknown as PrismaService,
|
|
mockCryptoService as unknown as CryptoService
|
|
);
|
|
});
|
|
|
|
it("generateUserConfig returns valid openclaw.json structure", async () => {
|
|
mockPrismaService.userAgentConfig.findUnique.mockResolvedValue({
|
|
id: "cfg-1",
|
|
userId: "user-1",
|
|
primaryModel: "my-zai/glm-5",
|
|
});
|
|
|
|
mockPrismaService.userContainer.findUnique.mockResolvedValue({
|
|
id: "container-1",
|
|
userId: "user-1",
|
|
gatewayPort: 19001,
|
|
});
|
|
|
|
mockPrismaService.llmProvider.findMany.mockResolvedValue([
|
|
{
|
|
id: "provider-1",
|
|
userId: "user-1",
|
|
name: "my-zai",
|
|
displayName: "Z.ai",
|
|
type: "zai",
|
|
baseUrl: "https://api.z.ai/v1",
|
|
apiKey: "enc:secret-zai-key",
|
|
apiType: "openai-completions",
|
|
models: [{ id: "glm-5" }],
|
|
isActive: true,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
]);
|
|
|
|
const result = await service.generateUserConfig("user-1");
|
|
|
|
expect(result).toEqual({
|
|
gateway: {
|
|
mode: "local",
|
|
port: 19001,
|
|
bind: "lan",
|
|
auth: { mode: "token" },
|
|
http: {
|
|
endpoints: {
|
|
chatCompletions: { enabled: true },
|
|
},
|
|
},
|
|
},
|
|
agents: {
|
|
defaults: {
|
|
model: {
|
|
primary: "my-zai/glm-5",
|
|
},
|
|
},
|
|
},
|
|
models: {
|
|
providers: {
|
|
"my-zai": {
|
|
apiKey: "secret-zai-key",
|
|
baseUrl: "https://api.z.ai/v1",
|
|
models: {
|
|
"glm-5": {},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it("generateUserConfig decrypts API keys correctly", async () => {
|
|
mockPrismaService.userAgentConfig.findUnique.mockResolvedValue({
|
|
id: "cfg-1",
|
|
userId: "user-1",
|
|
primaryModel: "openai-work/gpt-4.1",
|
|
});
|
|
|
|
mockPrismaService.userContainer.findUnique.mockResolvedValue({
|
|
id: "container-1",
|
|
userId: "user-1",
|
|
gatewayPort: 18789,
|
|
});
|
|
|
|
mockPrismaService.llmProvider.findMany.mockResolvedValue([
|
|
{
|
|
id: "provider-1",
|
|
userId: "user-1",
|
|
name: "openai-work",
|
|
displayName: "OpenAI Work",
|
|
type: "openai",
|
|
baseUrl: "https://api.openai.com/v1",
|
|
apiKey: "enc:encrypted-openai-key",
|
|
apiType: "openai-completions",
|
|
models: [{ id: "gpt-4.1" }],
|
|
isActive: true,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
]);
|
|
|
|
const result = await service.generateUserConfig("user-1");
|
|
|
|
expect(mockCryptoService.decrypt).toHaveBeenCalledWith("enc:encrypted-openai-key");
|
|
expect(result.models.providers["openai-work"]?.apiKey).toBe("encrypted-openai-key");
|
|
});
|
|
|
|
it("generateUserConfig handles user with no providers", async () => {
|
|
mockPrismaService.userAgentConfig.findUnique.mockResolvedValue({
|
|
id: "cfg-1",
|
|
userId: "user-2",
|
|
primaryModel: "openai/gpt-4o-mini",
|
|
});
|
|
|
|
mockPrismaService.userContainer.findUnique.mockResolvedValue({
|
|
id: "container-2",
|
|
userId: "user-2",
|
|
gatewayPort: null,
|
|
});
|
|
|
|
mockPrismaService.llmProvider.findMany.mockResolvedValue([]);
|
|
|
|
const result = await service.generateUserConfig("user-2");
|
|
|
|
expect(result.models.providers).toEqual({});
|
|
expect(result.gateway.port).toBe(18789);
|
|
});
|
|
|
|
it("validateContainerToken returns correct type for user container", async () => {
|
|
mockPrismaService.userContainer.findMany.mockResolvedValue([
|
|
{
|
|
id: "user-container-1",
|
|
gatewayToken: "enc:user-token-1",
|
|
},
|
|
]);
|
|
mockPrismaService.systemContainer.findMany.mockResolvedValue([]);
|
|
|
|
const result = await service.validateContainerToken("user-token-1");
|
|
|
|
expect(result).toEqual({
|
|
type: "user",
|
|
id: "user-container-1",
|
|
});
|
|
});
|
|
|
|
it("validateContainerToken returns correct type for system container", async () => {
|
|
mockPrismaService.userContainer.findMany.mockResolvedValue([]);
|
|
mockPrismaService.systemContainer.findMany.mockResolvedValue([
|
|
{
|
|
id: "system-container-1",
|
|
gatewayToken: "enc:system-token-1",
|
|
},
|
|
]);
|
|
|
|
const result = await service.validateContainerToken("system-token-1");
|
|
|
|
expect(result).toEqual({
|
|
type: "system",
|
|
id: "system-container-1",
|
|
});
|
|
});
|
|
|
|
it("validateContainerToken returns null for invalid token", async () => {
|
|
mockPrismaService.userContainer.findMany.mockResolvedValue([
|
|
{
|
|
id: "user-container-1",
|
|
gatewayToken: "enc:user-token-1",
|
|
},
|
|
]);
|
|
|
|
mockPrismaService.systemContainer.findMany.mockResolvedValue([
|
|
{
|
|
id: "system-container-1",
|
|
gatewayToken: "enc:system-token-1",
|
|
},
|
|
]);
|
|
|
|
const result = await service.validateContainerToken("no-match");
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|