const { test, beforeEach } = require('node:test') const assert = require('node:assert/strict') const shardIngest = require('../src/utils/shardIngest') // Protocol 3.0 world.ruleset routing. Same shape as shardIngest.protocol2.test.js: // stubbed deps, asserting where the dispatcher sends the frame and whether it is // appended to the event log. function makeDeps() { const calls = { rulesetSet: [], appended: [], broadcast: [] } const noop = async () => {} return { calls, shardEvents: { append: async (row) => { calls.appended.push(row); return true } }, shardState: { setRuleset: async (ev) => { calls.rulesetSet.push(ev) }, // Present so any stray routing is a harmless no-op. clearOnline: noop, upsertOnline: noop, setOffline: noop, upsertHouse: noop, addEconomySample: noop, }, shardLinks: { removeByAccount: noop }, uoLinkConfig: { recordStatus: noop }, broadcast: (ev) => { calls.broadcast.push(ev) }, pushDispatch: async () => {}, log: { warn() {}, info() {}, error() {} }, } } const FRAME = { kind: 'world.ruleset', t: 1000, rev: '1a2b3c4d', shard: 'UOMysticmoon', expansion: 'EJ', systems: { cityLoyalty: true, vvv: true, factions: false }, caps: { skill: 1000, totalSkill: 7000 }, } beforeEach(() => shardIngest.reset()) test('world.ruleset routes to setRuleset with the whole frame', async () => { const deps = makeDeps() await shardIngest.ingest(FRAME, deps) assert.equal(deps.calls.rulesetSet.length, 1) const stored = deps.calls.rulesetSet[0] assert.equal(stored.rev, '1a2b3c4d') assert.equal(stored.expansion, 'EJ') // The nested blocks must survive intact — the read model serves the frame whole. assert.equal(stored.systems.vvv, true) assert.equal(stored.caps.totalSkill, 7000) }) // The shard re-emits world.ruleset on EVERY sidecar connect. Logging it would put // a duplicate row in shard_events per reconnect, and server.hello already marks // each of those — so this assertion is the guard on that decision. test('world.ruleset is NOT appended to the event log', async () => { const deps = makeDeps() const r = await shardIngest.ingest(FRAME, deps) assert.equal(r.logged, false) assert.equal(deps.calls.appended.length, 0) assert.equal(shardIngest.LOGGED_KINDS.has('world.ruleset'), false) }) test('world.ruleset is broadcast (the rules page updates live)', async () => { const deps = makeDeps() await shardIngest.ingest(FRAME, deps) assert.equal(deps.calls.broadcast.length, 1) assert.equal(deps.calls.broadcast[0].kind, 'world.ruleset') }) // A backfill replay must reach the store but must NOT re-animate the live ticker. test('a backfilled world.ruleset still stores but does not broadcast', async () => { const deps = makeDeps() await shardIngest.ingest(FRAME, { ...deps, fromBackfill: true }) assert.equal(deps.calls.rulesetSet.length, 1) assert.equal(deps.calls.broadcast.length, 0) }) // A re-emitted identical ruleset is an overwrite, not an append: two ingests of // the same rev leave one stored frame's worth of state, never a growing log. test('a repeated world.ruleset overwrites rather than accumulating', async () => { const deps = makeDeps() await shardIngest.ingest(FRAME, deps) await shardIngest.ingest({ ...FRAME, t: 2000 }, deps) assert.equal(deps.calls.appended.length, 0) assert.equal(deps.calls.rulesetSet.length, 2) // two writes... assert.equal(deps.calls.rulesetSet[1].rev, '1a2b3c4d') // ...of the same singleton }) // A model write that throws must not kill the feed — ingest swallows it and the // frame is still broadcast. test('a setRuleset failure does not throw or stop the broadcast', async () => { const deps = makeDeps() deps.shardState.setRuleset = async () => { throw new Error('db down') } const r = await shardIngest.ingest(FRAME, deps) assert.equal(r.logged, false) assert.equal(deps.calls.broadcast.length, 1) }) // ── Shard name fallback ──────────────────────────────────────────────────── // // ServUO ships Server.cfg with `Name=My Shard`. An operator who never edited it // publishes that verbatim, which says "unnamed" rather than naming anything — so // the site answers with its own instance name instead of printing the stock // default under a header carrying the real one. // // Applied at INGEST, not on read, because world.ruleset is also broadcast live: // the same object goes to the SSE fan-out, so a read-time fix would be undone by // the next reconnect's frame. These tests assert both halves. function withSettings(deps, name) { return { ...deps, settings: { getInstanceName: async () => name } } } test('the stock ServUO shard name is replaced with the instance name', async () => { const deps = makeDeps() await shardIngest.ingest({ ...FRAME, shard: 'My Shard' }, withSettings(deps, 'UOMysticmoon')) assert.equal(deps.calls.rulesetSet[0].shard, 'UOMysticmoon') }) test('the substituted name reaches the live broadcast, not just the store', async () => { const deps = makeDeps() await shardIngest.ingest({ ...FRAME, shard: 'My Shard' }, withSettings(deps, 'UOMysticmoon')) assert.equal(deps.calls.broadcast.length, 1) assert.equal(deps.calls.broadcast[0].shard, 'UOMysticmoon') }) test('a missing or blank shard name gets the same treatment', async () => { for (const shard of [undefined, null, '', ' ']) { const deps = makeDeps() await shardIngest.ingest({ ...FRAME, shard }, withSettings(deps, 'UOMysticmoon')) assert.equal(deps.calls.rulesetSet[0].shard, 'UOMysticmoon') } }) // The match is on the whole value, case- and padding-insensitive. A shard that // deliberately calls itself "My Shard Reborn" has named itself and keeps it. test('a real name that merely contains the stock one is left alone', async () => { const deps = makeDeps() await shardIngest.ingest({ ...FRAME, shard: 'My Shard Reborn' }, withSettings(deps, 'UOMysticmoon')) assert.equal(deps.calls.rulesetSet[0].shard, 'My Shard Reborn') const padded = makeDeps() await shardIngest.ingest({ ...FRAME, shard: ' MY SHARD ' }, withSettings(padded, 'UOMysticmoon')) assert.equal(padded.calls.rulesetSet[0].shard, 'UOMysticmoon') }) test('a shard that named itself is never overridden by the brand', async () => { const deps = makeDeps() await shardIngest.ingest(FRAME, withSettings(deps, 'Some Other Brand')) assert.equal(deps.calls.rulesetSet[0].shard, 'UOMysticmoon') }) // The settings read is a DB call on a path that must never fail ingest. test('a settings read failure leaves the frame storable', async () => { const deps = makeDeps() const boom = { ...deps, settings: { getInstanceName: async () => { throw new Error('db down') } } } await shardIngest.ingest({ ...FRAME, shard: 'My Shard' }, boom) assert.equal(deps.calls.rulesetSet.length, 1) assert.equal(deps.calls.rulesetSet[0].shard, 'My Shard') })