Files
chimera-Public/test/server/v3-repositories.test.js
T

263 lines
8.4 KiB
JavaScript

'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');
const {
createV3Repositories,
sanitizePublicLocalCopy,
sanitizePublicConsoleInstall,
} = require('../../src/services/v3-repositories');
function withTempDatabase(fn) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-v3-repositories-'));
database.configure({
dataDir: root,
logger: { info() {}, warn() {}, error() {},
},
});
return database.initialize()
.then(() => fn())
.finally(() => {
database.close();
fs.rmSync(root, { recursive: true, force: true });
});
}
function seedCoreRows() {
database.runMutatingSqlWithParams(`
INSERT INTO titles (platform, title_id, content_id, name, sort_name, region, metadata_source)
VALUES ('ps5', 'PPSA00001', 'content-01', 'Repo Test', 'Repo Test', 'US', 'tests')
`);
const title = Number(database.runQuery('SELECT last_insert_rowid() AS id')[0]?.id || 0);
database.runMutatingSqlWithParams(`
INSERT INTO storage_devices (scope, stable_fingerprint, display_name, device_type, availability_state)
VALUES ('server', 'test-device', 'Test Device', 'server', 'available')
`);
const device = Number(database.runQuery('SELECT last_insert_rowid() AS id')[0]?.id || 0);
database.runMutatingSqlWithParams(`
INSERT INTO storage_volumes (device_id, stable_volume_key, mount_path, can_copy, can_play, can_install)
VALUES (@deviceId, 'test-volume', '/test-volume', 1, 1, 1)
`, { deviceId: device });
const volume = Number(database.runQuery('SELECT last_insert_rowid() AS id')[0]?.id || 0);
return { title, volume };
}
function rowCount(table) {
return Number(database.runQuery(`SELECT COUNT(*) AS c FROM ${table}`)[0]?.c || 0);
}
test('local-copy repository writes only local copies and returns sanitized public model', () => {
return withTempDatabase(() => {
const { title, volume } = seedCoreRows();
const { localCopies } = createV3Repositories(database);
const result = localCopies.upsertLocalCopy({
titleId: title,
volumeId: volume,
relativePath: 'games/TestFolder',
copyType: 'folder',
baseVersion: '1.00',
versionSource: 'legacy',
generation: 10,
});
assert.equal(result.ok, true);
assert.equal(result.reason, 'inserted');
assert.equal(sanitizePublicLocalCopy(result.copy).copyType, 'folder');
assert.equal(rowCount('console_installs'), 0);
assert.equal(rowCount('local_copies'), 1);
});
});
test('console-install repository writes only console installs and returns sanitized public model', () => {
return withTempDatabase(() => {
const { title, volume } = seedCoreRows();
const { consoleInstalls } = createV3Repositories(database);
const result = consoleInstalls.upsertConsoleInstall({
titleId: title,
volumeId: volume,
consoleProfileId: 'profile-A',
remoteLocationKey: 'ux0:/app0/PPSA00001',
installedVersion: '1.00',
installState: 'observed',
versionSource: 'scan',
evidenceConfidence: 'medium',
generation: 5,
});
assert.equal(result.ok, true);
assert.equal(result.reason, 'inserted');
assert.equal(sanitizePublicConsoleInstall(result.install).installState, 'observed');
assert.equal(rowCount('local_copies'), 0);
assert.equal(rowCount('console_installs'), 1);
});
});
test('generation-aware upserts prevent stale local copy evidence overwrite', () => {
return withTempDatabase(() => {
const { title, volume } = seedCoreRows();
const { localCopies } = createV3Repositories(database);
localCopies.upsertLocalCopy({
titleId: title,
volumeId: volume,
relativePath: 'games/TestFolder',
copyType: 'folder',
baseVersion: '1.00',
generation: 10,
});
const stale = localCopies.upsertLocalCopy({
titleId: title,
volumeId: volume,
relativePath: 'games/TestFolder',
copyType: 'folder',
baseVersion: '2.00',
generation: 9,
});
assert.equal(stale.ok, false);
assert.equal(stale.reason, 'outdated-evidence');
const current = localCopies.upsertLocalCopy({
titleId: title,
volumeId: volume,
relativePath: 'games/TestFolder',
copyType: 'folder',
baseVersion: '2.00',
generation: 20,
});
assert.equal(current.ok, true);
assert.equal(current.reason, 'updated');
assert.equal(current.copy.baseVersion, '2.00');
});
});
test('generation-aware upserts prevent stale console install overwrite', () => {
return withTempDatabase(() => {
const { title, volume } = seedCoreRows();
const { consoleInstalls } = createV3Repositories(database);
consoleInstalls.upsertConsoleInstall({
titleId: title,
volumeId: volume,
consoleProfileId: 'profile-A',
remoteLocationKey: 'ux0:/app0/PPSA00001',
installedVersion: '1.00',
installState: 'observed',
generation: 10,
});
const stale = consoleInstalls.upsertConsoleInstall({
titleId: title,
volumeId: volume,
consoleProfileId: 'profile-A',
remoteLocationKey: 'ux0:/app0/PPSA00001',
installedVersion: '0.99',
installState: 'absent',
generation: 9,
});
assert.equal(stale.ok, false);
assert.equal(stale.reason, 'outdated-evidence');
const fresh = consoleInstalls.upsertConsoleInstall({
titleId: title,
volumeId: volume,
consoleProfileId: 'profile-A',
remoteLocationKey: 'ux0:/app0/PPSA00001',
installedVersion: '1.01',
installState: 'observed',
generation: 20,
});
assert.equal(fresh.ok, true);
assert.equal(fresh.reason, 'updated');
assert.equal(fresh.install.installedVersion, '1.01');
});
});
test('evidence writes are persisted with source/time/confidence metadata', () => {
return withTempDatabase(() => {
const { title, volume } = seedCoreRows();
const { consoleInstalls } = createV3Repositories(database);
const generation = Date.now();
const result = consoleInstalls.upsertConsoleInstall({
titleId: title,
volumeId: volume,
consoleProfileId: 'profile-A',
remoteLocationKey: 'ux0:/app0/PPSA00001',
installedVersion: '1.00',
installState: 'observed',
versionSource: 'legacy-console',
evidenceConfidence: 'high',
generation,
});
const install = database.runQuery(`
SELECT version_evidence_id, installed_version
FROM console_installs
WHERE id = ${result.install.id}
`)[0];
assert.equal(install.installed_version, '1.00');
assert.ok(install.version_evidence_id > 0);
const evidence = database.runQuery(`
SELECT subject_type, subject_id, semantic_version, version_source, confidence, observed_at
FROM version_evidence WHERE id = ${install.version_evidence_id}
`)[0];
assert.equal(evidence.subject_type, 'console_install');
assert.equal(evidence.subject_id, title);
assert.equal(evidence.semantic_version, '1.00');
assert.equal(evidence.version_source, 'legacy-console');
assert.equal(evidence.confidence, 'high');
assert.equal(Number(evidence.observed_at), generation);
});
});
test('public models are sanitized for invalid external fields', () => {
const sanitizedCopy = sanitizePublicLocalCopy({
id: 'bad-id',
title_id: '42',
volume_id: '100',
relative_path: ' games/Test ',
copy_type: 'not-a-type',
base_version: 1.23,
version_source: null,
size_bytes: 'abc',
scan_run_id: null,
last_seen_at: 'bad-ts',
availability_state: 'nonsense',
});
const sanitizedInstall = sanitizePublicConsoleInstall({
id: 'bad-id',
title_id: '42',
console_profile_id: ' profile-legacy',
volume_id: 3,
remote_location_key: 'ux0:/app0',
installed_version: 4,
install_state: 'invalid-state',
first_seen_at: 'bad',
last_seen_at: 'bad',
});
assert.equal(sanitizedCopy.copyType, 'unknown');
assert.equal(sanitizedCopy.availabilityState, 'unknown');
assert.equal(sanitizedCopy.relativePath, 'games/Test');
assert.equal(typeof sanitizedCopy.sizeBytes, 'number');
assert.equal(sanitizedCopy.availabilityState, 'unknown');
assert.equal(sanitizedInstall.installState, 'unknown');
assert.equal(typeof sanitizedInstall.firstSeenAt, 'number');
assert.equal(typeof sanitizedInstall.lastSeenAt, 'number');
});