source: Klonkt/test/feed-changes.test.js@ 1d5ffc0

main
Last change on this file since 1d5ffc0 was e215090, checked in by Robin <roboburr@…>, 4 weeks ago

Het verschil draagt ook de rechten

Zonder dit valt de client bij elke verschil-lezing terug op zijn standaard
Caps, en die standaard is 'alles mag': een gesloten poort zou zichzelf stil
openzetten. Dezelfde reden waarom een 304 de caps met rust laat -- dat stond
er al, met de reden erbij, en dat gold hier net zo goed.

Het rechtenblok staat nu in capabilitiesOf() zodat beide lezingen hetzelfde
beschrijven. De pariteitstest leest de bron en wees naar de oude plek; die
wijst nu naar de functie.

862/862 groen.

Co-Authored-By: Claude Opus 5 <noreply@…>

  • Property mode set to 100644
File size: 5.3 KB
Line 
1// Alleen het verschil, als de client erom vraagt (shaer-pq4).
2//
3// De wachtende lezing zei tot nu toe alleen DAT er iets veranderde, waarna de
4// client alles opnieuw las. Deze toetsen leggen drie dingen vast: dat het
5// verschil klopt, dat een verwijdering meereist (want de volledigheid die dat
6// tot nu toe deed valt hier weg), en dat de OUDE lezing niet verandert -- een
7// app in het veld stuurt `since` al mee en zou zichzelf leegwissen.
8//
9// In-memory SQLite. Run: npm test
10import { test } from 'node:test';
11import assert from 'node:assert/strict';
12
13process.env.DATABASE_PATH = ':memory:';
14process.env.PUBLIC_BASE_URL = 'https://klonkt.test';
15
16const dbMod = await import('../src/config/database.js');
17const db = dbMod.default;
18dbMod.initializeDatabase();
19const AP = await import('../src/services/ActivityPubService.js');
20
21db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
22 .run('u1', 'u1', 'u1@t', 'x', 'god');
23db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,1)').run('s1', 'kind', 'Kind', 'u1');
24
25const post = (id, tekst) => db.prepare(
26 `INSERT INTO ap_timeline (id, slug, author_uri, author_name, author_handle, content)
27 VALUES (?, 'kind', 'https://elders/u/til', 'Til', '@til@elders', ?)`).run(id, tekst);
28
29// De server leeft over de hele lezing heen: sluiten in een t.after van de
30// EERSTE test zou hem dichttrekken voordat de tweede eraan toe is.
31const crypto = await import('crypto');
32const express = (await import('express')).default;
33const routes = (await import('../src/routes/activitypub.js')).default;
34const bearer = 'test-token-' + 'f'.repeat(24);
35db.prepare('INSERT INTO oauth_tokens (token_hash, client_id, user_id, site_slug, scope) VALUES (?,?,?,?,?)')
36 .run(crypto.createHash('sha256').update(bearer).digest('base64url'), 'c', 'u1', 'kind', 'read write');
37const app = express();
38app.use(routes);
39const server = app.listen(0);
40await new Promise((r) => server.once('listening', r));
41const poort = server.address().port;
42// unref: een luisterende socket houdt de lus open, en dan wacht de testrunner
43// eeuwig op een proces dat nooit vanzelf afloopt.
44server.unref();
45
46const get = async (qs) => {
47 const r = await fetch(`http://127.0.0.1:${poort}/ap/users/kind/inbox${qs}`,
48 { headers: { Authorization: `Bearer ${bearer}` } });
49 return { status: r.status, body: r.status === 304 ? null : await r.json() };
50};
51
52test('het verschil draagt alleen wat er veranderde', async () => {
53 post('https://elders/n/1', '<p>eerste</p>');
54 const vol = await get('');
55 const cursor = vol.body['shaer:cursor'];
56 assert.equal(vol.body.orderedItems.length, 1);
57
58 post('https://elders/n/2', '<p>tweede</p>');
59 const delta = await get(`?changes=1&since=${encodeURIComponent(cursor)}`);
60 assert.equal(delta.body.type, 'OrderedCollectionPage', 'een deel, en dat zegt het ook');
61 assert.ok(delta.body.partOf.endsWith('/inbox'));
62 assert.equal(delta.body.orderedItems.length, 1, 'alleen de nieuwe');
63 assert.equal(delta.body.orderedItems[0].object.id, 'https://elders/n/2');
64 // En de byline staat er gewoon op: dezelfde kaartvorm als de volle lezing.
65 assert.equal(delta.body.orderedItems[0].object.attributedTo.name, 'Til');
66});
67
68test('een verwijdering reist mee als grafsteen', async () => {
69 const heen = await get('');
70 const cursor = heen.body['shaer:cursor'];
71 db.prepare("DELETE FROM ap_timeline WHERE id = ?").run('https://elders/n/1');
72 const delta = await get(`?changes=1&since=${encodeURIComponent(cursor)}`);
73 const weg = delta.body.orderedItems.find((i) => i.type === 'Delete');
74 assert.ok(weg, 'zonder dit zou de post voor altijd in de app blijven staan');
75 assert.equal(weg.object.id, 'https://elders/n/1');
76 assert.equal(weg.object.type, 'Tombstone');
77});
78
79test('zonder changes=1 verandert er NIETS aan de oude lezing', async () => {
80 // De belangrijkste van deze vier: een app in het veld stuurt since al mee en
81 // vervangt haar hele feed door wat er terugkomt.
82 const vol = await get('');
83 const cursor = vol.body['shaer:cursor'];
84 const oud = await get(`?since=${encodeURIComponent(cursor)}`);
85 assert.equal(oud.body.type, 'OrderedCollection', 'nog steeds de hele collectie');
86 assert.equal(oud.body.orderedItems.length, vol.body.orderedItems.length);
87});
88
89test('het verschil draagt de rechten mee', async () => {
90 // Zonder dit valt de client terug op zijn standaard, en die standaard is
91 // 'alles mag': een gesloten poort zou zichzelf stil openzetten bij elke
92 // verschil-lezing.
93 const vol = await get('');
94 db.prepare("UPDATE sites SET gate_images = 0 WHERE slug = 'kind'").run();
95 db.prepare("INSERT INTO ap_guardianships (slug, other_uri, role, status) VALUES ('kind', 'https://elders/u/oma', 'guardian', 'accepted')").run();
96 post('https://elders/n/9', '<p>na de poort</p>');
97 const delta = await get(`?changes=1&since=${encodeURIComponent(vol.body['shaer:cursor'])}`);
98 assert.equal(delta.body['shaer:capabilities']['shaer:images'], false, 'de dichte poort reist mee');
99});
100
101test('niets veranderd is een leeg verschil, niet een leeg antwoord', async () => {
102 const vol = await get('');
103 const delta = await get(`?changes=1&since=${encodeURIComponent(vol.body['shaer:cursor'])}`);
104 assert.equal(delta.status, 200);
105 assert.deepEqual(delta.body.orderedItems, []);
106 assert.equal(delta.body['shaer:cursor'], vol.body['shaer:cursor'], 'en de cursor staat stil');
107});
Note: See TracBrowser for help on using the repository browser.