82 lines
4.4 KiB
JavaScript
82 lines
4.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 { createBackupReplicationService } = require('../../src/services/backup-replication-service');
|
|
|
|
test('backup replication copies core files and verifies every hash', async t => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-replication-'));
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
const backups = path.join(root, 'source', 'backups');
|
|
const target = path.join(root, 'target');
|
|
const tmp = path.join(root, 'tmp');
|
|
fs.mkdirSync(path.join(backups, 'save-vault'), { recursive: true });
|
|
fs.mkdirSync(target, { recursive: true });
|
|
fs.mkdirSync(tmp, { recursive: true });
|
|
fs.writeFileSync(path.join(backups, 'save-vault', 'PPSA00001.zip'), 'encrypted-save-data');
|
|
const service = createBackupReplicationService({ paths: { backups, tmp }, targetRoot: target, gameBackupsRoot: path.join(root, 'games') });
|
|
|
|
const result = await service.replicate({ label: 'Veilige test' });
|
|
assert.equal(result.phase, 'complete');
|
|
assert.equal(result.copiedFiles, 1);
|
|
assert.equal(service.list()[0].label, 'Veilige test');
|
|
const verified = await service.verify({ id: result.id });
|
|
assert.equal(verified.ok, true);
|
|
assert.equal(verified.files, 1);
|
|
const drill = await service.restoreDrill({ id: result.id });
|
|
assert.equal(drill.ok, true);
|
|
assert.equal(drill.ps5Modified, false);
|
|
assert.equal(drill.temporaryTargetRemoved, true);
|
|
assert.equal(fs.readdirSync(path.join(tmp, 'restore-drills')).length, 0);
|
|
const protection = service.status().protection;
|
|
assert.equal(protection.threeTwoOneSatisfied, false);
|
|
assert.equal(protection.copiesObserved, 2);
|
|
assert.equal(protection.immutableObserved, false);
|
|
assert.ok(protection.lastVerifiedAt);
|
|
assert.ok(protection.lastRestoreDrillAt);
|
|
assert.ok(Number.isFinite(protection.lastRestoreDrillDurationMs));
|
|
assert.ok(service.list()[0].lastRestoreDrillAt);
|
|
|
|
const copied = path.join(target, result.id, 'data', 'chimera-core', 'save-vault', 'PPSA00001.zip');
|
|
fs.appendFileSync(copied, 'tampered');
|
|
await assert.rejects(() => service.verify({ id: result.id }), /Bestandsgrootte|Hash wijkt af/);
|
|
});
|
|
|
|
test('replication retention keeps at least two valid snapshots and exposes immutable-target truthfully', async t => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-replication-retention-'));
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
const backups = path.join(root, 'backups'); const target = path.join(root, 'target'); const tmp = path.join(root, 'tmp');
|
|
for (const directory of [backups, target, tmp]) fs.mkdirSync(directory, { recursive: true });
|
|
fs.writeFileSync(path.join(backups, 'settings.json'), '{}');
|
|
const values = new Map([['backup.replicationRetentionEnabled', true], ['backup.replicationRetention', 2], ['backup.replicationMaxAgeDays', 180]]);
|
|
const settings = { get: (key, fallback) => values.has(key) ? values.get(key) : fallback, set: (key, value) => values.set(key, value) };
|
|
const service = createBackupReplicationService({ paths: { backups, tmp }, settings, targetRoot: target, gameBackupsRoot: path.join(root, 'games') });
|
|
await service.replicate({ label: 'one' });
|
|
await new Promise(resolve => setTimeout(resolve, 5));
|
|
await service.replicate({ label: 'two' });
|
|
await new Promise(resolve => setTimeout(resolve, 5));
|
|
const third = await service.replicate({ label: 'three' });
|
|
assert.equal(third.retention.removed, 1);
|
|
assert.equal(service.list().length, 2);
|
|
assert.equal(service.status().targetContract.immutable, false);
|
|
assert.equal(service.retentionPreview().retainedMinimum, 2);
|
|
});
|
|
|
|
test('backup replication refuses a target nested in its source', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-replication-unsafe-'));
|
|
try {
|
|
const backups = path.join(root, 'backups');
|
|
const target = path.join(backups, 'replication');
|
|
fs.mkdirSync(target, { recursive: true });
|
|
const service = createBackupReplicationService({ paths: { backups }, targetRoot: target, gameBackupsRoot: path.join(root, 'games') });
|
|
const status = service.status();
|
|
assert.equal(status.available, false);
|
|
assert.match(status.error, /mogen niet in elkaar liggen/);
|
|
} finally {
|
|
fs.rmSync(root, { recursive: true, force: true });
|
|
}
|
|
});
|