Files
openproject-mcp/tests/config.test.ts
T

168 lines
5.7 KiB
TypeScript

import { describe, test, expect, beforeEach, afterEach } from "bun:test";
import { loadConfig, parseConfig } from "../src/config/index.ts";
describe("Configuration Loader (HTTP & Stdio Support)", () => {
const originalEnv = { ...process.env };
const originalArgv = [...process.argv];
beforeEach(() => {
process.env = { ...originalEnv };
process.argv = [...originalArgv.slice(0, 2)];
});
afterEach(() => {
process.env = originalEnv;
process.argv = originalArgv;
});
test("loads stdio configuration when PORT is unset and OPENPROJECT_API_KEY is provided", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
process.env.OPENPROJECT_API_KEY = "test-key";
delete process.env.PORT;
const config = loadConfig();
expect(config.baseUrl).toBe("https://openproject.example.com");
expect(config.apiKey).toBe("test-key");
expect(config.readOnly).toBe(false);
expect(config.port).toBeUndefined();
});
test("throws error if OPENPROJECT_API_KEY is missing in stdio mode", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
delete process.env.OPENPROJECT_API_KEY;
delete process.env.PORT;
expect(() => loadConfig()).toThrow();
});
test("throws error if OPENPROJECT_API_KEY is whitespace in stdio mode", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
process.env.OPENPROJECT_API_KEY = " ";
delete process.env.PORT;
expect(() => loadConfig()).toThrow();
});
test("throws error if OPENPROJECT_BASE_URL is invalid", () => {
process.env.OPENPROJECT_BASE_URL = "not-a-valid-url";
process.env.OPENPROJECT_API_KEY = "test-key";
delete process.env.PORT;
expect(() => loadConfig()).toThrow();
});
test("normalizes baseUrl by stripping trailing slashes", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com///";
process.env.OPENPROJECT_API_KEY = "test-key";
delete process.env.PORT;
const config = loadConfig();
expect(config.baseUrl).toBe("https://openproject.example.com");
});
test("loads HTTP configuration when PORT environment variable is set without API key", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
delete process.env.OPENPROJECT_API_KEY;
process.env.PORT = "3000";
const config = loadConfig();
expect(config.baseUrl).toBe("https://openproject.example.com");
expect(config.port).toBe(3000);
expect(config.apiKey).toBeUndefined();
});
test("loads HTTP configuration with PORT=0 for dynamic assignment", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
delete process.env.OPENPROJECT_API_KEY;
process.env.PORT = "0";
const config = loadConfig();
expect(config.baseUrl).toBe("https://openproject.example.com");
expect(config.port).toBe(0);
expect(config.apiKey).toBeUndefined();
});
test("loads HTTP configuration when HOST_PORT is set as fallback without PORT", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
delete process.env.OPENPROJECT_API_KEY;
delete process.env.PORT;
process.env.HOST_PORT = "3000";
const config = loadConfig();
expect(config.baseUrl).toBe("https://openproject.example.com");
expect(config.port).toBe(3000);
expect(config.apiKey).toBeUndefined();
});
test("loads HTTP configuration with API key when provided", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
process.env.OPENPROJECT_API_KEY = "test-key";
process.env.PORT = "3000";
const config = loadConfig();
expect(config.baseUrl).toBe("https://openproject.example.com");
expect(config.port).toBe(3000);
expect(config.apiKey).toBe("test-key");
});
test("parses --port and --host CLI arguments", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
delete process.env.OPENPROJECT_API_KEY;
delete process.env.PORT;
process.argv.push("--port", "8080", "--host", "127.0.0.1", "--read-only");
const config = loadConfig();
expect(config.port).toBe(8080);
expect(config.host).toBe("127.0.0.1");
expect(config.readOnly).toBe(true);
});
test("parses --port=value and --host=value CLI arguments", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
delete process.env.OPENPROJECT_API_KEY;
delete process.env.PORT;
process.argv.push("--port=9090", "--host=0.0.0.0");
const config = loadConfig();
expect(config.port).toBe(9090);
expect(config.host).toBe("0.0.0.0");
});
test("CLI arguments take precedence over environment variables", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
process.env.PORT = "3000";
process.env.HOST = "127.0.0.1";
process.argv.push("--port", "4000", "--host", "0.0.0.0");
const config = loadConfig();
expect(config.port).toBe(4000);
expect(config.host).toBe("0.0.0.0");
});
test("throws error if port is non-numeric", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
process.env.PORT = "not-a-port";
expect(() => loadConfig()).toThrow();
});
test("throws error if port is out of range", () => {
process.env.OPENPROJECT_BASE_URL = "https://openproject.example.com";
process.env.PORT = "70000";
expect(() => loadConfig()).toThrow();
});
test("parseConfig alias works identically to loadConfig", () => {
const config = parseConfig(
{
OPENPROJECT_BASE_URL: "https://openproject.example.com",
OPENPROJECT_API_KEY: "alias-key",
},
[]
);
expect(config.baseUrl).toBe("https://openproject.example.com");
expect(config.apiKey).toBe("alias-key");
});
});