import { OllamaLocalBackend } from "../backends/ollama-local.js"; import { OllamaCloudBackend } from "../backends/ollama-cloud.js"; import { OpencodeBackend } from "../backends/opencode.js"; import { resolveBackend, createBackend } from "../backends/index.js"; import { DEFAULT_BACKEND_CONFIG, BackendUnavailableError } from "../backends/types.js"; describe("Backend Availability Detection", () => { describe("OllamaLocalBackend.isAvailable", () => { it("returns false for unreachable host", async () => { const backend = new OllamaLocalBackend({ base_url: "http://localhost:1", model_profile: "balanced", }); expect(await backend.isAvailable()).toBe(false); }); it("returns false for invalid URL", async () => { const backend = new OllamaLocalBackend({ base_url: "not-a-url", model_profile: "balanced", }); expect(await backend.isAvailable()).toBe(false); }); it("returns false for timeout", async () => { const backend = new OllamaLocalBackend({ base_url: "http://192.0.2.1", model_profile: "balanced", }); expect(await backend.isAvailable()).toBe(false); }, 10000); }); describe("OllamaCloudBackend.isAvailable", () => { it("returns false when base_url is empty", async () => { const backend = new OllamaCloudBackend({ base_url: "", api_key_env: "OLLAMA_CLOUD_API_KEY", model_profile: "quality", }); expect(await backend.isAvailable()).toBe(false); }); it("returns false when no API key in env", async () => { const backend = new OllamaCloudBackend({ base_url: "https://api.example.com", api_key_env: "NONEXISTENT_ENV_VAR_12345", model_profile: "quality", timeout_ms: 5000, }); expect(await backend.isAvailable()).toBe(false); }); }); describe("OpencodeBackend.isAvailable", () => { it("returns false when executable not found", async () => { const backend = new OpencodeBackend({ enabled: true, executable: "nonexistent-opencode-binary-xyz", }); expect(await backend.isAvailable()).toBe(false); }); it("returns false when disabled", async () => { const backend = new OpencodeBackend({ enabled: false }); expect(await backend.isAvailable()).toBe(false); }); }); describe("resolveBackend auto-detection", () => { it("throws BackendUnavailableError when no backends available", async () => { const config = { ...DEFAULT_BACKEND_CONFIG, llm_backends: { "ollama-local": { base_url: "http://localhost:1", model_profile: "balanced" as const }, "ollama-cloud": { base_url: "", api_key_env: "NONEXISTENT_12345", model_profile: "quality" as const }, }, agent_backends: { opencode: { enabled: true, executable: "nonexistent-opencode-binary-xyz" }, }, }; await expect(resolveBackend(config)).rejects.toThrow(BackendUnavailableError); }); it("tries opencode before ollama-local", async () => { expect(DEFAULT_BACKEND_CONFIG.provider).toBe("auto"); }); it("createBackend throws for unknown provider", () => { expect(() => createBackend("unknown-provider" as "opencode", DEFAULT_BACKEND_CONFIG)).toThrow(BackendUnavailableError); }); }); describe("BackendUnavailableError", () => { it("contains installation hints", () => { const err = new BackendUnavailableError("auto"); expect(err.message).toContain("opencode"); expect(err.message).toContain("OpenAI"); expect(err.message).toContain("Ollama"); expect(err.message).toContain("OLLAMA_CLOUD_API_KEY"); }); }); });