// ── Asking a server how it is now, before saying no (W7, W11) ────────────── // // Each test is one way the feature could look right and be wrong: // // a "no" from the stored status is asked again, and the fresh answer is the one acted on // a "yes" is never asked again: the plugin refuses at the run, as it always has // a "no" the sidecar cannot change is still a "no" // ten steps against one server in one dry run ask it once // a step refused for Backpacks just after a restart passes once the server says it is back const test = require('node:test') const assert = require('node:assert') const { fakeCtx } = require('./_fakes') require('../core')._reset() require('../core').init(fakeCtx({ db: { query: () => Promise.resolve([]), pool: {} } })) const boot = require('../boot') const live = require('../liveStatus') const MAIN = { id: 'main', name: 'Main', baseUrl: 'http://main:1', token: 't' } /** `boot.refreshOne` replaced by `onAsk`, counted. */ function stubAsk(t, onAsk = () => {}) { const saved = boot.refreshOne const asked = [] live._reset() boot.refreshOne = async (server) => { asked.push(server.id) await onAsk(server) } t.after(() => { boot.refreshOne = saved live._reset() }) return asked } test('a refusal from the stored status is asked again, and the fresh answer is the one acted on', async (t) => { let stored = { loaded: false } const asked = stubAsk(t, () => { stored = { loaded: true } }) const answer = await live.confirmed(MAIN, async () => stored, (r) => !r.loaded) assert.deepStrictEqual(answer, { loaded: true }) assert.deepStrictEqual(asked, ['main']) }) test('a pass is never asked again', async (t) => { const asked = stubAsk(t) const answer = await live.confirmed(MAIN, async () => ({ loaded: true }), (r) => !r.loaded) assert.deepStrictEqual(answer, { loaded: true }) assert.deepStrictEqual(asked, []) }) test('a refusal the fresh answer agrees with is still a refusal, and a failed ask leaves the stored one', async (t) => { stubAsk(t) assert.strictEqual(await live.confirmed(MAIN, async () => 'Backpacks is not installed', Boolean), 'Backpacks is not installed') stubAsk(t, () => { throw new Error('boom') }) assert.strictEqual(await live.refresh(MAIN), false) assert.strictEqual(await live.confirmed(MAIN, async () => 'still no', Boolean), 'still no') }) test('many refusals against one server at once ask it once, and again only after a while', async (t) => { let release const gate = new Promise((resolve) => { release = resolve }) const asked = stubAsk(t, () => gate) const all = Promise.all(Array.from({ length: 10 }, () => live.confirmed(MAIN, async () => 'no', Boolean))) release() await all assert.deepStrictEqual(asked, ['main'], 'one ask in flight serves every step') await live.confirmed(MAIN, async () => 'no', Boolean) assert.deepStrictEqual(asked, ['main'], `an ask within ${live.FRESH_MS} ms is as fresh as asking again`) await live.confirmed({ ...MAIN, id: 'pve' }, async () => 'no', Boolean) assert.deepStrictEqual(asked, ['main', 'pve'], 'another server is its own') }) test('a step waits at most ASK_MS for the ask, and a late ask leaves the stored answer', async (t) => { t.mock.timers.enable({ apis: ['setTimeout'] }) stubAsk(t, () => new Promise(() => {})) const answer = live.confirmed(MAIN, async () => 'not installed', Boolean) // Let the first read and the ask start before the clock moves. for (let i = 0; i < 5; i++) await Promise.resolve() t.mock.timers.tick(live.ASK_MS) assert.strictEqual(await answer, 'not installed') }) test('a bigger backpack refused on a stale "not installed" passes once the server says Backpacks is back (W7)', async (t) => { const rewards = require('../eventRewards') const serversDb = require('../model/servers/servers.db') const backpacksDb = require('../model/backpacks/backpacks.db') const saved = { getServer: serversDb.getServer, reportFor: backpacksDb.reportFor } t.after(() => Object.assign(serversDb, { getServer: saved.getServer }) && Object.assign(backpacksDb, { reportFor: saved.reportFor })) serversDb.getServer = async (id) => (id === 'main' ? { id: 'main', name: 'Main', enabled: 1, sidecarBaseUrl: 'http://main:1' } : null) let report = null backpacksDb.reportFor = async () => ({ serverId: 'main', backpacks: report }) const asked = stubAsk(t, () => { report = JSON.stringify({ loaded: true, sizes: [6, 48] }) }) const step = rewards.ACTIONS.find((a) => a.id === 'rust.backpack.size') const result = await step.perform({ runId: 7, stepId: 1, idempotencyKey: '7:1', params: { server: 'main', size: 48, recipients: 'linked' }, verify: true }) assert.deepStrictEqual(asked, ['main']) assert.deepStrictEqual(result, { ok: true }) })