From 375304bf13dca09cc17ccbb7cb8c4e27d2acf0e1 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 15 Jan 2026 06:18:40 +0000 Subject: [PATCH] test: remove legacy config migration test --- ...doctor.migrates-legacy-config-file.test.ts | 445 ------------------ 1 file changed, 445 deletions(-) delete mode 100644 src/commands/doctor.migrates-legacy-config-file.test.ts diff --git a/src/commands/doctor.migrates-legacy-config-file.test.ts b/src/commands/doctor.migrates-legacy-config-file.test.ts deleted file mode 100644 index f23bbc7fd..000000000 --- a/src/commands/doctor.migrates-legacy-config-file.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; - -let originalIsTTY: boolean | undefined; -let originalStateDir: string | undefined; -let originalUpdateInProgress: string | undefined; -let tempStateDir: string | undefined; - -function setStdinTty(value: boolean | undefined) { - try { - Object.defineProperty(process.stdin, "isTTY", { - value, - configurable: true, - }); - } catch { - // ignore - } -} - -beforeEach(() => { - confirm.mockReset().mockResolvedValue(true); - select.mockReset().mockResolvedValue("node"); - note.mockClear(); - - readConfigFileSnapshot.mockReset(); - writeConfigFile.mockReset().mockResolvedValue(undefined); - resolveClawdbotPackageRoot.mockReset().mockResolvedValue(null); - runGatewayUpdate.mockReset().mockResolvedValue({ - status: "skipped", - mode: "unknown", - steps: [], - durationMs: 0, - }); - legacyReadConfigFileSnapshot.mockReset().mockResolvedValue({ - path: "/tmp/clawdis.json", - exists: false, - raw: null, - parsed: {}, - valid: true, - config: {}, - issues: [], - legacyIssues: [], - }); - createConfigIO.mockReset().mockImplementation(() => ({ - readConfigFileSnapshot: legacyReadConfigFileSnapshot, - })); - runExec.mockReset().mockResolvedValue({ stdout: "", stderr: "" }); - runCommandWithTimeout.mockReset().mockResolvedValue({ - stdout: "", - stderr: "", - code: 0, - signal: null, - killed: false, - }); - ensureAuthProfileStore.mockReset().mockReturnValue({ version: 1, profiles: {} }); - migrateLegacyConfig.mockReset().mockImplementation((raw: unknown) => ({ - config: raw as Record, - changes: ["Moved routing.allowFrom → channels.whatsapp.allowFrom."], - })); - findLegacyGatewayServices.mockReset().mockResolvedValue([]); - uninstallLegacyGatewayServices.mockReset().mockResolvedValue([]); - findExtraGatewayServices.mockReset().mockResolvedValue([]); - renderGatewayServiceCleanupHints.mockReset().mockReturnValue(["cleanup"]); - resolveGatewayProgramArguments.mockReset().mockResolvedValue({ - programArguments: ["node", "cli", "gateway", "--port", "18789"], - }); - serviceInstall.mockReset().mockResolvedValue(undefined); - serviceIsLoaded.mockReset().mockResolvedValue(false); - serviceStop.mockReset().mockResolvedValue(undefined); - serviceRestart.mockReset().mockResolvedValue(undefined); - serviceUninstall.mockReset().mockResolvedValue(undefined); - callGateway.mockReset().mockRejectedValue(new Error("gateway closed")); - - originalIsTTY = process.stdin.isTTY; - setStdinTty(true); - originalStateDir = process.env.CLAWDBOT_STATE_DIR; - originalUpdateInProgress = process.env.CLAWDBOT_UPDATE_IN_PROGRESS; - process.env.CLAWDBOT_UPDATE_IN_PROGRESS = "1"; - tempStateDir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-doctor-state-")); - process.env.CLAWDBOT_STATE_DIR = tempStateDir; - fs.mkdirSync(path.join(tempStateDir, "agents", "main", "sessions"), { - recursive: true, - }); - fs.mkdirSync(path.join(tempStateDir, "credentials"), { recursive: true }); -}); - -afterEach(() => { - setStdinTty(originalIsTTY); - if (originalStateDir === undefined) { - delete process.env.CLAWDBOT_STATE_DIR; - } else { - process.env.CLAWDBOT_STATE_DIR = originalStateDir; - } - if (originalUpdateInProgress === undefined) { - delete process.env.CLAWDBOT_UPDATE_IN_PROGRESS; - } else { - process.env.CLAWDBOT_UPDATE_IN_PROGRESS = originalUpdateInProgress; - } - if (tempStateDir) { - fs.rmSync(tempStateDir, { recursive: true, force: true }); - tempStateDir = undefined; - } -}); - -const readConfigFileSnapshot = vi.fn(); -const confirm = vi.fn().mockResolvedValue(true); -const select = vi.fn().mockResolvedValue("node"); -const note = vi.fn(); -const writeConfigFile = vi.fn().mockResolvedValue(undefined); -const resolveClawdbotPackageRoot = vi.fn().mockResolvedValue(null); -const runGatewayUpdate = vi.fn().mockResolvedValue({ - status: "skipped", - mode: "unknown", - steps: [], - durationMs: 0, -}); -const migrateLegacyConfig = vi.fn((raw: unknown) => ({ - config: raw as Record, - changes: ["Moved routing.allowFrom → channels.whatsapp.allowFrom."], -})); - -const runExec = vi.fn().mockResolvedValue({ stdout: "", stderr: "" }); -const runCommandWithTimeout = vi.fn().mockResolvedValue({ - stdout: "", - stderr: "", - code: 0, - signal: null, - killed: false, -}); - -const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: {} }); - -const legacyReadConfigFileSnapshot = vi.fn().mockResolvedValue({ - path: "/tmp/clawdis.json", - exists: false, - raw: null, - parsed: {}, - valid: true, - config: {}, - issues: [], - legacyIssues: [], -}); -const createConfigIO = vi.fn(() => ({ - readConfigFileSnapshot: legacyReadConfigFileSnapshot, -})); - -const findLegacyGatewayServices = vi.fn().mockResolvedValue([]); -const uninstallLegacyGatewayServices = vi.fn().mockResolvedValue([]); -const findExtraGatewayServices = vi.fn().mockResolvedValue([]); -const renderGatewayServiceCleanupHints = vi.fn().mockReturnValue(["cleanup"]); -const resolveGatewayProgramArguments = vi.fn().mockResolvedValue({ - programArguments: ["node", "cli", "gateway", "--port", "18789"], -}); -const serviceInstall = vi.fn().mockResolvedValue(undefined); -const serviceIsLoaded = vi.fn().mockResolvedValue(false); -const serviceStop = vi.fn().mockResolvedValue(undefined); -const serviceRestart = vi.fn().mockResolvedValue(undefined); -const serviceUninstall = vi.fn().mockResolvedValue(undefined); -const callGateway = vi.fn().mockRejectedValue(new Error("gateway closed")); - -vi.mock("@clack/prompts", () => ({ - confirm, - intro: vi.fn(), - note, - outro: vi.fn(), - select, -})); - -vi.mock("../agents/skills-status.js", () => ({ - buildWorkspaceSkillStatus: () => ({ skills: [] }), -})); - -vi.mock("../config/config.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", - createConfigIO, - readConfigFileSnapshot, - writeConfigFile, - migrateLegacyConfig, - }; -}); - -vi.mock("../daemon/legacy.js", () => ({ - findLegacyGatewayServices, - uninstallLegacyGatewayServices, -})); - -vi.mock("../daemon/inspect.js", () => ({ - findExtraGatewayServices, - renderGatewayServiceCleanupHints, -})); - -vi.mock("../daemon/program-args.js", () => ({ - resolveGatewayProgramArguments, -})); - -vi.mock("../gateway/call.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - callGateway, - }; -}); - -vi.mock("../process/exec.js", () => ({ - runExec, - runCommandWithTimeout, -})); - -vi.mock("../infra/clawdbot-root.js", () => ({ - resolveClawdbotPackageRoot, -})); - -vi.mock("../infra/update-runner.js", () => ({ - runGatewayUpdate, -})); - -vi.mock("../agents/auth-profiles.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - ensureAuthProfileStore, - }; -}); - -vi.mock("../daemon/service.js", () => ({ - resolveGatewayService: () => ({ - label: "LaunchAgent", - loadedText: "loaded", - notLoadedText: "not loaded", - install: serviceInstall, - uninstall: serviceUninstall, - stop: serviceStop, - restart: serviceRestart, - isLoaded: serviceIsLoaded, - readCommand: vi.fn(), - readRuntime: vi.fn().mockResolvedValue({ status: "running" }), - }), -})); - -vi.mock("../telegram/pairing-store.js", () => ({ - readTelegramAllowFromStore: vi.fn().mockResolvedValue([]), -})); - -vi.mock("../pairing/pairing-store.js", () => ({ - readChannelAllowFromStore: vi.fn().mockResolvedValue([]), -})); - -vi.mock("../telegram/token.js", () => ({ - resolveTelegramToken: vi.fn(() => ({ token: "", source: "none" })), -})); - -vi.mock("../runtime.js", () => ({ - defaultRuntime: { - log: () => {}, - error: () => {}, - exit: () => { - throw new Error("exit"); - }, - }, -})); - -vi.mock("../utils.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - resolveUserPath: (value: string) => value, - sleep: vi.fn(), - }; -}); - -vi.mock("./health.js", () => ({ - healthCommand: vi.fn().mockResolvedValue(undefined), -})); - -vi.mock("./onboard-helpers.js", () => ({ - applyWizardMetadata: (cfg: Record) => cfg, - DEFAULT_WORKSPACE: "/tmp", - guardCancel: (value: unknown) => value, - printWizardHeader: vi.fn(), - randomToken: vi.fn(() => "test-gateway-token"), -})); - -vi.mock("./doctor-state-migrations.js", () => ({ - detectLegacyStateMigrations: vi.fn().mockResolvedValue({ - targetAgentId: "main", - targetMainKey: "main", - stateDir: "/tmp/state", - oauthDir: "/tmp/oauth", - sessions: { - legacyDir: "/tmp/state/sessions", - legacyStorePath: "/tmp/state/sessions/sessions.json", - targetDir: "/tmp/state/agents/main/sessions", - targetStorePath: "/tmp/state/agents/main/sessions/sessions.json", - hasLegacy: false, - }, - agentDir: { - legacyDir: "/tmp/state/agent", - targetDir: "/tmp/state/agents/main/agent", - hasLegacy: false, - }, - whatsappAuth: { - legacyDir: "/tmp/oauth", - targetDir: "/tmp/oauth/whatsapp/default", - hasLegacy: false, - }, - preview: [], - }), - runLegacyStateMigrations: vi.fn().mockResolvedValue({ - changes: [], - warnings: [], - }), -})); - -describe("doctor command", () => { - it("migrates legacy config file", async () => { - readConfigFileSnapshot - .mockResolvedValueOnce({ - path: "/tmp/clawdbot.json", - exists: false, - raw: null, - parsed: {}, - valid: true, - config: {}, - issues: [], - legacyIssues: [], - }) - .mockResolvedValueOnce({ - path: "/tmp/clawdbot.json", - exists: true, - raw: "{}", - parsed: { - gateway: { mode: "local", bind: "loopback" }, - agents: { - defaults: { - workspace: "/Users/steipete/clawd", - sandbox: { - workspaceRoot: "/Users/steipete/clawd/sandboxes", - docker: { - image: "clawdbot-sandbox", - containerPrefix: "clawdbot-sbx", - }, - }, - }, - }, - }, - valid: true, - config: { - gateway: { mode: "local", bind: "loopback" }, - agents: { - defaults: { - workspace: "/Users/steipete/clawd", - sandbox: { - workspaceRoot: "/Users/steipete/clawd/sandboxes", - docker: { - image: "clawdbot-sandbox", - containerPrefix: "clawdbot-sbx", - }, - }, - }, - }, - }, - issues: [], - legacyIssues: [], - }); - - legacyReadConfigFileSnapshot.mockResolvedValueOnce({ - path: "/Users/steipete/.clawdis/clawdis.json", - exists: true, - raw: "{}", - parsed: { - gateway: { mode: "local", bind: "loopback" }, - agent: { - workspace: "/Users/steipete/clawd", - sandbox: { - workspaceRoot: "/Users/steipete/clawd/sandboxes", - docker: { - image: "clawdis-sandbox", - containerPrefix: "clawdis-sbx", - }, - }, - }, - }, - valid: true, - config: { - gateway: { mode: "local", bind: "loopback" }, - agent: { - workspace: "/Users/steipete/clawd", - sandbox: { - workspaceRoot: "/Users/steipete/clawd/sandboxes", - docker: { - image: "clawdis-sandbox", - containerPrefix: "clawdis-sbx", - }, - }, - }, - }, - issues: [], - legacyIssues: [], - }); - - migrateLegacyConfig.mockReturnValueOnce({ - config: { - gateway: { mode: "local", bind: "loopback" }, - agents: { - defaults: { - workspace: "/Users/steipete/clawd", - sandbox: { - workspaceRoot: "/Users/steipete/clawd/sandboxes", - docker: { - image: "clawdis-sandbox", - containerPrefix: "clawdis-sbx", - }, - }, - }, - }, - }, - changes: [], - }); - - const { doctorCommand } = await import("./doctor.js"); - const runtime = { - log: vi.fn(), - error: vi.fn(), - exit: vi.fn(), - }; - - await doctorCommand(runtime); - - const written = writeConfigFile.mock.calls.at(-1)?.[0] as Record; - const agents = written.agents as Record; - const defaults = agents.defaults as Record; - const sandbox = defaults.sandbox as Record; - const docker = sandbox.docker as Record; - - expect(defaults.workspace).toBe("/Users/steipete/clawd"); - expect(sandbox.workspaceRoot).toBe("/Users/steipete/clawd/sandboxes"); - expect(docker.image).toBe("clawdbot-sandbox"); - expect(docker.containerPrefix).toBe("clawdbot-sbx"); - }, 20_000); -});