import { describe, expect, it, vi } from 'vitest'; import type { BackupConfig, MinioSyncAutomationConfig } from '../config/schema.js'; import type { MemoryStore } from '../memory/store.js'; import { MinioSyncScheduler } from './minioSync.js'; function makeBackupConfig(): BackupConfig { return { enabled: true, schedule: undefined, interval: '24h', run_on_start: false, notify: undefined, failure_threshold: 1, notify_recovery: true, local_dir: '~/.local/share/flynn/backups', include_vectors: true, minio: { enabled: true, endpoint: 'localhost:9000', access_key: 'minio-admin', secret_key: 'minio-secret', bucket: 'flynn-knowledge', prefix: 'flynn', secure: false, }, }; } function makeAutomationConfig(overrides?: Partial): MinioSyncAutomationConfig { return { enabled: true, interval: '6h', run_on_start: false, tasks: [{ prefix: 'knowledge/', bucket: undefined, namespace_base: 'global/knowledge/minio', mode: 'append', max_objects: 20, max_chars_per_object: 8000, force: false, }], notify: undefined, notify_on_success: false, ...overrides, }; } describe('MinioSyncScheduler', () => { it('skips when memory store is unavailable', async () => { const scheduler = new MinioSyncScheduler({ config: makeAutomationConfig(), backupConfig: makeBackupConfig(), memoryStore: undefined, channelLookup: { get: () => undefined }, }); const result = await scheduler.runOnce(); expect(result).toEqual({ succeeded: 0, failed: 0, details: [] }); }); it('runs configured sync tasks and records success/failure counts', async () => { const memoryStore = { write: vi.fn() } as unknown as MemoryStore; const send = vi.fn(async () => undefined); const scheduler = new MinioSyncScheduler({ config: makeAutomationConfig({ tasks: [ { prefix: 'knowledge/good/', bucket: undefined, namespace_base: 'global/knowledge/minio', mode: 'append', max_objects: 20, max_chars_per_object: 8000, force: false, }, { prefix: 'knowledge/fail/', bucket: undefined, namespace_base: 'global/knowledge/minio', mode: 'append', max_objects: 20, max_chars_per_object: 8000, force: false, }, ], notify: { channel: 'telegram', peer: '123' }, }), backupConfig: makeBackupConfig(), memoryStore, channelLookup: { get: () => ({ send }) }, createSyncTool: () => ({ name: 'minio.sync', description: '', inputSchema: { type: 'object', properties: {} }, execute: async (rawArgs: unknown) => { const prefix = (rawArgs as { prefix: string }).prefix; if (prefix === 'knowledge/fail/') { return { success: false, output: '', error: 'boom' }; } return { success: true, output: 'ok' }; }, }), }); const result = await scheduler.runOnce(); expect(result.succeeded).toBe(1); expect(result.failed).toBe(1); expect(result.details).toContain('OK knowledge/good/'); expect(result.details).toContain('FAIL knowledge/fail/: boom'); expect(send).toHaveBeenCalledTimes(1); scheduler.stop(); }); });