feat: 2.0.0-alpha.11 — DB-backed service registry + LAN auto-discovery
- monitored_services table (mig 015) replaces config/services.json (now a boot seed) - owner CRUD over /api/health/services; GET is DB-backed; cron+worker read the DB - discover.lan worker: pure-Node TCP sweep + HTTP-title probe -> disabled 'discovered' candidates (never clobbers curated entries); POST /api/health/discover + GET .../discovered - dashboard: Scan button + Discovered(N) section with one-click promote Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,33 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { load, grouped, iconSlug, CATEGORY_ORDER } from '../../lib/health/registry.js';
|
||||
import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
|
||||
import { resetDb } from '../helpers/db.js';
|
||||
import { migrateUp } from '../../lib/db/migrate.js';
|
||||
import { grouped, iconSlug, CATEGORY_ORDER, seedFromConfig } from '../../lib/health/registry.js';
|
||||
import * as services from '../../lib/db/repos/monitored_services.js';
|
||||
|
||||
beforeAll(async () => { await resetDb(); await migrateUp(); });
|
||||
beforeEach(async () => { await resetDb(); await migrateUp(); });
|
||||
|
||||
describe('registry', () => {
|
||||
it('loads the seed config', () => { expect(load().length).toBeGreaterThan(0); });
|
||||
it('derives an icon slug from icon or name', () => {
|
||||
it('iconSlug derives from icon or name', () => {
|
||||
expect(iconSlug({ name: 'Open WebUI' })).toBe('open-webui');
|
||||
expect(iconSlug({ name: 'Plex', icon: 'plex' })).toBe('plex');
|
||||
});
|
||||
it('groups in agents→infrastructure→media order', () => {
|
||||
const g = grouped(load());
|
||||
|
||||
it('grouped orders agents→infrastructure→media; unknown categories fold into "other" (last)', () => {
|
||||
const g = grouped([{ category: 'media', name: 'a' }, { category: 'agents', name: 'b' }, { category: 'zzz', name: 'c' }]);
|
||||
const cats = g.map(x => x.category);
|
||||
const ai = cats.indexOf('agents'), mi = cats.indexOf('media');
|
||||
expect(ai).toBeLessThan(mi);
|
||||
expect(cats.indexOf('agents')).toBeLessThan(cats.indexOf('media'));
|
||||
expect(cats[cats.length - 1]).toBe('other'); // 'zzz' normalized to 'other'
|
||||
expect(g.find(x => x.category === 'other').services[0].name).toBe('c');
|
||||
expect(CATEGORY_ORDER[0]).toBe('agents');
|
||||
});
|
||||
|
||||
it('seedFromConfig populates the DB from config/services.json once (idempotent)', async () => {
|
||||
const n = await seedFromConfig();
|
||||
expect(n).toBeGreaterThan(0);
|
||||
const after = await services.all();
|
||||
expect(after.length).toBe(n);
|
||||
expect(after.every(s => s.source === 'manual' && s.enabled)).toBe(true);
|
||||
expect(await seedFromConfig()).toBe(0); // table not empty → no-op
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user