'use strict'; const assert = require('node:assert/strict'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const test = require('node:test'); const { createConsoleProfileService } = require('../../src/services/console-profile-service'); class MemorySettings { constructor(data = {}) { this.data = data; } get(key, fallback) { let value = this.data; for (const part of String(key).split('.')) { if (!value || !Object.prototype.hasOwnProperty.call(value, part)) return fallback; value = value[part]; } return value; } set(key, next) { const parts = String(key).split('.'); let value = this.data; while (parts.length > 1) { const part = parts.shift(); if (!value[part] || typeof value[part] !== 'object') value[part] = {}; value = value[part]; } value[parts[0]] = next; } } function secretFixture(initial = {}) { const values = new Map(Object.entries(initial)); return { has: key => values.has(key), get: key => values.get(key) || '', set: (key, value) => value ? values.set(key, String(value)) : values.delete(key), values }; } test('console profiles migrate the legacy single-console settings and scope pairing secrets', () => { const settings = new MemorySettings({ ftp: { host: '192.168.1.55', port: '1337', ports: ['1337', '21'], user: 'ps5' }, payloadManager: { port: 8084 } }); const secrets = secretFixture({ 'ftp.password': 'legacy-pass', 'remotePlay.registrationKey': 'ABCD' }); const service = createConsoleProfileService({ settings, secrets, now: () => 100, uuid: () => 'profile-default' }); const packet = service.list(); assert.equal(packet.schema, 1); assert.equal(packet.profiles.length, 1); assert.equal(packet.profiles[0].host, '192.168.1.55'); assert.equal(packet.profiles[0].ports.ftp, 1337); assert.equal(packet.profiles[0].secrets.remotePlayKey, true); assert.equal(secrets.get('consoleProfile:profile-default:ftpPassword'), 'legacy-pass'); assert.equal(service.getSecret('remotePlayKey'), 'ABCD'); }); test('switching profiles applies configuration but never initiates a connection', () => { let serial = 0; const settings = new MemorySettings({ ftp: { host: 'ps5-a.local', port: 21, ports: ['21'] } }); const service = createConsoleProfileService({ settings, secrets: secretFixture(), uuid: () => `profile-${++serial}` }); const added = service.save({ label: 'PS5 B', host: 'ps5-b.local', ports: { ftp: 2121 }, ftpPorts: ['2121'], makeActive: false }); const second = added.profiles.find(profile => profile.label === 'PS5 B'); const result = service.activate(second.id); assert.equal(result.activeId, second.id); assert.equal(result.requiresReconnect, true); assert.equal(result.automaticConnectionStarted, false); assert.equal(settings.get('ftp.host'), 'ps5-b.local'); assert.equal(Number(settings.get('ftp.port')), 2121); assert.equal(service.comparison().profiles.find(profile => profile.id === second.id).firmware, 'unknown'); }); test('storage topology never invents unavailable PS5 capacity', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-profile-storage-')); try { const service = createConsoleProfileService({ settings: new MemorySettings(), secrets: secretFixture(), uuid: () => 'profile-storage' }); const topology = service.storageTopology({ roots: [root], games: [{ backup_path: path.join(root, 'PPSA00001') }] }); const consoleVolumes = topology.volumes.filter(volume => volume.scope === 'console'); assert.deepEqual(consoleVolumes, []); assert.equal(topology.provenance.console, 'unavailable'); const server = topology.volumes.find(volume => volume.scope === 'server'); assert.ok(server.totalBytes > 0); assert.equal(server.games, 1); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); test('console profile component updates are allowlisted and bounded', () => { const service = createConsoleProfileService({ settings: new MemorySettings(), secrets: secretFixture(), uuid: () => 'profile-components' }); const current = service.list().profiles[0]; const updated = service.save({ id: current.id, components: { firmware: ' 7.61 ', shellCommand: 'never', loader: 'x'.repeat(200) } }).profiles[0]; assert.equal(updated.components.firmware, '7.61'); assert.equal(updated.components.loader.length, 64); assert.equal(Object.prototype.hasOwnProperty.call(updated.components, 'shellCommand'), false); });