#!/usr/bin/env bash # Dedicated local integration fixture; never uses the primary Phase 0 runtime. set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")/.." export MC_ROOT="$PWD/.tools/phase4-server" export MC_RELEASE_DIR="$PWD/dist/minecraft-lab-neoforge-spike-0.0.4" evidence="$PWD/.tools/phase5-evidence" restored="$PWD/.tools/phase5-restored-server" mkdir -p "$evidence" if [[ -e "$restored" ]]; then echo "Restore fixture already exists; choose a new destination before repeating." >&2 exit 1 fi scripts/server.sh up -d --wait --wait-timeout 120 mkdir -p "$MC_ROOT/runtime/mod-state" printf '{"phase":5,"progress":42}\n' > "$MC_ROOT/runtime/mod-state/phase5.json" printf 'preserve-unmanaged-phase5\n' > "$MC_ROOT/runtime/config/phase5-unmanaged.txt" ./mcpack backup > "$evidence/backup.log" 2>&1 node --input-type=module <<'JS' > "$evidence/snapshot-path.txt" import fs from 'node:fs'; const operation=JSON.parse(fs.readFileSync(process.env.MC_ROOT+'/.mcpack-backup-operation.json')); if(operation.phase!=='complete'||!operation.snapshot)throw new Error('Backup did not complete'); console.log(operation.snapshot); JS snapshot=$(cat "$evidence/snapshot-path.txt") scripts/server.sh exec -T minecraft mc-health > "$evidence/resumed-health.txt" scripts/server.sh logs --tail 150 > "$evidence/resumed-start.log" mkdir -p "$evidence/failure-bin" cat > "$evidence/failure-bin/tar" <<'SH' #!/bin/sh echo 'intentional Phase 5 archive failure' >&2 exit 42 SH chmod +x "$evidence/failure-bin/tar" if PATH="$evidence/failure-bin:$PATH" ./mcpack backup > "$evidence/failed-backup.log" 2>&1; then echo 'Invalid archive unexpectedly succeeded' >&2 exit 1 fi node --input-type=module <<'JS' > "$evidence/failure-verification.txt" import fs from 'node:fs'; import {execFileSync} from 'node:child_process'; const root=process.env.MC_ROOT; const operation=JSON.parse(fs.readFileSync(root+'/.mcpack-backup-operation.json')); if(operation.phase!=='failed'||!operation.stopped_confirmed||operation.snapshot!==null)throw new Error('Incorrect backup failure state'); const state=JSON.parse(execFileSync('docker',['inspect','minecraft-lab-phase4-minecraft-1']))[0].State; if(state.Running)throw new Error('Failed backup unexpectedly restarted server'); const snapshots=fs.readdirSync(root+'/backups'); if(snapshots.length!==1||snapshots.some(name=>name.startsWith('.')))throw new Error('Incomplete snapshot published or left behind'); console.log('Failed backup: non-zero, server stopped, no additional snapshot, no staging directories.'); JS scripts/server.sh down ./mcpack restore --backup "$snapshot" --destination "$restored" > "$evidence/restore.log" 2>&1 SNAPSHOT="$snapshot" RESTORED="$restored" node --input-type=module <<'JS' > "$evidence/restore-verification.txt" import fs from 'node:fs'; import assert from 'node:assert/strict'; import {verifySnapshot,runtimeInventory} from './platform/backups.mjs'; import {verifyRelease} from './platform/runtime.mjs'; const metadata=verifySnapshot(process.env.SNAPSHOT); assert.deepEqual(runtimeInventory(process.env.RESTORED+'/runtime'),metadata.runtime_inventory); assert.equal(verifyRelease(process.env.RESTORED+'/release').identity,metadata.source_release.manifest_sha256); assert.equal(fs.readFileSync(process.env.RESTORED+'/runtime/mod-state/phase5.json','utf8'),'{"phase":5,"progress":42}\n'); assert.equal(fs.readFileSync(process.env.RESTORED+'/runtime/config/phase5-unmanaged.txt','utf8'),'preserve-unmanaged-phase5\n'); assert(!fs.existsSync(process.env.RESTORED+'/.env')); console.log(`Verified ${metadata.runtime_inventory.length} runtime entries including bytes/modes/UID/GID; retained release ${metadata.source_release.name}.`); console.log('Mod data outside world, unmanaged config, server.properties, operators and whitelist preserved; host settings not copied.'); JS export MC_ENV_FILE="$MC_ROOT/.env" export MC_ROOT="$restored" export MC_RELEASE_DIR="$restored/release" scripts/server.sh up -d --wait --wait-timeout 120 scripts/server.sh exec -T minecraft mc-health > "$evidence/restored-health.txt" scripts/server.sh logs --tail 150 > "$evidence/restored-start.log" scripts/server.sh down scripts/spike-server.sh ps > "$evidence/primary-server-status.txt" printf 'Phase 5 backup, failure and restored server health checks passed.\n'