Files
openwork/apps/app/tests/mcp-oauth-status-synchronization.test.ts

147 lines
6.0 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { getMcpIdentityKey } from "../src/app/mcp";
import type { McpServerEntry, McpStatusMap } from "../src/app/types";
import {
createMcpStatusSynchronizer,
resolveObservedMcpStatus,
} from "../src/react-app/domains/connections/mcp-status-synchronization";
function server(input?: Partial<McpServerEntry>): McpServerEntry {
return {
id: "cloud-mcp",
name: "cloud-mcp",
config: { type: "remote", url: "https://cloud.example/mcp", enabled: true },
...input,
};
}
describe("MCP OAuth status synchronization", () => {
test("resolves canonical and uniquely normalized producer identities", () => {
const entry = server({ id: "cloud-mcp", name: "Cloud MCP" });
expect(resolveObservedMcpStatus({ "cloud-mcp": { status: "connected" } }, entry)).toEqual({
status: "connected",
});
expect(resolveObservedMcpStatus({ "CLOUD MCP": { status: "connected" } }, entry)).toEqual({
status: "connected",
});
expect(resolveObservedMcpStatus({
"cloud mcp": { status: "connected" },
"cloud_mcp": { status: "failed", error: "foreign collision" },
}, entry)).toBeUndefined();
});
test("uses the configured server identity for display names and preserves underscores", () => {
expect(getMcpIdentityKey({ name: "Cloud MCP", serverName: "company_cloud" })).toBe("company_cloud");
expect(getMcpIdentityKey({ name: "Company_Cloud" })).toBe("company_cloud");
});
test("keeps verified OAuth success ready through delayed engine status, dialog close, and refresh", () => {
const sync = createMcpStatusSynchronizer();
const workspace = "web:workspace-a";
const entry = server();
sync.recordAuthenticated(workspace, "cloud-mcp");
const delayed = sync.project(sync.beginRefresh(workspace), {
"cloud-mcp": { status: "disconnected" },
}, [entry]);
const afterDialogClose = sync.project(sync.beginRefresh(workspace), {}, [entry]);
const converged = sync.project(sync.beginRefresh(workspace), {
"Cloud MCP": { status: "connected" },
}, [entry]);
const owningRefresh = sync.project(sync.beginRefresh(workspace), {
"cloud-mcp": { status: "connected" },
}, [entry]);
expect(delayed?.[entry.name]).toEqual({ status: "connected" });
expect(afterDialogClose?.[entry.name]).toEqual({ status: "connected" });
expect(converged?.[entry.name]).toEqual({ status: "connected" });
expect(owningRefresh?.[entry.name]).toEqual({ status: "connected" });
expect(sync.isPending(workspace, entry.name)).toBe(false);
});
test("a delayed refresh cannot regress a newer connected response", () => {
const sync = createMcpStatusSynchronizer();
const workspace = "web:workspace-a";
const entry = server();
const stale = sync.beginRefresh(workspace);
const latest = sync.beginRefresh(workspace);
expect(sync.project(latest, { "cloud-mcp": { status: "connected" } }, [entry])).toEqual({
"cloud-mcp": { status: "connected" },
});
expect(sync.project(stale, { "cloud-mcp": { status: "disconnected" } }, [entry])).toBeNull();
});
test.each([
["failed", { status: "failed", error: "provider rejected the token" }],
["needs auth", { status: "needs_auth" }],
["reconnect required", { status: "reconnect_required" }],
["client registration required", { status: "needs_client_registration", error: "register first" }],
] as const)("real %s overrides verified-success grace", (_label, status) => {
const sync = createMcpStatusSynchronizer();
const workspace = "web:workspace-a";
const entry = server();
sync.recordAuthenticated(workspace, entry.name);
const projected = sync.project(
sync.beginRefresh(workspace),
{ [entry.name]: status } as McpStatusMap,
[entry],
);
expect(projected?.[entry.name]).toEqual(status);
expect(projected?.[entry.name]?.status).not.toBe("connected");
expect(sync.isPending(workspace, entry.name)).toBe(false);
});
test("disabled entries, removal, and foreign workspaces never inherit green", () => {
const sync = createMcpStatusSynchronizer();
const workspace = "web:workspace-a";
const disabled = server({ config: { type: "remote", url: "https://cloud.example/mcp", enabled: false } });
sync.recordAuthenticated(workspace, disabled.name);
expect(sync.project(sync.beginRefresh(workspace), {}, [disabled])?.[disabled.name]).toEqual({
status: "disabled",
});
sync.recordAuthenticated(workspace, disabled.name);
expect(sync.project(sync.beginRefresh(workspace), {}, [])).toEqual({});
expect(sync.isPending(workspace, disabled.name)).toBe(false);
sync.recordAuthenticated(workspace, disabled.name);
const foreign = sync.beginRefresh("web:workspace-b");
expect(sync.project(foreign, {}, [server()])).toEqual({});
});
test("missing or disconnected status loses success grace after a bounded number of refreshes", () => {
const sync = createMcpStatusSynchronizer({ maxPendingRefreshes: 3 });
const workspace = "web:workspace-a";
const entry = server();
sync.recordAuthenticated(workspace, entry.name);
const first = sync.project(sync.beginRefresh(workspace), {}, [entry]);
const second = sync.project(sync.beginRefresh(workspace), {
[entry.name]: { status: "disconnected" },
}, [entry]);
const boundedFinal = sync.project(sync.beginRefresh(workspace), {}, [entry]);
expect(first?.[entry.name]).toEqual({ status: "connected" });
expect(second?.[entry.name]).toEqual({ status: "connected" });
expect(boundedFinal?.[entry.name]).toBeUndefined();
expect(sync.isPending(workspace, entry.name)).toBe(false);
});
test("ordinary disconnected and missing entries never become ready without verified OAuth success", () => {
const sync = createMcpStatusSynchronizer();
const workspace = "web:workspace-a";
const entry = server();
expect(sync.project(sync.beginRefresh(workspace), {
[entry.name]: { status: "disconnected" },
}, [entry])).toEqual({});
expect(sync.project(sync.beginRefresh(workspace), {}, [entry])).toEqual({});
});
});