From 69371b78b719ffba805b0beba9a866ccb7ca9431 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 18 May 2026 13:21:02 +0900 Subject: [PATCH] test(mcp): stabilize lsp builtin and doctor checks Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/cli/doctor/checks/tools-lsp.test.ts | 96 ++++++++++++++++++++++ src/mcp/zauc-mocks-mcp-index/index.test.ts | 19 ++++- 2 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/cli/doctor/checks/tools-lsp.test.ts diff --git a/src/cli/doctor/checks/tools-lsp.test.ts b/src/cli/doctor/checks/tools-lsp.test.ts new file mode 100644 index 000000000..07045be97 --- /dev/null +++ b/src/cli/doctor/checks/tools-lsp.test.ts @@ -0,0 +1,96 @@ +/// + +import { afterEach, describe, expect, it, mock } from "bun:test" +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { clearPluginConfigFileDetectionCache } from "../../../shared/jsonc-parser" + +const originalCwd = process.cwd() +const originalOpenCodeConfigDir = process.env.OPENCODE_CONFIG_DIR +const temporaryDirectories: string[] = [] + +function createTemporaryDirectory(prefix: string): string { + const directory = mkdtempSync(join(tmpdir(), prefix)) + temporaryDirectories.push(directory) + return directory +} + +afterEach(() => { + mock.restore() + clearPluginConfigFileDetectionCache() + process.chdir(originalCwd) + + if (originalOpenCodeConfigDir === undefined) { + delete process.env.OPENCODE_CONFIG_DIR + } else { + process.env.OPENCODE_CONFIG_DIR = originalOpenCodeConfigDir + } + + for (const directory of temporaryDirectories.splice(0)) { + rmSync(directory, { recursive: true, force: true }) + } +}) + +describe("getInstalledLspServers", () => { + it("returns empty when lsp MCP is disabled via config", async () => { + // given + const userConfigDirectory = createTemporaryDirectory("omo-tools-lsp-user-") + const workspaceDirectory = createTemporaryDirectory("omo-tools-lsp-workspace-") + const projectConfigDirectory = join(workspaceDirectory, ".opencode") + mkdirSync(projectConfigDirectory, { recursive: true }) + writeFileSync( + join(projectConfigDirectory, "oh-my-openagent.json"), + JSON.stringify({ disabled_mcps: ["lsp"] }), + "utf-8", + ) + process.env.OPENCODE_CONFIG_DIR = userConfigDirectory + process.chdir(workspaceDirectory) + clearPluginConfigFileDetectionCache() + + const { getInstalledLspServers } = await import(`./tools-lsp?t=${Date.now()}-disabled`) + + // when + const servers = getInstalledLspServers() + + // then + expect(servers).toEqual([]) + }) + + it("returns bundled lsp server info when MCP is enabled and available", async () => { + // given + const userConfigDirectory = createTemporaryDirectory("omo-tools-lsp-user-") + const workspaceDirectory = createTemporaryDirectory("omo-tools-lsp-enabled-") + const lspCliDirectory = join(workspaceDirectory, "vendor", "lsp-tools-mcp", "dist") + mkdirSync(lspCliDirectory, { recursive: true }) + writeFileSync(join(lspCliDirectory, "cli.js"), "#!/usr/bin/env node\n", "utf-8") + process.env.OPENCODE_CONFIG_DIR = userConfigDirectory + process.chdir(workspaceDirectory) + clearPluginConfigFileDetectionCache() + + const { getInstalledLspServers } = await import(`./tools-lsp?t=${Date.now()}-enabled`) + + // when + const servers = getInstalledLspServers() + + // then + expect(servers).toEqual([{ id: "lsp-tools-mcp", extensions: ["*"] }]) + }) + + it("returns empty when lsp MCP binary is unavailable", async () => { + // given + const userConfigDirectory = createTemporaryDirectory("omo-tools-lsp-user-") + const workspaceDirectory = createTemporaryDirectory("omo-tools-lsp-missing-") + process.env.OPENCODE_CONFIG_DIR = userConfigDirectory + process.chdir(workspaceDirectory) + clearPluginConfigFileDetectionCache() + + const { getInstalledLspServers } = await import(`./tools-lsp?t=${Date.now()}-missing-cli`) + + // when + const servers = getInstalledLspServers() + + // then + expect(servers).toEqual([]) + }) +}) diff --git a/src/mcp/zauc-mocks-mcp-index/index.test.ts b/src/mcp/zauc-mocks-mcp-index/index.test.ts index d69ec1609..7e152c12c 100644 --- a/src/mcp/zauc-mocks-mcp-index/index.test.ts +++ b/src/mcp/zauc-mocks-mcp-index/index.test.ts @@ -1,9 +1,16 @@ -import { describe, expect, test } from "bun:test" -import { createBuiltinMcps } from "../index" +import { afterEach, describe, expect, mock, test } from "bun:test" + +afterEach(() => { + mock.restore() +}) describe("createBuiltinMcps", () => { test("should return all MCPs when disabled_mcps is empty", () => { // given + mock.module("../lsp", () => ({ + createLspMcpConfig: () => ({ type: "local", command: ["node", "dist/cli.js", "mcp"], enabled: true }), + })) + const { createBuiltinMcps } = require("../index") as typeof import("../index") const disabledMcps: string[] = [] // when @@ -19,6 +26,10 @@ describe("createBuiltinMcps", () => { test("should filter out disabled MCPs", () => { // given + mock.module("../lsp", () => ({ + createLspMcpConfig: () => ({ type: "local", command: ["node", "dist/cli.js", "mcp"], enabled: true }), + })) + const { createBuiltinMcps } = require("../index") as typeof import("../index") const disabledMcps = ["websearch"] // when @@ -33,6 +44,10 @@ describe("createBuiltinMcps", () => { test("should return empty array when all MCPs are disabled", () => { // given - disable all known MCPs + mock.module("../lsp", () => ({ + createLspMcpConfig: () => ({ type: "local", command: ["node", "dist/cli.js", "mcp"], enabled: true }), + })) + const { createBuiltinMcps } = require("../index") as typeof import("../index") const disabledMcps = ["websearch", "context7", "grep_app", "lsp"] // when