Files
cloudron-box/src/routes/test/apps-test.js

1334 lines
54 KiB
JavaScript
Raw Normal View History

'use strict';
/* global it:false */
/* global describe:false */
/* global before:false */
2019-08-30 13:12:49 -07:00
let apps = require('../../apps.js'),
async = require('async'),
child_process = require('child_process'),
clients = require('../../clients.js'),
constants = require('../../constants.js'),
database = require('../../database.js'),
docker = require('../../docker.js').connection,
expect = require('expect.js'),
fs = require('fs'),
2019-04-18 13:11:56 +02:00
hat = require('../../hat.js'),
hock = require('hock'),
http = require('http'),
ldap = require('../../ldap.js'),
net = require('net'),
nock = require('nock'),
2018-02-05 17:28:30 +01:00
path = require('path'),
paths = require('../../paths.js'),
2018-10-29 11:49:37 -07:00
platform = require('../../platform.js'),
safe = require('safetydance'),
server = require('../../server.js'),
settings = require('../../settings.js'),
settingsdb = require('../../settingsdb.js'),
superagent = require('superagent'),
2019-04-18 13:11:56 +02:00
tokendb = require('../../tokendb.js'),
2019-09-08 16:57:08 -07:00
url = require('url');
2019-07-25 15:43:51 -07:00
var SERVER_URL = 'http://localhost:' + constants.PORT;
2015-09-29 13:51:50 -07:00
// Test image information
var TEST_IMAGE_REPO = 'cloudron/test';
2019-08-06 10:27:19 -07:00
var TEST_IMAGE_TAG = '25.19.0';
var TEST_IMAGE = TEST_IMAGE_REPO + ':' + TEST_IMAGE_TAG;
const DOMAIN_0 = {
domain: 'example-apps-test.com',
adminFqdn: 'my.example-apps-test.com',
zoneName: 'example-apps-test.com',
config: {},
provider: 'noop',
fallbackCertificate: null,
tlsConfig: { provider: 'fallback' }
};
2015-09-29 13:51:50 -07:00
var APP_STORE_ID = 'test', APP_ID;
var APP_LOCATION = 'appslocation';
var APP_LOCATION_2 = 'appslocationtwo';
var APP_LOCATION_NEW = 'appslocationnew';
var APP_MANIFEST = JSON.parse(fs.readFileSync(__dirname + '/../../../../test-app/CloudronManifest.json', 'utf8'));
APP_MANIFEST.dockerImage = TEST_IMAGE;
2018-02-05 22:17:16 +01:00
const USERNAME = 'superadmin';
const PASSWORD = 'Foobar?1337';
const EMAIL ='admin@me.com';
const USER_1_APPSTORE_TOKEN = 'appstoretoken';
2018-02-05 22:17:16 +01:00
const USERNAME_1 = 'user';
const EMAIL_1 ='user@me.com';
var user_1_id = null;
// authentication token
var token = null;
var token_1 = null;
2019-09-08 16:57:08 -07:00
let KEY, CERT;
let appstoreIconServer = hock.createHock({ throwOnUnmatched: false });
2016-06-16 14:43:07 -05:00
function checkAddons(appEntry, done) {
async.retry({ times: 15, interval: 3000 }, function (callback) {
// this was previously written with superagent but it was getting sporadic EPIPE
var req = http.get({ hostname: 'localhost', port: appEntry.httpPort, path: '/check_addons?username=' + USERNAME + '&password=' + PASSWORD });
req.on('error', callback);
req.on('response', function (res) {
if (res.statusCode !== 200) return callback('app returned non-200 status : ' + res.statusCode);
2016-06-16 14:43:07 -05:00
var d = '';
res.on('data', function (chunk) { d += chunk.toString('utf8'); });
res.on('end', function () {
var body = JSON.parse(d);
2016-06-16 14:43:07 -05:00
delete body.recvmail; // unclear why dovecot mail delivery won't work
delete body.stdenv; // cannot access APP_ORIGIN
2018-02-05 22:17:16 +01:00
delete body.email; // sieve will fail not sure why yet
2019-04-18 13:11:56 +02:00
delete body.docker; // TODO fix this for some reason we cannot connect to the docker proxy on port 3003
for (var key in body) {
2019-04-24 14:23:19 -07:00
if (body[key] !== 'OK') {
console.log('Not done yet: ' + JSON.stringify(body));
return callback('Not done yet: ' + JSON.stringify(body));
}
}
2016-06-16 14:43:07 -05:00
callback();
});
2016-06-16 14:43:07 -05:00
});
req.end();
2016-06-16 14:43:07 -05:00
}, done);
}
function checkRedis(containerId, done) {
var redisIp, exportedRedisPort;
docker.getContainer(containerId).inspect(function (error, data) {
expect(error).to.not.be.ok();
expect(data).to.be.ok();
redisIp = safe.query(data, 'NetworkSettings.Networks.cloudron.IPAddress');
expect(redisIp).to.be.ok();
exportedRedisPort = safe.query(data, 'NetworkSettings.Ports.6379/tcp');
expect(exportedRedisPort).to.be(null);
done();
});
}
2019-09-08 16:57:08 -07:00
function waitForTask(taskId, callback) {
process.stdout.write('Waiting for task ' + taskId + ' .');
async.retry({ times: 50, interval: 4000 }, function (retryCallback) {
superagent.get(SERVER_URL + '/api/v1/tasks/' + taskId)
.query({ access_token: token })
.end(function (error, result) {
process.stdout.write('.');
if (!result || result.statusCode !== 200) return retryCallback(null, new Error('Bad result'));
if (result.body.active) return retryCallback(new Error('Still active'));
retryCallback();
});
}, function (error, result) {
console.log();
callback(error || result);
});
}
2017-02-06 21:53:29 -08:00
function waitForSetup(done) {
async.retry({ times: 5, interval: 4000 }, function (retryCallback) {
superagent.get(SERVER_URL + '/api/v1/cloudron/status')
.end(function (error, result) {
if (!result || result.statusCode !== 200) return retryCallback(new Error('Bad result'));
if (!result.body.setup.active && result.body.setup.errorMessage === '' && result.body.adminFqdn) return retryCallback();
retryCallback(new Error('Not done yet: ' + JSON.stringify(result.body)));
});
}, done);
}
2017-02-06 21:53:29 -08:00
function startBox(done) {
2019-04-18 13:11:56 +02:00
console.log('Starting box code...');
2019-09-08 16:57:08 -07:00
child_process.execSync('openssl req -subj "/CN=*.' + DOMAIN_0.domain + '/O=My Company Name LTD./C=US" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /tmp/server.key -out /tmp/server.crt');
KEY = fs.readFileSync('/tmp/server.key', 'utf8');
CERT = fs.readFileSync('/tmp/server.crt', 'utf8');
2017-02-06 21:53:29 -08:00
process.env.TEST_CREATE_INFRA = 1;
safe.fs.unlinkSync(paths.INFRA_VERSION_FILE);
async.series([
// first clear, then start server. otherwise, taskmanager spins up tasks for obsolete appIds
database.initialize,
database._clear,
server.start,
2017-02-06 21:53:29 -08:00
ldap.start,
2019-08-05 07:01:12 -07:00
settings._setApiServerOrigin.bind(null, 'http://localhost:6060'),
2017-02-06 21:53:29 -08:00
function (callback) {
superagent.post(SERVER_URL + '/api/v1/cloudron/setup')
.send({ dnsConfig: DOMAIN_0 })
2018-04-30 21:41:09 -07:00
.end(function (error, result) {
expect(result).to.be.ok();
expect(result.statusCode).to.eql(200);
2017-02-06 21:53:29 -08:00
waitForSetup(callback);
2018-04-30 21:41:09 -07:00
});
},
function (callback) {
2017-02-06 21:53:29 -08:00
superagent.post(SERVER_URL + '/api/v1/cloudron/activate')
2018-04-30 21:41:09 -07:00
.send({ username: USERNAME, password: PASSWORD, email: EMAIL })
.end(function (error, result) {
expect(result).to.be.ok();
expect(result.statusCode).to.eql(201);
2017-02-06 21:53:29 -08:00
2018-04-30 21:41:09 -07:00
// stash for further use
token = result.body.token;
2018-04-30 21:41:09 -07:00
callback();
});
2017-02-06 21:53:29 -08:00
},
2017-02-06 21:53:29 -08:00
function (callback) {
superagent.post(SERVER_URL + '/api/v1/users')
2018-04-30 21:41:09 -07:00
.query({ access_token: token })
.send({ username: USERNAME_1, email: EMAIL_1, invite: false })
.end(function (err, res) {
expect(res.statusCode).to.equal(201);
2018-04-30 21:41:09 -07:00
user_1_id = res.body.id;
2019-04-18 13:11:56 +02:00
token_1 = hat(8 * 32);
2016-12-13 11:31:14 -08:00
2019-04-18 13:11:56 +02:00
// HACK to get a token for second user (passwords are generated and the user should have gotten a password setup link...)
2019-04-24 15:39:47 -07:00
tokendb.add({ id: 'tid-1', accessToken: token_1, identifier: user_1_id, clientId: 'cid-sdk', expires: Date.now() + 1000000, scope: 'apps', name: '' }, callback); // cid-sdk means we don't need to send password
2018-04-30 21:41:09 -07:00
});
2017-02-06 21:53:29 -08:00
},
2015-10-13 10:03:50 +02:00
2019-09-08 16:57:08 -07:00
function (callback) {
appstoreIconServer
.get('/api/v1/apps/' + APP_STORE_ID + '/versions/' + APP_MANIFEST.version + '/icon')
.replyWithFile(200, path.resolve(__dirname, '../../../assets/avatar.png'));
var port = parseInt(url.parse(settings.apiServerOrigin()).port, 10);
http.createServer(appstoreIconServer.handler).listen(port, callback);
},
2018-10-29 11:49:37 -07:00
function (callback) {
2019-04-18 13:11:56 +02:00
process.stdout.write('Waiting for platform to be ready...');
async.retry({ times: 500, interval: 1000 }, function (retryCallback) {
2018-10-29 11:49:37 -07:00
if (platform._isReady) return retryCallback();
2019-04-18 13:11:56 +02:00
process.stdout.write('.');
2018-10-29 11:49:37 -07:00
retryCallback('Platform not ready yet');
2019-04-18 13:11:56 +02:00
}, function (error) {
if (error) return callback(error);
console.log();
2019-08-05 07:01:12 -07:00
console.log('Platform is ready');
2019-04-18 13:11:56 +02:00
callback();
});
2018-10-29 11:49:37 -07:00
}
], done);
2017-02-06 21:53:29 -08:00
}
2017-02-06 21:53:29 -08:00
function stopBox(done) {
2019-04-18 13:11:56 +02:00
console.log('Stopping box code...');
2017-02-06 21:53:29 -08:00
delete process.env.TEST_CREATE_INFRA;
2019-04-18 13:11:56 +02:00
child_process.execSync('docker ps -qa --filter \'network=cloudron\' | xargs --no-run-if-empty docker rm -f');
2019-09-08 16:57:08 -07:00
appstoreIconServer.done();
2017-02-06 21:53:29 -08:00
async.series([
2019-08-20 13:42:03 -07:00
database._clear,
2017-02-06 21:53:29 -08:00
server.stop,
2019-09-08 16:57:08 -07:00
ldap.stop,
2017-02-06 21:53:29 -08:00
], done);
}
2017-02-06 21:53:29 -08:00
describe('App API', function () {
let taskId = '';
2017-02-06 21:53:29 -08:00
before(startBox);
2019-09-08 16:57:08 -07:00
describe('Install', function () {
it('app install fails - missing manifest', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.eql('appStoreId or manifest is required');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - null manifest', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.eql('appStoreId or manifest is required');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - bad manifest format', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: 'epic' })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.eql('manifest must be an object');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - empty appStoreId format', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: null, appStoreId: '' })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.eql('appStoreId or manifest is required');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - invalid json', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send('garbage')
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - missing domain', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: 'some', accessRestriction: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.eql('domain is required');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - non-existing domain', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: 'some', accessRestriction: null, domain: 'doesnotexist.com' })
.end(function (err, res) {
expect(res.statusCode).to.equal(404);
expect(res.body.message).to.eql('No such domain');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - invalid location type', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: 42, accessRestriction: null, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.eql('location is required');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - reserved admin location', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: 'my', accessRestriction: null, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.contain('my is reserved');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - reserved smtp location', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: constants.SMTP_LOCATION, accessRestriction: null, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.contain(constants.SMTP_LOCATION + ' is reserved');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - portBindings must be object', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: APP_LOCATION, portBindings: 23, accessRestriction: null, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.contain('portBindings must be an object');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - accessRestriction is required', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: APP_LOCATION, portBindings: {}, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.contain('accessRestriction is required');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails - accessRestriction type is wrong', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: APP_LOCATION, portBindings: {}, accessRestriction: '', domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
expect(res.body.message).to.contain('accessRestriction is required');
done();
});
});
2016-05-23 17:34:25 -07:00
2019-09-08 16:57:08 -07:00
it('app install fails for non admin', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token_1 })
.send({ manifest: APP_MANIFEST, location: APP_LOCATION, portBindings: null, accessRestriction: null, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(403);
done();
});
});
2019-09-08 16:57:08 -07:00
it('app install fails because manifest download fails', function (done) {
var fake = nock(settings.apiServerOrigin()).get('/api/v1/apps/test').reply(404, {});
2019-09-08 16:57:08 -07:00
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ appStoreId: APP_STORE_ID, location: APP_LOCATION, portBindings: null, domain: DOMAIN_0.domain, accessRestriction: { users: [ 'someuser' ], groups: [] } })
.end(function (err, res) {
expect(res.statusCode).to.equal(404);
expect(fake.isDone()).to.be.ok();
done();
});
});
2016-04-18 18:12:56 -07:00
2019-09-08 16:57:08 -07:00
it('app install fails due to purchase failure', function (done) {
var fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/test').reply(200, { manifest: APP_MANIFEST });
2019-09-08 16:57:08 -07:00
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ appStoreId: APP_STORE_ID, location: APP_LOCATION, domain: DOMAIN_0.domain, portBindings: null, accessRestriction: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(424);
expect(fake1.isDone()).to.be.ok();
done();
});
});
it('app install succeeds with purchase', function (done) {
var fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST });
var fake2 = nock(settings.apiServerOrigin()).post(function (uri) { return uri.indexOf('/api/v1/cloudronapps') >= 0; }, (body) => body.appstoreId === APP_STORE_ID && body.manifestId === APP_MANIFEST.id && body.appId).reply(201, { });
2019-09-08 16:57:08 -07:00
settingsdb.set(settings.CLOUDRON_TOKEN_KEY, USER_1_APPSTORE_TOKEN, function (error) {
if (error) return done(error);
2019-09-08 16:57:08 -07:00
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ appStoreId: APP_STORE_ID, location: APP_LOCATION, domain: DOMAIN_0.domain, portBindings: { ECHO_SERVER_PORT: 7171 }, accessRestriction: { users: [ 'someuser' ], groups: [] } })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
expect(res.body.id).to.be.a('string');
APP_ID = res.body.id;
expect(fake1.isDone()).to.be.ok();
expect(fake2.isDone()).to.be.ok();
taskId = res.body.taskId;
done();
});
});
});
2019-09-08 16:57:08 -07:00
it('app install fails because of conflicting location', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
2019-09-08 16:57:08 -07:00
.send({ manifest: APP_MANIFEST, location: APP_LOCATION, domain: DOMAIN_0.domain, portBindings: null, accessRestriction: null })
.end(function (err, res) {
2019-09-08 16:57:08 -07:00
expect(res.statusCode).to.equal(409);
done();
});
});
2017-02-06 21:53:29 -08:00
});
2019-09-08 16:57:08 -07:00
describe('get', function () {
it('can get app status', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
expect(res.body.id).to.eql(APP_ID);
expect(res.body.installationState).to.be.ok();
done();
});
});
2019-09-08 16:57:08 -07:00
it('cannot get invalid app status', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/kubachi')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(404);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can get all apps', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
expect(res.body.apps).to.be.an('array');
expect(res.body.apps[0].id).to.eql(APP_ID);
expect(res.body.apps[0].installationState).to.be.ok();
done();
});
});
2016-01-29 17:24:18 +01:00
2019-09-08 16:57:08 -07:00
it('non admin cannot see the app due to accessRestriction', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps')
.query({ access_token: token_1 })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
expect(res.body.apps).to.be.an('array');
expect(res.body.apps.length).to.equal(0);
done();
});
});
2017-02-06 21:53:29 -08:00
});
2016-01-29 17:24:18 +01:00
2019-09-08 16:57:08 -07:00
describe('post installation', function () {
let appResult, appEntry;
2019-09-08 16:57:08 -07:00
it('task completed', function (done) {
waitForTask(taskId, done);
});
it('app is running', function (callback) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
.query({ access_token: token })
.end(function (err, res) {
if (res.statusCode !== 200) return callback(new Error('Response error'));
if (res.body.installationState === apps.ISTATE_INSTALLED) { appResult = res.body; return callback(); }
if (res.body.installationState === apps.ISTATE_ERROR) return callback(new Error('Install error'));
callback(new Error('Unknown app state:' + res.body.installationState));
});
});
2019-09-08 16:57:08 -07:00
it('can get app', function (done) {
apps.get(appResult.id, function (error, app) {
expect(!error).to.be.ok();
expect(app).to.be.an('object');
appEntry = app;
2018-04-30 21:41:09 -07:00
done();
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('container created', function (done) {
expect(appResult.containerId).to.be(undefined);
expect(appEntry.containerId).to.be.ok();
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
expect(error).to.not.be.ok();
expect(data.Config.ExposedPorts['7777/tcp']).to.eql({ });
expect(data.Config.Env).to.contain('CLOUDRON_WEBADMIN_ORIGIN=' + settings.adminOrigin());
expect(data.Config.Env).to.contain('CLOUDRON_API_ORIGIN=' + settings.adminOrigin());
expect(data.Config.Env).to.contain('CLOUDRON=1');
expect(data.Config.Env).to.contain('CLOUDRON_APP_ORIGIN=https://' + APP_LOCATION + '.' + DOMAIN_0.domain);
expect(data.Config.Env).to.contain('CLOUDRON_APP_DOMAIN=' + APP_LOCATION + '.' + DOMAIN_0.domain);
// Hostname must not be set of app fqdn or app location!
expect(data.Config.Hostname).to.not.contain(APP_LOCATION);
expect(data.Config.Env).to.contain('ECHO_SERVER_PORT=7171');
expect(data.HostConfig.PortBindings['7778/tcp'][0].HostPort).to.eql('7171');
done();
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('nginx config', function (done) {
expect(fs.existsSync(paths.NGINX_APPCONFIG_DIR + '/' + APP_LOCATION + '.conf'));
done();
});
2019-09-08 16:57:08 -07:00
it('volume created', function (done) {
expect(fs.existsSync(paths.APPS_DATA_DIR + '/' + APP_ID));
let volume = docker.getVolume(APP_ID + '-localstorage');
volume.inspect(function (error, volume) {
expect(error).to.be(null);
expect(volume.Labels.appId).to.eql(APP_ID);
expect(volume.Options.device).to.eql(paths.APPS_DATA_DIR + '/' + APP_ID + '/data');
2018-04-30 21:41:09 -07:00
done();
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('http is up and running', function (done) {
var tryCount = 20;
2019-09-08 16:57:08 -07:00
// TODO what does that check for?
expect(appResult.httpPort).to.be(undefined);
2019-09-08 16:57:08 -07:00
(function healthCheck() {
superagent.get('http://localhost:' + appEntry.httpPort + appResult.manifest.healthCheckPath)
2017-11-23 23:41:01 +01:00
.end(function (err, res) {
2019-09-08 16:57:08 -07:00
if (err || res.statusCode !== 200) {
if (--tryCount === 0) {
console.log('Unable to curl http://localhost:' + appEntry.httpPort + appResult.manifest.healthCheckPath);
return done(new Error('Timedout'));
}
return setTimeout(healthCheck, 2000);
}
expect(!err).to.be.ok();
expect(res.statusCode).to.equal(200);
2018-04-30 21:41:09 -07:00
done();
});
2019-09-08 16:57:08 -07:00
})();
});
it('tcp port mapping works', function (done) {
var client = net.connect(7171);
client.on('data', function (data) {
expect(data.toString()).to.eql('ECHO_SERVER_PORT=7171');
done();
});
2019-09-08 16:57:08 -07:00
client.on('error', done);
});
it('running container has volume mounted', function (done) {
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
expect(error).to.not.be.ok();
expect(data.Mounts.filter(function (mount) { return mount.Destination === '/app/data'; })[0].Type).to.eql('volume');
done();
});
});
2019-09-08 16:57:08 -07:00
it('app responds to http request', function (done) {
superagent.get('http://localhost:' + appEntry.httpPort).end(function (err, res) {
expect(!err).to.be.ok();
expect(res.statusCode).to.equal(200);
done();
});
});
2019-09-08 16:57:08 -07:00
it('oauth addon config', function (done) {
var appContainer = docker.getContainer(appEntry.containerId);
appContainer.inspect(function (error, data) {
expect(error).to.not.be.ok();
2019-09-08 16:57:08 -07:00
clients.getByAppIdAndType(APP_ID, clients.TYPE_OAUTH, function (error, client) {
expect(error).to.not.be.ok();
expect(client.id.length).to.be(40); // cid- + 32 hex chars (128 bits) + 4 hyphens
expect(client.clientSecret.length).to.be(256); // 32 hex chars (8 * 256 bits)
expect(data.Config.Env).to.contain('CLOUDRON_OAUTH_CLIENT_ID=' + client.id);
expect(data.Config.Env).to.contain('CLOUDRON_OAUTH_CLIENT_SECRET=' + client.clientSecret);
done();
});
});
});
2019-09-08 16:57:08 -07:00
it('installation - app can populate addons', function (done) {
superagent.get(`http://localhost:${appEntry.httpPort}/populate_addons`).end(function (error, res) {
expect(!error).to.be.ok();
expect(res.statusCode).to.equal(200);
for (var key in res.body) {
expect(res.body[key]).to.be('OK');
}
done();
});
});
2019-09-08 16:57:08 -07:00
it('installation - app can check addons', function (done) {
console.log('This test can take a while as it waits for scheduler addon to tick 3');
checkAddons(appEntry, done);
});
2016-01-29 17:24:18 +01:00
2019-09-08 16:57:08 -07:00
it('installation - redis addon created', function (done) {
checkRedis('redis-' + APP_ID, done);
});
});
2019-09-08 16:57:08 -07:00
describe('logs', function () {
it('logs - stdout and stderr', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID + '/logs')
.query({ access_token: token })
.buffer(false)
.end(function (err, res) {
var data = '';
res.on('data', function (d) { data += d.toString('utf8'); });
res.on('end', function () {
expect(data.length).to.not.be(0);
done();
});
res.on('error', done);
});
});
2019-09-08 16:57:08 -07:00
it('logStream - requires event-stream accept header', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID + '/logstream')
.query({ access_token: token, fromLine: 0 })
.end(function (err, res) {
expect(res.statusCode).to.be(400);
done();
2018-02-05 17:28:30 +01:00
});
2019-09-08 16:57:08 -07:00
});
it('logStream - stream logs', function (done) {
var options = {
port: constants.PORT, host: 'localhost', path: '/api/v1/apps/' + APP_ID + '/logstream?access_token=' + token,
headers: { 'Accept': 'text/event-stream', 'Connection': 'keep-alive' }
};
// superagent doesn't work. maybe https://github.com/visionmedia/superagent/issues/420
var req = http.get(options, function (res) {
var data = '';
res.on('data', function (d) { data += d.toString('utf8'); });
setTimeout(function checkData() {
expect(data.length).to.not.be(0);
data.split('\n').forEach(function (line) {
if (line.indexOf('id: ') !== 0) return;
expect(parseInt(line.substr(4), 10)).to.be.a('number'); // timestamp
});
req.abort();
done();
}, 1000);
res.on('error', done);
});
req.on('error', done);
});
2017-02-06 21:53:29 -08:00
});
2015-10-20 11:33:19 -07:00
2019-09-08 16:57:08 -07:00
describe('configure (db fields)', function () {
it('fails for no label', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/label')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
it('fails for invalid label', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/label')
.query({ access_token: token })
.send({ label: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can set the label', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/label')
.query({ access_token: token })
.send({ label: 'LABEL'})
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2019-09-08 16:57:08 -07:00
it('did set the label', function (done) {
2017-02-06 21:53:29 -08:00
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
2018-04-30 21:41:09 -07:00
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
2019-09-08 16:57:08 -07:00
expect(res.body.label).to.be('LABEL');
done();
});
});
2019-04-18 13:11:56 +02:00
2019-09-08 16:57:08 -07:00
///////////// tags
it('fails for no tags', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/tags')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-04-18 13:11:56 +02:00
2019-09-08 16:57:08 -07:00
it('fails for null tags', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/tags')
.query({ access_token: token })
.send({ tags: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('fails for empty tag', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/tags')
.query({ access_token: token })
.send({ tags: ['tag1', '', 'tag2'] })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('fails for non-string tag', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/tags')
.query({ access_token: token })
.send({ tags: ['tag1', 123, 'tag2'] })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can set the tags', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/tags')
.query({ access_token: token })
.send({ tags: [ 'tag1', 'tag2' ] })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2019-09-08 16:57:08 -07:00
it('did set the tags', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
expect(res.body.tags).to.eql([ 'tag1', 'tag2' ]);
done();
});
});
2019-09-08 16:57:08 -07:00
///////////// icon
it('fails for no icon', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/icon')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('fails for invalid icon', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/icon')
.query({ access_token: token })
.send({ icon: 'something non base64' })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('can set the icon', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/icon')
.query({ access_token: token })
.send({ icon: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=' })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('did set the icon', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID + '/icon')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(200); // response is some PNG
done();
});
});
2019-04-18 13:11:56 +02:00
2019-09-08 16:57:08 -07:00
it('can reset the icon', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/icon')
.query({ access_token: token })
.send({ icon: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2019-04-18 13:11:56 +02:00
2019-09-08 16:57:08 -07:00
////////////// automatic updates
it('can disable automatic updates', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/automatic_update')
.query({ access_token: token })
.send({ enable: false })
2017-02-06 21:53:29 -08:00
.end(function (err, res) {
2019-09-08 16:57:08 -07:00
expect(res.statusCode).to.equal(200);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('did disable automatic updates', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
.query({ access_token: token })
.end(function (err, res) {
2018-04-30 21:41:09 -07:00
expect(res.statusCode).to.equal(200);
2019-09-08 16:57:08 -07:00
expect(res.body.enableAutomaticUpdate).to.be(false);
2018-04-30 21:41:09 -07:00
done();
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('can disable automatic backups', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/automatic_backup')
.query({ access_token: token })
.send({ enable: false })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('did disable automatic backups', function (done) {
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
expect(res.body.enableBackup).to.be(false);
done();
});
});
2019-09-08 16:57:08 -07:00
////////////// access restriction
it('cannot set bad accessRestriction', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/access_restriction')
.query({ access_token: token })
.send({ accessRestriction: false })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can clear accessRestriction', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/access_restriction')
.query({ access_token: token })
.send({ accessRestriction: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can set accessRestriction', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/access_restriction')
.query({ access_token: token })
.send({ accessRestriction: { users: [ 'someuserid' ], groups: [ 'somegroupid' ] } })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2015-09-09 15:48:35 -07:00
2019-09-08 16:57:08 -07:00
/////////////// cert
it('cannot set only the cert, no key', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/cert')
.query({ access_token: token })
.send({ cert: CERT })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('cannot reconfigure app with only the key, no cert', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/cert')
.query({ access_token: token })
.send({ key: KEY })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
2017-02-06 21:53:29 -08:00
});
2019-09-08 16:57:08 -07:00
it('cannot set invalid cert', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/cert')
.query({ access_token: token })
.send({ cert: 'x' + CERT, key: KEY })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('can set cert', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/cert')
.query({ access_token: token })
.send({ cert: CERT, key: KEY })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can reset cert', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/cert')
.query({ access_token: token })
.send({ cert: null, key: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(200);
2018-04-30 21:41:09 -07:00
done();
});
2019-09-08 16:57:08 -07:00
});
2017-02-06 21:53:29 -08:00
});
2019-09-08 16:57:08 -07:00
describe('memory limit', function () {
it('fails for no memory limit', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/memory_limit')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('fails for invalid memory limit', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/memory_limit')
.query({ access_token: token })
.send({ memoryLimit: -34 })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('can set the memory limit', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/memory_limit')
.query({ access_token: token })
.send({ memoryLimit: 512 * 1024 * 1024 })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
taskId = res.body.taskId;
done();
2017-02-06 21:53:29 -08:00
});
2019-09-08 16:57:08 -07:00
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('wait for memory limit', function (done) {
waitForTask(taskId, done);
});
2019-09-08 16:57:08 -07:00
it('did set memory limit', function (done) {
apps.get(APP_ID, function (error, app) {
if (error) return done(error);
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
docker.getContainer(app.containerId).inspect(function (error, data) {
expect(error).to.not.be.ok();
expect(data.HostConfig.Memory).to.be(512 * 1024 * 1024/2);
done();
});
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2017-02-06 21:53:29 -08:00
});
2019-09-08 16:57:08 -07:00
describe('configure location', function () {
it('cannot reconfigure app with missing domain', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/location')
.query({ access_token: token })
.send({ location: 'hellothre' })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('cannot reconfigure app with bad location', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/location')
.query({ access_token: token })
.send({ location: 1234, domain: DOMAIN_0.domain })
.end(function (err, res) {
expect(res.statusCode).to.equal(400);
done();
});
});
2019-09-08 16:57:08 -07:00
it('non admin cannot reconfigure app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/location')
.query({ access_token: token_1 })
.send({ location: APP_LOCATION_NEW, domain: DOMAIN_0.domain, portBindings: { ECHO_SERVER_PORT: 7172 }, accessRestriction: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(403);
2017-02-06 21:53:29 -08:00
done();
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('can change location', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/location')
.query({ access_token: token })
.send({ location: APP_LOCATION_NEW, domain: DOMAIN_0.domain, portBindings: { ECHO_SERVER_PORT: 7172 } })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
taskId = res.body.taskId;
done();
});
});
2016-06-04 18:07:02 -07:00
2019-09-08 16:57:08 -07:00
it('wait for task', function (done) {
waitForTask(taskId, done);
});
2019-09-08 16:57:08 -07:00
it('did change env vars', function (done) {
apps.get(APP_ID, function (error, app) {
if (error) return done(error);
docker.getContainer(app.containerId).inspect(function (error, data) {
expect(error).to.not.be.ok();
expect(data.Config.Env).to.contain('CLOUDRON_APP_ORIGIN=https://' + APP_LOCATION_NEW + '.' + DOMAIN_0.domain);
expect(data.Config.Env).to.contain('CLOUDRON_APP_DOMAIN=' + APP_LOCATION_NEW + '.' + DOMAIN_0.domain);
expect(data.Config.Hostname).to.not.contain(APP_LOCATION_NEW);
expect(data.Config.Env).to.contain('ECHO_SERVER_PORT=7172');
expect(data.HostConfig.PortBindings['7778/tcp'][0].HostPort).to.eql('7172');
done();
});
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('port mapping works after reconfiguration', function (done) {
setTimeout(function () {
var client = net.connect(7172);
client.on('data', function (data) {
expect(data.toString()).to.eql('ECHO_SERVER_PORT=7172');
done();
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
client.on('error', done);
}, 4000);
});
2019-09-08 16:57:08 -07:00
it('app can check addons', function (done) {
console.log('This test can take a while as it waits for scheduler addon to tick 4');
apps.get(APP_ID, function (error, app) {
if (error) return done(error);
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
checkAddons(app, done);
});
});
2017-02-06 21:53:29 -08:00
});
2019-09-08 16:57:08 -07:00
describe('start/stop', function () {
it('non admin cannot stop app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/stop')
.query({ access_token: token_1 })
.end(function (err, res) {
expect(res.statusCode).to.equal(403);
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('can stop app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/stop')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
taskId = res.body.taskId;
done();
});
});
2017-02-06 21:53:29 -08:00
2019-09-08 16:57:08 -07:00
it('wait for task', function (done) {
waitForTask(taskId, done);
});
2019-04-18 13:11:56 +02:00
2019-09-08 16:57:08 -07:00
it('did stop the app', function (done) {
apps.get(APP_ID, function (error, app) {
if (error) return done(error);
2019-09-08 16:57:08 -07:00
superagent.get('http://localhost:' + app.httpPort + APP_MANIFEST.healthCheckPath).end(function (err) {
if (!err || err.code !== 'ECONNREFUSED') return done(new Error('App has not died'));
2019-09-08 16:57:08 -07:00
// wait for app status to be updated
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID).query({ access_token: token }).end(function (error, result) {
if (error || result.statusCode !== 200 || result.body.runState !== 'stopped') return done(new Error('App is not in stopped state'));
2019-09-08 16:57:08 -07:00
done();
});
});
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('nonadmin cannot start app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/start')
.query({ access_token: token_1 })
.end(function (err, res) {
expect(res.statusCode).to.equal(403);
done();
});
});
2019-09-08 16:57:08 -07:00
it('can start app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/start')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
taskId = res.body.taskId;
done();
});
});
2019-09-08 16:57:08 -07:00
it('wait for app to start', function (done) {
waitForTask(taskId, function () { setTimeout(done, 5000); }); // give app 5 seconds to start
});
2019-09-08 16:57:08 -07:00
it('did start the app', function (done) {
apps.get(APP_ID, function (error, app) {
if (error) return done(error);
superagent.get('http://localhost:' + app.httpPort + APP_MANIFEST.healthCheckPath)
.end(function (err, res) {
2019-09-08 16:57:08 -07:00
if (res && res.statusCode === 200) return done();
done(new Error('app is not running'));
});
});
2019-09-08 16:57:08 -07:00
});
});
2019-09-08 16:57:08 -07:00
describe('uninstall', function () {
it('cannot uninstall invalid app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/whatever/uninstall')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(404);
done();
});
});
2015-10-28 11:50:50 +01:00
2019-09-08 16:57:08 -07:00
it('non admin cannot uninstall app', function (done) {
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/uninstall')
.query({ access_token: token_1 })
.end(function (err, res) {
expect(res.statusCode).to.equal(403);
done();
});
2015-10-28 11:50:50 +01:00
});
2019-09-08 16:57:08 -07:00
it('can uninstall app', function (done) {
var fake1 = nock(settings.apiServerOrigin()).get(function (uri) { return uri.indexOf('/api/v1/cloudronapps/') >= 0; }).reply(200, { });
var fake2 = nock(settings.apiServerOrigin()).delete(function (uri) { return uri.indexOf('/api/v1/cloudronapps/') >= 0; }).reply(204, { });
2016-01-29 17:24:18 +01:00
2019-09-08 16:57:08 -07:00
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/uninstall')
.query({ access_token: token })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
taskId = res.body.taskId;
expect(fake1.isDone()).to.be.ok();
expect(fake2.isDone()).to.be.ok();
done();
});
});
2017-02-06 21:53:29 -08:00
});
2016-01-29 17:24:18 +01:00
2019-09-08 16:57:08 -07:00
describe('post uninstall', function () {
let appEntry;
2016-01-29 17:24:18 +01:00
2019-09-08 16:57:08 -07:00
it('can get app', function (done) {
apps.get(APP_ID, function (error, app) {
expect(!error).to.be.ok();
expect(app).to.be.an('object');
appEntry = app;
done();
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2019-09-08 16:57:08 -07:00
it('did uninstall the app', function (done) {
waitForTask(taskId, done);
});
2019-09-08 16:57:08 -07:00
it('app is gone', function (done) {
2017-02-06 21:53:29 -08:00
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
2018-04-30 21:41:09 -07:00
.query({ access_token: token })
.end(function (err, res) {
if (res.statusCode === 404) return done(null);
2019-09-08 16:57:08 -07:00
done(new Error('App is still there'));
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2018-02-05 22:17:16 +01:00
2019-09-08 16:57:08 -07:00
it('container destroyed', function (done) {
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
expect(error).to.be.ok();
expect(data).to.not.be.ok();
done();
2018-04-30 21:41:09 -07:00
});
2019-09-08 16:57:08 -07:00
});
2015-10-20 11:33:19 -07:00
2019-09-08 16:57:08 -07:00
it('volume destroyed', function (done) {
expect(!fs.existsSync(paths.APPS_DATA_DIR + '/' + APP_ID));
done();
});
2019-09-08 16:57:08 -07:00
it('removed nginx', function (done) {
expect(!fs.existsSync(paths.NGINX_APPCONFIG_DIR + '/' + APP_LOCATION + '.conf'));
2018-02-05 22:17:16 +01:00
done();
});
2019-09-08 16:57:08 -07:00
it('removed redis addon', function (done) {
docker.getContainer('redis-' + APP_ID).inspect(function (error) {
expect(error).to.be.ok();
done();
});
});
2017-02-06 21:53:29 -08:00
});
2015-09-09 15:48:35 -07:00
2019-09-08 16:57:08 -07:00
describe('not sure what this is', function () {
it('app install succeeds again', function (done) {
var fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST });
var fake2 = nock(settings.apiServerOrigin()).post(function (uri) { return uri.indexOf('/api/v1/cloudronapps') >= 0; }, (body) => body.appstoreId === APP_STORE_ID && body.manifestId === APP_MANIFEST.id && body.appId).reply(201, { });
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ appStoreId: APP_STORE_ID, location: APP_LOCATION_2, domain: DOMAIN_0.domain, portBindings: null, accessRestriction: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(202);
expect(res.body.id).to.be.a('string');
APP_ID = res.body.id;
expect(fake1.isDone()).to.be.ok();
expect(fake2.isDone()).to.be.ok();
done();
});
});
it('app install fails with developer token', function (done) {
superagent.post(SERVER_URL + '/api/v1/developer/login')
.send({ username: USERNAME, password: PASSWORD })
.end(function (error, result) {
expect(error).to.not.be.ok();
expect(result.statusCode).to.equal(200);
expect(new Date(result.body.expires).toString()).to.not.be('Invalid Date');
expect(result.body.accessToken).to.be.a('string');
// overwrite non dev token
token = result.body.accessToken;
superagent.post(SERVER_URL + '/api/v1/apps/install')
.query({ access_token: token })
.send({ manifest: APP_MANIFEST, location: APP_LOCATION+APP_LOCATION, domain: DOMAIN_0.domain, portBindings: null, accessRestriction: null })
.end(function (err, res) {
expect(res.statusCode).to.equal(424); // appstore purchase external error
done();
});
});
});
});
2019-08-05 07:01:12 -07:00
2019-09-08 16:57:08 -07:00
describe('the end', function () {
// this is here so we can debug things if tests fail
it('can stop box', stopBox);
});
});