'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('fs'); const os = require('os'); const path = require('path'); const database = require('../../src/database'); test('database initializes headlessly with the injected server logger', async () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'porkfolio-db-')); const messages = []; database.configure({ dataDir: root, logger: { info: (...args) => messages.push(args.join(' ')), warn() {}, error() {}, }, }); try { await database.initialize(); assert.ok(messages.some(message => message.includes('[DB] Ready'))); database.upsertGame({ game_id: 'CUSA03041', title: '', content_id: '', size: 0, version: '', installed: 0, backed_up: 0, ftp_path: '', last_scanned: Date.now(), }); database.updateProsperoData('CUSA03041', { name: 'Red Dead Redemption 2', iconUrl: '/pork-cache/game-metadata/CUSA03041/icon.webp', coverUrl: '/pork-cache/game-metadata/CUSA03041/cover.jpg', coverSource: 'wikipedia-portrait-v3', coverSourceUrl: 'https://en.wikipedia.org/wiki/Red_Dead_Redemption_2', coverFetchedAt: Date.now(), }); const game = database.getGame('CUSA03041'); assert.equal(game.title, 'Red Dead Redemption 2'); assert.equal(game.prospero_name, 'Red Dead Redemption 2'); assert.match(game.prospero_icon_url, /icon\.webp$/); assert.match(game.prospero_cover_url, /cover\.jpg$/); assert.equal(game.cover_source, 'wikipedia-portrait-v3'); assert.equal(game.metadata_failure_count, 0); assert.equal(database.getGameCatalogHealth().complete, 1); assert.equal(database.getGameCatalogHealth().missing_artwork, 0); assert.deepEqual(database.listGames({ search: 'Dead', limit: 1 }).map(item => item.game_id), ['CUSA03041']); database.updateProsperoData('CUSA03041', { name: 'Red Dead Redemption 2', coverUrl: '/pork-cache/game-metadata/CUSA03041/cover.png', coverSource: 'steamgriddb', coverSourceUrl: 'https://www.steamgriddb.com/game/1', coverFetchedAt: Date.now(), }); database.close(); await database.initialize(); const retiredCover = database.getGame('CUSA03041'); assert.equal(retiredCover.prospero_cover_url, null); assert.equal(retiredCover.cover_source, 'steamgriddb-retired'); assert.equal(retiredCover.cover_fetched_at, null); database.updateProsperoData('CUSA03041', { name: 'Red Dead Redemption 2', iconUrl: '/pork-cache/game-metadata/CUSA03041/icon.webp', coverUrl: '/pork-cache/game-metadata/CUSA03041/cover.jpg', coverSource: 'wikipedia-portrait-v3', coverSourceUrl: 'https://en.wikipedia.org/wiki/Red_Dead_Redemption_2', coverFetchedAt: Date.now(), }); database.upsertGame({ game_id: 'PPSA01467', title: "Marvel's Spider-Man Remastered", content_id: '', size: 0, version: '', installed: 0, backed_up: 0, ftp_path: '', last_scanned: Date.now(), }); database.updateProsperoData('PPSA01467', { name: "Marvel's Spider-Man Remastered", coverUrl: '/pork-cache/game-metadata/PPSA01467/cover.jpg', coverSource: 'wikipedia-portrait-v2', coverSourceUrl: 'https://en.wikipedia.org/wiki/Spider-Man_(2018_video_game)', coverFetchedAt: Date.now(), }); database.close(); await database.initialize(); assert.equal(database.getGame('CUSA03041').cover_source, 'wikipedia-portrait-v3'); assert.equal(database.getGame('PPSA01467').prospero_cover_url, null); assert.equal(database.getGame('PPSA01467').cover_source, 'wikipedia-retired'); assert.equal(database.getGame('PPSA01467').cover_fetched_at, null); database.upsertPayloadSource({ name: 'etaHEN', github_url: 'https://github.com/etaHEN/etaHEN', category: 'homebrew', description: 'Official', homepage: 'https://github.com/etaHEN/etaHEN', trust: 'official', built_in: 1, }); const source = database.listPayloadSources()[0]; database.upsertPayloadFile({ source_id: source.id, asset_name: 'etaHEN.elf', asset_url: 'https://example.com/etaHEN.elf', remote_hash: 'a'.repeat(64), version: '2.5', asset_size: 42, }); database.updatePayloadFileLocal({ source_id: source.id, asset_name: 'etaHEN.elf', local_path: '/payloads/etaHEN.elf', local_hash: 'b'.repeat(64), local_size: 42, version: '2.4', }); const catalog = database.getPayloadCatalog(); assert.equal(catalog.stats.available, 1); assert.equal(catalog.stats.updates, 1); assert.equal(catalog.files[0].local_version, '2.4'); const runId = database.startAutomationRun({ task_id: 'library-scan', trigger: 'test' }); database.finishAutomationRun(runId, { status: 'completed', summary: '{"found":1}' }); const runs = database.listAutomationRuns(); assert.equal(runs[0].task_id, 'library-scan'); assert.equal(runs[0].status, 'completed'); const recoveryPoint = database.exportDatabaseBuffer(); database.upsertGame({ game_id: 'PPSA99999', title: 'Temporary', content_id: '', size: 0, version: '', installed: 0, backed_up: 0, ftp_path: '', last_scanned: Date.now(), }); assert.equal(database.getGame('PPSA99999').title, 'Temporary'); assert.deepEqual(database.listGames({ platform: 'ps4' }).map(item => item.game_id), ['CUSA03041']); assert.deepEqual(database.listGames({ platform: 'ps5' }).map(item => item.game_id), ['PPSA01467', 'PPSA99999']); const restored = database.restoreDatabaseBuffer(recoveryPoint); assert.equal(restored.ok, true); assert.equal(database.getGame('PPSA99999'), undefined); assert.equal(database.getGame('CUSA03041').title, 'Red Dead Redemption 2'); assert.deepEqual(database.runQuery("SELECT game_id FROM games WHERE game_id = 'CUSA03041'"), [{ game_id: 'CUSA03041' }]); assert.ok(database.runQuery('PRAGMA table_info(games)').some(column => column.name === 'game_id')); assert.throws(() => database.runQuery('PRAGMA user_version = 123'), /read-only|niet beschikbaar/); assert.throws(() => database.runQuery('PRAGMA user_version(123)'), /read-only|niet beschikbaar/); assert.throws(() => database.runQuery('WITH target AS (SELECT id FROM games) DELETE FROM games WHERE id IN target'), /niet read-only/); assert.throws(() => database.runQuery('SELECT 1; DELETE FROM games'), /één SQL-statement/); assert.equal(database.getGame('CUSA03041').title, 'Red Dead Redemption 2'); } finally { database.close(); fs.rmSync(root, { recursive: true, force: true }); } });