import { test } from 'node:test'; import assert from 'node:assert/strict'; import { DockerHostPool, GAMEFILES_UPDATE_SCRIPT, parseUpdateOutput } from '../src/servers/dockerAdapter.js'; const options = (runDocker) => new DockerHostPool({ bin: 'docker', image: 'joedwards32/cs2:latest', host: '10.0.0.9', rconHost: '10.0.0.9', portRangeStart: 27100, portRangeEnd: 27139, volume: 'cs2-mapveto-gamefiles', startTimeoutMinutes: 1, lanPorts: [], hosts: [{ name: 'a', publicHost: '10.0.0.1' }, { name: 'b', publicHost: '10.0.0.2', volume: 'andere-dateien' }], }, { runDocker }); test('Ausgabe von SteamCMD: Fortschritt und Build-Nummern', () => { const info = parseUpdateOutput('BUILD_BEFORE=100\n Update state (0x61) downloading, progress: 42.50 (1 / 2)\n'); assert.equal(info.buildBefore, '100'); assert.equal(info.progress, 42.5); parseUpdateOutput('Success! App \'730\' fully installed.\nBUILD_AFTER=105\n', info); assert.equal(info.buildAfter, '105'); assert.match(GAMEFILES_UPDATE_SCRIPT, /\+app_update 730 -beta public \+quit/); }); test('Spieldateien-Update: eigener Container je Host, Hosts mit Servern ausgelassen', async () => { const calls = []; const pool = options(async (args, host) => { calls.push({ args, host }); return 'BUILD_BEFORE=100\nBUILD_AFTER=105\n'; }); const res = await pool.updateGameFiles({ skip: new Map([['b', 'ausgelassen: 1 laufender Server']]) }); assert.equal(calls.length, 1); assert.equal(calls[0].host, 'a'); const args = calls[0].args; assert.deepEqual(args.slice(0, 2), ['run', '--rm']); assert.ok(args.includes('cs2-mapveto-gamefiles:/home/steam/cs2-dedicated')); assert.equal(args[args.indexOf('--entrypoint') + 1], 'bash'); assert.ok(!args.includes('cs2-mapveto=1'), 'Update-Container zählen nicht als Gameserver'); assert.deepEqual(res.results.map((r) => [r.name, r.state]), [['a', 'ok'], ['b', 'skipped']]); assert.match(res.results[0].message, /Build 105 \(vorher 100\)/); assert.equal(res.running, false); }); test('Bereits aktuell und Fehler werden gemeldet', async () => { const same = options(async () => 'BUILD_BEFORE=105\nBUILD_AFTER=105\n'); assert.match((await same.updateGameFiles()).results[0].message, /bereits aktuell \(Build 105\)/); const broken = options(async () => { throw new Error('SteamCMD failed (rc 8)'); }); const r = (await broken.updateGameFiles()).results; assert.deepEqual(r.map((x) => x.state), ['failed', 'failed']); assert.match(r[0].message, /rc 8/); }); test('Während des Updates startet auf dem Host kein neuer Server', () => { const pool = options(async () => ''); pool.files = { running: true, results: [{ name: 'a', state: 'running' }, { name: 'b', state: 'ok' }] }; assert.equal(pool.pickHost().name, 'b'); pool.files.results[1].state = 'running'; assert.throws(() => pool.pickHost(), /Spieldateien/); }); test('Unvollständige Installation oder SteamCMD-Fehler gelten als fehlgeschlagen, auch mit Exit-Code 0', async () => { const partial = options(async () => 'BUILD_BEFORE=0\nBUILD_AFTER=0\nSTATE_AFTER=1026\n'); const [a] = (await partial.updateGameFiles()).results; assert.equal(a.state, 'failed'); assert.match(a.message, /StateFlags 1026/); const err = options(async () => "Error! App '730' state is 0x202 after update job.\nBUILD_BEFORE=1\nBUILD_AFTER=1\nSTATE_AFTER=4\n"); assert.match((await err.updateGameFiles()).results[0].message, /Error! App '730'/); const fine = options(async () => 'BUILD_BEFORE=1\nBUILD_AFTER=2\nSTATE_AFTER=4\n'); assert.equal((await fine.updateGameFiles()).results[0].state, 'ok'); });