/* global it:false */ /* global describe:false */ /* global before:false */ /* global after:false */ 'use strict'; const apps = require('../apps.js'), BoxError = require('../boxerror.js'), common = require('./common.js'), expect = require('expect.js'), safe = require('safetydance'); describe('Apps', function () { const { domainSetup, cleanup, app, admin, user } = common; before(domainSetup); after(cleanup); describe('validatePortBindings', function () { it('does not allow invalid host port', function () { expect(apps._validatePortBindings({ port: -1 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 0 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 'text' }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 65536 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 470 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); }); it('does not allow ports not as part of manifest', function () { expect(apps._validatePortBindings({ port: 1567 }, { tcpPorts: { } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 1567 }, { tcpPorts: { port3: null } })).to.be.an(Error); }); it('does not allow reserved ports', function () { expect(apps._validatePortBindings({ port: 443 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 50000 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 51000 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); expect(apps._validatePortBindings({ port: 50100 }, { tcpPorts: { port: 5000 } })).to.be.an(Error); }); it('allows valid bindings', function () { expect(apps._validatePortBindings({ port: 1024 }, { tcpPorts: { port: 5000 } })).to.be(null); expect(apps._validatePortBindings({ port1: 4033, port2: 3242, port3: 1234 }, { tcpPorts: { port1: null, port2: null, port3: null } })).to.be(null); }); }); describe('validateAccessRestriction', function () { it('allows null input', function () { expect(apps._validateAccessRestriction(null)).to.eql(null); }); it('does not allow wrong user type', function () { expect(apps._validateAccessRestriction({ users: {} })).to.be.an(Error); }); it('allows user input', function () { expect(apps._validateAccessRestriction({ users: [] })).to.eql(null); }); it('allows single user input', function () { expect(apps._validateAccessRestriction({ users: [ 'someuserid' ] })).to.eql(null); }); it('allows multi user input', function () { expect(apps._validateAccessRestriction({ users: [ 'someuserid', 'someuserid1', 'someuserid2', 'someuserid3' ] })).to.eql(null); }); }); describe('canAccess', function () { const someuser = { id: 'someuser', groupIds: [], role: 'user' }; const adminuser = { id: 'adminuser', groupIds: [ 'groupie' ], role: 'admin' }; it('returns true for unrestricted access', function () { expect(apps.canAccess({ accessRestriction: null }, someuser)).to.be(true); }); it('returns true for allowed user', function () { expect(apps.canAccess({ accessRestriction: { users: [ 'someuser' ] } }, someuser)).to.be(true); }); it('returns true for allowed user with multiple allowed', function () { expect(apps.canAccess({ accessRestriction: { users: [ 'foo', 'someuser', 'anotheruser' ] } }, someuser)).to.be(true); }); it('returns false for not allowed user', function () { expect(apps.canAccess({ accessRestriction: { users: [ 'foo' ] } }, someuser)).to.be(false); }); it('returns false for not allowed user with multiple allowed', function () { expect(apps.canAccess({ accessRestriction: { users: [ 'foo', 'anotheruser' ] } }, someuser)).to.be(false); }); it('returns false for no group or user', function () { expect(apps.canAccess({ accessRestriction: { users: [ ], groups: [ ] } }, someuser)).to.be(false); }); it('returns false for invalid group or user', function () { expect(apps.canAccess({ accessRestriction: { users: [ ], groups: [ 'nop' ] } }, someuser)).to.be(false); }); it('returns true for admin user', function () { expect(apps.canAccess({ accessRestriction: { users: [ ], groups: [ 'nop' ] } }, adminuser)).to.be(true); }); }); describe('crud', function () { it('cannot get invalid app', async function () { const result = await apps.get('nope'); expect(result).to.be(null); }); it('can add app', async function () { await apps.add(app.id, app.appStoreId, app.manifest, app.location, app.domain, app.portBindings, app); }); 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 () { 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); }); after(async function () { await apps.del(app1.id); await apps.del(app2.id); }); it('can mark apps for reconfigure', async function () { await apps.configureInstalledApps(); 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 () { 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); }); after(async function () { await apps.del(app1.id); await apps.del(app2.id); }); it('can mark apps for reconfigure', async function () { await apps.restoreInstalledApps({}); 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); }); }); });