mirror of https://github.com/portainer/portainer
278 lines
8.0 KiB
TypeScript
278 lines
8.0 KiB
TypeScript
import { http, HttpResponse } from 'msw';
|
|
|
|
import { server } from '@/setup-tests/server';
|
|
|
|
import { StackType } from '../../types';
|
|
|
|
import { duplicateStack } from './useDuplicateStackMutation';
|
|
|
|
type StackRequestBody = {
|
|
name: string;
|
|
swarmID: string;
|
|
env?: Array<{ name: string; value: string }>;
|
|
};
|
|
|
|
describe('Swarm stack duplication', () => {
|
|
it('should call getSwarm with targetEnvironmentId for Swarm stacks', async () => {
|
|
const swarmId = 'swarm123';
|
|
let swarmRequestCalled = false;
|
|
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', ({ params }) => {
|
|
swarmRequestCalled = true;
|
|
expect(params.id).toBe('2');
|
|
return HttpResponse.json({ ID: swarmId });
|
|
}),
|
|
http.post('/api/stacks/create/:type/:method', async () =>
|
|
HttpResponse.json({ Id: 123 })
|
|
)
|
|
);
|
|
|
|
await duplicateStack({
|
|
name: 'test-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerSwarm,
|
|
env: [{ name: 'VAR1', value: 'value1' }],
|
|
});
|
|
|
|
expect(swarmRequestCalled).toBe(true);
|
|
});
|
|
|
|
it('should call createSwarmStackFromFileContent with correct parameters', async () => {
|
|
const swarmId = 'swarm123';
|
|
let stackRequestBody: undefined | StackRequestBody;
|
|
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () =>
|
|
HttpResponse.json({ ID: swarmId })
|
|
),
|
|
http.post('/api/stacks/create/:type/:method', async ({ request }) => {
|
|
stackRequestBody = (await request.json()) as StackRequestBody;
|
|
|
|
return HttpResponse.json({ Id: 123 });
|
|
})
|
|
);
|
|
|
|
const fileContent = 'version: "3"\nservices:\n app:\n image: nginx';
|
|
const env = [{ name: 'VAR1', value: 'value1' }];
|
|
|
|
await duplicateStack({
|
|
name: 'test-stack',
|
|
fileContent,
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerSwarm,
|
|
env,
|
|
});
|
|
|
|
expect(stackRequestBody).toBeDefined();
|
|
expect(stackRequestBody?.name).toBe('test-stack');
|
|
expect(stackRequestBody?.swarmID).toBe(swarmId);
|
|
});
|
|
|
|
it('should throw error if Swarm ID is missing', async () => {
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () =>
|
|
HttpResponse.json({ ID: '' })
|
|
)
|
|
);
|
|
|
|
await expect(
|
|
duplicateStack({
|
|
name: 'test-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerSwarm,
|
|
})
|
|
).rejects.toThrow('Swarm ID is required');
|
|
});
|
|
|
|
it('should pass swarmID from getSwarm response', async () => {
|
|
const swarmId = 'custom-swarm-id-456';
|
|
let stackRequestBody: StackRequestBody | undefined;
|
|
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () =>
|
|
HttpResponse.json({ ID: swarmId })
|
|
),
|
|
http.post('/api/stacks/create/:type/:method', async ({ request }) => {
|
|
stackRequestBody = (await request.json()) as StackRequestBody;
|
|
return HttpResponse.json({ Id: 123 });
|
|
})
|
|
);
|
|
|
|
await duplicateStack({
|
|
name: 'test-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerSwarm,
|
|
});
|
|
|
|
expect(stackRequestBody?.swarmID).toBe(swarmId);
|
|
});
|
|
|
|
it('should pass environmentId, name, stackFileContent, env', async () => {
|
|
const swarmId = 'swarm123';
|
|
let stackRequestBody: StackRequestBody | undefined;
|
|
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () =>
|
|
HttpResponse.json({ ID: swarmId })
|
|
),
|
|
http.post('/api/stacks/create/:type/:method', async ({ request }) => {
|
|
stackRequestBody = (await request.json()) as StackRequestBody;
|
|
return HttpResponse.json({ Id: 123 });
|
|
})
|
|
);
|
|
|
|
const fileContent = 'version: "3"\nservices:\n app:\n image: nginx';
|
|
const env = [
|
|
{ name: 'VAR1', value: 'value1' },
|
|
{ name: 'VAR2', value: 'value2' },
|
|
];
|
|
|
|
await duplicateStack({
|
|
name: 'my-swarm-stack',
|
|
fileContent,
|
|
targetEnvironmentId: 3,
|
|
type: StackType.DockerSwarm,
|
|
env,
|
|
});
|
|
|
|
expect(stackRequestBody).toBeDefined();
|
|
expect(stackRequestBody?.name).toBe('my-swarm-stack');
|
|
expect(stackRequestBody?.env).toEqual(env);
|
|
});
|
|
});
|
|
|
|
describe('Standalone stack duplication', () => {
|
|
it('should call createStandaloneStackFromFileContent for non-Swarm stacks', async () => {
|
|
let stackRequestBody: StackRequestBody | undefined;
|
|
|
|
server.use(
|
|
http.post('/api/stacks/create/:type/:method', async ({ request }) => {
|
|
stackRequestBody = (await request.json()) as StackRequestBody;
|
|
return HttpResponse.json({ Id: 123 });
|
|
})
|
|
);
|
|
|
|
await duplicateStack({
|
|
name: 'standalone-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerCompose,
|
|
});
|
|
|
|
expect(stackRequestBody).toBeDefined();
|
|
expect(stackRequestBody?.name).toBe('standalone-stack');
|
|
});
|
|
|
|
it('should pass environmentId, name, stackFileContent, env', async () => {
|
|
let stackRequestBody: StackRequestBody | undefined;
|
|
|
|
server.use(
|
|
http.post('/api/stacks/create/:type/:method', async ({ request }) => {
|
|
stackRequestBody = (await request.json()) as StackRequestBody;
|
|
return HttpResponse.json({ Id: 123 });
|
|
})
|
|
);
|
|
|
|
const fileContent = 'version: "3"\nservices:\n web:\n image: nginx';
|
|
const env = [{ name: 'PORT', value: '8080' }];
|
|
|
|
await duplicateStack({
|
|
name: 'compose-stack',
|
|
fileContent,
|
|
targetEnvironmentId: 5,
|
|
type: StackType.DockerCompose,
|
|
env,
|
|
});
|
|
|
|
expect(stackRequestBody).toBeDefined();
|
|
expect(stackRequestBody?.name).toBe('compose-stack');
|
|
expect(stackRequestBody?.env).toEqual(env);
|
|
});
|
|
|
|
it('should not call getSwarm for standalone stacks', async () => {
|
|
let swarmRequestCalled = false;
|
|
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () => {
|
|
swarmRequestCalled = true;
|
|
return HttpResponse.json({ ID: 'swarm123' });
|
|
}),
|
|
http.post('/api/stacks/create/:type/:method', () =>
|
|
HttpResponse.json({ Id: 123 })
|
|
)
|
|
);
|
|
|
|
await duplicateStack({
|
|
name: 'standalone-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerCompose,
|
|
});
|
|
|
|
expect(swarmRequestCalled).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('error handling', () => {
|
|
it('should propagate errors from getSwarm', async () => {
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () =>
|
|
HttpResponse.json({ message: 'Swarm not found' }, { status: 404 })
|
|
)
|
|
);
|
|
|
|
await expect(
|
|
duplicateStack({
|
|
name: 'test-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerSwarm,
|
|
})
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('should propagate errors from createSwarmStackFromFileContent', async () => {
|
|
server.use(
|
|
http.get('/api/endpoints/:id/docker/swarm', () =>
|
|
HttpResponse.json({ ID: 'swarm123' })
|
|
),
|
|
http.post('/api/stacks/create/:type/:method', () =>
|
|
HttpResponse.json({ message: 'Stack creation failed' }, { status: 500 })
|
|
)
|
|
);
|
|
|
|
await expect(
|
|
duplicateStack({
|
|
name: 'test-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerSwarm,
|
|
})
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('should propagate errors from createStandaloneStackFromFileContent', async () => {
|
|
server.use(
|
|
http.post('/api/stacks/create/:type/:method', () =>
|
|
HttpResponse.json(
|
|
{ message: 'Stack name already exists' },
|
|
{ status: 409 }
|
|
)
|
|
)
|
|
);
|
|
|
|
await expect(
|
|
duplicateStack({
|
|
name: 'existing-stack',
|
|
fileContent: 'version: "3"\nservices:\n app:\n image: nginx',
|
|
targetEnvironmentId: 2,
|
|
type: StackType.DockerCompose,
|
|
})
|
|
).rejects.toThrow();
|
|
});
|
|
});
|