oxedyne/daimond/dev/verify_syncstitch.mjs
5.2 KiB, 1 run
created by r2519314175:717, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | // verify_syncstitch.mjs — the providers ride in the parcel, through the core. |
| 2 | // |
| 3 | // `models.js` grew `exportSync`/`applySync` and they are tested hard next door (verify_sync drives |
| 4 | // them directly: the freshest-per-fact merge, the sealed key, the refused default). None of that |
| 5 | // mattered while the sync ENGINE did not carry the section, and nothing tested the join: a device |
| 6 | // could merge a providers parcel perfectly and never be handed one. |
| 7 | // |
| 8 | // So this drives the seam and only the seam. Two claims: |
| 9 | // |
| 10 | // * `DaimondCore.collectSync()` puts the providers in the parcel, and puts them there |
| 11 | // DETERMINISTICALLY. The engine skips a push whose serialisation matches the last one, so a |
| 12 | // section that followed enumeration order rather than a sort would push for ever -- a battery |
| 13 | // and bandwidth bug that looks like nothing at all. |
| 14 | // * `DaimondCore.applySync(parcel)` hands the section to `models.js`, and a parcel that has no |
| 15 | // such section (a device that predates it) still applies without complaint. |
| 16 | // |
| 17 | // No gateway: the parcel is collected and applied in one page, which is the whole of the seam. |
| 18 | // What travels between two devices is verify_sync's business. |
| 19 | import { open, shot } from './harness.mjs'; |
| 20 | |
| 21 | const ok = [], bad = []; |
| 22 | const check = (name, pass, detail) => { |
| 23 | (pass ? ok : bad).push(name + (detail ? ' — ' + detail : '')); |
| 24 | console.log((pass ? ' ok ' : ' FAIL ') + name + (detail ? ' — ' + detail : '')); |
| 25 | }; |
| 26 | |
| 27 | const s = await open({ name: 'syncstitch' }); |
| 28 | const p = s.page; |
| 29 | await p.waitForTimeout(1200); |
| 30 | |
| 31 | // ── Collect ───────────────────────────────────────────────────────────── |
| 32 | |
| 33 | const out = await p.evaluate(async () => { |
| 34 | const a = await window.DaimondCore.collectSync(); |
| 35 | const b = await window.DaimondCore.collectSync(); |
| 36 | return { |
| 37 | hasField: Object.prototype.hasOwnProperty.call(a, 'models'), |
| 38 | providers: a.models ? Object.keys(a.models.providers || {}) : null, |
| 39 | stable: JSON.stringify(a.models) === JSON.stringify(b.models), |
| 40 | v: a.models ? a.models.v : null, |
| 41 | }; |
| 42 | }); |
| 43 | check('the parcel carries a models section at all', |
| 44 | out.hasField === true && out.providers !== null, |
| 45 | 'field present: ' + out.hasField); |
| 46 | check('and it holds the provider this device is configured with', |
| 47 | Array.isArray(out.providers) && out.providers.length >= 1, |
| 48 | JSON.stringify(out.providers)); |
| 49 | check('collected twice, it serialises identically — so a push can be skipped', |
| 50 | out.stable === true, 'v' + out.v); |
| 51 | |
| 52 | // ── Apply ─────────────────────────────────────────────────────────────── |
| 53 | // |
| 54 | // A provider this device has never held, stamped now, arriving inside a parcel the core applies. |
| 55 | // If the core drops the section on the floor, the provider simply is not there afterwards. |
| 56 | |
| 57 | const merged = await p.evaluate(async () => { |
| 58 | const parcel = await window.DaimondCore.collectSync(); |
| 59 | const now = Date.now(); |
| 60 | parcel.models = parcel.models || { v: 2, def: { provider: '', model: '' }, defAt: 0, providers: {} }; |
| 61 | parcel.models.providers['stitchtest'] = { |
| 62 | name: 'Stitch Test', url: 'https://stitch.test/v1', |
| 63 | models: ['s-two', 's-one'], fetched: now, touched: now, |
| 64 | keyEnc: 'SEALED-BY-THE-OTHER-DEVICE', |
| 65 | }; |
| 66 | let threw = ''; |
| 67 | try { await window.DaimondCore.applySync(parcel); } catch (e) { threw = String(e && e.message ? e.message : e); } |
| 68 | const held = window.DaimondModels.providers().find(x => x.id === 'stitchtest') || null; |
| 69 | const ex = window.DaimondModels.exportSync().providers['stitchtest'] || null; |
| 70 | return { |
| 71 | threw, |
| 72 | arrived: !!held, |
| 73 | name: held ? held.name : '', |
| 74 | sealed: !!(ex && ex.keyEnc === 'SEALED-BY-THE-OTHER-DEVICE'), |
| 75 | sorted: ex ? (ex.models || []).join(',') : '', |
| 76 | }; |
| 77 | }); |
| 78 | check('the core hands the models section to models.js', merged.arrived === true, |
| 79 | merged.threw ? 'threw: ' + merged.threw : 'name: ' + merged.name); |
| 80 | check("and the other device's sealed key arrives with it", merged.sealed === true); |
| 81 | check('and the model list arrives sorted, as the export promises', |
| 82 | merged.sorted === 's-one,s-two', merged.sorted); |
| 83 | |
| 84 | // A device that predates the section. `applySync` reads every section by name, so an absent one |
| 85 | // must be a no-op rather than a throw -- otherwise an old device's parcel takes the chats down |
| 86 | // with it. |
| 87 | const old = await p.evaluate(async () => { |
| 88 | const parcel = await window.DaimondCore.collectSync(); |
| 89 | delete parcel.models; |
| 90 | parcel.v = 1; |
| 91 | let threw = ''; |
| 92 | try { await window.DaimondCore.applySync(parcel); } catch (e) { threw = String(e && e.message ? e.message : e); } |
| 93 | return { threw, stillHeld: !!window.DaimondModels.providers().find(x => x.id === 'stitchtest') }; |
| 94 | }); |
| 95 | check('a parcel with no models section applies without complaint', |
| 96 | old.threw === '', old.threw); |
| 97 | check('and takes nothing away — an absence is "never had it", not "delete it"', |
| 98 | old.stillHeld === true); |
| 99 | |
| 100 | await shot(s, 'syncstitch'); |
| 101 | const errs = s.errs.filter(e => !/favicon|404|401|net::ERR/.test(e)); |
| 102 | console.log('\nconsole errors:', errs.slice(0, 4)); |
| 103 | await s.close(); |
| 104 | |
| 105 | console.log(`\n${ok.length} passed, ${bad.length} failed`); |
| 106 | if (bad.length) console.log('FAILED:\n ' + bad.join('\n ')); |
| 107 | process.exit(bad.length ? 1 : 0); |