From 879bc3c37f1044871730f3aea066697eff3a104b Mon Sep 17 00:00:00 2001 From: Girish Ramakrishnan Date: Tue, 16 Jun 2015 12:00:46 -0700 Subject: [PATCH] test backup --- appstore.js | 24 +++--- cloudron.js | 27 +++++++ test/app-flow-test.js | 1 + test/cloudron-backup-test.js | 144 +++++++++++++++++++++++++++++++++++ test/cloudron-user-test.js | 1 + test/new-user-test.js | 1 + test/update-test.js | 1 + 7 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 test/cloudron-backup-test.js diff --git a/appstore.js b/appstore.js index e8e1854..8e94555 100644 --- a/appstore.js +++ b/appstore.js @@ -34,21 +34,14 @@ AppStore.prototype.setCredentials = function (password, accessToken) { this._credentials = { password: password, accessToken: accessToken }; }; -AppStore.prototype.createCloudron = function (box) { - var accessToken = this._credentials.accessToken; - var res = request.post(this._origin + '/api/v1/cloudrons').send(box).query({ accessToken: accessToken }).end(); - verifyResponse(res, 'Could not create cloudron'); - var boxId = res.body.box.id; - debug('Cloudron %s created'.green, box.name); - - ////////// wait for cloudron to come up +AppStore.prototype.waitForCloudron = function (boxId) { var creationTime = new Date(); process.stdout.write('Waiting for cloudron to come up.'); while (true) { sleep(10); process.stdout.write('.'); - res = request.get(this._origin + '/api/v1/cloudrons/' + boxId).query({ accessToken: accessToken }).end(); + var res = request.get(this._origin + '/api/v1/cloudrons/' + boxId).query({ accessToken: this._credentials.accessToken }).end(); verifyResponse(res, 'Could not query cloudron status'); if (res.body.box.status === 'ready') { @@ -58,12 +51,18 @@ AppStore.prototype.createCloudron = function (box) { } debug('Box created in %s minutes'.green, (new Date() - creationTime) / 60000); +}; +AppStore.prototype.createCloudron = function (box) { + var accessToken = this._credentials.accessToken; + var res = request.post(this._origin + '/api/v1/cloudrons').send(box).query({ accessToken: accessToken }).end(); + verifyResponse(res, 'Could not create cloudron'); + + debug('Cloudron %s created'.green, box.name); return res.body.box; }; AppStore.prototype.deleteCloudron = function (box) { - debug('Deleting cloudron'); var res = request.post(this._origin + '/api/v1/cloudrons/' + box.id) .query({ accessToken: this._credentials.accessToken }) .set('X-HTTP-Method-Override', 'DELETE') @@ -78,3 +77,8 @@ AppStore.prototype.getManifest = function (appId, version) { return res.body.manifest; }; +AppStore.prototype.restore = function (boxId, backupId) { + var res = request.post(this._origin + '/api/v1/cloudrons/' + boxId + '/restore/' + backupId).query({ accessToken: this._credentials.accessToken }).end(); + verifyResponse(res, 'Could not restore cloudron'); +}; + diff --git a/cloudron.js b/cloudron.js index c57bc9d..7777deb 100644 --- a/cloudron.js +++ b/cloudron.js @@ -199,3 +199,30 @@ Cloudron.prototype.resetPassword = function (resetToken, password) { verifyResponse(res, 'Could not setup password for user'); }; +Cloudron.prototype.backup = function () { + var res = request.get(this._origin + '/api/v1/backups').query({ access_token: this._credentials.accessToken }).end(); + verifyResponse(res, 'Could not get backups'); + + var existingBackups = res.body.backups; + console.dir(existingBackups); + + res = request.post(this._origin + '/api/v1/cloudron/backups').query({ access_token: this._credentials.accessToken }).end(); + verifyResponse(res, 'Could not schedule backup'); + + while (true) { + sleep(5); + res = request.get(this._origin + '/api/v1/cloudron/progress').end(); + if (res.body.backup === null || res.body.backup.percent === 100) { + debug('backup done'); + break; + } + debug('Backing up: %s %s', res.body.backup.percent, res.body.backup.message); + } + + res = request.get(this._origin + '/api/v1/backups').query({ access_token: this._credentials.accessToken }).end(); + verifyResponse(res, 'Could not get backups'); + var latestBackups = res.body.backups; + assert.strictEqual(latestBackups.length, existingBackups.length + 1); + return latestBackups[0]; // { creationTime, boxVersion, restoreKey, dependsOn } +}; + diff --git a/test/app-flow-test.js b/test/app-flow-test.js index c801d62..9eee44f 100644 --- a/test/app-flow-test.js +++ b/test/app-flow-test.js @@ -66,6 +66,7 @@ describe('Application flow test', function () { size: '512mb', version: latestVersion }); + appStore.waitForCloudron(box.id); cloudron = new Cloudron(box); }); diff --git a/test/cloudron-backup-test.js b/test/cloudron-backup-test.js new file mode 100644 index 0000000..f57e2cd --- /dev/null +++ b/test/cloudron-backup-test.js @@ -0,0 +1,144 @@ +#!/usr/bin/env node + +/* + * This tests a flow for the cloudron owner backs up a cloudron. + * The backup is validated and restored from. + */ + +'use strict'; + +var AppStore = require('../appstore.js'), + assert = require('assert'), + Cloudron = require('../cloudron.js'), + path = require('path'), + readlineSync = require('readline-sync'), + request = require('superagent-sync'), + semver = require('semver'), + util = require('util'); + +require('colors'); + +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + +function cloudronName() { + var r = (Math.random() * 1000).toFixed(); + return 't-' + path.basename(__filename, '-test.js') + '-' + r + '.smartserver.io'; +} + +function verifyResponse(res, errorMessage) { + if (res.statusCode < 200 || res.statusCode > 299) { + console.log('Response error statusCode:%s error:%s body:%s', res.statusCode, res.error, res.body); + console.log(errorMessage.red); + process.exit(1); + } +} + +describe('Cloudron backup testing', function () { + this.timeout(0); + + var appStore = new AppStore('https://api.staging.cloudron.io'); + + var owner = { + username: 'test', + password: 'test1234', + email: 'test@cloudron.io' + }; + + var res, latestVersion, cloudron, appId, box, backupInfo; + + it('can query versions', function () { + res = request.get('https://s3.amazonaws.com/staging-cloudron-releases/versions.json').end(); + verifyResponse(res); + var boxVersions = Object.keys(res.body).sort(semver.rcompare); + latestVersion = boxVersions[0]; + }); + + it('can login to the store', function () { + var accessToken = appStore.getAccessToken(owner); + appStore.setCredentials(owner.password, accessToken); + }); + + it('can create a cloudron', function () { + box = appStore.createCloudron({ + name: cloudronName(), + zoneName: 'smartserver.io', + region: 'sfo1', + size: '512mb', + version: latestVersion + }); + console.dir(box); + appStore.waitForCloudron(box.id); + cloudron = new Cloudron(box); + }); + + it('can activate the box', function () { + cloudron.activate(owner); + }); + + it('can login to the box', function () { + var token = cloudron.getOauthToken(owner); + cloudron.setCredentials(owner.password, token); + }); + + var location = 'test' + (Math.random() * 10000).toFixed(); + it('can install app', function () { + var manifest = appStore.getManifest('io.cloudron.testapp', '1.0.0'); + appId = cloudron.installApp(location, manifest); + }); + + it('can populate the addons', function () { + var res = request.post('https://' + location + '-' + box.domain + '/populate_addons').end(); + assert.strictEqual(res.statusCode, 200); + assert.strictEqual(res.body.mysql, 'OK'); + assert.strictEqual(res.body.postgresql, 'OK'); + assert.strictEqual(res.body.mongodb, 'OK'); + }); + + it('can check the addons', function () { + var res = request.post('https://' + location + '-' + box.domain + '/check_addons').end(); + assert.strictEqual(res.statusCode, 200); + assert.strictEqual(res.body.mysql, 'OK'); + assert.strictEqual(res.body.postgresql, 'OK'); + assert.strictEqual(res.body.mongodb, 'OK'); + }); + + it('can backup the box', function () { + backupInfo = cloudron.backup(); + assert.strictEqual(backupInfo.dependsOn.length, 1); + }); + + it('can restore the box', function () { + appStore.restore(box.id, backupInfo.restoreKey); + appStore.waitForCloudron(box.id); + }); + + it('wait for cloudron to be networked', function () { + sleep(30); // DO networking + }); + + it('can login to cloudron', function () { + var token = cloudron.getOauthToken(owner); + cloudron.setCredentials(owner.password, token); + }); + + it('wait for app', function () { + cloudron.waitForApp(appId); + }); + + it('can check the addons', function () { + var res = request.post('https://' + location + '-' + box.domain + '/check_addons').end(); + assert.strictEqual(res.statusCode, 200); + assert.strictEqual(res.body.mysql, 'OK'); + assert.strictEqual(res.body.postgresql, 'OK'); + assert.strictEqual(res.body.mongodb, 'OK'); + }); + + it('can uninstall app', function () { + cloudron.uninstallApp(appId); + }); + + it('can delete the cloudron', function () { + appStore.deleteCloudron(box); + }); +}); + diff --git a/test/cloudron-user-test.js b/test/cloudron-user-test.js index 273f363..2ca1353 100644 --- a/test/cloudron-user-test.js +++ b/test/cloudron-user-test.js @@ -67,6 +67,7 @@ describe('Cloudron user creation testing', function () { size: '512mb', version: latestVersion }); + appStore.waitForCloudron(box.id); cloudron = new Cloudron(box); }); diff --git a/test/new-user-test.js b/test/new-user-test.js index 677bae9..5cb1d61 100644 --- a/test/new-user-test.js +++ b/test/new-user-test.js @@ -67,6 +67,7 @@ describe('Appstore new user flow', function () { size: '512mb', version: latestVersion }); + appStore.waitForCloudron(box.id); cloudron = new Cloudron(box); }); diff --git a/test/update-test.js b/test/update-test.js index 1050e53..f2cfc31 100644 --- a/test/update-test.js +++ b/test/update-test.js @@ -70,6 +70,7 @@ describe('Cloudron update testing', function () { size: '512mb', version: fromVersion }); + appStore.waitForCloudron(box.id); cloudron = new Cloudron(box); });