const { test, beforeEach } = require('node:test') const assert = require('node:assert/strict') const shardIngest = require('../src/utils/shardIngest') // Build a set of stub deps that record the champ/page/state calls the dispatcher // makes, plus a spy shardEvents.append and broadcast. Only the methods the tested // kinds touch need to be real; the rest are no-op async so ingest() never throws. function makeDeps() { const calls = { champUpsert: [], champRemove: [], pageUpsert: [], pageRemove: [], appended: [], broadcast: [] } const noop = async () => {} return { calls, shardEvents: { append: async (row) => { calls.appended.push(row); return true } }, shardState: { upsertChamp: async (ev) => { calls.champUpsert.push(ev) }, removeChamp: async (serial) => { calls.champRemove.push(serial) }, upsertPage: async (ev) => { calls.pageUpsert.push(ev) }, removePage: async (id) => { calls.pageRemove.push(id) }, // Unused by these kinds but present so any stray routing is a no-op. clearOnline: noop, upsertOnline: noop, setOffline: noop, upsertHouse: noop, addEconomySample: noop, }, uoLinkConfig: { recordStatus: noop }, broadcast: (ev) => { calls.broadcast.push(ev) }, log: { warn() {}, info() {}, error() {} }, } } beforeEach(() => shardIngest.reset()) test('champ.update routes to shardState.upsertChamp and is not written to the event log', async () => { const deps = makeDeps() const ev = { kind: 'champ.update', serial: '0x1', category: 'champion', name: 'Abyss', status: 'active', t: 1 } const r = await shardIngest.ingest(ev, deps) assert.equal(deps.calls.champUpsert.length, 1) assert.equal(deps.calls.champUpsert[0].serial, '0x1') assert.equal(r.logged, false) // champ.* is state-only, not appended to shard_events assert.equal(deps.calls.appended.length, 0) assert.equal(deps.calls.broadcast.length, 1) // still broadcast live }) test('champ.remove routes to shardState.removeChamp', async () => { const deps = makeDeps() await shardIngest.ingest({ kind: 'champ.remove', serial: '0x2', t: 2 }, deps) assert.deepEqual(deps.calls.champRemove, ['0x2']) }) test('page.new and page.updated upsert the page; page.closed removes it', async () => { const deps = makeDeps() await shardIngest.ingest({ kind: 'page.new', pageId: '0x24C', type: 'Bug', sender: { name: 'Al' }, t: 3 }, deps) await shardIngest.ingest({ kind: 'page.updated', pageId: '0x24C', handled: true, t: 4 }, deps) await shardIngest.ingest({ kind: 'page.closed', pageId: '0x24C', t: 5 }, deps) assert.equal(deps.calls.pageUpsert.length, 2) assert.deepEqual(deps.calls.pageRemove, ['0x24C']) }) test('admin.audit is appended to the event log (moderation history)', async () => { const deps = makeDeps() const r = await shardIngest.ingest({ kind: 'admin.audit', action: 'ban', actor: 'web:jane', target: 'griefer', t: 6 }, deps) assert.equal(r.logged, true) assert.equal(deps.calls.appended.length, 1) assert.equal(deps.calls.appended[0].kind, 'admin.audit') }) test('champ.remove without a serial is a harmless no-op', async () => { const deps = makeDeps() await shardIngest.ingest({ kind: 'champ.remove', t: 7 }, deps) assert.deepEqual(deps.calls.champRemove, [undefined]) })