/* global it, describe, before, after */ 'use strict'; const backupSites = require('../../backupsites.js'), common = require('./common.js'), expect = require('expect.js'), superagent = require('@cloudron/superagent'); describe('Backups API', function () { const { setup, cleanup, waitForTask, serverUrl, owner, admin, getDefaultBackupSite } = common; before(setup); after(cleanup); const newSite = { provider: 'filesystem', name: 'NewSite', config: { backupDir: '/tmp/boxtest-newsite' }, format: 'tgz', retention: { keepWithinSecs: 60 * 60 }, schedule: '00 01 * * * *', contents: null }; const encryptedSite = { provider: 'filesystem', name: 'EncryptedSite', config: { backupDir: '/tmp/boxtest-encsite' }, format: 'rsync', retention: { keepMonthly: 60 }, schedule: '* 1 * * * *', contents: { exclude: [ 'thatapp' ] } }; describe('add', function () { it('fails as admin', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites`) .query({ access_token: admin.token }) .send(newSite) .ok(() => true); expect(response.status).to.equal(403); }); it('succeeds as owner', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites`) .query({ access_token: owner.token }) .send(newSite) .ok(() => true); expect(response.status).to.equal(200); newSite.id = response.body.id; }); it('succeeds with password', async function () { const tmp = Object.assign({}, encryptedSite, { encryptionPassword: 'deutsch-a1', encryptedFilenames: true }); const response = await superagent.post(`${serverUrl}/api/v1/backup_sites`) .query({ access_token: owner.token }) .send(tmp) .ok(() => true); expect(response.status).to.equal(200); encryptedSite.id = response.body.id; }); }); describe('list', function () { it('succeeds as admin', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backup_sites`) .query({ access_token: admin.token }); expect(response.status).to.equal(200); expect(response.body.backupSites.length).to.be(3); const tmp = response.body.backupSites.find(t => t.id === newSite.id); expect(tmp.provider).to.be(newSite.provider); expect(tmp.config).to.be.ok(); expect(tmp.format).to.be(newSite.format); expect(tmp.name).to.be(newSite.name); expect(tmp.primary).to.be(false); }); }); describe('get', function () { it('succeeds as admin', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backup_sites/${newSite.id}`) .query({ access_token: admin.token }); expect(response.status).to.equal(200); expect(response.body.provider).to.be(newSite.provider); expect(response.body.config).to.be.ok(); expect(response.body.format).to.be(newSite.format); expect(response.body.name).to.be(newSite.name); expect(response.body.primary).to.be(false); }); it('succeeds as admin (encrypted)', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backup_sites/${encryptedSite.id}`) .query({ access_token: admin.token }); expect(response.status).to.equal(200); expect(response.body.provider).to.be(encryptedSite.provider); expect(response.body.config).to.be.ok(); expect(response.body.format).to.be(encryptedSite.format); expect(response.body.name).to.be(encryptedSite.name); expect(response.body.primary).to.be(false); expect(response.body.encrypted).to.be(true); expect(response.body.encryptedFilenames).to.be(true); }); }); describe('schedule', function () { it('cannot set without schedule', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/schedule`) .query({ access_token: owner.token }) .send({}) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set invalid schedule', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/schedule`) .query({ access_token: owner.token }) .send({ schedule: 'whatever' }) .ok(() => true); expect(response.status).to.equal(400); }); it('can set "never" schedule', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/schedule`) .query({ access_token: owner.token }) .send({ schedule: 'never' }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.schedule).to.be('never'); }); it('can set valid schedule', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/schedule`) .query({ access_token: owner.token }) .send({ schedule: '00 00 3 * * *' }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.schedule).to.be('00 00 3 * * *'); }); }); describe('retention', function () { it('cannot set without retention', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/retention`) .query({ access_token: owner.token }) .send({}) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set invalid retention', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/retention`) .query({ access_token: owner.token }) .send({ retention: 'whatever' }) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set backup_policy with retention with invalid keepWithinSecs', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/retention`) .query({ access_token: owner.token }) .send({ retention: { keepWithinSecs: 'not a number' } }) .ok(() => true); expect(response.status).to.equal(400); }); it('can set valid retention', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/retention`) .query({ access_token: owner.token }) .send({ retention: { keepWithinSecs: 2 * 24 * 60 * 60 } }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.retention).to.eql({ keepWithinSecs: 2 * 24 * 60 * 60 }); }); }); describe('limits', function () { it('cannot set invalid limits', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/limits`) .query({ access_token: owner.token }) .send({ limits: 2 }) .ok(() => true); expect(response.status).to.equal(400); }); it('can set valid limits', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/limits`) .query({ access_token: owner.token }) .send({ limits: { syncConcurrency: 34 } }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.limits).to.eql({ syncConcurrency: 34 }); }); }); describe('contents', function () { it('cannot set invalid contents', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/contents`) .query({ access_token: owner.token }) .send({ contents: 'garbage' }) .ok(() => true); expect(response.status).to.equal(400); }); it('cannot set invalid include', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/contents`) .query({ access_token: owner.token }) .send({ contents: { include: 'something' } }) .ok(() => true); expect(response.status).to.equal(400); }); it('can set include', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/contents`) .query({ access_token: owner.token }) .send({ contents: { include: [ 'something' ]} }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.contents).to.eql({ include: [ 'something' ]}); }); it('can set exclude', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/contents`) .query({ access_token: owner.token }) .send({ contents: { exclude: [ 'something' ]} }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.contents).to.eql({ exclude: [ 'something' ] }); }); it('can set null', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/contents`) .query({ access_token: owner.token }) .send({ contents: null }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.contents).to.eql(null); }); }); describe('primary', function () { it('cannot set invalid id', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}xx/configure/primary`) .query({ access_token: owner.token }) .send({}) .ok(() => true); expect(response.status).to.equal(404); }); it('can set valid primary', async function () { const oldDefault = await getDefaultBackupSite(); const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/primary`) .query({ access_token: owner.token }) .send({}) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.primary).to.be(true); const result2 = await backupSites.get(oldDefault.id); expect(result2.primary).to.be(false); }); }); // at this point , newSite is the primary and the default one is not describe('del', function () { it('cannot delete invalid id', async function () { const response = await superagent.del(`${serverUrl}/api/v1/backup_sites/${newSite.id}xx`) .query({ access_token: owner.token }) .ok(() => true); expect(response.status).to.equal(404); }); it('cannot delete primary', async function () { const response = await superagent.del(`${serverUrl}/api/v1/backup_sites/${newSite.id}`) .query({ access_token: owner.token }) .ok(() => true); expect(response.status).to.equal(409); }); it('can delete non-primary', async function () { const result2 = (await backupSites.list(1, 10)).pop(); const response = await superagent.del(`${serverUrl}/api/v1/backup_sites/${result2.id}`) .query({ access_token: owner.token }) .ok(() => true); expect(response.status).to.equal(204); }); }); describe('config', function () { const someConfig = { backupDir: '/tmp/boxtest-someconfig', }; it('cannot set invalid config', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/config`) .query({ access_token: owner.token }) .send({ config: 32 }) .ok(() => true); expect(response.status).to.equal(400); }); it('can set valid config', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/configure/config`) .query({ access_token: owner.token }) .send({ config: someConfig }) .ok(() => true); expect(response.status).to.equal(200); const result = await backupSites.get(newSite.id); expect(result.config.backupDir).to.be(someConfig.backupDir); }); }); describe('mounting', function () { it('mount status', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backup_sites/${newSite.id}/status`) .query({ access_token: owner.token }); expect(response.status).to.equal(200); expect(response.body.state).to.be('active'); expect(response.body.message).to.be('Mounted'); }); it('remount', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/remount`) .query({ access_token: owner.token }) .send({}); expect(response.status).to.equal(202); }); }); describe('create', function () { it('succeeds', async function () { const response = await superagent.post(`${serverUrl}/api/v1/backup_sites/${newSite.id}/create_backup`) .query({ access_token: admin.token }); expect(response.status).to.equal(202); expect(response.body.taskId).to.be.a('string'); await waitForTask(response.body.taskId); }); }); });