49 lines
3.1 KiB
JavaScript
49 lines
3.1 KiB
JavaScript
'use strict';
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { generate } = require('../discovery/engine');
|
|
const { DiscoveryStore } = require('../discovery/store');
|
|
|
|
test('discovery is bounded, diversified, opt-in, evidence-linked and user-specific', () => {
|
|
const { loadCatalog } = require('../greatest');
|
|
const greatest = loadCatalog();
|
|
const users = { alice: { name: 'alice', settings: { discoveryEnabled: true } },
|
|
bob: { name: 'bob', settings: { discoveryEnabled: true } },
|
|
off: { name: 'off', settings: {} } };
|
|
const db = { users, greatestRatings: { alice: { [greatest.entries[0].id]: 'flame' },
|
|
bob: { [greatest.entries[20].id]: 'flame' } }, discoveryFeedback: { alice: {} }, progress: {} };
|
|
const result = generate({ db, library: [], greatest, cacheDir: path.join(os.tmpdir(), 'nonexistent-discovery-cache') });
|
|
assert.equal(Object.keys(result.candidates).length, 50);
|
|
assert.ok(result.feeds.alice.items.length > 0 && result.feeds.alice.items.length <= 20);
|
|
assert.ok(result.feeds.bob.items.length > 0);
|
|
assert.equal(result.feeds.off.disabled, true);
|
|
assert.ok(new Set(Object.values(result.candidates).map(c => c.period)).size >= 10, 'An early catalog page must not crowd out later eras');
|
|
assert.ok(result.feeds.alice.items.every(item => item.evidenceIds.every(id => item.evidence.some(e => e.id === id))));
|
|
assert.ok(result.feeds.alice.items.some(item => item.evidence.some(e => e.kind === 'personal')));
|
|
assert.ok(!result.feeds.bob.items.some(item => item.evidence.some(e => e.label?.includes(greatest.entries[0].title) && e.kind === 'personal')));
|
|
assert.notDeepEqual(result.feeds.alice.items.map(x => x.candidateId), result.feeds.bob.items.map(x => x.candidateId));
|
|
const first = result.feeds.alice.items[0].candidateId;
|
|
db.discoveryFeedback.alice[first] = 'dismissed';
|
|
const rerun = generate({ db, library: [], greatest, cacheDir: path.join(os.tmpdir(), 'nonexistent-discovery-cache') });
|
|
assert.ok(!rerun.feeds.alice.items.some(item => item.candidateId === first));
|
|
assert.equal(rerun.feeds.bob.items.length, result.feeds.bob.items.length);
|
|
});
|
|
|
|
test('discovery store publishes atomically and refuses to overwrite corrupt data', t => {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mc-discovery-store-'));
|
|
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
const store = new DiscoveryStore(dir);
|
|
assert.equal(store.load().revision, 0);
|
|
const value = store.publish({ candidates: {}, feeds: {}, startedAt: new Date().toISOString(), examined: 0, clipped: 0 });
|
|
assert.equal(value.revision, 1);
|
|
store.publish({ candidates: {}, feeds: {}, startedAt: new Date().toISOString(), examined: 0, clipped: 0 });
|
|
assert.equal(store.load().revision, 2);
|
|
assert.ok(fs.existsSync(store.file + '.prev'));
|
|
fs.writeFileSync(store.file, '{broken');
|
|
assert.throws(() => store.publish({ candidates: {}, feeds: {} }), /refusing to overwrite/);
|
|
assert.equal(fs.readFileSync(store.file, 'utf8'), '{broken');
|
|
});
|