app.portBindings and newManifest.tcpPorts may be null

This commit is contained in:
Girish Ramakrishnan
2015-07-20 00:09:47 -07:00
commit df9d321ac3
243 changed files with 42623 additions and 0 deletions

161
src/test/apps-test.js Normal file
View File

@@ -0,0 +1,161 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var appdb = require('../appdb.js'),
apps = require('../apps.js'),
AppsError = apps.AppsError,
async = require('async'),
config = require('../config.js'),
constants = require('../constants.js'),
database = require('../database.js'),
expect = require('expect.js');
describe('Apps', function () {
var APP_0 = {
id: 'appid-0',
appStoreId: 'appStoreId-0',
installationState: appdb.ISTATE_PENDING_INSTALL,
installationProgress: null,
runState: null,
location: 'some-location-0',
manifest: {
version: '0.1', dockerImage: 'docker/app0', healthCheckPath: '/', httpPort: 80, title: 'app0',
tcpPorts: {
PORT: {
description: 'this is a port that i expose',
containerPort: '1234'
}
}
},
httpPort: null,
containerId: null,
portBindings: { PORT: 5678 },
healthy: null,
accessRestriction: ''
};
before(function (done) {
async.series([
database.initialize,
database._clear,
appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.portBindings, APP_0.accessRestriction)
], done);
});
after(function (done) {
database._clear(done);
});
describe('validateHostname', function () {
it('does not allow admin subdomain', function () {
expect(apps._validateHostname(constants.ADMIN_LOCATION, 'cloudron.us')).to.be.an(Error);
});
it('cannot have >63 length subdomains', function () {
var s = '';
for (var i = 0; i < 64; i++) s += 's';
expect(apps._validateHostname(s, 'cloudron.us')).to.be.an(Error);
});
it('allows only alphanumerics and hypen', function () {
expect(apps._validateHostname('#2r', 'cloudron.us')).to.be.an(Error);
expect(apps._validateHostname('a%b', 'cloudron.us')).to.be.an(Error);
expect(apps._validateHostname('ab_', 'cloudron.us')).to.be.an(Error);
expect(apps._validateHostname('a.b', 'cloudron.us')).to.be.an(Error);
expect(apps._validateHostname('-ab', 'cloudron.us')).to.be.an(Error);
expect(apps._validateHostname('ab-', 'cloudron.us')).to.be.an(Error);
});
it('total length cannot exceed 255', function () {
var s = '';
for (var i = 0; i < (255 - 'cloudron.us'.length); i++) s += 's';
expect(apps._validateHostname(s, 'cloudron.us')).to.be.an(Error);
});
it('allow valid domains', function () {
expect(apps._validateHostname('a', 'cloudron.us')).to.be(null);
expect(apps._validateHostname('a0-x', 'cloudron.us')).to.be(null);
expect(apps._validateHostname('01', 'cloudron.us')).to.be(null);
});
});
describe('validatePortBindings', function () {
it('does not allow invalid host port', function () {
expect(apps._validatePortBindings({ port: -1 })).to.be.an(Error);
expect(apps._validatePortBindings({ port: 0 })).to.be.an(Error);
expect(apps._validatePortBindings({ port: 'text' })).to.be.an(Error);
expect(apps._validatePortBindings({ port: 65536 })).to.be.an(Error);
expect(apps._validatePortBindings({ port: 1024 })).to.be.an(Error);
});
it('does not allow ports not as part of manifest', function () {
expect(apps._validatePortBindings({ port: 1567 })).to.be.an(Error);
expect(apps._validatePortBindings({ port: 1567 }, { port3: null })).to.be.an(Error);
});
it('allows valid bindings', function () {
expect(apps._validatePortBindings({ port: 1025 }, { port: null })).to.be(null);
expect(apps._validatePortBindings({
port1: 4033,
port2: 3242,
port3: 1234
}, { port1: null, port2: null, port3: null })).to.be(null);
});
});
describe('getters', function () {
it('cannot get invalid app', function (done) {
apps.get('nope', function (error, app) {
expect(error).to.be.ok();
expect(error.reason).to.be(AppsError.NOT_FOUND);
done();
});
});
it('can get valid app', function (done) {
apps.get(APP_0.id, function (error, app) {
expect(error).to.be(null);
expect(app).to.be.ok();
expect(app.iconUrl).to.be(null);
expect(app.fqdn).to.eql(APP_0.location + '-' + config.fqdn());
done();
});
});
it('cannot getBySubdomain', function (done) {
apps.getBySubdomain('moang', function (error, app) {
expect(error).to.be.ok();
expect(error.reason).to.be(AppsError.NOT_FOUND);
done();
});
});
it('can getBySubdomain', function (done) {
apps.getBySubdomain(APP_0.location, function (error, app) {
expect(error).to.be(null);
expect(app).to.be.ok();
expect(app.iconUrl).to.eql(null);
expect(app.fqdn).to.eql(APP_0.location + '-' + config.fqdn());
done();
});
});
it('can getAll', function (done) {
apps.getAll(function (error, apps) {
expect(error).to.be(null);
expect(apps).to.be.an(Array);
expect(apps[0].id).to.be(APP_0.id);
expect(apps[0].iconUrl).to.be(null);
expect(apps[0].fqdn).to.eql(APP_0.location + '-' + config.fqdn());
done();
});
});
});
});

212
src/test/apptask-test.js Normal file
View File

@@ -0,0 +1,212 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var addons = require('../addons.js'),
appdb = require('../appdb.js'),
apptask = require('../apptask.js'),
config = require('../config.js'),
database = require('../database.js'),
expect = require('expect.js'),
fs = require('fs'),
net = require('net'),
nock = require('nock'),
paths = require('../paths.js'),
sysinfo = require('../sysinfo.js'),
_ = require('underscore');
var MANIFEST = {
"id": "io.cloudron.test",
"author": "The Presidents Of the United States Of America",
"title": "test title",
"description": "test description",
"tagline": "test rocks",
"website": "http://test.cloudron.io",
"contactEmail": "support@cloudron.io",
"version": "0.1.0",
"manifestVersion": 1,
"dockerImage": "girish/test:0.2.0",
"healthCheckPath": "/",
"httpPort": 7777,
"tcpPorts": {
"ECHO_SERVER_PORT": {
"title": "Echo Server Port",
"description": "Echo server",
"containerPort": 7778
}
},
"addons": {
"oauth": { },
"redis": { },
"mysql": { },
"postgresql": { }
}
};
var APP = {
id: 'appid',
appStoreId: 'appStoreId',
installationState: appdb.ISTATE_PENDING_INSTALL,
runState: null,
location: 'applocation',
manifest: MANIFEST,
containerId: null,
httpPort: 4567,
portBindings: null,
accessRestriction: '',
dnsRecordId: 'someDnsRecordId'
};
describe('apptask', function () {
before(function (done) {
config.set('version', '0.5.0');
database.initialize(function (error) {
expect(error).to.be(null);
appdb.add(APP.id, APP.appStoreId, APP.manifest, APP.location, APP.portBindings, APP.accessRestriction, done);
});
});
after(function (done) {
database._clear(done);
});
it('initializes succesfully', function (done) {
apptask.initialize(done);
});
it('free port', function (done) {
apptask._getFreePort(function (error, port) {
expect(error).to.be(null);
expect(port).to.be.a('number');
var client = net.connect(port);
client.on('connect', function () { done(new Error('Port is not free:' + port)); });
client.on('error', function (error) { done(); });
});
});
it('configure nginx correctly', function (done) {
apptask._configureNginx(APP, function (error) {
expect(fs.existsSync(paths.NGINX_APPCONFIG_DIR + '/' + APP.id + '.conf'));
// expect(error).to.be(null); // this fails because nginx cannot be restarted
done();
});
});
it('unconfigure nginx', function (done) {
apptask._unconfigureNginx(APP, function (error) {
expect(!fs.existsSync(paths.NGINX_APPCONFIG_DIR + '/' + APP.id + '.conf'));
// expect(error).to.be(null); // this fails because nginx cannot be restarted
done();
});
});
it('create volume', function (done) {
apptask._createVolume(APP, function (error) {
expect(fs.existsSync(paths.DATA_DIR + '/' + APP.id + '/data')).to.be(true);
expect(error).to.be(null);
done();
});
});
it('delete volume', function (done) {
apptask._deleteVolume(APP, function (error) {
expect(!fs.existsSync(paths.DATA_DIR + '/' + APP.id + '/data')).to.be(true);
expect(error).to.be(null);
done();
});
});
it('allocate OAuth credentials', function (done) {
addons._allocateOAuthCredentials(APP, function (error) {
expect(error).to.be(null);
done();
});
});
it('remove OAuth credentials', function (done) {
addons._removeOAuthCredentials(APP, function (error) {
expect(error).to.be(null);
done();
});
});
it('remove OAuth credentials twice succeeds', function (done) {
addons._removeOAuthCredentials(APP, function (error) {
expect(!error).to.be.ok();
done();
});
});
it('barfs on empty manifest', function (done) {
var badApp = _.extend({ }, APP);
badApp.manifest = { };
apptask._verifyManifest(badApp, function (error) {
expect(error).to.be.ok();
done();
});
});
it('barfs on bad manifest', function (done) {
var badApp = _.extend({ }, APP);
badApp.manifest = _.extend({ }, APP.manifest);
delete badApp.manifest['id'];
apptask._verifyManifest(badApp, function (error) {
expect(error).to.be.ok();
done();
});
});
it('barfs on incompatible manifest', function (done) {
var badApp = _.extend({ }, APP);
badApp.manifest = _.extend({ }, APP.manifest);
badApp.manifest.maxBoxVersion = '0.0.0'; // max box version is too small
apptask._verifyManifest(badApp, function (error) {
expect(error).to.be.ok();
done();
});
});
it('verifies manifest', function (done) {
var goodApp = _.extend({ }, APP);
apptask._verifyManifest(goodApp, function (error) {
expect(error).to.be(null);
done();
});
});
it('registers subdomain', function (done) {
nock.cleanAll();
var scope = nock(config.apiServerOrigin())
.post('/api/v1/subdomains?token=' + config.token(), { records: [ { subdomain: APP.location, type: 'A', value: sysinfo.getIp() } ] })
.reply(201, { ids: [ APP.dnsRecordId ] });
apptask._registerSubdomain(APP, function (error) {
expect(error).to.be(null);
expect(scope.isDone()).to.be.ok();
done();
});
});
it('unregisters subdomain', function (done) {
nock.cleanAll();
var scope = nock(config.apiServerOrigin())
.delete('/api/v1/subdomains/' + APP.dnsRecordId + '?token=' + config.token())
.reply(204, {});
apptask._unregisterSubdomain(APP, function (error) {
expect(error).to.be(null);
expect(scope.isDone()).to.be.ok();
done();
});
});
});

58
src/test/checkInstall Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/bash
set -eu
readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# reset sudo timestamp to avoid wrong success
sudo -k || sudo --reset-timestamp
# checks if all scripts are sudo access
scripts=("${SOURCE_DIR}/scripts/rmappdir.sh" \
"${SOURCE_DIR}/scripts/createappdir.sh" \
"${SOURCE_DIR}/scripts/reloadnginx.sh" \
"${SOURCE_DIR}/scripts/backupbox.sh" \
"${SOURCE_DIR}/scripts/backupapp.sh" \
"${SOURCE_DIR}/scripts/restoreapp.sh" \
"${SOURCE_DIR}/scripts/reboot.sh" \
"${SOURCE_DIR}/scripts/backupswap.sh" \
"${SOURCE_DIR}/scripts/reloadcollectd.sh")
for script in "${scripts[@]}"; do
if [[ $(sudo -n "${script}" --check 2>/dev/null) != "OK" ]]; then
echo ""
echo "${script} does not have sudo access."
echo "You have to add the lines below to /etc/sudoers.d/yellowtent."
echo ""
echo "Defaults!${script} env_keep=\"HOME NODE_ENV\""
echo "${USER} ALL=(ALL) NOPASSWD: ${script}"
echo ""
exit 1
fi
done
if ! docker inspect girish/test:0.2.0 >/dev/null 2>/dev/null; then
echo "docker pull girish/test:0.2.0 for tests to run"
exit 1
fi
if ! docker inspect cloudron/redis:0.3.0 >/dev/null 2>/dev/null; then
echo "docker pull cloudron/redis:0.3.0 for tests to run"
exit 1
fi
if ! docker inspect cloudron/mysql:0.3.0 >/dev/null 2>/dev/null; then
echo "docker pull cloudron/mysql:0.3.0 for tests to run"
exit 1
fi
if ! docker inspect cloudron/postgresql:0.3.0 >/dev/null 2>/dev/null; then
echo "docker pull cloudron/postgresql:0.3.0 for tests to run"
exit 1
fi
if ! docker inspect cloudron/mongodb:0.3.0 >/dev/null 2>/dev/null; then
echo "docker pull cloudron/mongodb:0.3.0 for tests to run"
exit 1
fi

95
src/test/config-test.js Normal file
View File

@@ -0,0 +1,95 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global after:false */
/* global before:false */
'use strict';
var constants = require('../constants.js'),
expect = require('expect.js'),
fs = require('fs'),
path = require('path');
var config = null;
describe('config', function () {
before(function () {
delete require.cache[require.resolve('../config.js')];
config = require('../config.js');
});
after(function () {
delete require.cache[require.resolve('../config.js')];
});
it('baseDir() is set', function (done) {
expect(config.baseDir()).to.be.ok();
done();
});
it('cloudron.conf generated automatically', function (done) {
expect(fs.existsSync(path.join(config.baseDir(), 'configs/cloudron.conf'))).to.be.ok();
done();
});
it('did set default values', function () {
expect(config.isCustomDomain()).to.equal(false);
expect(config.fqdn()).to.equal('localhost');
expect(config.adminOrigin()).to.equal('https://' + constants.ADMIN_LOCATION + '-localhost');
expect(config.appFqdn('app')).to.equal('app-localhost');
expect(config.zoneName()).to.equal('localhost');
});
it('set saves value in file', function (done) {
config.set('foobar', 'somevalue');
expect(JSON.parse(fs.readFileSync(path.join(config.baseDir(), 'configs/cloudron.conf'))).foobar).to.eql('somevalue');
done();
});
it('set - simple key value', function (done) {
config.set('foobar', 'somevalue2');
expect(config.get('foobar')).to.eql('somevalue2');
done();
});
it('set - object', function (done) {
config.set( { fqdn: 'something.com' } );
expect(config.fqdn()).to.eql('something.com');
done();
});
it('uses dotted locations with custom domain', function () {
config.set('fqdn', 'example.com');
config.set('isCustomDomain', true);
expect(config.isCustomDomain()).to.equal(true);
expect(config.fqdn()).to.equal('example.com');
expect(config.adminOrigin()).to.equal('https://' + constants.ADMIN_LOCATION + '.example.com');
expect(config.appFqdn('app')).to.equal('app.example.com');
expect(config.zoneName()).to.equal('example.com');
});
it('uses hyphen locations with non-custom domain', function () {
config.set('fqdn', 'test.example.com');
config.set('isCustomDomain', false);
expect(config.isCustomDomain()).to.equal(false);
expect(config.fqdn()).to.equal('test.example.com');
expect(config.adminOrigin()).to.equal('https://' + constants.ADMIN_LOCATION + '-test.example.com');
expect(config.appFqdn('app')).to.equal('app-test.example.com');
expect(config.zoneName()).to.equal('example.com');
});
it('can set arbitrary values', function (done) {
config.set('random', 'value');
expect(config.get('random')).to.equal('value');
config.set('this.is.madness', 42);
expect(config.get('this.is.madness')).to.equal(42);
done();
});
});

933
src/test/database-test.js Normal file
View File

@@ -0,0 +1,933 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var appdb = require('../appdb.js'),
authcodedb = require('../authcodedb.js'),
clientdb = require('../clientdb.js'),
hat = require('hat'),
database = require('../database'),
DatabaseError = require('../databaseerror.js'),
expect = require('expect.js'),
async = require('async'),
settingsdb = require('../settingsdb.js'),
tokendb = require('../tokendb.js'),
userdb = require('../userdb.js');
describe('database', function () {
before(function (done) {
async.series([
database.initialize,
database._clear
], done);
});
after(function (done) {
database._clear(done);
});
describe('userdb', function () {
var USER_0 = {
id: 'uuid213',
username: 'uuid213',
password: 'secret',
email: 'safe@me.com',
admin: false,
salt: 'morton',
createdAt: 'sometime back',
modifiedAt: 'now',
resetToken: hat(256)
};
var ADMIN_0 = {
id: 'uuid456',
username: 'uuid456',
password: 'secret',
email: 'safe2@me.com',
admin: true,
salt: 'tata',
createdAt: 'sometime back',
modifiedAt: 'now',
resetToken: ''
};
it('can add user', function (done) {
userdb.add(USER_0.id, USER_0, function (error) {
expect(!error).to.be.ok();
done();
});
});
it('can add admin user', function (done) {
userdb.add(ADMIN_0.id, ADMIN_0, function (error) {
expect(!error).to.be.ok();
done();
});
});
it('cannot add same user again', function (done) {
userdb.add(USER_0.id, USER_0, function (error) {
expect(error).to.be.ok();
expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS);
done();
});
});
it('can get by user id', function (done) {
userdb.get(USER_0.id, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get by user name', function (done) {
userdb.getByUsername(USER_0.username, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get by email', function (done) {
userdb.getByEmail(USER_0.email, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get by resetToken fails for empty resetToken', function (done) {
userdb.getByResetToken('', function (error, user) {
expect(error).to.be.ok();
expect(error.reason).to.be(DatabaseError.INTERNAL_ERROR);
expect(user).to.not.be.ok();
done();
});
});
it('can get by resetToken', function (done) {
userdb.getByResetToken(USER_0.resetToken, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get all', function (done) {
userdb.getAll(function (error, all) {
expect(error).to.not.be.ok();
expect(all.length).to.equal(2);
expect(all[0]).to.eql(USER_0);
expect(all[1]).to.eql(ADMIN_0);
done();
});
});
it('can get all admins', function (done) {
userdb.getAllAdmins(function (error, all) {
expect(error).to.not.be.ok();
expect(all.length).to.equal(1);
expect(all[0]).to.eql(ADMIN_0);
done();
});
});
it('counts the users', function (done) {
userdb.count(function (error, count) {
expect(error).to.not.be.ok();
expect(count).to.equal(2);
done();
});
});
it('counts the admin users', function (done) {
userdb.adminCount(function (error, count) {
expect(error).to.not.be.ok();
expect(count).to.equal(1);
done();
});
});
it('can update the user', function (done) {
userdb.update(USER_0.id, { email: 'some@thing.com' }, function (error) {
expect(error).to.not.be.ok();
userdb.get(USER_0.id, function (error, user) {
expect(user.email).to.equal('some@thing.com');
done();
});
});
});
it('cannot update with null field', function (done) {
userdb.update(USER_0.id, { email: null }, function (error) {
expect(error).to.be.ok();
done();
});
});
it('cannot del non-existing user', function (done) {
userdb.del(USER_0.id + USER_0.id, function (error) {
expect(error).to.be.ok();
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
done();
});
});
it('can del existing user', function (done) {
userdb.del(USER_0.id, function (error) {
expect(error).to.not.be.ok();
done();
});
});
it('did remove the user', function (done) {
userdb.count(function (error, count) {
expect(count).to.equal(1);
done();
});
});
it('can clear table', function (done) {
userdb._clear(function (error) {
expect(error).to.not.be.ok();
userdb.count(function (error, count) {
expect(error).to.not.be.ok();
expect(count).to.equal(0);
done();
});
});
});
});
describe('authcode', function () {
var AUTHCODE_0 = {
authCode: 'authcode-0',
clientId: 'clientid-0',
userId: 'userid-0',
expiresAt: Date.now() + 5000
};
var AUTHCODE_1 = {
authCode: 'authcode-1',
clientId: 'clientid-1',
userId: 'userid-1',
expiresAt: Date.now() + 5000
};
var AUTHCODE_2 = {
authCode: 'authcode-2',
clientId: 'clientid-2',
userId: 'userid-2',
expiresAt: Date.now()
};
it('add fails due to missing arguments', function () {
expect(function () { authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId); }).to.throwError();
expect(function () { authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, function () {}); }).to.throwError();
expect(function () { authcodedb.add(AUTHCODE_0.authCode, function () {}); }).to.throwError();
});
it('add succeeds', function (done) {
authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId, AUTHCODE_0.expiresAt, function (error) {
expect(error).to.be(null);
done();
});
});
it('add of same authcode fails', function (done) {
authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId, AUTHCODE_0.expiresAt, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS);
done();
});
});
it('get succeeds', function (done) {
authcodedb.get(AUTHCODE_0.authCode, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(AUTHCODE_0);
done();
});
});
it('get of nonexisting code fails', function (done) {
authcodedb.get(AUTHCODE_1.authCode, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
it('get of expired code fails', function (done) {
authcodedb.add(AUTHCODE_2.authCode, AUTHCODE_2.clientId, AUTHCODE_2.userId, AUTHCODE_2.expiresAt, function (error) {
expect(error).to.be(null);
authcodedb.get(AUTHCODE_2.authCode, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
});
it('delExpired succeeds', function (done) {
authcodedb.delExpired(function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.eql(1);
authcodedb.get(AUTHCODE_2.authCode, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
});
it('delete succeeds', function (done) {
authcodedb.del(AUTHCODE_0.authCode, function (error) {
expect(error).to.be(null);
done();
});
});
it('cannot delete previously delete record', function (done) {
authcodedb.del(AUTHCODE_0.authCode, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
done();
});
});
});
describe('token', function () {
var TOKEN_0 = {
accessToken: tokendb.generateToken(),
identifier: tokendb.PREFIX_USER + '0',
clientId: 'clientid-0',
expires: Date.now() + 60 * 60000,
scope: '*'
};
var TOKEN_1 = {
accessToken: tokendb.generateToken(),
identifier: tokendb.PREFIX_USER + '1',
clientId: 'clientid-1',
expires: Number.MAX_SAFE_INTEGER,
scope: '*'
};
var TOKEN_2 = {
accessToken: tokendb.generateToken(),
identifier: tokendb.PREFIX_USER + '2',
clientId: 'clientid-2',
expires: Date.now(),
scope: '*'
};
it('add fails due to missing arguments', function () {
expect(function () { tokendb.add(TOKEN_0.accessToken, TOKEN_0.identifier, TOKEN_0.clientId, TOKEN_0.scope); }).to.throwError();
expect(function () { tokendb.add(TOKEN_0.accessToken, TOKEN_0.identifier, TOKEN_0.clientId, function () {}); }).to.throwError();
expect(function () { tokendb.add(TOKEN_0.accessToken, TOKEN_0.identifier, function () {}); }).to.throwError();
expect(function () { tokendb.add(TOKEN_0.accessToken, function () {}); }).to.throwError();
});
it('add succeeds', function (done) {
tokendb.add(TOKEN_0.accessToken, TOKEN_0.identifier, TOKEN_0.clientId, TOKEN_0.expires, TOKEN_0.scope, function (error) {
expect(error).to.be(null);
done();
});
});
it('add of same token fails', function (done) {
tokendb.add(TOKEN_0.accessToken, TOKEN_0.identifier, TOKEN_0.clientId, TOKEN_0.expires, TOKEN_0.scope, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS);
done();
});
});
it('get succeeds', function (done) {
tokendb.get(TOKEN_0.accessToken, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(TOKEN_0);
done();
});
});
it('get of nonexisting token fails', function (done) {
tokendb.get(TOKEN_1.accessToken, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
it('getByIdentifier succeeds', function (done) {
tokendb.getByIdentifier(TOKEN_0.identifier, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.equal(1);
expect(result[0]).to.be.an('object');
expect(result[0]).to.be.eql(TOKEN_0);
done();
});
});
it('delete succeeds', function (done) {
tokendb.del(TOKEN_0.accessToken, function (error) {
expect(error).to.be(null);
done();
});
});
it('getByIdentifier succeeds after token deletion', function (done) {
tokendb.getByIdentifier(TOKEN_0.identifier, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.equal(0);
done();
});
});
it('delByIdentifier succeeds', function (done) {
tokendb.add(TOKEN_1.accessToken, TOKEN_1.identifier, TOKEN_1.clientId, TOKEN_1.expires, TOKEN_1.scope, function (error) {
expect(error).to.be(null);
tokendb.delByIdentifier(TOKEN_1.identifier, function (error) {
expect(error).to.be(null);
done();
});
});
});
it('cannot delete previously delete record', function (done) {
tokendb.del(TOKEN_0.accessToken, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
done();
});
});
it('getByIdentifierAndClientId succeeds', function (done) {
tokendb.add(TOKEN_0.accessToken, TOKEN_0.identifier, TOKEN_0.clientId, TOKEN_0.expires, TOKEN_0.scope, function (error) {
expect(error).to.be(null);
tokendb.getByIdentifierAndClientId(TOKEN_0.identifier, TOKEN_0.clientId, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.equal(1);
expect(result[0]).to.eql(TOKEN_0);
done();
});
});
});
it('delExpired succeeds', function (done) {
tokendb.add(TOKEN_2.accessToken, TOKEN_2.identifier, TOKEN_2.clientId, TOKEN_2.expires, TOKEN_2.scope, function (error) {
expect(error).to.be(null);
tokendb.delExpired(function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.eql(1);
tokendb.get(TOKEN_2.accessToken, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
});
});
it('delByIdentifierAndClientId succeeds', function (done) {
tokendb.delByIdentifierAndClientId(TOKEN_0.identifier, TOKEN_0.clientId, function (error) {
expect(error).to.be(null);
done();
});
});
it('get of previously deleted token fails', function (done) {
tokendb.get(TOKEN_0.accessToken, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
});
describe('app', function () {
var APP_0 = {
id: 'appid-0',
appStoreId: 'appStoreId-0',
dnsRecordId: null,
installationState: appdb.ISTATE_PENDING_INSTALL,
installationProgress: null,
runState: null,
location: 'some-location-0',
manifest: { version: '0.1', dockerImage: 'docker/app0', healthCheckPath: '/', httpPort: 80, title: 'app0' },
httpPort: null,
containerId: null,
portBindings: { port: 5678 },
health: null,
accessRestriction: '',
lastBackupId: null,
lastBackupConfig: null,
oldConfig: null
};
var APP_1 = {
id: 'appid-1',
appStoreId: 'appStoreId-1',
dnsRecordId: null,
installationState: appdb.ISTATE_PENDING_INSTALL, // app health tests rely on this initial state
installationProgress: null,
runState: null,
location: 'some-location-1',
manifest: { version: '0.2', dockerImage: 'docker/app1', healthCheckPath: '/', httpPort: 80, title: 'app1' },
httpPort: null,
containerId: null,
portBindings: { },
health: null,
accessRestriction: 'roleAdmin',
lastBackupId: null,
lastBackupConfig: null,
oldConfig: null
};
it('add fails due to missing arguments', function () {
expect(function () { appdb.add(APP_0.id, APP_0.manifest, APP_0.installationState, function () {}); }).to.throwError();
expect(function () { appdb.add(APP_0.id, function () {}); }).to.throwError();
});
it('exists returns false', function (done) {
appdb.exists(APP_0.id, function (error, exists) {
expect(error).to.be(null);
expect(exists).to.be(false);
done();
});
});
it('add succeeds', function (done) {
appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.portBindings, APP_0.accessRestriction, function (error) {
expect(error).to.be(null);
done();
});
});
it('exists succeeds', function (done) {
appdb.exists(APP_0.id, function (error, exists) {
expect(error).to.be(null);
expect(exists).to.be(true);
done();
});
});
it('getPortBindings succeeds', function (done) {
appdb.getPortBindings(APP_0.id, function (error, bindings) {
expect(error).to.be(null);
expect(bindings).to.be.an(Object);
expect(bindings).to.be.eql({ port: '5678' });
done();
});
});
it('add of same app fails', function (done) {
appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, [ ], APP_0.accessRestriction, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS);
done();
});
});
it('get succeeds', function (done) {
appdb.get(APP_0.id, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(APP_0);
done();
});
});
it('get of nonexisting code fails', function (done) {
appdb.get(APP_1.id, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
it('update succeeds', function (done) {
APP_0.installationState = 'some-other-status';
APP_0.location = 'some-other-location';
APP_0.manifest.version = '0.2';
APP_0.accessRestriction = true;
APP_0.httpPort = 1337;
appdb.update(APP_0.id, { installationState: APP_0.installationState, location: APP_0.location, manifest: APP_0.manifest, accessRestriction: APP_0.accessRestriction, httpPort: APP_0.httpPort }, function (error) {
expect(error).to.be(null);
appdb.get(APP_0.id, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(APP_0);
done();
});
});
});
it('getByHttpPort succeeds', function (done) {
appdb.getByHttpPort(APP_0.httpPort, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(APP_0);
done();
});
});
it('update of nonexisting app fails', function (done) {
appdb.update(APP_1.id, { installationState: APP_1.installationState, location: APP_1.location }, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
done();
});
});
it('add second app succeeds', function (done) {
appdb.add(APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, [ ], APP_1.accessRestriction, function (error) {
expect(error).to.be(null);
done();
});
});
it('getAll succeeds', function (done) {
appdb.getAll(function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.be(2);
expect(result[0]).to.be.eql(APP_0);
expect(result[1]).to.be.eql(APP_1);
done();
});
});
it('getAppStoreIds succeeds', function (done) {
appdb.getAppStoreIds(function (error, results) {
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(2);
expect(results[0].appStoreId).to.equal(APP_0.appStoreId);
expect(results[1].appStoreId).to.equal(APP_1.appStoreId);
done();
});
});
it('delete succeeds', function (done) {
appdb.del(APP_0.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('getPortBindings should be empty', function (done) {
appdb.getPortBindings(APP_0.id, function (error, bindings) {
expect(error).to.be(null);
expect(bindings).to.be.an(Object);
expect(bindings).to.be.eql({ });
done();
});
});
it('cannot delete previously delete record', function (done) {
appdb.del(APP_0.id, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.be(DatabaseError.NOT_FOUND);
done();
});
});
it('cannot set app as healthy because app is not installed', function (done) {
appdb.setHealth(APP_1.id, appdb.HEALTH_HEALTHY, function (error) {
expect(error).to.be.ok();
done();
});
});
it('cannot set app as healthy because app has pending run state', function (done) {
appdb.update(APP_1.id, { runState: appdb.RSTATE_PENDING_STOP, installationState: appdb.ISTATE_INSTALLED }, function (error) {
expect(error).to.be(null);
appdb.setHealth(APP_1.id, appdb.HEALTH_HEALTHY, function (error) {
expect(error).to.be.ok();
done();
});
});
});
it('cannot set app as healthy because app has null run state', function (done) {
appdb.update(APP_1.id, { runState: null, installationState: appdb.ISTATE_INSTALLED }, function (error) {
expect(error).to.be(null);
appdb.setHealth(APP_1.id, appdb.HEALTH_HEALTHY, function (error) {
expect(error).to.be.ok();
done();
});
});
});
it('can set app as healthy when installed and no pending runState', function (done) {
appdb.update(APP_1.id, { runState: appdb.RSTATE_RUNNING, installationState: appdb.ISTATE_INSTALLED }, function (error) {
expect(error).to.be(null);
appdb.setHealth(APP_1.id, appdb.HEALTH_HEALTHY, function (error) {
expect(error).to.be(null);
appdb.get(APP_1.id, function (error, app) {
expect(error).to.be(null);
expect(app.health).to.be(appdb.HEALTH_HEALTHY);
done();
});
});
});
});
it('cannot set health of unknown app', function (done) {
appdb.setHealth('randomId', appdb.HEALTH_HEALTHY, function (error) {
expect(error).to.be.ok();
done();
});
});
it('return empty addon config array for invalid app', function (done) {
appdb.getAddonConfigByAppId('randomid', function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ ]);
done();
});
});
it('setAddonConfig succeeds', function (done) {
appdb.setAddonConfig(APP_1.id, 'addonid1', [ 'ENV1=env', 'ENV2=env' ], function (error) {
expect(error).to.be(null);
done();
});
});
it('setAddonConfig succeeds', function (done) {
appdb.setAddonConfig(APP_1.id, 'addonid2', [ 'ENV3=env' ], function (error) {
expect(error).to.be(null);
done();
});
});
it('getAddonConfig succeeds', function (done) {
appdb.getAddonConfig(APP_1.id, 'addonid1', function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ 'ENV1=env', 'ENV2=env' ]);
done();
});
});
it('getAddonConfigByAppId succeeds', function (done) {
appdb.getAddonConfigByAppId(APP_1.id, function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ 'ENV1=env', 'ENV2=env', 'ENV3=env' ]);
done();
});
});
it('unsetAddonConfig succeeds', function (done) {
appdb.unsetAddonConfig(APP_1.id, 'addonid1', function (error) {
expect(error).to.be(null);
done();
});
});
it('unsetAddonConfig did remove configs', function (done) {
appdb.getAddonConfigByAppId(APP_1.id, function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ 'ENV3=env' ]);
done();
});
});
it('unsetAddonConfigByAppId succeeds', function (done) {
appdb.unsetAddonConfigByAppId(APP_1.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('unsetAddonConfigByAppId did remove configs', function (done) {
appdb.getAddonConfigByAppId(APP_1.id, function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ ]);
done();
});
});
});
describe('client', function () {
var CLIENT_0 = {
id: 'cid-0',
appId: 'someappid_0',
clientSecret: 'secret-0',
redirectURI: 'http://foo.bar',
scope: '*'
};
var CLIENT_1 = {
id: 'cid-1',
appId: 'someappid_1',
clientSecret: 'secret-',
redirectURI: 'http://foo.bar',
scope: '*'
};
var CLIENT_2 = {
id: 'cid-2',
appId: 'someappid_2',
clientSecret: 'secret-2',
redirectURI: 'http://foo.bar.baz',
scope: 'profile,roleUser'
};
it('add succeeds', function (done) {
clientdb.add(CLIENT_0.id, CLIENT_0.appId, CLIENT_0.clientSecret, CLIENT_0.redirectURI, CLIENT_0.scope, function (error) {
expect(error).to.be(null);
clientdb.add(CLIENT_1.id, CLIENT_1.appId, CLIENT_1.clientSecret, CLIENT_1.redirectURI, CLIENT_1.scope, function (error) {
expect(error).to.be(null);
done();
});
});
});
it('add same client id fails', function (done) {
clientdb.add(CLIENT_0.id, CLIENT_0.appId, CLIENT_0.clientSecret, CLIENT_0.redirectURI, CLIENT_0.scope, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.equal(DatabaseError.ALREADY_EXISTS);
done();
});
});
it('get succeeds', function (done) {
clientdb.get(CLIENT_0.id, function (error, result) {
expect(error).to.be(null);
expect(result).to.eql(CLIENT_0);
done();
});
});
it('getByAppId succeeds', function (done) {
clientdb.getByAppId(CLIENT_0.appId, function (error, result) {
expect(error).to.be(null);
expect(result).to.eql(CLIENT_0);
done();
});
});
it('getByAppId fails for unknown client id', function (done) {
clientdb.getByAppId(CLIENT_0.appId + CLIENT_0.appId, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.equal(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
it('getAll succeeds', function (done) {
clientdb.getAll(function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.equal(3); // one of them is webadmin
expect(result[0]).to.eql(CLIENT_0);
expect(result[1]).to.eql(CLIENT_1);
done();
});
});
it('update client fails due to unknown client id', function (done) {
clientdb.update(CLIENT_2.id, CLIENT_2.appId, CLIENT_2.clientSecret, CLIENT_2.redirectURI, CLIENT_2.scope, function (error) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.equal(DatabaseError.NOT_FOUND);
done();
});
});
it('update client succeeds', function (done) {
clientdb.update(CLIENT_1.id, CLIENT_2.appId, CLIENT_2.clientSecret, CLIENT_2.redirectURI, CLIENT_2.scope, function (error) {
expect(error).to.be(null);
clientdb.get(CLIENT_1.id, function (error, result) {
expect(error).to.be(null);
expect(result.appId).to.eql(CLIENT_2.appId);
expect(result.clientSecret).to.eql(CLIENT_2.clientSecret);
expect(result.redirectURI).to.eql(CLIENT_2.redirectURI);
expect(result.scope).to.eql(CLIENT_2.scope);
done();
});
});
});
it('delByAppId succeeds', function (done) {
clientdb.delByAppId(CLIENT_0.appId, function (error) {
expect(error).to.be(null);
clientdb.getByAppId(CLIENT_0.appId, function (error, result) {
expect(error).to.be.a(DatabaseError);
expect(error.reason).to.equal(DatabaseError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
});
});
describe('settings', function () {
it('can set value', function (done) {
settingsdb.set('somekey', 'somevalue', function (error) {
expect(error).to.be(null);
done();
});
});
it('can get the set value', function (done) {
settingsdb.get('somekey', function (error, value) {
expect(error).to.be(null);
expect(value).to.be('somevalue');
done();
});
});
it('can get all values', function (done) {
settingsdb.getAll(function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result[0].name).to.be('somekey');
expect(result[0].value).to.be('somevalue');
expect(result.length).to.be(1); // the value set above
done();
});
});
it('can update a value', function (done) {
settingsdb.set('somekey', 'someothervalue', function (error) {
expect(error).to.be(null);
done();
});
});
it('can get updated value', function (done) {
settingsdb.get('somekey', function (error, value) {
expect(error).to.be(null);
expect(value).to.be('someothervalue');
done();
});
});
});
});

273
src/test/server-test.js Normal file
View File

@@ -0,0 +1,273 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var progress = require('../progress.js'),
config = require('../config.js'),
database = require('../database.js'),
expect = require('expect.js'),
nock = require('nock'),
request = require('superagent'),
server = require('../server.js');
var SERVER_URL = 'http://localhost:' + config.get('port');
function cleanup(done) {
done();
}
describe('Server', function () {
this.timeout(5000);
before(function () {
config.set('version', '0.5.0');
});
after(cleanup);
describe('startup', function () {
it('start fails due to wrong arguments', function (done) {
expect(function () { server.start(); }).to.throwException();
expect(function () { server.start('foobar', function () {}); }).to.throwException();
expect(function () { server.start(1337, function () {}); }).to.throwException();
done();
});
it('succeeds', function (done) {
server.start(function (error) {
expect(error).to.not.be.ok();
done();
});
});
it('is reachable', function (done) {
request.get(SERVER_URL + '/api/v1/cloudron/status', function (err, res) {
expect(res.statusCode).to.equal(200);
done(err);
});
});
it('should fail because already running', function (done) {
expect(server.start).to.throwException(function () {
done();
});
});
after(function (done) {
server.stop(function () {
done();
});
});
});
describe('runtime', function () {
before(function (done) {
server.start(done);
});
after(function (done) {
database._clear(function (error) {
expect(!error).to.be.ok();
server.stop(function () {
done();
});
});
});
it('random bad requests', function (done) {
request.get(SERVER_URL + '/random', function (err, res) {
expect(err).to.not.be.ok();
expect(res.statusCode).to.equal(404);
done(err);
});
});
it('version', function (done) {
request.get(SERVER_URL + '/api/v1/cloudron/status', function (err, res) {
expect(err).to.not.be.ok();
expect(res.statusCode).to.equal(200);
expect(res.body.version).to.equal('0.5.0');
done(err);
});
});
it('status route is GET', function (done) {
request.post(SERVER_URL + '/api/v1/cloudron/status')
.end(function (err, res) {
expect(res.statusCode).to.equal(404);
request.get(SERVER_URL + '/api/v1/cloudron/status')
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done(err);
});
});
});
});
describe('config', function () {
before(function (done) {
server.start(done);
});
after(function (done) {
server.stop(function () {
done();
});
});
it('config fails due missing token', function (done) {
request.get(SERVER_URL + '/api/v1/cloudron/config', function (err, res) {
expect(err).to.not.be.ok();
expect(res.statusCode).to.equal(401);
done(err);
});
});
it('config fails due wrong token', function (done) {
request.get(SERVER_URL + '/api/v1/cloudron/config').query({ access_token: 'somewrongtoken' }).end(function (err, res) {
expect(err).to.not.be.ok();
expect(res.statusCode).to.equal(401);
done(err);
});
});
});
describe('progress', function () {
before(function (done) {
server.start(done);
});
after(function (done) {
server.stop(function () {
done();
});
});
it('succeeds with no progress', function (done) {
request.get(SERVER_URL + '/api/v1/cloudron/progress', function (error, result) {
expect(error).to.not.be.ok();
expect(result.statusCode).to.equal(200);
expect(result.body.update).to.be(null);
expect(result.body.backup).to.be(null);
done();
});
});
it('succeeds with update progress', function (done) {
progress.set(progress.UPDATE, 13, 'This is some status string');
request.get(SERVER_URL + '/api/v1/cloudron/progress', function (error, result) {
expect(error).to.not.be.ok();
expect(result.statusCode).to.equal(200);
expect(result.body.update).to.be.an('object');
expect(result.body.update.percent).to.be.a('number');
expect(result.body.update.percent).to.equal(13);
expect(result.body.update.message).to.be.a('string');
expect(result.body.update.message).to.equal('This is some status string');
expect(result.body.backup).to.be(null);
done();
});
});
it('succeeds with no progress after clearing the update', function (done) {
progress.clear(progress.UPDATE);
request.get(SERVER_URL + '/api/v1/cloudron/progress', function (error, result) {
expect(error).to.not.be.ok();
expect(result.statusCode).to.equal(200);
expect(result.body.update).to.be(null);
expect(result.body.backup).to.be(null);
done();
});
});
});
describe('shutdown', function () {
before(function (done) {
server.start(done);
});
it('fails due to wrong arguments', function (done) {
expect(function () { server.stop(); }).to.throwException();
expect(function () { server.stop('foobar'); }).to.throwException();
expect(function () { server.stop(1337); }).to.throwException();
expect(function () { server.stop({}); }).to.throwException();
expect(function () { server.stop({ httpServer: {} }); }).to.throwException();
done();
});
it('succeeds', function (done) {
server.stop(function () {
done();
});
});
it('is not reachable anymore', function (done) {
request.get(SERVER_URL + '/api/v1/cloudron/status', function (error, result) {
expect(error).to.not.be(null);
done();
});
});
});
describe('cors', function () {
before(function (done) {
server.start(function (error) {
done(error);
});
});
it('responds to OPTIONS', function (done) {
request('OPTIONS', SERVER_URL + '/api/v1/cloudron/status')
.set('Access-Control-Request-Method', 'GET')
.set('Access-Control-Request-Headers', 'accept, origin, x-requested-with')
.set('Origin', 'http://localhost')
.end(function (res) {
expect(res.headers['access-control-allow-methods']).to.be('GET, PUT, DELETE, POST, OPTIONS');
expect(res.headers['access-control-allow-credentials']).to.be('true');
expect(res.headers['access-control-allow-headers']).to.be('accept, origin, x-requested-with'); // mirrored from request
expect(res.headers['access-control-allow-origin']).to.be('http://localhost'); // mirrors from request
done();
});
});
after(function (done) {
server.stop(function () {
done();
});
});
});
describe('heartbeat', function () {
var successfulHeartbeatGet;
before(function (done) {
server.start(done);
var scope = nock(config.apiServerOrigin());
successfulHeartbeatGet = scope.get('/api/v1/boxes/' + config.fqdn() + '/heartbeat');
successfulHeartbeatGet.reply(200);
});
after(function (done) {
server.stop(done);
nock.cleanAll();
});
it('sends heartbeat', function (done) {
setTimeout(function () {
expect(successfulHeartbeatGet.counter).to.equal(1);
done();
}, 100);
});
});
});

66
src/test/settings-test.js Normal file
View File

@@ -0,0 +1,66 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var database = require('../database.js'),
expect = require('expect.js'),
settings = require('../settings.js');
function setup(done) {
// ensure data/config/mount paths
database.initialize(function (error) {
expect(error).to.be(null);
done();
});
}
function cleanup(done) {
database._clear(done);
}
describe('Settings', function () {
before(setup);
after(cleanup);
it('can get default timezone', function (done) {
settings.getTimeZone(function (error, tz) {
expect(error).to.be(null);
expect(tz.length).to.not.be(0);
done();
});
});
it('can get default autoupdate_pattern', function (done) {
settings.getAutoupdatePattern(function (error, pattern) {
expect(error).to.be(null);
expect(pattern).to.be('00 00 1,3,5,23 * * *');
done();
});
});
it ('can get default cloudron name', function (done) {
settings.getCloudronName(function (error, name) {
expect(error).to.be(null);
expect(name).to.be('Cloudron');
done();
});
});
it('can get default cloudron avatar', function (done) {
settings.getCloudronAvatar(function (error, gravatar) {
expect(error).to.be(null);
expect(gravatar).to.be.a(Buffer);
done();
});
});
it('can get all values', function (done) {
settings.getAll(function (error, allSettings) {
expect(error).to.be(null);
expect(allSettings[settings.TIME_ZONE_KEY]).to.be.a('string');
expect(allSettings[settings.AUTOUPDATE_PATTERN_KEY]).to.be.a('string');
expect(allSettings[settings.CLOUDRON_NAME_KEY]).to.be.a('string');
done();
});
});
});

20
src/test/setupTest Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
set -eu
readonly ADMIN_LOCATION=admin
readonly source_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)"
! "${source_dir}/src/test/checkInstall" && exit 1
# create dir structure
rm -rf $HOME/.cloudron_test
mkdir -p $HOME/.cloudron_test
cd $HOME/.cloudron_test
mkdir -p data/appdata data/box/appicons data/mail data/nginx/cert data/nginx/applications data/collectd/collectd.conf.d data/addons configs
webadmin_scopes="root,profile,users,apps,settings,roleAdmin"
webadmin_origin="https://${ADMIN_LOCATION}-localhost"
mysql --user=root --password="" \
-e "REPLACE INTO clients (id, appId, clientSecret, redirectURI, scope) VALUES (\"cid-webadmin\", \"webadmin\", \"secret-webadmin\", \"${webadmin_origin}\", \"${webadmin_scopes}\")" boxtest

51
src/test/shell-test.js Normal file
View File

@@ -0,0 +1,51 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global after:false */
/* global before:false */
'use strict';
var expect = require('expect.js'),
path = require('path'),
shell = require('../shell.js');
describe('shell', function () {
it('can run valid program', function (done) {
var cp = shell.exec('test', 'ls', [ '-l' ], function (error) {
expect(cp).to.be.ok();
expect(error).to.be(null);
done();
});
});
it('fails on invalid program', function (done) {
var cp = shell.exec('test', 'randomprogram', [ ], function (error) {
expect(error).to.be.ok();
done();
});
});
it('fails on failing program', function (done) {
var cp = shell.exec('test', '/usr/bin/false', [ ], function (error) {
expect(error).to.be.ok();
done();
});
});
it('cannot sudo invalid program', function (done) {
var cp = shell.sudo('test', [ 'randomprogram' ], function (error) {
expect(error).to.be.ok();
done();
});
});
it('can sudo valid program', function (done) {
var RELOAD_NGINX_CMD = path.join(__dirname, '../src/scripts/reloadnginx.sh');
var cp = shell.sudo('test', [ RELOAD_NGINX_CMD ], function (error) {
expect(error).to.be.ok();
done();
});
});
});

401
src/test/user-test.js Normal file
View File

@@ -0,0 +1,401 @@
/* jslint node:true */
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var database = require('../database.js'),
expect = require('expect.js'),
user = require('../user.js'),
userdb = require('../userdb.js'),
UserError = user.UserError;
var USERNAME = 'nobody';
var USERNAME_NEW = 'nobodynew';
var EMAIL = 'nobody@no.body';
var EMAIL_NEW = 'nobodynew@no.body';
var PASSWORD = 'foobar';
var NEW_PASSWORD = 'somenewpassword';
var IS_ADMIN = true;
function cleanupUsers(done) {
userdb._clear(function () {
done();
});
}
function createUser(done) {
user.create(USERNAME, PASSWORD, EMAIL, IS_ADMIN, null /* invitor */, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
done();
});
}
function setup(done) {
// ensure data/config/mount paths
database.initialize(function (error) {
expect(error).to.be(null);
done();
});
}
function cleanup(done) {
database._clear(done);
}
describe('User', function () {
before(setup);
after(cleanup);
describe('create', function() {
before(cleanupUsers);
after(cleanupUsers);
it('succeeds', function (done) {
user.create(USERNAME, PASSWORD, EMAIL, IS_ADMIN, null /* invitor */, function (error, result) {
expect(error).not.to.be.ok();
expect(result).to.be.ok();
expect(result.username).to.equal(USERNAME);
expect(result.email).to.equal(EMAIL);
done();
});
});
it('fails because of invalid BAD_FIELD', function (done) {
expect(function () {
user.create(EMAIL, {}, function () {});
}).to.throwException();
expect(function () {
user.create(12345, PASSWORD, EMAIL, function () {});
}).to.throwException();
expect(function () {
user.create(USERNAME, PASSWORD, EMAIL, {});
}).to.throwException();
expect(function () {
user.create(USERNAME, PASSWORD, EMAIL, {}, function () {});
}).to.throwException();
expect(function () {
user.create(USERNAME, PASSWORD, EMAIL, {});
}).to.throwException();
done();
});
it('fails because user exists', function (done) {
user.create(USERNAME, PASSWORD, EMAIL, IS_ADMIN, null /* invitor */, function (error, result) {
expect(error).to.be.ok();
expect(result).not.to.be.ok();
expect(error.reason).to.equal(UserError.ALREADY_EXISTS);
done();
});
});
it('fails because password is empty', function (done) {
user.create(USERNAME, '', EMAIL, IS_ADMIN, null /* invitor */, function (error, result) {
expect(error).to.be.ok();
expect(result).not.to.be.ok();
expect(error.reason).to.equal(UserError.BAD_PASSWORD);
done();
});
});
});
describe('verify', function () {
before(createUser);
after(cleanupUsers);
it('fails due to non existing username', function (done) {
user.verify(USERNAME+USERNAME, PASSWORD, function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.NOT_FOUND);
done();
});
});
it('fails due to empty password', function (done) {
user.verify(USERNAME, '', function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.WRONG_PASSWORD);
done();
});
});
it('fails due to wrong password', function (done) {
user.verify(USERNAME, PASSWORD+PASSWORD, function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.WRONG_PASSWORD);
done();
});
});
it('succeeds', function (done) {
user.verify(USERNAME, PASSWORD, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
done();
});
});
});
describe('verifyWithEmail', function () {
before(createUser);
after(cleanupUsers);
it('fails due to non existing user', function (done) {
user.verifyWithEmail(EMAIL+EMAIL, PASSWORD, function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.NOT_FOUND);
done();
});
});
it('fails due to empty password', function (done) {
user.verifyWithEmail(EMAIL, '', function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.WRONG_PASSWORD);
done();
});
});
it('fails due to wrong password', function (done) {
user.verifyWithEmail(EMAIL, PASSWORD+PASSWORD, function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.WRONG_PASSWORD);
done();
});
});
it('succeeds', function (done) {
user.verifyWithEmail(EMAIL, PASSWORD, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
done();
});
});
});
describe('retrieving', function () {
before(createUser);
after(cleanupUsers);
it('fails due to non existing user', function (done) {
user.get('some non existing username', function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
done();
});
});
it('succeeds', function (done) {
user.get(USERNAME, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
done();
});
});
});
describe('update', function () {
before(createUser);
after(cleanupUsers);
it('fails due to unknown userid', function (done) {
user.update(USERNAME+USERNAME, USERNAME_NEW, EMAIL_NEW, function (error) {
expect(error).to.be.a(UserError);
expect(error.reason).to.equal(UserError.NOT_FOUND);
done();
});
});
it('fails due to invalid username', function (done) {
user.update(USERNAME, '', EMAIL_NEW, function (error) {
expect(error).to.be.a(UserError);
expect(error.reason).to.equal(UserError.BAD_USERNAME);
done();
});
});
it('fails due to invalid email', function (done) {
user.update(USERNAME, USERNAME_NEW, 'brokenemailaddress', function (error) {
expect(error).to.be.a(UserError);
expect(error.reason).to.equal(UserError.BAD_EMAIL);
done();
});
});
it('succeeds', function (done) {
user.update(USERNAME, USERNAME_NEW, EMAIL_NEW, function (error) {
expect(error).to.not.be.ok();
user.get(USERNAME, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
expect(result.email).to.equal(EMAIL_NEW);
expect(result.username).to.equal(USERNAME_NEW);
done();
});
});
});
});
describe('admin change', function () {
before(createUser);
after(cleanupUsers);
it('fails to remove admin flag of only admin', function (done) {
user.changeAdmin(USERNAME, false, function (error) {
expect(error).to.be.an('object');
done();
});
});
it('make second user admin succeeds', function (done) {
var user1 = {
username: 'seconduser',
password: 'foobar',
email: 'some@thi.ng'
};
user.create(user1.username, user1.password, user1.email, false, { username: USERNAME, email: EMAIL } /* invitor */, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
user.changeAdmin(user1.username, true, function (error) {
expect(error).to.not.be.ok();
done();
});
});
});
it('succeeds to remove admin flag of first user', function (done) {
user.changeAdmin(USERNAME, false, function (error) {
expect(error).to.not.be.ok();
done();
});
});
});
describe('password change', function () {
before(createUser);
after(cleanupUsers);
it('fails due to wrong arumgent count', function () {
expect(function () { user.changePassword(); }).to.throwError();
expect(function () { user.changePassword(USERNAME); }).to.throwError();
expect(function () { user.changePassword(USERNAME, PASSWORD, NEW_PASSWORD); }).to.throwError();
});
it('fails due to wrong arumgents', function () {
expect(function () { user.changePassword(USERNAME, {}, NEW_PASSWORD, function () {}); }).to.throwError();
expect(function () { user.changePassword(1337, PASSWORD, NEW_PASSWORD, function () {}); }).to.throwError();
expect(function () { user.changePassword(USERNAME, PASSWORD, 1337, function () {}); }).to.throwError();
expect(function () { user.changePassword(USERNAME, PASSWORD, NEW_PASSWORD, 'some string'); }).to.throwError();
});
it('fails due to wrong password', function (done) {
user.changePassword(USERNAME, 'wrongpassword', NEW_PASSWORD, function (error) {
expect(error).to.be.ok();
done();
});
});
it('fails due to empty new password', function (done) {
user.changePassword(USERNAME, PASSWORD, '', function (error) {
expect(error).to.be.ok();
done();
});
});
it('fails due to unknown user', function (done) {
user.changePassword('somerandomuser', PASSWORD, NEW_PASSWORD, function (error) {
expect(error).to.be.ok();
done();
});
});
it('succeeds', function (done) {
user.changePassword(USERNAME, PASSWORD, NEW_PASSWORD, function (error) {
expect(error).to.not.be.ok();
done();
});
});
it('actually changed the password (unable to login with old pasword)', function (done) {
user.verify(USERNAME, PASSWORD, function (error, result) {
expect(error).to.be.ok();
expect(result).to.not.be.ok();
expect(error.reason).to.equal(UserError.WRONG_PASSWORD);
done();
});
});
it('actually changed the password (login with new password)', function (done) {
user.verify(USERNAME, NEW_PASSWORD, function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.be.ok();
done();
});
});
});
describe('resetPasswordByIdentifier', function () {
before(createUser);
after(cleanupUsers);
it('fails due to unkown email', function (done) {
user.resetPasswordByIdentifier('unknown@mail.com', function (error) {
expect(error).to.be.an(UserError);
expect(error.reason).to.eql(UserError.NOT_FOUND);
done();
});
});
it('fails due to unkown username', function (done) {
user.resetPasswordByIdentifier('unknown', function (error) {
expect(error).to.be.an(UserError);
expect(error.reason).to.eql(UserError.NOT_FOUND);
done();
});
});
it('succeeds with email', function (done) {
user.resetPasswordByIdentifier(EMAIL, function (error) {
expect(error).to.not.be.ok();
done();
});
});
it('succeeds with username', function (done) {
user.resetPasswordByIdentifier(USERNAME, function (error) {
expect(error).to.not.be.ok();
done();
});
});
});
});