merge appdb.js into apps.js
This commit is contained in:
@@ -5,151 +5,17 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const appdb = require('../appdb.js'),
|
||||
apps = require('../apps.js'),
|
||||
async = require('async'),
|
||||
constants = require('../constants.js'),
|
||||
const apps = require('../apps.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
common = require('./common.js'),
|
||||
domains = require('../domains.js'),
|
||||
expect = require('expect.js'),
|
||||
hat = require('../hat.js');
|
||||
|
||||
let AUDIT_SOURCE = { ip: '1.2.3.4' };
|
||||
safe = require('safetydance');
|
||||
|
||||
describe('Apps', function () {
|
||||
var ADMIN_0 = common.ADMIN;
|
||||
const { domainSetup, cleanup, app, admin, user } = common;
|
||||
|
||||
var USER_0 = common.USER;
|
||||
|
||||
var USER_1 = {
|
||||
id: 'uuid2134',
|
||||
username: 'uuid2134',
|
||||
password: 'secret',
|
||||
email: 'safe1@me.com',
|
||||
fallbackEmail: 'safe1@me.com',
|
||||
salt: 'morton',
|
||||
createdAt: 'sometime back',
|
||||
resetToken: hat(256),
|
||||
displayName: '',
|
||||
groupIds: [ 'somegroup' ],
|
||||
role: 'user',
|
||||
source: '',
|
||||
avatar: constants.AVATAR_NONE
|
||||
};
|
||||
|
||||
var GROUP_0 = {
|
||||
id: 'somegroup',
|
||||
name: 'group0',
|
||||
source: ''
|
||||
};
|
||||
var GROUP_1 = {
|
||||
id: 'anothergroup',
|
||||
name: 'group1',
|
||||
source: 'ldap'
|
||||
};
|
||||
|
||||
const DOMAIN_0 = common.DOMAIN;
|
||||
|
||||
const DOMAIN_1 = {
|
||||
domain: 'example2.com',
|
||||
zoneName: 'example2.com',
|
||||
provider: 'noop',
|
||||
config: { },
|
||||
fallbackCertificate: null,
|
||||
tlsConfig: { provider: 'fallback' },
|
||||
wellKnown: null
|
||||
};
|
||||
|
||||
var APP_0 = {
|
||||
id: 'appid-0',
|
||||
appStoreId: 'appStoreId-0',
|
||||
location: 'some-location-0',
|
||||
domain: DOMAIN_0.domain,
|
||||
fqdn: 'some-location-0.' + DOMAIN_0.domain,
|
||||
manifest: {
|
||||
version: '0.1', dockerImage: 'docker/app0', healthCheckPath: '/', httpPort: 80, title: 'app0',
|
||||
tcpPorts: {
|
||||
PORT: {
|
||||
description: 'this is a port that i expose',
|
||||
containerPort: '1234'
|
||||
}
|
||||
}
|
||||
},
|
||||
portBindings: { PORT: 5678 },
|
||||
accessRestriction: null,
|
||||
memoryLimit: 0,
|
||||
cpuShares: 512,
|
||||
reverseProxyConfig: null,
|
||||
sso: false,
|
||||
mailboxDomain: DOMAIN_0.domain,
|
||||
env: {
|
||||
'CUSTOM_KEY': 'CUSTOM_VALUE'
|
||||
},
|
||||
dataDir: '',
|
||||
installationState: 'installed',
|
||||
runState: 'running'
|
||||
};
|
||||
|
||||
var APP_1 = {
|
||||
id: 'appid-1',
|
||||
appStoreId: 'appStoreId-1',
|
||||
location: 'some-location-1',
|
||||
domain: DOMAIN_0.domain,
|
||||
fqdn: 'some-location-1.' + DOMAIN_0.domain,
|
||||
manifest: {
|
||||
version: '0.1', dockerImage: 'docker/app1', healthCheckPath: '/', httpPort: 80, title: 'app1',
|
||||
tcpPorts: {}
|
||||
},
|
||||
portBindings: {},
|
||||
accessRestriction: { users: [ 'someuser' ], groups: [ GROUP_0.id ] },
|
||||
memoryLimit: 0,
|
||||
cpuShares: 512,
|
||||
env: {},
|
||||
dataDir: '',
|
||||
mailboxDomain: DOMAIN_0.domain,
|
||||
installationState: 'installed',
|
||||
runState: 'running'
|
||||
};
|
||||
|
||||
var APP_2 = {
|
||||
id: 'appid-2',
|
||||
appStoreId: 'appStoreId-2',
|
||||
location: 'some-location-2',
|
||||
domain: DOMAIN_1.domain,
|
||||
fqdn: 'some-location-2.' + DOMAIN_1.domain,
|
||||
manifest: {
|
||||
version: '0.1', dockerImage: 'docker/app2', healthCheckPath: '/', httpPort: 80, title: 'app2',
|
||||
tcpPorts: {}
|
||||
},
|
||||
portBindings: {},
|
||||
accessRestriction: { users: [ 'someuser', USER_0.id ], groups: [ GROUP_1.id ] },
|
||||
memoryLimit: 0,
|
||||
cpuShares: 512,
|
||||
reverseProxyConfig: null,
|
||||
sso: false,
|
||||
env: {},
|
||||
dataDir: '',
|
||||
mailboxDomain: DOMAIN_0.domain,
|
||||
installationState: 'installed',
|
||||
runState: 'running'
|
||||
};
|
||||
|
||||
before(function (done) {
|
||||
common.setup(function (error) {
|
||||
if (error) return done(error);
|
||||
|
||||
async.series([
|
||||
userdb.add.bind(null, USER_1.id, USER_1),
|
||||
domains.add.bind(null, DOMAIN_1.domain, DOMAIN_1, AUDIT_SOURCE),
|
||||
appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, apps._translatePortBindings(APP_0.portBindings, APP_0.manifest), APP_0),
|
||||
appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, apps._translatePortBindings(APP_1.portBindings, APP_1.manifest), APP_1),
|
||||
appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.domain, apps._translatePortBindings(APP_2.portBindings, APP_2.manifest), APP_2),
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
||||
after(common.cleanup);
|
||||
before(domainSetup);
|
||||
after(cleanup);
|
||||
|
||||
describe('validatePortBindings', function () {
|
||||
it('does not allow invalid host port', function () {
|
||||
@@ -183,39 +49,6 @@ describe('Apps', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getters', function () {
|
||||
it('cannot get invalid app', function (done) {
|
||||
apps.get('nope', function (error) {
|
||||
expect(error).to.be.ok();
|
||||
expect(error.reason).to.be(BoxError.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 + '.' + DOMAIN_0.domain);
|
||||
expect(app.memoryLimit).to.eql(0);
|
||||
expect(app.cpuShares).to.eql(512);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can getAll', function (done) {
|
||||
apps.getAll(function (error, apps) {
|
||||
expect(error).to.be(null);
|
||||
expect(apps).to.be.an(Array);
|
||||
expect(apps[1].id).to.be(APP_0.id);
|
||||
expect(apps[1].iconUrl).to.be(null);
|
||||
expect(apps[1].fqdn).to.eql(APP_0.location + '.' + DOMAIN_0.domain);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateAccessRestriction', function () {
|
||||
it('allows null input', function () {
|
||||
expect(apps._validateAccessRestriction(null)).to.eql(null);
|
||||
@@ -242,155 +75,188 @@ describe('Apps', function () {
|
||||
const someuser = { id: 'someuser', groupIds: [], role: 'user' };
|
||||
const adminuser = { id: 'adminuser', groupIds: [ 'groupie' ], role: 'admin' };
|
||||
|
||||
it('returns true for unrestricted access', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: null }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(true);
|
||||
done();
|
||||
});
|
||||
it('returns true for unrestricted access', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: null }, someuser)).to.be(true);
|
||||
});
|
||||
|
||||
it('returns true for allowed user', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ 'someuser' ] } }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(true);
|
||||
done();
|
||||
});
|
||||
it('returns true for allowed user', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ 'someuser' ] } }, someuser)).to.be(true);
|
||||
});
|
||||
|
||||
it('returns true for allowed user with multiple allowed', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ 'foo', 'someuser', 'anotheruser' ] } }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(true);
|
||||
done();
|
||||
});
|
||||
it('returns true for allowed user with multiple allowed', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ 'foo', 'someuser', 'anotheruser' ] } }, someuser)).to.be(true);
|
||||
});
|
||||
|
||||
it('returns false for not allowed user', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ 'foo' ] } }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(false);
|
||||
done();
|
||||
});
|
||||
it('returns false for not allowed user', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ 'foo' ] } }, someuser)).to.be(false);
|
||||
});
|
||||
|
||||
it('returns false for not allowed user with multiple allowed', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ 'foo', 'anotheruser' ] } }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(false);
|
||||
done();
|
||||
});
|
||||
it('returns false for not allowed user with multiple allowed', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ 'foo', 'anotheruser' ] } }, someuser)).to.be(false);
|
||||
});
|
||||
|
||||
it('returns false for no group or user', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ ], groups: [ ] } }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(false);
|
||||
done();
|
||||
});
|
||||
it('returns false for no group or user', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ ], groups: [ ] } }, someuser)).to.be(false);
|
||||
});
|
||||
|
||||
it('returns false for invalid group or user', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ ], groups: [ 'nop' ] } }, someuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(false);
|
||||
done();
|
||||
});
|
||||
it('returns false for invalid group or user', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ ], groups: [ 'nop' ] } }, someuser)).to.be(false);
|
||||
});
|
||||
|
||||
it('returns true for admin user', function (done) {
|
||||
apps.hasAccessTo({ accessRestriction: { users: [ ], groups: [ 'nop' ] } }, adminuser, function (error, access) {
|
||||
expect(error).to.be(null);
|
||||
expect(access).to.be(true);
|
||||
done();
|
||||
});
|
||||
it('returns true for admin user', function () {
|
||||
expect(apps.hasAccessTo({ accessRestriction: { users: [ ], groups: [ 'nop' ] } }, adminuser)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllByUser', function () {
|
||||
it('succeeds for USER_0', function (done) {
|
||||
apps.getAllByUser(USER_0, function (error, result) {
|
||||
expect(error).to.equal(null);
|
||||
expect(result.length).to.equal(3);
|
||||
expect(result[0].id).to.equal(common.APP.id);
|
||||
expect(result[1].id).to.equal(APP_0.id);
|
||||
expect(result[2].id).to.equal(APP_2.id);
|
||||
done();
|
||||
});
|
||||
describe('crud', function () {
|
||||
it('cannot get invalid app', async function () {
|
||||
const result = await apps.get('nope');
|
||||
expect(result).to.be(null);
|
||||
});
|
||||
|
||||
it('succeeds for USER_1', function (done) {
|
||||
apps.getAllByUser(USER_1, function (error, result) {
|
||||
expect(error).to.equal(null);
|
||||
expect(result.length).to.equal(3);
|
||||
expect(result[0].id).to.equal(common.APP.id);
|
||||
expect(result[1].id).to.equal(APP_0.id);
|
||||
expect(result[2].id).to.equal(APP_1.id);
|
||||
done();
|
||||
});
|
||||
it('can add app', async function () {
|
||||
await apps.add(app.id, app.appStoreId, app.manifest, app.location, app.domain, app.portBindings, app);
|
||||
});
|
||||
|
||||
it('returns all apps for admin', function (done) {
|
||||
apps.getAllByUser(ADMIN_0, function (error, result) {
|
||||
expect(error).to.equal(null);
|
||||
expect(result.length).to.equal(4);
|
||||
expect(result[0].id).to.equal(common.APP.id);
|
||||
expect(result[1].id).to.equal(APP_0.id);
|
||||
expect(result[2].id).to.equal(APP_1.id);
|
||||
expect(result[3].id).to.equal(APP_2.id);
|
||||
done();
|
||||
});
|
||||
it('cannot add with same app id', async function () {
|
||||
const [error] = await safe(apps.add(app.id, app.appStoreId, app.manifest, app.location, app.domain, app.portBindings, app));
|
||||
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
|
||||
});
|
||||
|
||||
it('cannot add with same app id', async function () {
|
||||
const [error] = await safe(apps.add(app.id, app.appStoreId, app.manifest, app.location, app.domain, app.portBindings, app));
|
||||
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
|
||||
});
|
||||
|
||||
it('can get app', async function () {
|
||||
const result = await apps.get(app.id);
|
||||
expect(result.manifest).to.eql(app.manifest);
|
||||
expect(result.portBindings).to.eql({});
|
||||
expect(result.location).to.eql(app.location);
|
||||
});
|
||||
|
||||
it('can list apps', async function () {
|
||||
const result = await apps.list();
|
||||
expect(result.length).to.be(1);
|
||||
expect(result[0].manifest).to.eql(app.manifest);
|
||||
expect(result[0].portBindings).to.eql({});
|
||||
expect(result[0].location).to.eql(app.location);
|
||||
});
|
||||
|
||||
it('can listByUser', async function () {
|
||||
let result = await apps.listByUser(admin);
|
||||
expect(result.length).to.be(1);
|
||||
|
||||
result = await apps.listByUser(user);
|
||||
expect(result.length).to.be(1);
|
||||
});
|
||||
|
||||
it('update succeeds', async function () {
|
||||
const data = {
|
||||
installationState: 'some-other-status',
|
||||
location:'some-other-location',
|
||||
domain: app.domain, // needs to be set whenever location is set
|
||||
manifest: Object.assign({}, app.manifest, { version: '0.2.0' }),
|
||||
accessRestriction: '',
|
||||
memoryLimit: 1337,
|
||||
cpuShares: 102,
|
||||
};
|
||||
|
||||
await apps.update(app.id, data);
|
||||
const newApp = await apps.get(app.id);
|
||||
expect(newApp.installationState).to.be('some-other-status');
|
||||
expect(newApp.location).to.be('some-other-location');
|
||||
expect(newApp.manifest.version).to.be('0.2.0');
|
||||
expect(newApp.accessRestriction).to.be('');
|
||||
expect(newApp.memoryLimit).to.be(1337);
|
||||
expect(newApp.cpuShares).to.be(102);
|
||||
});
|
||||
|
||||
it('update of nonexisting app fails', async function () {
|
||||
const [error] = await safe(apps.update('random', { installationState: app.installationState, location: app.location }));
|
||||
expect(error.reason).to.be(BoxError.NOT_FOUND);
|
||||
});
|
||||
|
||||
it('delete succeeds', async function () {
|
||||
await apps.del(app.id);
|
||||
});
|
||||
|
||||
it('cannot delete previously delete record', async function () {
|
||||
const [error] = await safe(apps.del(app.id));
|
||||
expect(error.reason).to.be(BoxError.NOT_FOUND);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setHealth', function () {
|
||||
before(async function () {
|
||||
await apps.add(app.id, app.appStoreId, app.manifest, app.location, app.domain, app.portBindings, app);
|
||||
});
|
||||
|
||||
it('can set app as healthy', async function () {
|
||||
const result = await apps.get(app.id);
|
||||
expect(result.health).to.be(null);
|
||||
|
||||
await apps.setHealth(app.id, apps.HEALTH_HEALTHY, new Date());
|
||||
});
|
||||
|
||||
it('did set app as healthy', async function () {
|
||||
const result = await apps.get(app.id);
|
||||
expect(result.health).to.be(apps.HEALTH_HEALTHY);
|
||||
});
|
||||
|
||||
it('cannot set health of unknown app', async function () {
|
||||
const [error] = await safe(apps.setHealth('randomId', apps.HEALTH_HEALTHY, new Date()));
|
||||
expect(error.reason).to.be(BoxError.NOT_FOUND);
|
||||
});
|
||||
});
|
||||
|
||||
describe('configureInstalledApps', function () {
|
||||
before(function (done) {
|
||||
async.series([
|
||||
appdb.update.bind(null, APP_0.id, { installationState: apps.ISTATE_INSTALLED }),
|
||||
appdb.update.bind(null, APP_1.id, { installationState: apps.ISTATE_ERROR }),
|
||||
appdb.update.bind(null, APP_2.id, { installationState: apps.ISTATE_INSTALLED })
|
||||
], done);
|
||||
const app1 = Object.assign({}, app, { id: 'id1', installationState: apps.ISTATE_ERROR, location: 'loc1' });
|
||||
const app2 = Object.assign({}, app, { id: 'id2', installationState: apps.ISTATE_INSTALLED, location: 'loc2' });
|
||||
|
||||
before(async function () {
|
||||
await apps.update(app.id, { installationState: apps.ISTATE_INSTALLED });
|
||||
await apps.add(app1.id, app1.appStoreId, app1.manifest, app1.location, app1.domain, app1.portBindings, app1);
|
||||
await apps.add(app2.id, app2.appStoreId, app2.manifest, app2.location, app2.domain, app2.portBindings, app2);
|
||||
});
|
||||
|
||||
it('can mark apps for reconfigure', function (done) {
|
||||
apps.configureInstalledApps(function (error) {
|
||||
expect(error).to.be(null);
|
||||
after(async function () {
|
||||
await apps.del(app1.id);
|
||||
await apps.del(app2.id);
|
||||
});
|
||||
|
||||
apps.getAll(function (error, result) {
|
||||
expect(result[0].installationState).to.be(apps.ISTATE_PENDING_CONFIGURE);
|
||||
expect(result[1].installationState).to.be(apps.ISTATE_PENDING_CONFIGURE);
|
||||
expect(result[2].installationState).to.be(apps.ISTATE_ERROR);
|
||||
expect(result[3].installationState).to.be(apps.ISTATE_PENDING_CONFIGURE);
|
||||
it('can mark apps for reconfigure', async function () {
|
||||
await apps.configureInstalledApps();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
const result = await apps.list();
|
||||
expect(result[0].installationState).to.be(apps.ISTATE_PENDING_CONFIGURE);
|
||||
expect(result[1].installationState).to.be(apps.ISTATE_ERROR);
|
||||
expect(result[2].installationState).to.be(apps.ISTATE_PENDING_CONFIGURE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('restoreInstalledApps', function () {
|
||||
before(function (done) {
|
||||
async.series([
|
||||
appdb.update.bind(null, APP_0.id, { installationState: apps.ISTATE_INSTALLED }),
|
||||
appdb.update.bind(null, APP_1.id, { installationState: apps.ISTATE_ERROR }),
|
||||
appdb.update.bind(null, APP_2.id, { installationState: apps.ISTATE_INSTALLED })
|
||||
], done);
|
||||
const app1 = Object.assign({}, app, { id: 'id1', installationState: apps.ISTATE_ERROR, location: 'loc1' });
|
||||
const app2 = Object.assign({}, app, { id: 'id2', installationState: apps.ISTATE_INSTALLED, location: 'loc2' });
|
||||
|
||||
before(async function () {
|
||||
await apps.update(app.id, { installationState: apps.ISTATE_INSTALLED });
|
||||
await apps.add(app1.id, app1.appStoreId, app1.manifest, app1.location, app1.domain, app1.portBindings, app1);
|
||||
await apps.add(app2.id, app2.appStoreId, app2.manifest, app2.location, app2.domain, app2.portBindings, app2);
|
||||
});
|
||||
|
||||
it('can mark apps for restore', function (done) {
|
||||
apps.restoreInstalledApps({}, function (error) {
|
||||
expect(error).to.be(null);
|
||||
after(async function () {
|
||||
await apps.del(app1.id);
|
||||
await apps.del(app2.id);
|
||||
});
|
||||
|
||||
apps.getAll(function (error, result) {
|
||||
expect(result[0].installationState).to.be(apps.ISTATE_PENDING_INSTALL);
|
||||
expect(result[1].installationState).to.be(apps.ISTATE_PENDING_INSTALL);
|
||||
expect(result[2].installationState).to.be(apps.ISTATE_ERROR);
|
||||
expect(result[3].installationState).to.be(apps.ISTATE_PENDING_INSTALL);
|
||||
it('can mark apps for reconfigure', async function () {
|
||||
await apps.restoreInstalledApps({});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
const result = await apps.list();
|
||||
expect(result[0].installationState).to.be(apps.ISTATE_PENDING_INSTALL);
|
||||
expect(result[1].installationState).to.be(apps.ISTATE_ERROR);
|
||||
expect(result[2].installationState).to.be(apps.ISTATE_PENDING_INSTALL);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user