128 lines
5.1 KiB
TypeScript
128 lines
5.1 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||
|
|
import { createInstanceCommands } from '../../src/commands/instances.js';
|
||
|
|
import type { ApiClient } from '../../src/api-client.js';
|
||
|
|
|
||
|
|
function mockClient(): ApiClient {
|
||
|
|
return {
|
||
|
|
get: vi.fn(async () => []),
|
||
|
|
post: vi.fn(async () => ({})),
|
||
|
|
put: vi.fn(async () => ({})),
|
||
|
|
delete: vi.fn(async () => {}),
|
||
|
|
} as unknown as ApiClient;
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('instance commands', () => {
|
||
|
|
let client: ReturnType<typeof mockClient>;
|
||
|
|
let output: string[];
|
||
|
|
const log = (...args: unknown[]) => output.push(args.map(String).join(' '));
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
client = mockClient();
|
||
|
|
output = [];
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('list', () => {
|
||
|
|
it('shows no instances message when empty', async () => {
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['list'], { from: 'user' });
|
||
|
|
expect(output.join('\n')).toContain('No instances found');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('shows instance table', async () => {
|
||
|
|
vi.mocked(client.get).mockResolvedValue([
|
||
|
|
{ id: 'inst-1', serverId: 'srv-1', status: 'RUNNING', containerId: 'ctr-abc123def', port: 3000, createdAt: '2025-01-01' },
|
||
|
|
]);
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['list'], { from: 'user' });
|
||
|
|
expect(output.join('\n')).toContain('inst-1');
|
||
|
|
expect(output.join('\n')).toContain('RUNNING');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('filters by server', async () => {
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['list', '-s', 'srv-1'], { from: 'user' });
|
||
|
|
expect(client.get).toHaveBeenCalledWith(expect.stringContaining('serverId=srv-1'));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('outputs json', async () => {
|
||
|
|
vi.mocked(client.get).mockResolvedValue([{ id: 'inst-1' }]);
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['list', '-o', 'json'], { from: 'user' });
|
||
|
|
expect(output[0]).toContain('"id"');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('start', () => {
|
||
|
|
it('starts an instance', async () => {
|
||
|
|
vi.mocked(client.post).mockResolvedValue({ id: 'inst-new', status: 'RUNNING' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['start', 'srv-1'], { from: 'user' });
|
||
|
|
expect(client.post).toHaveBeenCalledWith('/api/v1/instances', { serverId: 'srv-1' });
|
||
|
|
expect(output.join('\n')).toContain('started');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('passes host port', async () => {
|
||
|
|
vi.mocked(client.post).mockResolvedValue({ id: 'inst-new', status: 'RUNNING' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['start', 'srv-1', '-p', '8080'], { from: 'user' });
|
||
|
|
expect(client.post).toHaveBeenCalledWith('/api/v1/instances', { serverId: 'srv-1', hostPort: 8080 });
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('stop', () => {
|
||
|
|
it('stops an instance', async () => {
|
||
|
|
vi.mocked(client.post).mockResolvedValue({ id: 'inst-1', status: 'STOPPED' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['stop', 'inst-1'], { from: 'user' });
|
||
|
|
expect(client.post).toHaveBeenCalledWith('/api/v1/instances/inst-1/stop');
|
||
|
|
expect(output.join('\n')).toContain('stopped');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('restart', () => {
|
||
|
|
it('restarts an instance', async () => {
|
||
|
|
vi.mocked(client.post).mockResolvedValue({ id: 'inst-2', status: 'RUNNING' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['restart', 'inst-1'], { from: 'user' });
|
||
|
|
expect(client.post).toHaveBeenCalledWith('/api/v1/instances/inst-1/restart');
|
||
|
|
expect(output.join('\n')).toContain('restarted');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('remove', () => {
|
||
|
|
it('removes an instance', async () => {
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['remove', 'inst-1'], { from: 'user' });
|
||
|
|
expect(client.delete).toHaveBeenCalledWith('/api/v1/instances/inst-1');
|
||
|
|
expect(output.join('\n')).toContain('removed');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('logs', () => {
|
||
|
|
it('shows logs', async () => {
|
||
|
|
vi.mocked(client.get).mockResolvedValue({ stdout: 'hello world\n', stderr: '' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['logs', 'inst-1'], { from: 'user' });
|
||
|
|
expect(client.get).toHaveBeenCalledWith('/api/v1/instances/inst-1/logs');
|
||
|
|
expect(output.join('\n')).toContain('hello world');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('passes tail option', async () => {
|
||
|
|
vi.mocked(client.get).mockResolvedValue({ stdout: '', stderr: '' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['logs', 'inst-1', '-t', '50'], { from: 'user' });
|
||
|
|
expect(client.get).toHaveBeenCalledWith('/api/v1/instances/inst-1/logs?tail=50');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('inspect', () => {
|
||
|
|
it('shows container info as json', async () => {
|
||
|
|
vi.mocked(client.get).mockResolvedValue({ containerId: 'ctr-abc', state: 'running' });
|
||
|
|
const cmd = createInstanceCommands({ client, log });
|
||
|
|
await cmd.parseAsync(['inspect', 'inst-1'], { from: 'user' });
|
||
|
|
expect(client.get).toHaveBeenCalledWith('/api/v1/instances/inst-1/inspect');
|
||
|
|
expect(output[0]).toContain('ctr-abc');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|