Checkpoint peering identity and opt-in discovery
This commit is contained in:
1 parent
eba9b50e30
commit
47de081721
44 files changed
+1557
-55
No files matched your search
@@ -0,0 +1,48 @@
|
||||
'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');
|
||||
});
|
||||
@@ -68,6 +68,40 @@ test('three services integrate collections, auth, custom covers and private heal
|
||||
assert.equal((await (await request('/api/settings', { pageTone: 'sepia' })).json()).settings.pageTone, 'sepia');
|
||||
assert.equal((await (await request('/api/settings', { pageTone: 'invalid' })).json()).settings.pageTone, 'sepia');
|
||||
assert.equal((await (await anotherRequest('/api/me')).json()).settings.pageTone, 'original');
|
||||
assert.equal((await fetch(base + '/api/discovery')).status, 401);
|
||||
assert.equal((await anotherRequest('/api/admin/discovery/run', {})).status, 403);
|
||||
assert.equal((await request('/api/settings', { discoveryEnabled: true })).status, 200);
|
||||
assert.equal((await anotherRequest('/api/settings', { discoveryEnabled: true })).status, 200);
|
||||
const beforeDiscoveryQueue = fs.readFileSync(path.join(data, 'scraper', 'queue.json'), 'utf8');
|
||||
const firstRun = await request('/api/admin/discovery/run', {});
|
||||
assert.equal(firstRun.status, 200);
|
||||
const firstRunId = (await firstRun.json()).id;
|
||||
let discoveryAdmin;
|
||||
for (let n = 0; n < 50; n++) {
|
||||
discoveryAdmin = await (await request('/api/admin/discovery')).json();
|
||||
if (discoveryAdmin.currentRun?.id === firstRunId && discoveryAdmin.currentRun?.status === 'success') break;
|
||||
await delay(100);
|
||||
}
|
||||
assert.equal(discoveryAdmin.currentRun?.status, 'success');
|
||||
const discoveryMine = await (await request('/api/discovery')).json();
|
||||
const discoveryOther = await (await anotherRequest('/api/discovery')).json();
|
||||
assert.ok(discoveryMine.items.length > 0 && discoveryMine.items.length <= 20);
|
||||
assert.ok(discoveryOther.items.length > 0 && discoveryOther.items.length <= 20);
|
||||
assert.equal(discoveryMine.items[0].candidate.id, discoveryMine.items[0].candidateId);
|
||||
const dismissed = discoveryMine.items[0].candidateId;
|
||||
assert.equal((await request('/api/discovery/feedback', { candidateId: dismissed, value: 'dismissed' })).status, 200);
|
||||
assert.equal((await anotherRequest('/api/discovery')).status, 200);
|
||||
assert.equal((await anotherRequest('/api/discovery/feedback', { candidateId: 'nonexistent', value: 'interested' })).status, 404);
|
||||
const secondRun = await request('/api/admin/discovery/run', {});
|
||||
assert.equal(secondRun.status, 200);
|
||||
const secondRunId = (await secondRun.json()).id;
|
||||
for (let n = 0; n < 50; n++) {
|
||||
discoveryAdmin = await (await request('/api/admin/discovery')).json();
|
||||
if (discoveryAdmin.currentRun?.id === secondRunId && discoveryAdmin.currentRun?.status === 'success') break;
|
||||
await delay(100);
|
||||
}
|
||||
assert.ok(!(await (await request('/api/discovery')).json()).items.some(item => item.candidateId === dismissed));
|
||||
assert.equal(fs.readFileSync(path.join(data, 'scraper', 'queue.json'), 'utf8'), beforeDiscoveryQueue);
|
||||
assert.equal((await (await anotherRequest('/api/greatest')).json()).entries[0].myRating, null);
|
||||
assert.equal((await anotherRequest('/api/greatest/rating', { id: firstPick.id, rating: 'good' })).status, 200);
|
||||
const communityPick = (await (await request('/api/greatest')).json()).entries[0];
|
||||
|
||||
Reference in new issue
Block a user