132 lines
4.2 KiB
TypeScript
132 lines
4.2 KiB
TypeScript
import { Logger } from "@nestjs/common";
|
|
import type { AgentProviderConfig } from "@prisma/client";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { PrismaService } from "../../prisma/prisma.service";
|
|
import { AgentProviderRegistry } from "../agents/agent-provider.registry";
|
|
import { OpenClawProviderFactory } from "./openclaw/openclaw.provider-factory";
|
|
import { ProvidersModule } from "./providers.module";
|
|
|
|
type MockOpenClawProvider = {
|
|
providerId: string;
|
|
validateBaseUrl: ReturnType<typeof vi.fn>;
|
|
validateToken: ReturnType<typeof vi.fn>;
|
|
isAvailable: ReturnType<typeof vi.fn>;
|
|
};
|
|
|
|
describe("ProvidersModule", () => {
|
|
let moduleRef: ProvidersModule;
|
|
let prisma: {
|
|
agentProviderConfig: {
|
|
findMany: ReturnType<typeof vi.fn>;
|
|
};
|
|
};
|
|
let registry: {
|
|
registerProvider: ReturnType<typeof vi.fn>;
|
|
};
|
|
let factory: {
|
|
createProvider: ReturnType<typeof vi.fn>;
|
|
};
|
|
|
|
const config: AgentProviderConfig = {
|
|
id: "cfg-openclaw-1",
|
|
workspaceId: "workspace-1",
|
|
name: "openclaw-home",
|
|
provider: "openclaw",
|
|
gatewayUrl: "https://gateway.example.com",
|
|
credentials: { apiToken: "enc:token-value" },
|
|
isActive: true,
|
|
createdAt: new Date("2026-03-07T15:00:00.000Z"),
|
|
updatedAt: new Date("2026-03-07T15:00:00.000Z"),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
prisma = {
|
|
agentProviderConfig: {
|
|
findMany: vi.fn(),
|
|
},
|
|
};
|
|
|
|
registry = {
|
|
registerProvider: vi.fn(),
|
|
};
|
|
|
|
factory = {
|
|
createProvider: vi.fn(),
|
|
};
|
|
|
|
moduleRef = new ProvidersModule(
|
|
prisma as unknown as PrismaService,
|
|
registry as unknown as AgentProviderRegistry,
|
|
factory as unknown as OpenClawProviderFactory
|
|
);
|
|
});
|
|
|
|
it("registers reachable OpenClaw providers", async () => {
|
|
const provider: MockOpenClawProvider = {
|
|
providerId: "openclaw-home",
|
|
validateBaseUrl: vi.fn(),
|
|
validateToken: vi.fn(),
|
|
isAvailable: vi.fn().mockResolvedValue(true),
|
|
};
|
|
|
|
prisma.agentProviderConfig.findMany.mockResolvedValue([config]);
|
|
factory.createProvider.mockReturnValue(provider);
|
|
|
|
await moduleRef.onModuleInit();
|
|
|
|
expect(prisma.agentProviderConfig.findMany).toHaveBeenCalledWith({
|
|
where: {
|
|
provider: "openclaw",
|
|
isActive: true,
|
|
},
|
|
orderBy: [{ createdAt: "asc" }, { id: "asc" }],
|
|
});
|
|
expect(factory.createProvider).toHaveBeenCalledWith(config);
|
|
expect(provider.validateBaseUrl).toHaveBeenCalledTimes(1);
|
|
expect(provider.validateToken).toHaveBeenCalledTimes(1);
|
|
expect(provider.isAvailable).toHaveBeenCalledTimes(1);
|
|
expect(registry.registerProvider).toHaveBeenCalledWith(provider);
|
|
});
|
|
|
|
it("skips provider registration when gateway is unreachable", async () => {
|
|
const warnSpy = vi.spyOn(Logger.prototype, "warn").mockImplementation(() => undefined);
|
|
const provider: MockOpenClawProvider = {
|
|
providerId: "openclaw-home",
|
|
validateBaseUrl: vi.fn(),
|
|
validateToken: vi.fn(),
|
|
isAvailable: vi.fn().mockResolvedValue(false),
|
|
};
|
|
|
|
prisma.agentProviderConfig.findMany.mockResolvedValue([config]);
|
|
factory.createProvider.mockReturnValue(provider);
|
|
|
|
await moduleRef.onModuleInit();
|
|
|
|
expect(registry.registerProvider).not.toHaveBeenCalled();
|
|
expect(warnSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining("Skipping OpenClaw provider openclaw-home")
|
|
);
|
|
});
|
|
|
|
it("skips provider registration when token decryption fails", async () => {
|
|
const errorSpy = vi.spyOn(Logger.prototype, "error").mockImplementation(() => undefined);
|
|
const provider: MockOpenClawProvider = {
|
|
providerId: "openclaw-home",
|
|
validateBaseUrl: vi.fn(),
|
|
validateToken: vi.fn().mockImplementation(() => {
|
|
throw new Error("Failed to decrypt API token");
|
|
}),
|
|
isAvailable: vi.fn().mockResolvedValue(true),
|
|
};
|
|
|
|
prisma.agentProviderConfig.findMany.mockResolvedValue([config]);
|
|
factory.createProvider.mockReturnValue(provider);
|
|
|
|
await moduleRef.onModuleInit();
|
|
|
|
expect(registry.registerProvider).not.toHaveBeenCalled();
|
|
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("token decryption failed"));
|
|
expect(provider.isAvailable).not.toHaveBeenCalled();
|
|
});
|
|
});
|