Files
meshcentral-openclaw-bridge/implementation/src/__tests__/integration.test.ts
T

138 lines
4.4 KiB
TypeScript

/**
* Integration tests that validate the full bridge workflow.
*/
import { createMeshCentralAdapter, DiagnosticCheckType } from '../index';
describe('Bridge Integration', () => {
let adapter: ReturnType<typeof createMeshCentralAdapter>;
beforeEach(() => {
adapter = createMeshCentralAdapter({ adapterType: 'mock' });
});
describe('Device Discovery Workflow', () => {
it('should list all devices and groups, then fetch device details', async () => {
// Step 1: List all devices
const allDevices = await adapter.listDevices();
expect(allDevices).toHaveLength(4);
// Step 2: Get a specific device
const serverDevice = allDevices.find((d) => d.groupId === 'grp-servers');
if (!serverDevice) {
throw new Error('No server device found for testing');
}
const detailedDevice = await adapter.getDevice(serverDevice.id);
expect(detailedDevice.name).toBe(serverDevice.name);
// Step 3: Verify device belongs to expected group
expect(detailedDevice.groupId).toBe('grp-servers');
const group = await adapter.getGroup(detailedDevice.groupId);
expect(group.name).toBe('Servers');
});
it('should handle offline devices gracefully', async () => {
const allDevices = await adapter.listDevices();
const offlineDevices = allDevices.filter((d: { status: string }) => d.status === 'offline');
expect(offlineDevices).toHaveLength(1);
const offlineDevice = offlineDevices[0];
// Offline devices should still be retrievable
const detailed = await adapter.getDevice(offlineDevice.id);
expect(detailed.status).toBe('offline');
});
});
describe('Diagnostics Workflow', () => {
it('should run multiple diagnostic checks on a device', async () => {
const testDeviceId = 'dev-001';
const checks: DiagnosticCheckType[] = [
DiagnosticCheckType.DiskSpace,
DiagnosticCheckType.OSDetails,
DiagnosticCheckType.Uptime,
];
for (const checkType of checks) {
const result = await adapter.runDiagnostic({
deviceId: testDeviceId,
checkType,
});
expect(result.success).toBe(true);
expect(result.exitCode).toBe(0);
expect(result.output.length).toBeGreaterThan(0);
}
});
it('should handle diagnostics on offline devices', async () => {
const offlineDevice = await adapter.getDevice('dev-003');
expect(offlineDevice.status).toBe('offline');
// Diagnostics should still run (mock returns consistent data)
const result = await adapter.runDiagnostic({
deviceId: offlineDevice.id,
checkType: DiagnosticCheckType.OSDetails,
});
expect(result.success).toBe(true);
});
});
describe('Error Handling', () => {
it('should provide clear error messages for missing resources', async () => {
await expect(adapter.getDevice('nonexistent-device'))
.rejects
.toThrow('Device not found: nonexistent-device');
await expect(adapter.getGroup('nonexistent-group'))
.rejects
.toThrow('Group not found: nonexistent-group');
});
it('should include error codes in exceptions', async () => {
try {
await adapter.getDevice('nonexistent');
} catch (error: unknown) {
expect(error).toBeInstanceOf(Error);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect((error as any).code).toBe('RESOURCE_NOT_FOUND');
}
});
});
describe('Health Check', () => {
it('should report adapter health status', async () => {
const healthy = await adapter.healthCheck();
expect(healthy).toBe(true);
});
});
describe('Output Limits', () => {
it('should truncate large output when maxOutputLength is specified', async () => {
const result = await adapter.runDiagnostic({
deviceId: 'dev-001',
checkType: DiagnosticCheckType.DiskSpace,
maxOutputLength: 100,
});
expect(result.truncated).toBe(true);
expect(result.output.length).toBeLessThan(200); // 100 + truncation marker
});
it('should report output length and truncation status', async () => {
const result = await adapter.runDiagnostic({
deviceId: 'dev-001',
checkType: DiagnosticCheckType.DiskSpace,
maxOutputLength: 500,
});
expect(result.outputLength).toBeGreaterThan(0);
expect(result.maxOutputLength).toBe(500);
});
});
});