Files
ytplayer/server/p2p-db.test.js
2026-09-30 07:11:55 +00:00

72 lines
3.2 KiB
JavaScript

// P2P tables against a real temp libsql DB (docs/p2p-architecture.md).
import { test, expect, beforeAll } from 'bun:test';
import { mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const root = mkdtempSync(join(tmpdir(), 'ytp-p2p-test-'));
process.env.DB_PATH = join(root, 'test.db');
const dbmod = await import('./db.js');
const P = await import('./p2p-db.js');
const { loadP2pConfig } = await import('./p2p-config.js');
const CID = 'a'.repeat(64);
const CID2 = 'b'.repeat(64);
const T0 = Date.UTC(2026, 8, 29, 12);
beforeAll(async () => {
await dbmod.initDb();
await P.initP2pSchema();
await P.initP2pSchema(); // idempotent (ALTER TABLE duplicate column is ignored)
});
test('config defaults: P2P on, malware scan off', () => {
const c = loadP2pConfig({});
expect(c.enabled).toBe(true);
expect(c.malwareScan).toBe(false);
expect(c.staleDays).toBe(7);
expect(loadP2pConfig({ P2P_ENABLED: '0', P2P_MALWARE_SCAN: '1' })).toMatchObject({ enabled: false, malwareScan: true });
});
test('content upsert/get/known/revoke', async () => {
await P.upsertContent({ cid: CID, videoId: 'dQw4w9WgXcQ', size: 1000, height: 720, vcodec: 'h264', acodec: 'aac', duration: 212, meta: { title: 'x' }, origin: 'server', now: T0 });
const c = await P.getContent(CID);
expect(c.video_id).toBe('dQw4w9WgXcQ');
expect(c.status).toBe('verified');
expect([...(await P.knownCids([CID, CID2]))]).toEqual([CID]);
expect((await P.listContentForVideo('dQw4w9WgXcQ')).length).toBe(1);
await P.upsertContent({ cid: CID2, videoId: 'dQw4w9WgXcQ', size: 5, origin: 'intake', now: T0 });
await P.revokeContent(CID2);
expect([...(await P.knownCids([CID2]))]).toEqual([]);
});
test('holders persist, never expire, and a full report removes missing ones', async () => {
await P.createDevice({ deviceId: 'dev_1', secretHash: 'h', fingerprint: 'fp', now: T0 });
await P.upsertHolder({ cid: CID, deviceId: 'dev_1', now: T0 });
// 90 days later with no new report: still listed (UI marks it stale).
let hs = await P.listHolders(CID);
expect(hs.length).toBe(1);
expect(hs[0].last_verified_at).toBe(T0);
await P.setHolderTrust({ cid: CID, deviceId: 'dev_1', trust: 'challenged', now: T0 + 1000 });
await P.upsertHolder({ cid: CID, deviceId: 'dev_1', trust: 'reported', now: T0 + 2000 });
hs = await P.listHolders(CID);
expect(hs[0].trust).toBe('challenged'); // a later plain report never downgrades trust
expect(hs[0].last_verified_at).toBe(T0 + 2000);
expect(await P.removeHoldersExcept({ deviceId: 'dev_1', keep: [], now: T0 + 3000 })).toBe(1);
expect((await P.listHolders(CID)).length).toBe(0);
expect(await P.activeHoldingsOf('dev_1')).toEqual([]);
await P.upsertHolder({ cid: CID, deviceId: 'dev_1', now: T0 + 4000 }); // re-added
expect(await P.activeHoldingsOf('dev_1')).toEqual([CID]);
});
test('views per day and window sums', async () => {
await P.addView('vid00000001', T0);
await P.addView('vid00000001', T0);
await P.addView('vid00000001', T0 - 40 * 86400_000);
expect(await P.viewsSince('vid00000001', T0 - 30 * 86400_000)).toBe(2);
expect(await P.viewsSince('vid00000001', T0 - 50 * 86400_000)).toBe(3);
const s = await P.p2pStats();
expect(s.content).toBe(1);
expect(s.devices).toBe(1);
});