integrity: add stats

This commit is contained in:
Girish Ramakrishnan
2026-02-15 14:31:09 +01:00
parent 9f2eefcbb3
commit c7b321315c
4 changed files with 113 additions and 11 deletions
+96
View File
@@ -0,0 +1,96 @@
/* jslint node:true */
import backupIntegrity from '../backupintegrity.js';
import backups from '../backups.js';
import backupSites from '../backupsites.js';
import BoxError from '../boxerror.js';
import child_process from 'node:child_process';
import common from './common.js';
import expect from 'expect.js';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import tasks from '../tasks.js';
import timers from 'timers/promises';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
describe('backupintegrity', function () {
const { setup, cleanup, getDefaultBackupSite, auditSource } = common;
before(setup);
after(cleanup);
describe('check', function () {
const backupConfig = {
provider: 'filesystem',
backupDir: path.join(os.tmpdir(), 'backupintegrity-test-filesystem'),
};
let defaultBackupSite;
before(async function () {
fs.rmSync(backupConfig.backupDir, { recursive: true, force: true });
defaultBackupSite = await getDefaultBackupSite();
await backupSites.setConfig(defaultBackupSite, backupConfig, auditSource);
});
async function createBackup(site) {
const taskId = await backupSites.startBackupTask(site, auditSource);
while (true) {
await timers.setTimeout(1000);
const p = await tasks.get(taskId);
if (p.percent !== 100) continue;
if (p.error) throw new Error(`backup failed: taskId: ${taskId} ${p.error.message}`);
if (!p.result) throw new Error('backup has no result:' + p);
const result = await backups.listByIdentifierAndStatePaged(backups.BACKUP_IDENTIFIER_BOX, backups.BACKUP_STATE_NORMAL, 1, 1);
if (result.length !== 1) throw new Error('result is not of length 1');
// the task progress and the db entry is set in the worker. wait for 2 seconds for backup lock to get released in parent process
await timers.setTimeout(2000);
return result[0];
}
}
it('throws for missing backup id', async function () {
try {
await backupIntegrity.check('nonexistent-id', () => {});
expect().fail('expected BoxError');
} catch (err) {
expect(err).to.be.a(BoxError);
expect(err.reason).to.be(BoxError.BAD_FIELD);
expect(err.message).to.contain('Backup not found');
}
});
it('verifies backup integrity', async function () {
// arch only has maria db which lacks some mysqldump options we need, this is only here to allow running the tests :-/
if (child_process.execSync('/usr/bin/mysqldump --version').toString().indexOf('MariaDB') !== -1) {
console.log('test skipped because of MariaDB');
return;
}
const backup = await createBackup(defaultBackupSite);
const progressCalls = [];
await backupIntegrity.check(backup.id, (p) => { progressCalls.push(p); });
const updated = await backups.get(backup.id);
expect(updated.integrityCheckStatus).to.be('passed');
expect(updated.integrityCheckResult.messages).to.eql([]);
expect(updated.integrityCheckResult.stats).to.be.an('object');
});
it('cleanup', function () {
fs.rmSync(backupConfig.backupDir, { recursive: true, force: true });
});
});
});