/** * CLI 模块测试 * * 测试 qiming-file-server CLI 相关的功能 * * 覆盖范围: * - serviceManager.js 服务管理器 * - envUtils.js 环境变量工具 * - PID 文件操作 * - 跨平台兼容性 */ import path from "path"; import fs from "fs-extra"; import os from "os"; // 测试配置文件路径 const testConfig = { testPidDir: path.join(os.tmpdir(), "qiming-file-server-test"), testPidFile: path.join( os.tmpdir(), "qiming-file-server-test", "server.pid" ), }; describe("CLI Service Manager", () => { let serviceManager; beforeAll(async () => { const module = await import("../../src/utils/serviceManager.js"); serviceManager = module.default || module; }); afterEach(() => { try { if (fs.existsSync(testConfig.testPidFile)) { fs.removeSync(testConfig.testPidFile); } } catch (err) { // 忽略清理错误 } }); describe("getPidFilePath", () => { it("应该返回有效的 PID 文件路径", () => { const pidPath = serviceManager.getPidFilePath(); expect(pidPath).toBeDefined(); expect(typeof pidPath).toBe("string"); expect(pidPath.length).toBeGreaterThan(0); }); it("应该在临时目录中", () => { const pidPath = serviceManager.getPidFilePath(); const tmpDir = os.tmpdir(); expect(pidPath.startsWith(tmpDir)).toBe(true); }); }); describe("isWindows", () => { it("应该正确检测当前操作系统", () => { const isWin = serviceManager.isWindows(); const currentPlatform = process.platform; if (currentPlatform === "win32") { expect(isWin).toBe(true); } else { expect(isWin).toBe(false); } }); }); describe("isProcessRunning", () => { it("应该正确判断不存在的进程", () => { const result = serviceManager.isProcessRunning(999999999); expect(result).toBe(false); }); it("应该正确判断当前进程", () => { const result = serviceManager.isProcessRunning(process.pid); expect(result).toBe(true); }); }); describe("readPidFile", () => { it("应该返回 null 如果文件不存在", () => { const result = serviceManager.readPidFile(); expect(result === null || result === undefined).toBe(true); }); }); describe("writePidFile and readPidFile", () => { it("应该能够写入和读取 PID 文件", () => { const testPidInfo = { pid: 12345, startedAt: new Date().toISOString(), env: "test", port: "60000", version: "1.0.0", platform: process.platform, }; const testPidPath = path.join(testConfig.testPidDir, "server.pid"); fs.ensureDirSync(testConfig.testPidDir); fs.writeFileSync(testPidPath, JSON.stringify(testPidInfo, null, 2)); const content = fs.readFileSync(testPidPath, "utf8"); const readPidInfo = JSON.parse(content); expect(readPidInfo.pid).toBe(12345); expect(readPidInfo.env).toBe("test"); expect(readPidInfo.port).toBe("60000"); fs.removeSync(testConfig.testPidDir); }); }); describe("formatUptime", () => { it("应该正确格式化运行时间", () => { const startedAt = new Date(Date.now() - 3600000).toISOString(); const result = serviceManager.formatUptime(startedAt); expect(result).toContain("小时"); }); it("应该处理无效的日期", () => { const result = serviceManager.formatUptime("invalid-date"); expect(result).toBe("未知"); }); }); describe("getServiceStatus", () => { it("应该返回正确的服务状态", () => { const status = serviceManager.getServiceStatus(); expect(status).toHaveProperty("running"); expect(status).toHaveProperty("pidInfo"); expect(status).toHaveProperty("message"); expect(typeof status.running).toBe("boolean"); }); }); }); describe("CLI Environment Utils", () => { let envUtils; beforeAll(async () => { const module = await import("../../src/utils/envUtils.js"); envUtils = module.default || module; }); describe("isWindows", () => { it("应该正确检测 Windows 平台", () => { const isWin = envUtils.isWindows(); const currentPlatform = process.platform; expect(isWin).toBe(currentPlatform === "win32"); }); }); describe("normalizeEnvName", () => { it("Windows 环境应该转为大写", () => { if (process.platform === "win32") { const result = envUtils.normalizeEnvName("test_env"); expect(result).toBe("TEST_ENV"); } else { const result = envUtils.normalizeEnvName("test_env"); expect(result).toBe("test_env"); } }); it("应该处理空字符串", () => { const result = envUtils.normalizeEnvName(""); expect(result).toBe(""); }); }); describe("getEnv", () => { beforeEach(() => { process.env.TEST_VAR = "test-value"; }); afterEach(() => { delete process.env.TEST_VAR; }); it("应该返回已设置的环境变量", () => { const result = envUtils.getEnv("TEST_VAR"); expect(result).toBe("test-value"); }); it("应该返回默认值如果未设置", () => { const result = envUtils.getEnv("NON_EXISTENT_VAR", "default"); expect(result).toBe("default"); }); }); describe("getBoolEnv", () => { beforeEach(() => { process.env.TEST_BOOL_TRUE = "true"; process.env.TEST_BOOL_FALSE = "false"; process.env.TEST_BOOL_ONE = "1"; }); afterEach(() => { delete process.env.TEST_BOOL_TRUE; delete process.env.TEST_BOOL_FALSE; delete process.env.TEST_BOOL_ONE; }); it("应该正确解析 true 值", () => { expect(envUtils.getBoolEnv("TEST_BOOL_TRUE")).toBe(true); }); it("应该正确解析 1 值", () => { expect(envUtils.getBoolEnv("TEST_BOOL_ONE")).toBe(true); }); it("应该正确解析 false 值", () => { expect(envUtils.getBoolEnv("TEST_BOOL_FALSE")).toBe(false); }); it("应该返回默认值如果未设置", () => { expect(envUtils.getBoolEnv("NON_EXISTENT", true)).toBe(true); expect(envUtils.getBoolEnv("NON_EXISTENT", false)).toBe(false); }); }); describe("getNumberEnv", () => { beforeEach(() => { process.env.TEST_NUMBER = "123"; process.env.TEST_NAN = "abc"; }); afterEach(() => { delete process.env.TEST_NUMBER; delete process.env.TEST_NAN; }); it("应该正确解析数字", () => { const result = envUtils.getNumberEnv("TEST_NUMBER"); expect(result).toBe(123); }); it("应该返回默认值对于 NaN", () => { const result = envUtils.getNumberEnv("TEST_NAN", 0); expect(result).toBe(0); }); it("应该返回默认值如果未设置", () => { const result = envUtils.getNumberEnv("NON_EXISTENT", 42); expect(result).toBe(42); }); }); describe("parseEnvType", () => { it("应该正确解析 dev", () => { expect(envUtils.parseEnvType("dev")).toBe("development"); }); it("应该正确解析 prod", () => { expect(envUtils.parseEnvType("prod")).toBe("production"); }); it("应该正确解析 test", () => { expect(envUtils.parseEnvType("test")).toBe("test"); }); it("应该处理大小写", () => { expect(envUtils.parseEnvType("DEV")).toBe("development"); expect(envUtils.parseEnvType("PROD")).toBe("production"); }); it("应该处理空值", () => { expect(envUtils.parseEnvType("")).toBe("production"); expect(envUtils.parseEnvType(null)).toBe("production"); }); }); describe("loadEnvFromArgv", () => { it("应该解析命令行参数", () => { const originalArgv = process.argv; process.argv = ["node", "test", "--test-key", "test-value"]; const result = envUtils.loadEnvFromArgv(); process.argv = originalArgv; expect(result).toBeDefined(); }); }); }); describe("CLI Cross-Platform Compatibility", () => { describe("Platform Detection", () => { it("应该正确检测 darwin (macOS)", () => { if (process.platform === "darwin") { expect(process.platform).toBe("darwin"); } }); it("应该正确检测 linux", () => { if (process.platform === "linux") { expect(process.platform).toBe("linux"); } }); it("应该正确检测 win32", () => { if (process.platform === "win32") { expect(process.platform).toBe("win32"); } }); }); describe("Path Handling", () => { it("应该使用 path.join 进行路径拼接", () => { const result = path.join("dir", "subdir", "file.js"); expect(result).toMatch(/dir[\/\\]subdir[\/\\]file\.js/); }); it("应该使用 os.tmpdir() 获取临时目录", () => { const tmpDir = os.tmpdir(); expect(tmpDir).toBeDefined(); expect(tmpDir.length).toBeGreaterThan(0); }); it("应该使用 os.homedir() 获取主目录", () => { const homeDir = os.homedir(); expect(homeDir).toBeDefined(); expect(homeDir.length).toBeGreaterThan(0); }); }); describe("Environment Variables", () => { it("应该能够读取环境变量", () => { process.env.TEST_READ = "test"; expect(process.env.TEST_READ).toBe("test"); delete process.env.TEST_READ; }); it("应该支持设置和删除环境变量", () => { process.env.TEMP_TEST_VAR = "temp-value"; expect(process.env.TEMP_TEST_VAR).toBe("temp-value"); delete process.env.TEMP_TEST_VAR; expect(process.env.TEMP_TEST_VAR).toBeUndefined(); }); }); }); describe("CLI Config", () => { let config; beforeAll(async () => { const module = await import("../../src/appConfig/index.js"); config = module.default || module; }); describe("CLI Configuration", () => { it("应该包含 CLI 服务名称配置", () => { expect(config.CLI_SERVICE_NAME).toBe("qiming-file-server"); }); it("应该包含 CLI PID 目录配置", () => { expect(config.CLI_PID_DIR).toBeDefined(); expect(typeof config.CLI_PID_DIR).toBe("string"); }); it("应该包含 CLI 停止超时配置", () => { expect(config.CLI_STOP_TIMEOUT).toBeDefined(); expect(typeof config.CLI_STOP_TIMEOUT).toBe("number"); }); it("应该包含 CLI 检查间隔配置", () => { expect(config.CLI_CHECK_INTERVAL).toBeDefined(); expect(typeof config.CLI_CHECK_INTERVAL).toBe("number"); }); it("应该包含 Windows 平台检测配置", () => { expect(config.CLI_IS_WINDOWS).toBeDefined(); expect(typeof config.CLI_IS_WINDOWS).toBe("boolean"); }); }); describe("Standard Configuration", () => { it("应该包含标准配置项", () => { expect(config.NODE_ENV).toBeDefined(); expect(config.PORT).toBeDefined(); expect(config.PROJECT_SOURCE_DIR).toBeDefined(); }); }); });