Add cache pinning and health controls

This commit is contained in:
Jonathan Sykes
2026-10-14 01:59:23 +08:00
parent 180a28d3e4
commit 42c68609ec
9 changed files with 161 additions and 7 deletions

View File

@@ -6,6 +6,7 @@ import { Hono } from 'hono';
const root = mkdtempSync(join(tmpdir(), 'ytp-admin-tools-'));
process.env.DB_PATH = join(root, 'admin.db');
process.env.MEDIA_CACHE_PINNED_MAX_BYTES = '1000';
const db = await import('./db.js');
const { registerAdminToolsRoutes } = await import('./admin-tools.js');
const app = new Hono();
@@ -17,6 +18,7 @@ beforeAll(async () => {
await db.db.execute({ sql: 'INSERT INTO video_meta(id,card,hay,seen,updated_at) VALUES(?,?,?,?,?)', args: ['QualMiss001', JSON.stringify({ title: 'Missing lyric sample', channel: 'Choir' }), 'missing lyric sample choir', 1, Date.now()] });
await db.db.execute({ sql: 'INSERT INTO video_meta(id,card,hay,seen,updated_at) VALUES(?,?,?,?,?)', args: ['Untimely001', JSON.stringify({ title: 'Untimed sample', channel: 'Band' }), 'untimed sample band', 1, Date.now()] });
await db.db.execute({ sql: "INSERT INTO video_notes(video_id,kind,data,rev,source) VALUES(?, 'lyrics', ?, 1, 'user')", args: ['Untimely001', JSON.stringify({ lines: [{ t: null, text: 'A line' }, { t: 4, text: 'Next' }] })] });
await db.db.execute({ sql: "INSERT INTO media_cache(video_id,status,size,gen) VALUES('CacheItem001','ready',700,1),('CacheItem002','ready',400,1)" });
});
afterAll(() => rmSync(root, { recursive: true, force: true }));
@@ -34,4 +36,16 @@ describe('lyrics quality queue', () => {
const page = await (await app.request('/api/admin/lyrics/quality?limit=1&offset=1', { headers })).json();
expect(page.songs).toHaveLength(1);
});
test('pinning is authorized and enforces the configured pinned-byte cap', async () => {
const headers = { 'x-admin': 'yes', 'content-type': 'application/json' };
expect((await app.request('/api/admin/cache/CacheItem001/pin', { method: 'POST', headers, body: JSON.stringify({ pinned: true }) })).status).toBe(200);
const over = await app.request('/api/admin/cache/CacheItem002/pin', { method: 'POST', headers, body: JSON.stringify({ pinned: true }) });
expect(over.status).toBe(409);
expect((await over.json()).error).toContain('byte cap');
const refused = await app.request('/api/admin/cache/CacheItem001/evict', { method: 'POST', headers, body: '{}' });
expect(refused.status).toBe(409);
const health = await (await app.request('/api/admin/cache/health', { headers: { 'x-admin': 'yes' } })).json();
expect(health.pinnedBytes).toBe(700);
});
});