diff --git a/src/backups.js b/src/backups.js index 53219c2bc..5ba9bb315 100644 --- a/src/backups.js +++ b/src/backups.js @@ -37,7 +37,8 @@ exports = module.exports = { // for testing _getBackupFilePath: getBackupFilePath, _restoreFsMetadata: restoreFsMetadata, - _saveFsMetadata: saveFsMetadata + _saveFsMetadata: saveFsMetadata, + _applyBackupRetentionPolicy: applyBackupRetentionPolicy }; var addons = require('./addons.js'), @@ -1256,6 +1257,7 @@ function ensureBackup(auditSource, callback) { }); } +// backups must be descending in creationTime function applyBackupRetentionPolicy(backups, policy) { assert(Array.isArray(backups)); assert.strictEqual(typeof policy, 'object'); @@ -1267,8 +1269,8 @@ function applyBackupRetentionPolicy(backups, policy) { if ((now - backup.creationTime) < (backup.preserveSecs * 1000)) { backup.keepReason = 'preserveSecs'; - } else if ((now - backup.creationTime) < (policy.keepWithinSecs * 1000)) { - backup.keepReason = 'withinSecs'; + } else if ((now - backup.creationTime < policy.keepWithinSecs * 1000) || policy.keepWithinSecs < 0) { + backup.keepReason = 'keepWithinSecs'; } } diff --git a/src/test/backups-test.js b/src/test/backups-test.js index c4fae1658..97dabec1c 100644 --- a/src/test/backups-test.js +++ b/src/test/backups-test.js @@ -17,6 +17,7 @@ var async = require('async'), fs = require('fs'), os = require('os'), mkdirp = require('mkdirp'), + moment = require('moment'), path = require('path'), rimraf = require('rimraf'), settings = require('../settings.js'), @@ -68,6 +69,69 @@ function cleanupBackups(callback) { }); } +describe('retention policy', function () { + it('always keeps if reason is set', function () { + let backup = { keepReason: 'somereason' }; + backups._applyBackupRetentionPolicy([backup], { keepWithinSecs: 1 }); + expect(backup.keepReason).to.be('somereason'); + }); + + it('always keeps forever policy', function () { + let backup = { creationTime: new Date() }; + backups._applyBackupRetentionPolicy([backup], { keepWithinSecs: -1 }); + expect(backup.keepReason).to.be('keepWithinSecs'); + }); + + it('preserveSecs takes precedence', function () { + let backup = { creationTime: new Date(), preserveSecs: 3000 }; + backups._applyBackupRetentionPolicy([backup], { keepWithinSecs: 1 }); + expect(backup.keepReason).to.be('preserveSecs'); + }); + + it('1 daily', function () { + let b = [ + { id: '1', creationTime: moment().toDate() }, + { id: '2', creationTime: moment().subtract(3, 'h').toDate() }, + { id: '3', creationTime: moment().subtract(20, 'h').toDate() }, + { id: '4', creationTime: moment().subtract(5, 'd').toDate() } + ]; + backups._applyBackupRetentionPolicy(b, { keepDaily: 1 }); + expect(b[0].keepReason).to.be('keepDaily'); + expect(b[1].keepReason).to.be(undefined); + expect(b[2].keepReason).to.be(undefined); + expect(b[3].keepReason).to.be(undefined); + }); + + it('2 daily, 1 weekly', function () { + let b = [ + { id: '1', creationTime: moment().toDate() }, + { id: '2', creationTime: moment().subtract(3, 'h').toDate() }, + { id: '3', creationTime: moment().subtract(26, 'h').toDate() }, + { id: '4', creationTime: moment().subtract(5, 'd').toDate() } + ]; + backups._applyBackupRetentionPolicy(b, { keepDaily: 2, keepWeekly: 1 }); + expect(b[0].keepReason).to.be('keepDaily'); // today + expect(b[1].keepReason).to.be('keepWeekly'); + expect(b[2].keepReason).to.be('keepDaily'); // yesterday + expect(b[3].keepReason).to.be(undefined); + }); + + it('2 daily, 6 monthly, 1 yearly', function () { + let b = [ + { id: '1', creationTime: moment().toDate() }, + { id: '2', creationTime: moment().subtract(3, 'h').toDate() }, + { id: '3', creationTime: moment().subtract(26, 'h').toDate() }, + { id: '4', creationTime: moment().subtract(5, 'd').toDate() } + ]; + backups._applyBackupRetentionPolicy(b, { keepDaily: 2, keepMonthly: 6, keepYearly: 1 }); + expect(b[0].keepReason).to.be('keepDaily'); // today + expect(b[1].keepReason).to.be('keepMonthly'); + expect(b[2].keepReason).to.be('keepDaily'); // yesterday + expect(b[3].keepReason).to.be('keepYearly'); + }); + +}); + describe('backups', function () { before(function (done) { const BACKUP_DIR = path.join(os.tmpdir(), 'cloudron-backup-test');