Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions packages/cli/tests/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import { afterEach, beforeEach, expect, test } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { addServer, isValidUrl, removeServer } from "../src/registry.js";
import { loadRegistry, saveRegistry } from "../src/storage.js";
import {
addServer,
isValidUrl,
loadRegistry,
removeServer,
saveRegistry,
} from "@fiberplane/mcp-gateway-core";

let tempDir: string;

Expand Down Expand Up @@ -154,7 +159,7 @@ test("loadRegistry handles invalid JSON gracefully", async () => {

// CLI integration tests
test("CLI shows help when --help flag is used", async () => {
const proc = Bun.spawn(["bun", "run", "./src/run-v2.ts", "--help"], {
const proc = Bun.spawn(["bun", "run", "./src/cli.ts", "--help"], {
stdout: "pipe",
cwd: `${import.meta.dir}/..`,
});
Expand All @@ -169,7 +174,7 @@ test("CLI shows help when --help flag is used", async () => {
});

test("CLI shows version when --version flag is used", async () => {
const proc = Bun.spawn(["bun", "run", "./src/run-v2.ts", "--version"], {
const proc = Bun.spawn(["bun", "run", "./src/cli.ts", "--version"], {
stdout: "pipe",
cwd: `${import.meta.dir}/..`,
});
Expand All @@ -184,7 +189,7 @@ test("CLI shows version when --version flag is used", async () => {
// Headless mode tests (non-TTY environment)
test("Headless mode: CLI runs without TUI when stdin is not a TTY", async () => {
const proc = Bun.spawn(
["bun", "run", "./src/run-v2.ts", "--storage-dir", tempDir],
["bun", "run", "./src/cli.ts", "--storage-dir", tempDir],
{
stdin: "pipe",
stdout: "pipe",
Expand Down Expand Up @@ -238,7 +243,7 @@ test.skip("Headless mode: CLI server responds to SIGTERM gracefully", async () =
await new Promise((resolve) => setTimeout(resolve, 1000));

const proc = Bun.spawn(
["bun", "run", "./src/run-v2.ts", "--storage-dir", tempDir],
["bun", "run", "./src/cli.ts", "--storage-dir", tempDir],
{
stdin: "pipe",
stdout: "pipe",
Expand Down
139 changes: 64 additions & 75 deletions packages/cli/tests/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { logger } from "../src/logger.js";
import { logger } from "@fiberplane/mcp-gateway-core";

let tempDir: string;

Expand Down Expand Up @@ -96,7 +96,7 @@ describe("Logger Initialization", () => {
});

describe("Log Level Filtering", () => {
test.serial("should skip debug logs when minLevel is info", async () => {
test("should skip debug logs when minLevel is info", async () => {
await logger.initialize(tempDir);

logger.debug("This should not be written");
Expand All @@ -118,7 +118,7 @@ describe("Log Level Filtering", () => {
expect(entry.message).toBe("This should be written");
});

test.serial("should write all logs when minLevel is debug", async () => {
test("should write all logs when minLevel is debug", async () => {
// Create a fresh temp directory for this test
const testTempDir = await mkdtemp(join(tmpdir(), "mcp-logger-debug-test-"));
try {
Expand Down Expand Up @@ -151,42 +151,37 @@ describe("Log Level Filtering", () => {
}
});

test.serial(
"should only write warn and error when minLevel is warn",
async () => {
const testTempDir = await mkdtemp(
join(tmpdir(), "mcp-logger-warn-test-"),
);
try {
process.env.LOG_LEVEL = "warn";
await logger.initialize(testTempDir);

logger.debug("Debug message");
await new Promise((resolve) => setTimeout(resolve, 50));
logger.info("Info message");
await new Promise((resolve) => setTimeout(resolve, 50));
logger.warn("Warn message");
await new Promise((resolve) => setTimeout(resolve, 50));
logger.error("Error message");

// Wait for async file writes
await new Promise((resolve) => setTimeout(resolve, 100));

const logsDir = join(testTempDir, "logs");
const files = await readdir(logsDir);
const logContent = await readFile(join(logsDir, files[0]!), "utf-8");
const lines = logContent.trim().split("\n");

expect(lines.length).toBe(2);
expect(JSON.parse(lines[0]!).level).toBe("warn");
expect(JSON.parse(lines[1]!).level).toBe("error");
} finally {
await rm(testTempDir, { recursive: true, force: true });
}
},
);

test.serial("should only write error when minLevel is error", async () => {
test("should only write warn and error when minLevel is warn", async () => {
const testTempDir = await mkdtemp(join(tmpdir(), "mcp-logger-warn-test-"));
try {
process.env.LOG_LEVEL = "warn";
await logger.initialize(testTempDir);

logger.debug("Debug message");
await new Promise((resolve) => setTimeout(resolve, 50));
logger.info("Info message");
await new Promise((resolve) => setTimeout(resolve, 50));
logger.warn("Warn message");
await new Promise((resolve) => setTimeout(resolve, 50));
logger.error("Error message");

// Wait for async file writes
await new Promise((resolve) => setTimeout(resolve, 100));

const logsDir = join(testTempDir, "logs");
const files = await readdir(logsDir);
const logContent = await readFile(join(logsDir, files[0]!), "utf-8");
const lines = logContent.trim().split("\n");

expect(lines.length).toBe(2);
expect(JSON.parse(lines[0]!).level).toBe("warn");
expect(JSON.parse(lines[1]!).level).toBe("error");
} finally {
await rm(testTempDir, { recursive: true, force: true });
}
});

test("should only write error when minLevel is error", async () => {
process.env.LOG_LEVEL = "error";
await logger.initialize(tempDir);

Expand All @@ -209,7 +204,7 @@ describe("Log Level Filtering", () => {
});

describe("Log Writing", () => {
test.serial("should write log entries as JSON lines", async () => {
test("should write log entries as JSON lines", async () => {
await logger.initialize(tempDir);

logger.info("Test message");
Expand All @@ -234,7 +229,7 @@ describe("Log Writing", () => {
expect(entry.message).toBe("Test message");
});

test.serial("should include context object when provided", async () => {
test("should include context object when provided", async () => {
await logger.initialize(tempDir);

logger.info("Test with context", { userId: "123", action: "login" });
Expand All @@ -250,26 +245,23 @@ describe("Log Writing", () => {
expect(entry.context).toEqual({ userId: "123", action: "login" });
});

test.serial(
"should not include context field when context is empty",
async () => {
await logger.initialize(tempDir);
test("should not include context field when context is empty", async () => {
await logger.initialize(tempDir);

logger.info("Test without context");
logger.info("Test without context");

// Wait for async file writes
await new Promise((resolve) => setTimeout(resolve, 100));
// Wait for async file writes
await new Promise((resolve) => setTimeout(resolve, 100));

const logsDir = join(tempDir, "logs");
const files = await readdir(logsDir);
const logContent = await readFile(join(logsDir, files[0]!), "utf-8");
const entry = JSON.parse(logContent.trim());
const logsDir = join(tempDir, "logs");
const files = await readdir(logsDir);
const logContent = await readFile(join(logsDir, files[0]!), "utf-8");
const entry = JSON.parse(logContent.trim());

expect(entry).not.toHaveProperty("context");
},
);
expect(entry).not.toHaveProperty("context");
});

test.serial("should write timestamp in ISO 8601 format", async () => {
test("should write timestamp in ISO 8601 format", async () => {
await logger.initialize(tempDir);

logger.info("Test timestamp");
Expand All @@ -288,7 +280,7 @@ describe("Log Writing", () => {
);
});

test.serial("should append multiple log entries to same file", async () => {
test("should append multiple log entries to same file", async () => {
// Create a fresh temp directory for this test
const testTempDir = await mkdtemp(
join(tmpdir(), "mcp-logger-append-test-"),
Expand Down Expand Up @@ -323,28 +315,25 @@ describe("Log Writing", () => {
});

describe("Daily Log Rotation", () => {
test.serial(
"should create log file with current date in filename",
async () => {
await logger.initialize(tempDir);
test("should create log file with current date in filename", async () => {
await logger.initialize(tempDir);

logger.info("Test message");
logger.info("Test message");

// Wait for async file writes
await new Promise((resolve) => setTimeout(resolve, 100));
// Wait for async file writes
await new Promise((resolve) => setTimeout(resolve, 100));

const logsDir = join(tempDir, "logs");
const files = await readdir(logsDir);
const logsDir = join(tempDir, "logs");
const files = await readdir(logsDir);

const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const expectedFilename = `gateway-${year}-${month}-${day}.log`;
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const expectedFilename = `gateway-${year}-${month}-${day}.log`;

expect(files).toContain(expectedFilename);
},
);
expect(files).toContain(expectedFilename);
});

test("should handle logging without initialization gracefully", async () => {
// Don't initialize logger
Expand Down Expand Up @@ -441,7 +430,7 @@ describe("Error Handling", () => {
}).not.toThrow();
});

test.serial("should handle concurrent writes gracefully", async () => {
test("should handle concurrent writes gracefully", async () => {
await logger.initialize(tempDir);

// Write many logs concurrently
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/tests/proxy/auth-401s.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { saveRegistry } from "@fiberplane/mcp-gateway-core";
import { createApp } from "@fiberplane/mcp-gateway-server";
import type { Registry } from "@fiberplane/mcp-gateway-types";
import { McpServer, StreamableHttpTransport } from "mcp-lite";
import type { Registry } from "../../src/registry.js";
import { createApp } from "../../src/server/index.js";
import { saveRegistry } from "../../src/storage.js";

// JSON-RPC response type
interface JsonRpcResponse {
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/tests/proxy/oauth-routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { Registry } from "../../src/registry.js";
import { createApp } from "../../src/server/index.js";
import { saveRegistry } from "../../src/storage.js";
import { saveRegistry } from "@fiberplane/mcp-gateway-core";
import { createApp } from "@fiberplane/mcp-gateway-server";
import type { Registry } from "@fiberplane/mcp-gateway-types";

describe("OAuth Routes Integration Tests", () => {
let storageDir: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/tests/proxy/proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { saveRegistry } from "@fiberplane/mcp-gateway-core";
import { createApp } from "@fiberplane/mcp-gateway-server";
import type { Registry } from "@fiberplane/mcp-gateway-types";
import { McpServer, StreamableHttpTransport } from "mcp-lite";
import type { Registry } from "../../src/registry.js";
import { createApp } from "../../src/server/index.js";
import { saveRegistry } from "../../src/storage.js";

// JSON-RPC response type
interface JsonRpcResponse {
Expand Down
11 changes: 7 additions & 4 deletions packages/cli/tests/sse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { Registry } from "../src/registry.js";
import { createApp } from "../src/server/index.js";
import { createSSEEventStream, type SSEEvent } from "../src/sse-parser.js";
import { saveRegistry } from "../src/storage.js";
import {
createSSEEventStream,
type SSEEvent,
saveRegistry,
} from "@fiberplane/mcp-gateway-core";
import { createApp } from "@fiberplane/mcp-gateway-server";
import type { Registry } from "@fiberplane/mcp-gateway-types";

// Real SSE server for testing
function createSSEServer(port: number): { url: string; stop: () => void } {
Expand Down