/* global it:false */ /* global describe:false */ /* global before:false */ /* global after:false */ 'use strict'; const backupTargets = require('../../backuptargets.js'), common = require('./common.js'), expect = require('expect.js'), superagent = require('@cloudron/superagent'); const BACKUP_FOLDER = '/tmp/backup_test'; describe('Backups API', function () { const { setup, cleanup, waitForTask, serverUrl, owner } = common; before(setup); after(cleanup); describe('backup_policy', function () { const defaultPolicy = { retention: { keepWithinSecs: 2 * 24 * 60 * 60 }, // 2 days schedule: '00 00 23 * * *' // every day at 11pm }; it('cannot set backup_policy without schedule', async function () { const tmp = Object.assign({} , defaultPolicy); delete tmp.schedule; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy with invalid schedule', async function () { const tmp = Object.assign({} , defaultPolicy); tmp.schedule = 'not a pattern'; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy without retention', async function () { const tmp = Object.assign({} , defaultPolicy); delete tmp.retention; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy with invalid retention', async function () { const tmp = Object.assign({} , defaultPolicy); tmp.retention = 'not an object'; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy with empty retention', async function () { const tmp = Object.assign({} , defaultPolicy); tmp.retention = {}; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy with retention missing properties', async function () { const tmp = Object.assign({} , defaultPolicy); tmp.retention = { foo: 'bar' }; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy with retention with invalid keepWithinSecs', async function () { const tmp = Object.assign({} , defaultPolicy); tmp.retention = { keepWithinSecs: 'not a number' }; const response = await superagent.post(`${serverUrl}/api/v1/backups/policy`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); }); describe('backup_config', function () { // keep in sync with defaults in settings.js const defaultConfig = { provider: 'filesystem', backupFolder: '/var/backups', format: 'tgz', encryption: null, }; it('can get backup_config (default)', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backup_targets`) .query({ access_token: owner.token }); expect(response.status).to.equal(200); expect(response.body.config).to.eql(defaultConfig); expect(response.body.config).to.eql(defaultConfig); }); it('cannot set backup_config without provider', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); delete tmp.provider; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config with invalid provider', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.provider = 'invalid provider'; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config without format', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); delete tmp.format; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config with invalid format', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.format = 'invalid format'; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config with invalid password', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.password = 1234; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config with invalid syncConcurrency', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.limits = { syncConcurrency: 'not a number' }; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config with invalid syncConcurrency', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.limits = { syncConcurrency: 0 }; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_config with invalid acceptSelfSignedCerts', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.acceptSelfSignedCerts = 'not a boolean'; const response = await superagent.post(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(400); }); it('can set backup_config', async function () { const tmp = JSON.parse(JSON.stringify(defaultConfig)); tmp.format = 'rsync'; tmp.backupFolder = BACKUP_FOLDER; tmp.limits = { copyConcurrency: 34 }; const response = await superagent.post(`${serverUrl}/api/v1/backups/config/storage`) .query({ access_token: owner.token }) .send(tmp); expect(response.status).to.equal(200); }); it('can get backup_config', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backups/config`) .query({ access_token: owner.token }); expect(response.status).to.equal(200); expect(response.body.format).to.equal('rsync'); expect(response.body.backupFolder).to.equal(BACKUP_FOLDER); }); }); describe('create', function () { before(async function () { await backupTargets.setStorage({ provider: 'filesystem', backupFolder: '/tmp/backups', format: 'tgz', encryption: null, }); }); it('fails due to mising token', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backups/create`) .ok(() => true); expect(response.status).to.equal(401); }); it('fails due to wrong token', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backups/create`) .query({ access_token: 'randomtoken' }) .ok(() => true); expect(response.status).to.equal(401); }); it('succeeds', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backups/create`) .query({ access_token: owner.token }); expect(response.status).to.equal(202); expect(response.body.taskId).to.be.a('string'); await waitForTask(response.body.taskId); }); }); describe('list', function () { it('succeeds', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backups`) .query({ access_token: owner.token }); expect(response.status).to.equal(200); expect(response.body.backupTargets.length).to.be(1); }); }); describe('update', function () { let someBackup; before(async function () { const response = await superagent.get(`${serverUrl}/api/v1/backups`) .query({ access_token: owner.token }); expect(response.status).to.equal(200); expect(response.body.backupTargets.length).to.be(1); someBackup = response.body.backups[0]; }); it('fails for bad param', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backups/bad_id`) .query({ access_token: owner.token }) .send({ preserveSecs: 'not-a-number', label: 'some string' }) .ok(() => true); expect(response.status).to.equal(400); }); it('fails for unknown backup', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backups/bad_id`) .query({ access_token: owner.token }) .send({ preserveSecs: 30, label: 'NewOrleans' }) .ok(() => true); expect(response.status).to.equal(404); }); it('succeeds', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backups/${someBackup.id}`) .query({ access_token: owner.token }) .send({ preserveSecs: 30, label: 'NewOrleans' }); expect(response.status).to.equal(200); }); }); });