source: Klonkt/test/musicbrainz.test.js@ 5300652

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

Stap 2: "Ben jij dit?" in Beheer -> Audio (shaer-mbz)

Een paneel bovenaan het audioscherm: zoek op je artiestennaam (voorgevuld met
wat er al in de site staat), kies je eigen pagina, klaar. Drie talen.

DE TOELICHTING IS HET HELE PUNT. Elke kandidaat toont MusicBrainz'
disambiguation naast soort, land en jaren -- er zijn drie bands die Nirvana
heten, en met alleen een naam kiest iemand de verkeerde. Wij kiezen NIET voor
de artiest, ook niet als er precies een treffer is: een verkeerd geraden MBID
zet jouw naam onder andermans werk.

ONTKOPPELEN KAN. Om dezelfde reden: zo'n vergissing hoort met een klik terug
te draaien te zijn, niet met een databasebewerking.

Alleen een echte MBID komt de kolom in; de route weigert een URL of een handle.
De naam bewaren we ernaast zodat het scherm kan tonen WAT er hangt zonder
ervoor te netwerken -- en zodat een verkeerde koppeling opvalt.

TWEE DINGEN UIT DE HUISREGELS. De kandidaten gaan met textContent het scherm op
en niet als HTML: dat is tekst uit een vreemd register. En het blok hangt in
run() en niet op moduleniveau -- deze modules krijgen bij elke paginawissel
opnieuw init(), en een blok dat maar een keer per sessie draait is precies wat
shaer-5s1 opleverde. Ik had hem er eerst buiten gezet.

Als iemand niet in MusicBrainz staat zegt het scherm dat hij zich daar kan
aanmelden -- en erbij dat dat alleen dáár kan, niet vanuit Klonkt. Dat is geen
bescheidenheid maar hun API: artiesten zijn er niet mee aan te maken.

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

  • Property mode set to 100644
File size: 6.0 KB
Line 
1// De MusicBrainz-koppeling, stap 1 (shaer-mbz).
2//
3// Zonder netwerk: globalThis.fetch wordt vervangen en musicbrainz.org staat in
4// AP_ALLOW_HOSTS, zodat safeFetch geen DNS doet. Anders test dit of de
5// testmachine internet heeft en of MusicBrainz toevallig up is.
6//
7// Wat hier WEL getest wordt is wat wij beloven: hun twee harde regels. Die
8// leiden bij overtreding tot een BLOKKADE en niet tot een foutmelding, dus
9// "het werkte toen ik het probeerde" is er geen bewijs voor.
10import { test } from 'node:test';
11import assert from 'node:assert/strict';
12
13process.env.DATABASE_PATH = ':memory:';
14process.env.PUBLIC_BASE_URL = 'https://ons.test';
15process.env.MUSICBRAINZ_CONTACT = 'robin@ons.test';
16process.env.AP_ALLOW_HOSTS = 'musicbrainz.org';
17
18const dbMod = await import('../src/config/database.js');
19dbMod.initializeDatabase();
20const MB = await import('../src/services/MusicBrainzService.js');
21
22const verzoeken = [];
23const echt = globalThis.fetch;
24globalThis.fetch = async (url, opts) => {
25 verzoeken.push({ url: String(url), ua: opts?.headers?.['User-Agent'], op: Date.now() });
26 return {
27 ok: true,
28 status: 200,
29 headers: new Map(),
30 json: async () => ({
31 artists: [
32 { id: '8be31978-1884-4773-beae-f73df35b92aa', name: 'Nirvana', score: 100,
33 disambiguation: 'Seattle grunge band', type: 'Group', country: 'US',
34 'life-span': { begin: '1987', ended: true, end: '1994' } },
35 { id: 'aaaaaaaa-1111-2222-3333-444444444444', name: 'Nirvana', score: 72,
36 disambiguation: '60s UK band', type: 'Group', country: 'GB' },
37 { id: 'bad', name: '' }, // onbruikbaar: moet eruit vallen
38 ],
39 }),
40 };
41};
42
43test('een MBID is een UUID en niets anders', () => {
44 assert.equal(MB.isMbid('8be31978-1884-4773-beae-f73df35b92aa'), true);
45 assert.equal(MB.isMbid('the_ceeesg'), false, 'een handle is geen MBID');
46 assert.equal(MB.isMbid('https://musicbrainz.org/artist/8be31978-1884-4773-beae-f73df35b92aa'), false,
47 'een URL ook niet -- anders sluipt er een hele link de kolom in');
48 assert.equal(MB.isMbid(''), false);
49 assert.equal(MB.isMbid(null), false);
50});
51
52test('de artiest-URL wordt alleen uit een echte MBID gebouwd', () => {
53 assert.equal(MB.artiestUrl('8BE31978-1884-4773-BEAE-F73DF35B92AA'),
54 'https://musicbrainz.org/artist/8be31978-1884-4773-beae-f73df35b92aa',
55 'kleingeschreven, want een MBID is er een en niet twee');
56 assert.equal(MB.artiestUrl('rommel'), null, 'geen URL verzinnen om iets onbekends heen');
57});
58
59test('een lege zoekopdracht raakt het net niet eens', async () => {
60 verzoeken.length = 0;
61 assert.deepEqual(await MB.zoekArtiesten(' '), []);
62 assert.equal(verzoeken.length, 0, 'hun tempo is te kostbaar om aan niets te besteden');
63});
64
65test('de User-Agent noemt Klonkt EN een contact -- hun eis', async () => {
66 // Een generieke of lege User-Agent is precies waarop MusicBrainz blokkeert.
67 verzoeken.length = 0;
68 await MB.zoekArtiesten('iemand');
69 const ua = verzoeken.at(-1)?.ua;
70 assert.ok(ua, 'er is er een gezet');
71 assert.match(ua, /^Klonkt\//, 'met onze naam voorop');
72 assert.match(ua, /robin@ons\.test/, 'en een manier om contact op te nemen');
73});
74
75test('de kandidaten dragen wat een mens nodig heeft om te KIEZEN', async () => {
76 const uit = await MB.zoekArtiesten('Nirvana');
77 assert.equal(uit.length, 2, 'een naamloze treffer is geen kandidaat');
78 assert.equal(uit[0].mbid, '8be31978-1884-4773-beae-f73df35b92aa');
79 // De naam alleen is niet genoeg: er zijn drie bands die Nirvana heten.
80 assert.equal(uit[0].toelichting, 'Seattle grunge band');
81 assert.equal(uit[1].toelichting, '60s UK band');
82 assert.equal(uit[0].jaren, '1987 – 1994');
83 assert.equal(uit[1].jaren, '', 'een band die nog bestaat krijgt geen eindjaar aangepraat');
84 assert.equal(uit[0].url, 'https://musicbrainz.org/artist/8be31978-1884-4773-beae-f73df35b92aa');
85});
86
87test('twee zoekopdrachten liggen minstens een seconde uit elkaar', async () => {
88 // Hun harde regel, en de reden dat dit server-side draait: een verzoek per
89 // seconde geldt per APPLICATIE, niet per bezoeker. Twee tabbladen tegelijk
90 // zouden hem anders samen overtreden.
91 verzoeken.length = 0;
92 await Promise.all([MB.zoekArtiesten('een'), MB.zoekArtiesten('twee')]);
93 assert.equal(verzoeken.length, 2);
94 const gat = verzoeken[1].op - verzoeken[0].op;
95 assert.ok(gat >= 990, `verwacht >= 1000ms tussen twee verzoeken, was ${gat}ms`);
96});
97
98test.after(() => { globalThis.fetch = echt; });
99
100// ── Stap 2: de keuze vastleggen ───────────────────────────────────────────
101
102test('alleen een echte MBID komt de kolom in', async () => {
103 // De route weigert alles wat geen UUID is. Zonder die zeef sluipt er een
104 // hele URL of een handle in het veld dat straks naar buiten gaat.
105 const db = dbMod.default;
106 db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
107 .run('u1', 'u1', 'u1@t', 'x', 'god');
108 db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('s1', 'band', 'Band', 'u1');
109 for (const rommel of ['https://musicbrainz.org/artist/8be31978-1884-4773-beae-f73df35b92aa', 'nirvana', '']) {
110 assert.equal(MB.isMbid(rommel), false, `${rommel} hoort geweigerd te worden`);
111 }
112 db.prepare('UPDATE sites SET mb_artist_id = ?, mb_artist_name = ? WHERE id = ?')
113 .run('8be31978-1884-4773-beae-f73df35b92aa', 'Nirvana', 's1');
114 const s = db.prepare("SELECT mb_artist_id, mb_artist_name FROM sites WHERE id = 's1'").get();
115 assert.equal(s.mb_artist_id, '8be31978-1884-4773-beae-f73df35b92aa');
116 assert.equal(s.mb_artist_name, 'Nirvana', 'de naam ernaast, zodat het scherm kan tonen WAT er hangt');
117});
118
119test('ontkoppelen maakt beide velden leeg', () => {
120 const db = dbMod.default;
121 db.prepare('UPDATE sites SET mb_artist_id = NULL, mb_artist_name = NULL WHERE id = ?').run('s1');
122 const s = db.prepare("SELECT mb_artist_id, mb_artist_name FROM sites WHERE id = 's1'").get();
123 assert.equal(s.mb_artist_id, null);
124 assert.equal(s.mb_artist_name, null, 'anders blijft er een naam staan zonder koppeling');
125});
Note: See TracBrowser for help on using the repository browser.