import { describe, expect, it } from 'vitest' import { laneAdvice, mergeParts, queueKey } from '../src/utils/systemParts.js' // The System tab's one table (operator 2026-09-23: "combine the two sections // into a single table"). What is pinned here is the JOIN, because its failure // is silent and is precisely the thing the merge exists to fix: a lane that // stops matching its roster part does not throw — the table grows a SECOND row // for the same worker, one with controls and one without. const PART = { key: 'celery:default,download,import,thumbnail', kind: 'celery', name: 'Worker', state: 'ok', detail: 'Worker is running', // The roster SORTS a celery part's queues into its key. queues: ['default', 'download', 'import', 'thumbnail'], } const LANE = { name: 'worker', display_name: 'Worker', // The lane table lists them in the order the role reads them, which is NOT // sorted. If the join ever compares these two lists directly rather than as // sets, this fixture is what catches it. queues: ['default', 'import', 'thumbnail', 'download'], slots_cap: 4, ceiling: 8, live: { present: true, replicas: 1, pool: 2, active: 0 }, pending: 0, } const POSTGRES = { key: 'postgres', kind: 'datastore', name: 'PostgreSQL', state: 'ok', detail: 'answering', latency_ms: 2.5, } describe('queueKey', () => { it('does not care what order either side lists its queues in', () => { expect(queueKey(LANE.queues)).toBe(queueKey(PART.queues)) }) it('survives a part that has no queues at all', () => { // A datastore, and also the stale `Worker ()` row a previous deployment // left in the roster with an empty queue set. Neither must match a lane. expect(queueKey(undefined)).toBe('') expect(queueKey([])).toBe('') }) }) describe('mergeParts', () => { it('gives a worker ONE row, carrying its controls', () => { const rows = mergeParts([PART, POSTGRES], [LANE]) expect(rows).toHaveLength(2) const worker = rows.find((r) => r.name === 'Worker') expect(worker.lane).toBe(LANE) expect(rows.filter((r) => r.name === 'Worker')).toHaveLength(1) }) it('leaves a datastore without a lane rather than guessing one', () => { const pg = mergeParts([PART, POSTGRES], [LANE]).find((r) => r.key === 'postgres') expect(pg.lane).toBeUndefined() }) it('still lists a lane the roster has never seen', () => { // Parts are learned as they appear; the lane table is known up front. The // lane an operator most needs to find — an optional one, never started — // is exactly the one with no roster entry. const ml = { ...LANE, name: 'ml', display_name: 'ML tagging', queues: ['ml'], slots_cap: 0, optional: true, live: { present: false, replicas: 0, pool: null, active: 0 }, } const rows = mergeParts([POSTGRES], [ml]) const row = rows.find((r) => r.name === 'ML tagging') expect(row.lane).toBe(ml) expect(row.kindLabel).toBe('optional lane') }) it('does not call a lane capped at zero broken', () => { // The roster only knows a heartbeat age, so it goes on saying "is running" // for a lane the operator deliberately dialled to nothing. The lane knows // the difference; reporting the operator's own choice as a fault is how an // indicator stops being read. const off = { ...LANE, slots_cap: 0 } const row = mergeParts([PART], [off])[0] expect(row.detail).toBe('off — cap is zero') }) it('puts the broken thing first, whatever it is', () => { const down = { ...POSTGRES, state: 'down', detail: 'not answering' } const rows = mergeParts([PART, down], [LANE]) expect(rows[0].name).toBe('PostgreSQL') }) it('otherwise puts the rows you can act on first', () => { const rows = mergeParts([POSTGRES, PART], [LANE]) expect(rows.map((r) => r.name)).toEqual(['Worker', 'PostgreSQL']) }) it('reports a wedged lane, and only through the reporter it was given', () => { // `laneStuckFor` is passed in rather than imported, so this file does not // re-test the store's rule — it tests that the merge asks. const asked = [] const rows = mergeParts([PART], [LANE], (lane) => { asked.push(lane.name) return '40 minutes' }) expect(asked).toEqual(['worker']) expect(rows[0].stuckFor).toBe('40 minutes') // The roster still owns a matched row's state — `stuckFor` is a note // beside it, not a verdict that overrides the heartbeat. expect(rows[0].state).toBe('ok') }) it('handles an empty everything without inventing rows', () => { expect(mergeParts([], [])).toEqual([]) expect(mergeParts(undefined, undefined)).toEqual([]) }) }) // The nudge. Operator, 2026-09-23: *"there needs to be something that tells // you user to bump those numbers to improve processing rate or they'd never // know the controls exist."* // // The caps ship at one of each, so on a busy instance the SHIPPED // CONFIGURATION is the bottleneck. What is pinned here is that it fires only // when raising the cap would actually help — a notice on a lane that is // keeping up, or one already at the machine's limit, is a notice people learn // to scroll past, and at that point it is worse than not having it. describe('laneAdvice', () => { const busyAtCap = { slots_cap: 1, ceiling: 7, pending: 4060, live: { present: true, pool: 1, active: 1 }, } it('speaks when the cap is the limiting factor', () => { const advice = laneAdvice(busyAtCap) expect(advice).toContain('4,060 waiting') expect(advice).toContain('Raise the cap') // The headroom, so it is an instruction rather than a complaint. expect(advice).toContain('7') }) it('says something different about a lane that is switched off', () => { const advice = laneAdvice({ ...busyAtCap, slots_cap: 0 }) expect(advice).toContain('this lane is off') }) it('stays quiet when the lane is keeping up', () => { expect(laneAdvice({ ...busyAtCap, pending: 2 })).toBeNull() }) it('stays quiet when the cap is not the thing holding it back', () => { // Four allowed, two running — the sizing pass has room it has not taken, // so the queue is not the cap's fault. expect(laneAdvice({ ...busyAtCap, slots_cap: 4, live: { present: true, pool: 2, active: 2 }, })).toBeNull() }) it('stays quiet at the machine ceiling, where the advice is untakeable', () => { // The one case where saying "raise the cap" would send someone to a // control that will refuse them. expect(laneAdvice({ ...busyAtCap, ceiling: 1 })).toBeNull() }) it('stays quiet about a lane that is not answering', () => { // An unswept read is not a verdict: nothing replied, so "all workers // busy" is a claim nobody made. expect(laneAdvice({ ...busyAtCap, live: { present: false, pool: null, active: 0 }, })).toBeNull() }) it('stays quiet when the backlog is unknown rather than reading it as huge', () => { expect(laneAdvice({ ...busyAtCap, pending: null })).toBeNull() }) it('says nothing about a row that is not a lane at all', () => { expect(laneAdvice(undefined)).toBeNull() }) })