Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974
This commit is contained in:
commit
c737a37f71
531 files changed
+119270
No files matched your search
@@ -0,0 +1,87 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const test = require('node:test');
|
||||
const {
|
||||
SHADOWMOUNT_PLUS_PROFILE,
|
||||
createPs5ContentAdapterService,
|
||||
createPs5ContentSimulator,
|
||||
unavailableLiveAdapter,
|
||||
} = require('../../src/services/ps5-content-adapter-service');
|
||||
|
||||
const DIGEST = 'ab'.repeat(32);
|
||||
const artifact = kind => ({ kind, sourceRef: `library:item-${kind}`, fileName: kind === 'image' ? 'PPSA12345.ffpkg' : 'PPSA12345', sha256: DIGEST, size: 4096 });
|
||||
const volumeResolver = { resolve: async id => ({ id, adapterId: 'ShadowMountPlus', label: 'USB games', consoleRoots: ['/mnt/usb3'] }) };
|
||||
|
||||
test('simulator preserves transfer, stage, mount, register and verification as distinct states', async () => {
|
||||
const simulator = createPs5ContentSimulator();
|
||||
const service = createPs5ContentAdapterService({ adapter: simulator.adapter, volumeResolver, uuid: () => 'run-image', now: (() => { let n = 0; return () => ++n; })() });
|
||||
const result = await service.start({ titleId: 'PPSA12345', volumeId: 'usb-games', artifact: artifact('image') });
|
||||
assert.equal(result.state, 'verified');
|
||||
assert.deepEqual(result.history.map(item => item.state), ['planned', 'transferring', 'transferred', 'staging', 'staged', 'mounting', 'mounted', 'registering', 'registered', 'verifying', 'verified']);
|
||||
assert.deepEqual(simulator.calls, ['transfer', 'stage', 'mount', 'register', 'postMountVerify']);
|
||||
assert.equal(result.paths.transferPath, '/mnt/usb3/.chimera-transfer/PPSA12345/PPSA12345.ffpkg');
|
||||
assert.equal(result.paths.stagedPath, '/mnt/usb3/etaHEN/games/PPSA12345/PPSA12345.ffpkg');
|
||||
assert.equal(result.paths.mountPath, '/mnt/shadowmnt/PPSA12345_simulated');
|
||||
assert.equal('installed' in result, false);
|
||||
});
|
||||
|
||||
test('folder simulator uses the selected semantic volume and still requires post-mount verification', async () => {
|
||||
const simulator = createPs5ContentSimulator();
|
||||
const result = await createPs5ContentAdapterService({ adapter: simulator.adapter, volumeResolver }).start({ titleId: 'PPSA54321', volumeId: 'portable-library', artifact: artifact('folder') });
|
||||
assert.equal(result.state, 'verified');
|
||||
assert.match(result.paths.stagedPath, /^\/mnt\/usb3\/etaHEN\/games\/PPSA54321\//);
|
||||
assert.equal(result.paths.mountPath, result.paths.stagedPath);
|
||||
assert.ok(result.verificationEvidence);
|
||||
});
|
||||
|
||||
test('unavailable, unpinned and incomplete capability providers fail closed before mutation', async () => {
|
||||
const unavailable = createPs5ContentAdapterService({ adapter: unavailableLiveAdapter(), volumeResolver });
|
||||
assert.equal(unavailable.probe().compatible, false);
|
||||
await assert.rejects(unavailable.start({ titleId: 'PPSA12345', volumeId: 'usb-games', artifact: artifact('image') }), /unavailable or capability mismatch/i);
|
||||
|
||||
for (const probe of [
|
||||
{ version: '1.6test12' },
|
||||
{ revision: '00'.repeat(20) },
|
||||
{ capabilities: { semanticVolumePaths: true, transfer: true } },
|
||||
]) {
|
||||
const simulator = createPs5ContentSimulator({ probe });
|
||||
const service = createPs5ContentAdapterService({ adapter: simulator.adapter, volumeResolver });
|
||||
assert.equal(service.probe().compatible, false);
|
||||
await assert.rejects(service.start({ titleId: 'PPSA12345', volumeId: 'usb-games', artifact: artifact('image') }), new RegExp(SHADOWMOUNT_PLUS_PROFILE.id));
|
||||
assert.deepEqual(simulator.calls, []);
|
||||
}
|
||||
});
|
||||
|
||||
test('adapter-derived paths cannot escape the selected volume or use traversal', async () => {
|
||||
for (const derived of [
|
||||
{ transferPath: '/mnt/usb3/../system/PPSA12345.ffpkg', stagedPath: '/mnt/usb3/games/PPSA12345.ffpkg' },
|
||||
{ transferPath: '/mnt/usb3/incoming/PPSA12345.ffpkg', stagedPath: '/data/etaHEN/games/PPSA12345.ffpkg' },
|
||||
{ transferPath: 'relative/PPSA12345.ffpkg', stagedPath: '/mnt/usb3/games/PPSA12345.ffpkg' },
|
||||
]) {
|
||||
const simulator = createPs5ContentSimulator({ overrides: { derivePaths: () => derived } });
|
||||
await assert.rejects(
|
||||
createPs5ContentAdapterService({ adapter: simulator.adapter, volumeResolver }).start({ titleId: 'PPSA12345', volumeId: 'usb-games', artifact: artifact('image') }),
|
||||
/invalid|unsafe|outside/i,
|
||||
);
|
||||
assert.deepEqual(simulator.calls, []);
|
||||
}
|
||||
});
|
||||
|
||||
test('a timed-out adapter step stops before mount, register and verification', async () => {
|
||||
const simulator = createPs5ContentSimulator({ delayStep: 'stage', delayMs: 30 });
|
||||
const service = createPs5ContentAdapterService({ adapter: simulator.adapter, volumeResolver, timeoutMs: 5, uuid: () => 'run-timeout' });
|
||||
const result = await service.start({ titleId: 'PPSA12345', volumeId: 'usb-games', artifact: artifact('image') });
|
||||
assert.equal(result.state, 'needs_attention');
|
||||
assert.equal(result.failedStep, 'stage');
|
||||
assert.equal(result.error, 'timeout:stage');
|
||||
assert.deepEqual(simulator.calls, ['transfer', 'stage']);
|
||||
});
|
||||
|
||||
test('registration handoff alone never passes without exact post-mount evidence', async () => {
|
||||
const simulator = createPs5ContentSimulator({ overrides: { verifyPostMount: async input => ({ mounted: true, registered: false, titleId: input.titleId, mountPath: input.mountPath }) } });
|
||||
const result = await createPs5ContentAdapterService({ adapter: simulator.adapter, volumeResolver }).start({ titleId: 'PPSA12345', volumeId: 'usb-games', artifact: artifact('image') });
|
||||
assert.equal(result.state, 'needs_attention');
|
||||
assert.equal(result.failedStep, 'verifying');
|
||||
assert.match(result.error, /did not prove/);
|
||||
});
|
||||
Reference in new issue
Block a user