Files
archy-demo/neode-ui/src/api/__tests__/container-client.test.ts
2026-03-17 02:14:04 +00:00

179 lines
5.3 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
// Mock the rpc-client module
vi.mock('@/api/rpc-client', () => ({
rpcClient: {
call: vi.fn(),
},
}))
import { containerClient } from '../container-client'
import { rpcClient } from '@/api/rpc-client'
const mockedRpc = vi.mocked(rpcClient)
describe('containerClient', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('installApp calls container-install with manifest path', async () => {
mockedRpc.call.mockResolvedValue('container-abc123')
const result = await containerClient.installApp('/apps/bitcoin/manifest.yml')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-install',
params: { manifest_path: '/apps/bitcoin/manifest.yml' },
})
expect(result).toBe('container-abc123')
})
it('startContainer calls container-start with app_id', async () => {
mockedRpc.call.mockResolvedValue(undefined)
await containerClient.startContainer('bitcoin-knots')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-start',
params: { app_id: 'bitcoin-knots' },
})
})
it('stopContainer calls container-stop with app_id', async () => {
mockedRpc.call.mockResolvedValue(undefined)
await containerClient.stopContainer('lnd')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-stop',
params: { app_id: 'lnd' },
})
})
it('removeContainer calls container-remove with app_id', async () => {
mockedRpc.call.mockResolvedValue(undefined)
await containerClient.removeContainer('mempool')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-remove',
params: { app_id: 'mempool' },
})
})
it('getContainerStatus returns status for a container', async () => {
const mockStatus = {
id: '1',
name: 'bitcoin-knots',
state: 'running' as const,
image: 'bitcoinknots:29',
created: '2026-01-01',
ports: ['8332'],
lan_address: 'http://localhost:8332',
}
mockedRpc.call.mockResolvedValue(mockStatus)
const result = await containerClient.getContainerStatus('bitcoin-knots')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-status',
params: { app_id: 'bitcoin-knots' },
})
expect(result).toEqual(mockStatus)
})
it('getContainerLogs returns log lines with default line count', async () => {
const mockLogs = ['Starting bitcoin...', 'Block 850000 synced', 'Peer connected']
mockedRpc.call.mockResolvedValue(mockLogs)
const result = await containerClient.getContainerLogs('bitcoin-knots')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-logs',
params: { app_id: 'bitcoin-knots', lines: 100 },
})
expect(result).toEqual(mockLogs)
})
it('getContainerLogs respects custom line count', async () => {
mockedRpc.call.mockResolvedValue([])
await containerClient.getContainerLogs('lnd', 50)
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-logs',
params: { app_id: 'lnd', lines: 50 },
})
})
it('listContainers returns all containers', async () => {
const mockContainers = [
{ id: '1', name: 'bitcoin-knots', state: 'running', image: 'bitcoinknots:29', created: '2026-01-01', ports: ['8332'] },
{ id: '2', name: 'lnd', state: 'stopped', image: 'lnd:v0.18', created: '2026-01-01', ports: ['9735'] },
]
mockedRpc.call.mockResolvedValue(mockContainers)
const result = await containerClient.listContainers()
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-list',
params: {},
})
expect(result).toHaveLength(2)
})
it('getHealthStatus returns health map', async () => {
const mockHealth = { 'bitcoin-knots': 'healthy', lnd: 'unhealthy' }
mockedRpc.call.mockResolvedValue(mockHealth)
const result = await containerClient.getHealthStatus()
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'container-health',
params: {},
})
expect(result).toEqual(mockHealth)
})
it('startBundledApp sends full app config', async () => {
mockedRpc.call.mockResolvedValue(undefined)
const app = {
id: 'filebrowser',
name: 'FileBrowser',
image: 'filebrowser/filebrowser:v2',
ports: [{ host: 8083, container: 80 }],
volumes: [{ host: '/var/lib/archipelago/filebrowser', container: '/srv' }],
}
await containerClient.startBundledApp(app)
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'bundled-app-start',
params: {
app_id: 'filebrowser',
image: 'filebrowser/filebrowser:v2',
ports: [{ host: 8083, container: 80 }],
volumes: [{ host: '/var/lib/archipelago/filebrowser', container: '/srv' }],
},
})
})
it('stopBundledApp calls bundled-app-stop', async () => {
mockedRpc.call.mockResolvedValue(undefined)
await containerClient.stopBundledApp('filebrowser')
expect(mockedRpc.call).toHaveBeenCalledWith({
method: 'bundled-app-stop',
params: { app_id: 'filebrowser' },
})
})
it('propagates RPC errors from the client', async () => {
mockedRpc.call.mockRejectedValue(new Error('Connection refused'))
await expect(containerClient.startContainer('bitcoin-knots')).rejects.toThrow('Connection refused')
})
})