Skip to content

Commit 19b3078

Browse files
committed
test: add unit tests for unassigned target assignment and gateway removal
- getUnassignedTargets: returns targets, empty when no config, empty when field missing - createGatewayFromWizard: moves selected targets to new gateway, removes from unassigned - removeGateway: preserves targets as unassigned on removal, no-op for empty gateways - previewRemoveGateway: shows 'will become unassigned' warning
1 parent 325b30c commit 19b3078

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

src/cli/operations/mcp/__tests__/create-mcp.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,78 @@ describe('createExternalGatewayTarget', () => {
131131
expect(target.outboundAuth).toEqual({ type: 'API_KEY', credentialName: 'my-cred' });
132132
});
133133
});
134+
135+
import { createGatewayFromWizard, getUnassignedTargets } from '../create-mcp.js';
136+
import type { AddGatewayConfig } from '../../../tui/screens/mcp/types.js';
137+
138+
describe('getUnassignedTargets', () => {
139+
afterEach(() => vi.clearAllMocks());
140+
141+
it('returns unassigned targets from mcp spec', async () => {
142+
mockConfigExists.mockReturnValue(true);
143+
mockReadMcpSpec.mockResolvedValue({
144+
agentCoreGateways: [],
145+
unassignedTargets: [{ name: 't1' }, { name: 't2' }],
146+
});
147+
148+
const result = await getUnassignedTargets();
149+
expect(result).toHaveLength(2);
150+
expect(result[0]!.name).toBe('t1');
151+
});
152+
153+
it('returns empty array when no mcp config exists', async () => {
154+
mockConfigExists.mockReturnValue(false);
155+
expect(await getUnassignedTargets()).toEqual([]);
156+
});
157+
158+
it('returns empty array when unassignedTargets field is missing', async () => {
159+
mockConfigExists.mockReturnValue(true);
160+
mockReadMcpSpec.mockResolvedValue({ agentCoreGateways: [] });
161+
expect(await getUnassignedTargets()).toEqual([]);
162+
});
163+
});
164+
165+
describe('createGatewayFromWizard with selectedTargets', () => {
166+
afterEach(() => vi.clearAllMocks());
167+
168+
function makeGatewayConfig(overrides: Partial<AddGatewayConfig> = {}): AddGatewayConfig {
169+
return {
170+
name: 'new-gateway',
171+
authorizerType: 'AWS_IAM',
172+
...overrides,
173+
} as AddGatewayConfig;
174+
}
175+
176+
it('moves selected targets to new gateway and removes from unassigned', async () => {
177+
mockConfigExists.mockReturnValue(true);
178+
mockReadMcpSpec.mockResolvedValue({
179+
agentCoreGateways: [],
180+
unassignedTargets: [
181+
{ name: 'target-a', targetType: 'mcpServer' },
182+
{ name: 'target-b', targetType: 'mcpServer' },
183+
{ name: 'target-c', targetType: 'mcpServer' },
184+
],
185+
});
186+
187+
await createGatewayFromWizard(makeGatewayConfig({ selectedTargets: ['target-a', 'target-c'] }));
188+
189+
const written = mockWriteMcpSpec.mock.calls[0]![0];
190+
const gateway = written.agentCoreGateways.find((g: { name: string }) => g.name === 'new-gateway');
191+
expect(gateway.targets).toHaveLength(2);
192+
expect(gateway.targets[0]!.name).toBe('target-a');
193+
expect(gateway.targets[1]!.name).toBe('target-c');
194+
expect(written.unassignedTargets).toHaveLength(1);
195+
expect(written.unassignedTargets[0]!.name).toBe('target-b');
196+
});
197+
198+
it('creates gateway with empty targets when no selectedTargets', async () => {
199+
mockConfigExists.mockReturnValue(true);
200+
mockReadMcpSpec.mockResolvedValue({ agentCoreGateways: [] });
201+
202+
await createGatewayFromWizard(makeGatewayConfig());
203+
204+
const written = mockWriteMcpSpec.mock.calls[0]![0];
205+
const gateway = written.agentCoreGateways.find((g: { name: string }) => g.name === 'new-gateway');
206+
expect(gateway.targets).toHaveLength(0);
207+
});
208+
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { previewRemoveGateway, removeGateway } from '../remove-gateway.js';
2+
import { afterEach, describe, expect, it, vi } from 'vitest';
3+
4+
const { mockReadMcpSpec, mockWriteMcpSpec, mockConfigExists } = vi.hoisted(() => ({
5+
mockReadMcpSpec: vi.fn(),
6+
mockWriteMcpSpec: vi.fn(),
7+
mockConfigExists: vi.fn(),
8+
}));
9+
10+
vi.mock('../../../../lib/index.js', () => ({
11+
ConfigIO: class {
12+
configExists = mockConfigExists;
13+
readMcpSpec = mockReadMcpSpec;
14+
writeMcpSpec = mockWriteMcpSpec;
15+
},
16+
}));
17+
18+
describe('removeGateway', () => {
19+
afterEach(() => vi.clearAllMocks());
20+
21+
it('moves gateway targets to unassignedTargets on removal, preserving existing', async () => {
22+
mockReadMcpSpec.mockResolvedValue({
23+
agentCoreGateways: [
24+
{ name: 'gw-to-remove', targets: [{ name: 'target-1' }, { name: 'target-2' }] },
25+
{ name: 'other-gw', targets: [] },
26+
],
27+
unassignedTargets: [{ name: 'already-unassigned' }],
28+
});
29+
30+
const result = await removeGateway('gw-to-remove');
31+
32+
expect(result.ok).toBe(true);
33+
const written = mockWriteMcpSpec.mock.calls[0]![0];
34+
expect(written.agentCoreGateways).toHaveLength(1);
35+
expect(written.agentCoreGateways[0]!.name).toBe('other-gw');
36+
expect(written.unassignedTargets).toHaveLength(3);
37+
expect(written.unassignedTargets[0]!.name).toBe('already-unassigned');
38+
expect(written.unassignedTargets[1]!.name).toBe('target-1');
39+
expect(written.unassignedTargets[2]!.name).toBe('target-2');
40+
});
41+
42+
it('does not modify unassignedTargets when gateway has no targets', async () => {
43+
mockReadMcpSpec.mockResolvedValue({
44+
agentCoreGateways: [{ name: 'empty-gw', targets: [] }],
45+
});
46+
47+
const result = await removeGateway('empty-gw');
48+
49+
expect(result.ok).toBe(true);
50+
const written = mockWriteMcpSpec.mock.calls[0]![0];
51+
expect(written.agentCoreGateways).toHaveLength(0);
52+
expect(written.unassignedTargets).toBeUndefined();
53+
});
54+
});
55+
56+
describe('previewRemoveGateway', () => {
57+
afterEach(() => vi.clearAllMocks());
58+
59+
it('shows "will become unassigned" warning when gateway has targets', async () => {
60+
mockReadMcpSpec.mockResolvedValue({
61+
agentCoreGateways: [{ name: 'my-gw', targets: [{ name: 't1' }, { name: 't2' }] }],
62+
});
63+
64+
const preview = await previewRemoveGateway('my-gw');
65+
66+
expect(preview.summary.some(s => s.includes('2 target(s) will become unassigned'))).toBe(true);
67+
});
68+
});

0 commit comments

Comments
 (0)