Download src/api/plugins-service.test.ts from SaylorTwift/openhands: direct link, hf CLI and curl.
- Browser
- Download file 4.66 kB
-
https://huggingface.co/SaylorTwift/openhands/resolve/main/src/api/plugins-service.test.ts
- Command line
-
hf download hf://SaylorTwift/openhands/src/api/plugins-service.test.ts
-
curl -L -o plugins-service.test.ts https://huggingface.co/SaylorTwift/openhands/resolve/main/src/api/plugins-service.test.ts
4.66 kB
| import { beforeEach, describe, expect, it, vi } from "vitest"; | |
| import { | |
| FileClient, | |
| PluginsClient, | |
| } from "@openhands/typescript-client/clients"; | |
| import { | |
| setActiveSelection, | |
| setRegisteredBackends, | |
| } from "./backend-registry/active-store"; | |
| import PluginsService from "./plugins-service"; | |
| vi.mock("@openhands/typescript-client/clients", () => ({ | |
| PluginsClient: vi.fn(), | |
| FileClient: vi.fn(), | |
| })); | |
| const getPluginsMarketplace = vi.fn(); | |
| const getPlugins = vi.fn(); | |
| const downloadFile = vi.fn(); | |
| const close = vi.fn(); | |
| function useBackend(kind: "local" | "cloud"): void { | |
| setRegisteredBackends([ | |
| { | |
| id: kind, | |
| name: kind, | |
| host: "http://127.0.0.1:8001", | |
| apiKey: "session-key", | |
| kind, | |
| }, | |
| ]); | |
| setActiveSelection({ backendId: kind, orgId: null }); | |
| } | |
| describe("PluginsService.getPluginsMarketplace", () => { | |
| beforeEach(() => { | |
| vi.clearAllMocks(); | |
| vi.mocked(PluginsClient).mockImplementation(function MockPluginsClient() { | |
| return { getPluginsMarketplace, close } as unknown as PluginsClient; | |
| } as unknown as typeof PluginsClient); | |
| }); | |
| it("returns the catalog from the local agent-server", async () => { | |
| useBackend("local"); | |
| const plugin = { | |
| name: "city-weather", | |
| description: "Weather plugin", | |
| source: "github:OpenHands/extensions", | |
| ref: null, | |
| repo_path: "plugins/city-weather", | |
| installed: false, | |
| }; | |
| getPluginsMarketplace.mockResolvedValue({ plugins: [plugin] }); | |
| const result = await PluginsService.getPluginsMarketplace(); | |
| expect(result).toEqual([plugin]); | |
| expect(getPluginsMarketplace).toHaveBeenCalledTimes(1); | |
| }); | |
| it("returns an empty catalog on a cloud backend without calling the client", async () => { | |
| useBackend("cloud"); | |
| const result = await PluginsService.getPluginsMarketplace(); | |
| expect(result).toEqual([]); | |
| expect(PluginsClient).not.toHaveBeenCalled(); | |
| }); | |
| it("returns an empty catalog when the local request fails", async () => { | |
| useBackend("local"); | |
| getPluginsMarketplace.mockRejectedValue(new Error("unreachable")); | |
| const result = await PluginsService.getPluginsMarketplace(); | |
| expect(result).toEqual([]); | |
| }); | |
| }); | |
| describe("PluginsService.getLocalPlugins", () => { | |
| beforeEach(() => { | |
| vi.clearAllMocks(); | |
| vi.mocked(PluginsClient).mockImplementation(function MockPluginsClient() { | |
| return { getPlugins, close } as unknown as PluginsClient; | |
| } as unknown as typeof PluginsClient); | |
| }); | |
| it("requests user-level local plugins from the local agent-server", async () => { | |
| useBackend("local"); | |
| const plugin = { | |
| name: "hello-local", | |
| version: "1.0.0", | |
| description: "A local plugin", | |
| }; | |
| getPlugins.mockResolvedValue({ plugins: [plugin] }); | |
| const result = await PluginsService.getLocalPlugins(); | |
| expect(result).toEqual([plugin]); | |
| expect(getPlugins).toHaveBeenCalledWith({ | |
| load_user: true, | |
| load_project: false, | |
| }); | |
| }); | |
| it("returns an empty list on a cloud backend without calling the client", async () => { | |
| useBackend("cloud"); | |
| const result = await PluginsService.getLocalPlugins(); | |
| expect(result).toEqual([]); | |
| expect(PluginsClient).not.toHaveBeenCalled(); | |
| }); | |
| }); | |
| describe("PluginsService.getPluginFileContent", () => { | |
| beforeEach(() => { | |
| vi.clearAllMocks(); | |
| vi.mocked(FileClient).mockImplementation(function MockFileClient() { | |
| return { downloadFile, close } as unknown as FileClient; | |
| } as unknown as typeof FileClient); | |
| }); | |
| it("downloads the file under the plugin directory and decodes it as text", async () => { | |
| useBackend("local"); | |
| downloadFile.mockResolvedValue(new TextEncoder().encode("# Hello").buffer); | |
| const result = await PluginsService.getPluginFileContent( | |
| "/plugins/demo", | |
| "docs/README.md", | |
| ); | |
| expect(result).toEqual({ kind: "text", text: "# Hello" }); | |
| expect(downloadFile).toHaveBeenCalledWith("/plugins/demo/docs/README.md"); | |
| }); | |
| it("flags content containing NUL bytes as binary", async () => { | |
| useBackend("local"); | |
| downloadFile.mockResolvedValue( | |
| new Uint8Array([0x89, 0x50, 0x00, 0x47]).buffer, | |
| ); | |
| const result = await PluginsService.getPluginFileContent( | |
| "/plugins/demo", | |
| "logo.png", | |
| ); | |
| expect(result).toEqual({ kind: "binary", text: null }); | |
| }); | |
| it("rejects on a cloud backend without calling the client", async () => { | |
| useBackend("cloud"); | |
| await expect( | |
| PluginsService.getPluginFileContent("/plugins/demo", "README.md"), | |
| ).rejects.toThrow(); | |
| expect(FileClient).not.toHaveBeenCalled(); | |
| }); | |
| }); | |