import { noOpLogger } from "@mcpx/toolkit-core/logging";
import { SetupManager } from "./setup-manager.js";
import { TargetServer } from "../model/target-servers.js";
import { Config } from "../model/config/config.js";
import { ConfigService } from "../config.js";
import { TargetClients } from "./target-clients.js";
// Minimal stubs - these methods don't use the dependencies
const stubTargetClients = {} as TargetClients;
const stubConfigService = {} as ConfigService;
function createSetupManager(): SetupManager {
return new SetupManager(stubTargetClients, stubConfigService, noOpLogger);
}
const echoServer: TargetServer = {
type: "stdio",
name: "echo-service",
command: "node",
args: ["echo.js"],
env: {},
};
const calculatorServer: TargetServer = {
type: "stdio",
name: "calculator-service",
command: "node",
args: ["calc.js"],
env: {},
};
const baseConfig: Config = {
permissions: {
default: { _type: "default-allow", block: [] },
consumers: {},
},
toolGroups: [],
auth: { enabled: false },
toolExtensions: { services: {} },
targetServerAttributes: {},
};
describe("SetupManager", () => {
describe("#buildUserTargetServersChangePayload", () => {
it("returns payload on first call (no previous state)", () => {
const manager = createSetupManager();
const result = manager.buildUserTargetServersChangePayload([echoServer]);
expect(result).not.toBeNull();
expect(result?.source).toBe("user");
expect(result?.targetServers).toHaveProperty("echo-service");
});
it("returns null when called with empty array (matches initial state)", () => {
const manager = createSetupManager();
const result = manager.buildUserTargetServersChangePayload([]);
expect(result).toBeNull();
});
it("returns null when servers unchanged", () => {
const manager = createSetupManager();
// First call sets state
manager.buildUserTargetServersChangePayload([echoServer]);
// Second call with same servers
const result = manager.buildUserTargetServersChangePayload([echoServer]);
expect(result).toBeNull();
});
it("returns payload when servers change", () => {
const manager = createSetupManager();
// First call
manager.buildUserTargetServersChangePayload([echoServer]);
// Second call with different servers
const result = manager.buildUserTargetServersChangePayload([
echoServer,
calculatorServer,
]);
expect(result).not.toBeNull();
expect(result?.source).toBe("user");
expect(result?.targetServers).toHaveProperty("echo-service");
expect(result?.targetServers).toHaveProperty("calculator-service");
});
it("returns payload when server removed", () => {
const manager = createSetupManager();
// First call with two servers
manager.buildUserTargetServersChangePayload([
echoServer,
calculatorServer,
]);
// Second call with one server removed
const result = manager.buildUserTargetServersChangePayload([echoServer]);
expect(result).not.toBeNull();
expect(result?.targetServers).toHaveProperty("echo-service");
expect(result?.targetServers).not.toHaveProperty("calculator-service");
});
});
describe("#buildUserConfigChangePayload", () => {
it("returns payload on first call (no previous state)", () => {
const manager = createSetupManager();
const result = manager.buildUserConfigChangePayload(baseConfig);
expect(result).not.toBeNull();
expect(result?.source).toBe("user");
expect(result?.config).toBeDefined();
});
it("returns null when config unchanged", () => {
const manager = createSetupManager();
// First call sets state
manager.buildUserConfigChangePayload(baseConfig);
// Second call with same config
const result = manager.buildUserConfigChangePayload(baseConfig);
expect(result).toBeNull();
});
it("returns payload when config changes", () => {
const manager = createSetupManager();
// First call
manager.buildUserConfigChangePayload(baseConfig);
// Second call with different config
const changedConfig: Config = {
...baseConfig,
auth: { enabled: true },
};
const result = manager.buildUserConfigChangePayload(changedConfig);
expect(result).not.toBeNull();
expect(result?.source).toBe("user");
expect(result?.config?.auth).toEqual({ enabled: true });
});
it("returns payload when toolGroups change", () => {
const manager = createSetupManager();
// First call
manager.buildUserConfigChangePayload(baseConfig);
// Second call with toolGroups
const configWithToolGroups: Config = {
...baseConfig,
toolGroups: [{ name: "test-group", services: {} }],
};
const result = manager.buildUserConfigChangePayload(configWithToolGroups);
expect(result).not.toBeNull();
expect(result?.config?.toolGroups).toHaveLength(1);
});
});
describe("state consistency", () => {
it("preserves config when only servers change", () => {
const manager = createSetupManager();
// Set config first
manager.buildUserConfigChangePayload(baseConfig);
// Then change servers
const result = manager.buildUserTargetServersChangePayload([echoServer]);
expect(result).not.toBeNull();
expect(result?.config).toBeDefined();
expect(result?.targetServers).toHaveProperty("echo-service");
});
it("preserves servers when only config changes", () => {
const manager = createSetupManager();
// Set servers first
manager.buildUserTargetServersChangePayload([echoServer]);
// Then change config
const changedConfig: Config = { ...baseConfig, auth: { enabled: true } };
const result = manager.buildUserConfigChangePayload(changedConfig);
expect(result).not.toBeNull();
expect(result?.targetServers).toHaveProperty("echo-service");
expect(result?.config?.auth).toEqual({ enabled: true });
});
});
});