25 of 82 test files left with the module. Three that core keeps needed splitting rather than moving, and the split is the boundary in each case. announceJobs.test.js keeps the announce PIPELINE -- the shared backoff schedule, the parent-status rollup, core's Discord leg -- and loses the town-crier text building and classification, which are a module's leg. pushDispatch.test.js keeps the SSRF guard and publish() delivering a content-free tickle, and loses mapShardEvent and the shard fan-out, which are a module's catalog. playerRouteAccess.test.js is the one worth explaining. It guards a real past bug -- an admin 403'd off their own characters -- and it did so through /player/shard/accounts, which is now module-owned. The guarantee it protects is CORE's, though: /player/* is role-agnostic self-service, staff are a superset of players. So it stays here and asserts that through /player/appeals, a core route with the same gate. Moving it would have left core with no test of its own tier rule, which is precisely what regressed once before. The remaining updates are core's own tests catching up: ctx has four more members, registerCore now registers only what core owns (one stream, one leg, no filled slot), and the extension-slot test asks for the DECLARED slot's router rather than the filled one, since core declares it and a module fills it. The gated-surface floor drops from >100 to >50 -- it is there so a filter matching nothing fails loudly, not to track core's exact route count. 616 core tests and 160 client tests pass; the module's own suite is 351. Co-Authored-By: Claude <noreply@anthropic.com>
56 lines
3.3 KiB
JavaScript
56 lines
3.3 KiB
JavaScript
const { test } = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
|
|
const logic = require('../src/model/announceJobs/announceJobs.logic')
|
|
// Each leg owns its own text-building and result classification since PR 4 — a
|
|
// leg is a registration now, not a branch in the worker (MODULE_SYSTEM.md §1.8).
|
|
const discord = require('../src/utils/discordAnnounce')
|
|
|
|
// The town-crier leg's tests left with module-uo in Phase 3 — it is a MODULE's
|
|
// leg, and its text building and status classification are its business. What
|
|
// stays here is core's announce pipeline: the backoff schedule every leg shares,
|
|
// the parent-status rollup over all of a job's legs, and core's own Discord leg.
|
|
// ── classifyDiscord ──────────────────────────────────────────────────────────
|
|
test('discord classify: ok is done, every failure retries', () => {
|
|
assert.equal(discord.classify({ ok: true, status: 200 }).outcome, 'done')
|
|
for (const status of [400, 503, 0]) {
|
|
assert.equal(discord.classify({ ok: false, status }).outcome, 'retry', `status ${status}`)
|
|
}
|
|
})
|
|
|
|
// ── scheduleAfter (backoff) ──────────────────────────────────────────────────
|
|
test('scheduleAfter returns increasing delays then null at the attempt cap', () => {
|
|
const d1 = logic.scheduleAfter(1)
|
|
const d2 = logic.scheduleAfter(2)
|
|
assert.ok(d1 > 0 && d2 > d1, 'delays should grow')
|
|
// Exhausted once attempts reach MAX_ATTEMPTS.
|
|
assert.equal(logic.scheduleAfter(logic.MAX_ATTEMPTS), null)
|
|
assert.equal(logic.scheduleAfter(logic.MAX_ATTEMPTS + 3), null)
|
|
})
|
|
|
|
// ── rollupStatus ─────────────────────────────────────────────────────────────
|
|
// Takes the LIST of leg statuses, not two named legs: which legs exist is what a
|
|
// module decides (MODULE_SYSTEM.md §1.8).
|
|
test('rollupStatus derives the parent status from its legs', () => {
|
|
assert.equal(logic.rollupStatus(['done', 'done']), 'done')
|
|
assert.equal(logic.rollupStatus(['failed', 'failed']), 'failed')
|
|
assert.equal(logic.rollupStatus(['pending', 'pending']), 'pending')
|
|
// One terminal, the others not matching → partial.
|
|
assert.equal(logic.rollupStatus(['done', 'pending']), 'partial')
|
|
assert.equal(logic.rollupStatus(['pending', 'failed']), 'partial')
|
|
assert.equal(logic.rollupStatus(['done', 'failed']), 'partial')
|
|
})
|
|
|
|
test('rollupStatus generalises past two legs', () => {
|
|
assert.equal(logic.rollupStatus(['done', 'done', 'done']), 'done')
|
|
assert.equal(logic.rollupStatus(['done', 'done', 'pending']), 'partial')
|
|
assert.equal(logic.rollupStatus(['pending', 'pending', 'pending']), 'pending')
|
|
assert.equal(logic.rollupStatus(['failed', 'failed', 'failed']), 'failed')
|
|
// A single leg is not a special case.
|
|
assert.equal(logic.rollupStatus(['pending']), 'pending')
|
|
assert.equal(logic.rollupStatus(['done']), 'done')
|
|
// No legs registered at all: nothing is left to deliver, so the job is done
|
|
// rather than pending forever on a leg that does not exist.
|
|
assert.equal(logic.rollupStatus([]), 'done')
|
|
})
|