Files
gold_land_server/test/restore-safety.test.ts
T
safavimohadeseh78andCursor dfb20ca92c
Backend CI / type-check, build, tests (push) Successful in 1m0s
feat: prepare six-lesson trial backend with reliable rewards and operations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 14:35:42 +03:30

82 lines
2.6 KiB
TypeScript

import assert from 'node:assert/strict'
import { spawnSync } from 'node:child_process'
import { mkdtempSync, rmSync, existsSync, writeFileSync, readFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import Database from 'better-sqlite3'
import { up, migrationId } from '../src/database/migrations/001-initial-schema'
const backendRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
const root = mkdtempSync(join(tmpdir(), 'cgl-restore-safety-'))
function runRestore(backup: string, target: string, env: Record<string, string> = {}) {
return spawnSync('node', ['scripts/sqlite-restore.mjs', backup, target], {
cwd: backendRoot,
env: { ...process.env, ...env },
encoding: 'utf8',
})
}
function seedAppDb(path: string) {
const db = new Database(path)
db.exec(`
CREATE TABLE IF NOT EXISTS schema_migrations (
id TEXT PRIMARY KEY,
applied_at TEXT NOT NULL
);
`)
db.exec(up)
db.prepare('INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)').run(
migrationId,
new Date().toISOString(),
)
db.close()
}
try {
const goodBackup = join(root, 'good.db')
seedAppDb(goodBackup)
const wrongSchema = join(root, 'wrong.db')
const w = new Database(wrongSchema)
w.exec('CREATE TABLE users (id TEXT PRIMARY KEY);')
w.close()
writeFileSync(join(root, 'corrupt.db'), 'not-a-sqlite-file')
let r = runRestore(join(root, 'corrupt.db'), join(root, 't1.db'))
assert.notEqual(r.status, 0)
r = runRestore(wrongSchema, join(root, 't2.db'))
assert.notEqual(r.status, 0)
const existing = join(root, 'existing.db')
seedAppDb(existing)
const before = readFileSync(existing)
r = runRestore(goodBackup, existing, {})
assert.notEqual(r.status, 0)
assert.deepEqual(readFileSync(existing), before, 'failed restore must not change target')
const freshTarget = join(root, 'fresh.db')
r = runRestore(goodBackup, freshTarget, { RESTORE_ACK_STOPPED: 'YES' })
assert.equal(r.status, 0, r.stderr || r.stdout)
assert.ok(existsSync(freshTarget))
const liveConfigured = join(root, 'live-configured.db')
seedAppDb(liveConfigured)
r = runRestore(goodBackup, liveConfigured, {
DB_PATH: liveConfigured,
RESTORE_ACK_STOPPED: 'YES',
})
assert.notEqual(r.status, 0, 'must refuse restore onto configured live DB_PATH')
} finally {
try {
rmSync(root, { recursive: true, force: true, maxRetries: 8, retryDelay: 200 })
} catch {
// Windows may briefly lock SQLite files after close.
}
}
console.log('restore-safety tests passed')