Fix app test
This commit is contained in:
@@ -122,6 +122,10 @@ CloudronError.SELF_UPGRADE_NOT_SUPPORTED = 'Self upgrade not supported';
|
|||||||
function initialize(callback) {
|
function initialize(callback) {
|
||||||
assert.strictEqual(typeof callback, 'function');
|
assert.strictEqual(typeof callback, 'function');
|
||||||
|
|
||||||
|
gConfigState = { dns: false, tls: false, configured: false };
|
||||||
|
gUpdatingDns = false;
|
||||||
|
gBoxAndUserDetails = null;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
installAppBundle,
|
installAppBundle,
|
||||||
checkConfigState,
|
checkConfigState,
|
||||||
|
|||||||
+1
-1
@@ -64,7 +64,7 @@ function saveSync() {
|
|||||||
fs.writeFileSync(cloudronConfigFileName, JSON.stringify(data, null, 4)); // functions are ignored by JSON.stringify
|
fs.writeFileSync(cloudronConfigFileName, JSON.stringify(data, null, 4)); // functions are ignored by JSON.stringify
|
||||||
}
|
}
|
||||||
|
|
||||||
function _reset (callback) {
|
function _reset(callback) {
|
||||||
safe.fs.unlinkSync(cloudronConfigFileName);
|
safe.fs.unlinkSync(cloudronConfigFileName);
|
||||||
|
|
||||||
initConfig();
|
initConfig();
|
||||||
|
|||||||
+79
-355
@@ -62,20 +62,7 @@ var USER_1_ID = null, USERNAME_1 = 'user', EMAIL_1 ='user@me.com';
|
|||||||
var token = null; // authentication token
|
var token = null; // authentication token
|
||||||
var token_1 = null;
|
var token_1 = null;
|
||||||
|
|
||||||
var awsHostedZones = {
|
var awsHostedZones;
|
||||||
HostedZones: [{
|
|
||||||
Id: '/hostedzone/ZONEID',
|
|
||||||
Name: 'localhost.',
|
|
||||||
CallerReference: '305AFD59-9D73-4502-B020-F4E6F889CB30',
|
|
||||||
ResourceRecordSetCount: 2,
|
|
||||||
ChangeInfo: {
|
|
||||||
Id: '/change/CKRTFJA0ANHXB',
|
|
||||||
Status: 'INSYNC'
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
IsTruncated: false,
|
|
||||||
MaxItems: '100'
|
|
||||||
};
|
|
||||||
|
|
||||||
function startDockerProxy(interceptor, callback) {
|
function startDockerProxy(interceptor, callback) {
|
||||||
assert.strictEqual(typeof interceptor, 'function');
|
assert.strictEqual(typeof interceptor, 'function');
|
||||||
@@ -148,21 +135,38 @@ function checkRedis(containerId, done) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Apps', function () {
|
var dockerProxy;
|
||||||
this.timeout(100000);
|
var imageDeleted;
|
||||||
|
var imageCreated;
|
||||||
|
|
||||||
var dockerProxy;
|
function startBox(done) {
|
||||||
var imageDeleted = false;
|
|
||||||
var imageCreated = false;
|
|
||||||
|
|
||||||
before(function (done) {
|
|
||||||
config._reset();
|
config._reset();
|
||||||
|
|
||||||
|
imageDeleted = false;
|
||||||
|
imageCreated = false;
|
||||||
|
|
||||||
process.env.TEST_CREATE_INFRA = 1;
|
process.env.TEST_CREATE_INFRA = 1;
|
||||||
|
|
||||||
safe.fs.unlinkSync(paths.INFRA_VERSION_FILE);
|
safe.fs.unlinkSync(paths.INFRA_VERSION_FILE);
|
||||||
child_process.execSync('docker ps -qa | xargs --no-run-if-empty docker rm -f');
|
child_process.execSync('docker ps -qa | xargs --no-run-if-empty docker rm -f');
|
||||||
|
|
||||||
|
config.set('fqdn', 'foobar.com');
|
||||||
|
|
||||||
|
awsHostedZones = {
|
||||||
|
HostedZones: [{
|
||||||
|
Id: '/hostedzone/ZONEID',
|
||||||
|
Name: config.zoneName() + '.',
|
||||||
|
CallerReference: '305AFD59-9D73-4502-B020-F4E6F889CB30',
|
||||||
|
ResourceRecordSetCount: 2,
|
||||||
|
ChangeInfo: {
|
||||||
|
Id: '/change/CKRTFJA0ANHXB',
|
||||||
|
Status: 'INSYNC'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
IsTruncated: false,
|
||||||
|
MaxItems: '100'
|
||||||
|
};
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
// first clear, then start server. otherwise, taskmanager spins up tasks for obsolete appIds
|
// first clear, then start server. otherwise, taskmanager spins up tasks for obsolete appIds
|
||||||
database.initialize,
|
database.initialize,
|
||||||
@@ -238,9 +242,9 @@ describe('Apps', function () {
|
|||||||
console.log('This test can take ~40 seconds to start as it waits for infra to be ready');
|
console.log('This test can take ~40 seconds to start as it waits for infra to be ready');
|
||||||
setTimeout(done, 40000);
|
setTimeout(done, 40000);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
after(function (done) {
|
function stopBox(done) {
|
||||||
delete process.env.TEST_CREATE_INFRA;
|
delete process.env.TEST_CREATE_INFRA;
|
||||||
|
|
||||||
// child_process.execSync('docker ps -qa | xargs --no-run-if-empty docker rm -f');
|
// child_process.execSync('docker ps -qa | xargs --no-run-if-empty docker rm -f');
|
||||||
@@ -250,17 +254,19 @@ describe('Apps', function () {
|
|||||||
async.series([
|
async.series([
|
||||||
taskmanager.stopPendingTasks,
|
taskmanager.stopPendingTasks,
|
||||||
taskmanager.waitForPendingTasks,
|
taskmanager.waitForPendingTasks,
|
||||||
|
appdb._clear,
|
||||||
server.stop,
|
server.stop,
|
||||||
ldap.stop,
|
ldap.stop,
|
||||||
simpleauth.stop,
|
simpleauth.stop,
|
||||||
config._reset,
|
config._reset
|
||||||
], done);
|
], done);
|
||||||
});
|
}
|
||||||
|
|
||||||
describe('App API', function () {
|
describe('App API', function () {
|
||||||
after(function (done) {
|
this.timeout(100000);
|
||||||
appdb._clear(done); // TODO: test proper uninstall (requires mock for aws)
|
|
||||||
});
|
before(startBox);
|
||||||
|
after(stopBox);
|
||||||
|
|
||||||
it('app install fails - missing manifest', function (done) {
|
it('app install fails - missing manifest', function (done) {
|
||||||
superagent.post(SERVER_URL + '/api/v1/apps/install')
|
superagent.post(SERVER_URL + '/api/v1/apps/install')
|
||||||
@@ -607,21 +613,27 @@ describe('Apps', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('App installation', function () {
|
describe('App installation', function () {
|
||||||
this.timeout(50000);
|
this.timeout(100000);
|
||||||
|
|
||||||
var apiHockInstance = hock.createHock({ throwOnUnmatched: false }), apiHockServer;
|
var apiHockInstance = hock.createHock({ throwOnUnmatched: false }), apiHockServer;
|
||||||
var awsHockInstance = hock.createHock({ throwOnUnmatched: false }), awsHockServer;
|
var awsHockInstance = hock.createHock({ throwOnUnmatched: false }), awsHockServer;
|
||||||
|
|
||||||
|
// *.foobar.com
|
||||||
|
var validCert1, validKey1;
|
||||||
|
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
|
child_process.execSync('openssl req -subj "/CN=*.foobar.com/O=My Company Name LTD./C=US" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /tmp/server.key -out /tmp/server.crt');
|
||||||
|
validKey1 = fs.readFileSync('/tmp/server.key', 'utf8');
|
||||||
|
validCert1 = fs.readFileSync('/tmp/server.crt', 'utf8');
|
||||||
|
|
||||||
APP_ID = uuid.v4();
|
APP_ID = uuid.v4();
|
||||||
|
|
||||||
imageDeleted = false;
|
|
||||||
imageCreated = false;
|
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
|
startBox,
|
||||||
|
|
||||||
function (callback) {
|
function (callback) {
|
||||||
apiHockInstance
|
apiHockInstance
|
||||||
.get('/api/v1/apps/' + APP_STORE_ID + '/versions/' + APP_MANIFEST.version + '/icon')
|
.get('/api/v1/apps/' + APP_STORE_ID + '/versions/' + APP_MANIFEST.version + '/icon')
|
||||||
@@ -631,12 +643,17 @@ describe('Apps', function () {
|
|||||||
apiHockServer = http.createServer(apiHockInstance.handler).listen(port, callback);
|
apiHockServer = http.createServer(apiHockInstance.handler).listen(port, callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
settings.setDnsConfig.bind(null, { provider: 'route53', accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccessKey', endpoint: 'http://localhost:5353' }, config.fqdn()),
|
||||||
|
|
||||||
|
settings.setTlsConfig.bind(null, { provider: 'caas' }),
|
||||||
|
|
||||||
function (callback) {
|
function (callback) {
|
||||||
awsHockInstance
|
awsHockInstance
|
||||||
.get('/2013-04-01/hostedzone')
|
.get('/2013-04-01/hostedzone')
|
||||||
.max(Infinity)
|
.max(Infinity)
|
||||||
.reply(200, js2xml('ListHostedZonesResponse', awsHostedZones, { arrayMap: { HostedZones: 'HostedZone'} }), { 'Content-Type': 'application/xml' })
|
.reply(200, js2xml('ListHostedZonesResponse', awsHostedZones, { arrayMap: { HostedZones: 'HostedZone'} }), { 'Content-Type': 'application/xml' })
|
||||||
.get('/2013-04-01/hostedzone/ZONEID/rrset?maxitems=1&name=appslocation.localhost.&type=A')
|
.filteringPathRegEx(/name=[^&]*/, 'name=location')
|
||||||
|
.get('/2013-04-01/hostedzone/ZONEID/rrset?maxitems=1&name=location&type=A')
|
||||||
.max(Infinity)
|
.max(Infinity)
|
||||||
.reply(200, js2xml('ListResourceRecordSetsResponse', { ResourceRecordSets: [ ] }, { 'Content-Type': 'application/xml' }))
|
.reply(200, js2xml('ListResourceRecordSetsResponse', { ResourceRecordSets: [ ] }, { 'Content-Type': 'application/xml' }))
|
||||||
.filteringRequestBody(function (unusedBody) { return ''; }) // strip out body
|
.filteringRequestBody(function (unusedBody) { return ''; }) // strip out body
|
||||||
@@ -651,14 +668,14 @@ describe('Apps', function () {
|
|||||||
|
|
||||||
after(function (done) {
|
after(function (done) {
|
||||||
APP_ID = null;
|
APP_ID = null;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
apiHockServer.close.bind(apiHockServer),
|
apiHockServer.close.bind(apiHockServer),
|
||||||
awsHockServer.close.bind(awsHockServer)
|
awsHockServer.close.bind(awsHockServer),
|
||||||
|
stopBox
|
||||||
], done);
|
], done);
|
||||||
});
|
});
|
||||||
|
|
||||||
var appResult = null /* the json response */, appEntry = null /* entry from database */;
|
var appResult = null, appEntry = null;
|
||||||
|
|
||||||
it('can install test app', function (done) {
|
it('can install test app', function (done) {
|
||||||
var fake1 = nock(config.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST });
|
var fake1 = nock(config.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST });
|
||||||
@@ -680,11 +697,10 @@ describe('Apps', function () {
|
|||||||
|
|
||||||
superagent.post(SERVER_URL + '/api/v1/apps/install')
|
superagent.post(SERVER_URL + '/api/v1/apps/install')
|
||||||
.query({ access_token: token })
|
.query({ access_token: token })
|
||||||
.send({ appStoreId: APP_STORE_ID, password: PASSWORD, location: APP_LOCATION, portBindings: null, accessRestriction: null })
|
.send({ appStoreId: APP_STORE_ID, password: PASSWORD, location: APP_LOCATION, portBindings: { ECHO_SERVER_PORT: 7171 }, accessRestriction: null })
|
||||||
.end(function (err, res) {
|
.end(function (err, res) {
|
||||||
expect(res.statusCode).to.equal(202);
|
expect(res.statusCode).to.equal(202);
|
||||||
expect(fake1.isDone()).to.be.ok();
|
expect(fake1.isDone()).to.be.ok();
|
||||||
expect(res.body.id).to.be.a('string');
|
|
||||||
APP_ID = res.body.id;
|
APP_ID = res.body.id;
|
||||||
checkInstallStatus();
|
checkInstallStatus();
|
||||||
});
|
});
|
||||||
@@ -706,6 +722,7 @@ describe('Apps', function () {
|
|||||||
|
|
||||||
it('installation - container created', function (done) {
|
it('installation - container created', function (done) {
|
||||||
expect(appResult.containerId).to.be(undefined);
|
expect(appResult.containerId).to.be(undefined);
|
||||||
|
expect(appEntry.containerId).to.be.ok();
|
||||||
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
|
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
|
||||||
expect(error).to.not.be.ok();
|
expect(error).to.not.be.ok();
|
||||||
expect(data.Config.ExposedPorts['7777/tcp']).to.eql({ });
|
expect(data.Config.ExposedPorts['7777/tcp']).to.eql({ });
|
||||||
@@ -716,6 +733,8 @@ describe('Apps', function () {
|
|||||||
expect(data.Config.Env).to.contain('APP_DOMAIN=' + config.appFqdn(APP_LOCATION));
|
expect(data.Config.Env).to.contain('APP_DOMAIN=' + config.appFqdn(APP_LOCATION));
|
||||||
// Hostname must not be set of app fqdn or app location!
|
// Hostname must not be set of app fqdn or app location!
|
||||||
expect(data.Config.Hostname).to.not.contain(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();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -735,16 +754,31 @@ describe('Apps', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('installation - is up and running', function (done) {
|
it('installation - http is up and running', function (done) {
|
||||||
|
var tryCount = 20;
|
||||||
expect(appResult.httpPort).to.be(undefined);
|
expect(appResult.httpPort).to.be(undefined);
|
||||||
setTimeout(function () {
|
(function healthCheck() {
|
||||||
superagent.get('http://localhost:' + appEntry.httpPort + appResult.manifest.healthCheckPath)
|
superagent.get('http://localhost:' + appEntry.httpPort + appResult.manifest.healthCheckPath)
|
||||||
.end(function (err, res) {
|
.end(function (err, res) {
|
||||||
|
if (err || res.statusCode !== 200) {
|
||||||
|
if (--tryCount === 0) return done(new Error('Timedout'));
|
||||||
|
return setTimeout(healthCheck, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
expect(!err).to.be.ok();
|
expect(!err).to.be.ok();
|
||||||
expect(res.statusCode).to.equal(200);
|
expect(res.statusCode).to.equal(200);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}, 2000); // give some time for docker to settle
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('installation - 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();
|
||||||
|
});
|
||||||
|
client.on('error', done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('installation - running container has volume mounted', function (done) {
|
it('installation - running container has volume mounted', function (done) {
|
||||||
@@ -800,7 +834,7 @@ describe('Apps', function () {
|
|||||||
|
|
||||||
it('installation - app can check addons', function (done) {
|
it('installation - app can check addons', function (done) {
|
||||||
this.timeout(120000);
|
this.timeout(120000);
|
||||||
console.log('This test can take a while as it waits for scheduler addon to tick 1');
|
console.log('This test can take a while as it waits for scheduler addon to tick 3');
|
||||||
checkAddons(appEntry, done);
|
checkAddons(appEntry, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -933,276 +967,6 @@ describe('Apps', function () {
|
|||||||
checkAddons(appEntry, done);
|
checkAddons(appEntry, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can uninstall app', function (done) {
|
|
||||||
var fake1 = nock(config.apiServerOrigin()).post('/api/v1/exchangeBoxTokenWithUserToken?token=APPSTORE_TOKEN').reply(201, { userId: 'USER_ID', cloudronId: 'CLOUDRON_ID', token: 'ACCESS_TOKEN' });
|
|
||||||
var fake2 = nock(config.apiServerOrigin()).get(function (uri) { return uri.indexOf('/api/v1/users/USER_ID/cloudrons/CLOUDRON_ID/apps/') >= 0; }).reply(200, { });
|
|
||||||
var fake3 = nock(config.apiServerOrigin()).delete(function (uri) { return uri.indexOf('/api/v1/users/USER_ID/cloudrons/CLOUDRON_ID/apps/') >= 0; }).reply(204, { });
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
function checkUninstallStatus() {
|
|
||||||
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
|
|
||||||
.query({ access_token: token })
|
|
||||||
.end(function (err, res) {
|
|
||||||
if (res.statusCode === 404) return done(null);
|
|
||||||
if (++count > 50) return done(new Error('Timedout'));
|
|
||||||
setTimeout(checkUninstallStatus, 1000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/uninstall')
|
|
||||||
.send({ password: PASSWORD })
|
|
||||||
.query({ access_token: token })
|
|
||||||
.end(function (err, res) {
|
|
||||||
expect(res.statusCode).to.equal(202);
|
|
||||||
checkUninstallStatus();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uninstalled - container destroyed', function (done) {
|
|
||||||
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
|
|
||||||
if (data) {
|
|
||||||
console.log('Container is still alive', data);
|
|
||||||
}
|
|
||||||
expect(error).to.be.ok();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uninstalled - image destroyed', function (done) {
|
|
||||||
expect(imageDeleted).to.be.ok();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uninstalled - volume destroyed', function (done) {
|
|
||||||
expect(!fs.existsSync(paths.DATA_DIR + '/' + APP_ID));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uninstalled - unregistered subdomain', function (done) {
|
|
||||||
apiHockInstance.done(function (error) { // checks if all the apiHockServer APIs were called
|
|
||||||
expect(!error).to.be.ok();
|
|
||||||
|
|
||||||
awsHockInstance.done(function (error) {
|
|
||||||
expect(!error).to.be.ok();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uninstalled - removed nginx', function (done) {
|
|
||||||
expect(!fs.existsSync(paths.NGINX_APPCONFIG_DIR + '/' + APP_LOCATION + '.conf'));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uninstalled - removed redis addon', function (done) {
|
|
||||||
docker.getContainer('redis-' + APP_ID).inspect(function (error, data) {
|
|
||||||
expect(error).to.be.ok();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('App installation - port bindings', function () {
|
|
||||||
this.timeout(50000);
|
|
||||||
|
|
||||||
var apiHockInstance = hock.createHock({ throwOnUnmatched: false }), apiHockServer;
|
|
||||||
var awsHockInstance = hock.createHock({ throwOnUnmatched: false }), awsHockServer;
|
|
||||||
|
|
||||||
// *.foobar.com
|
|
||||||
var validCert1, validKey1;
|
|
||||||
|
|
||||||
before(function (done) {
|
|
||||||
imageDeleted = false;
|
|
||||||
imageCreated = false;
|
|
||||||
|
|
||||||
child_process.execSync('openssl req -subj "/CN=*.foobar.com/O=My Company Name LTD./C=US" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /tmp/server.key -out /tmp/server.crt');
|
|
||||||
validKey1 = fs.readFileSync('/tmp/server.key', 'utf8');
|
|
||||||
validCert1 = fs.readFileSync('/tmp/server.crt', 'utf8');
|
|
||||||
|
|
||||||
APP_ID = uuid.v4();
|
|
||||||
|
|
||||||
async.series([
|
|
||||||
function (callback) {
|
|
||||||
config.set('fqdn', 'test.foobar.com');
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
|
|
||||||
function (callback) {
|
|
||||||
apiHockInstance
|
|
||||||
.get('/api/v1/apps/' + APP_STORE_ID + '/versions/' + APP_MANIFEST.version + '/icon')
|
|
||||||
.replyWithFile(200, path.resolve(__dirname, '../../../webadmin/src/img/appicon_fallback.png'));
|
|
||||||
|
|
||||||
var port = parseInt(url.parse(config.apiServerOrigin()).port, 10);
|
|
||||||
apiHockServer = http.createServer(apiHockInstance.handler).listen(port, callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
settings.setDnsConfig.bind(null, { provider: 'route53', accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccessKey', endpoint: 'http://localhost:5353' }, config.fqdn()),
|
|
||||||
|
|
||||||
settings.setTlsConfig.bind(null, { provider: 'caas' }),
|
|
||||||
|
|
||||||
function (callback) {
|
|
||||||
awsHockInstance
|
|
||||||
.get('/2013-04-01/hostedzone')
|
|
||||||
.max(Infinity)
|
|
||||||
.reply(200, js2xml('ListHostedZonesResponse', awsHostedZones, { arrayMap: { HostedZones: 'HostedZone'} }), { 'Content-Type': 'application/xml' })
|
|
||||||
.filteringPathRegEx(/name=[^&]*/, 'name=location')
|
|
||||||
.get('/2013-04-01/hostedzone/ZONEID/rrset?maxitems=1&name=location&type=A')
|
|
||||||
.max(Infinity)
|
|
||||||
.reply(200, js2xml('ListResourceRecordSetsResponse', { ResourceRecordSets: [ ] }, { 'Content-Type': 'application/xml' }))
|
|
||||||
.filteringRequestBody(function (unusedBody) { return ''; }) // strip out body
|
|
||||||
.post('/2013-04-01/hostedzone/ZONEID/rrset/')
|
|
||||||
.max(Infinity)
|
|
||||||
.reply(200, js2xml('ChangeResourceRecordSetsResponse', { ChangeInfo: { Id: 'dnsrecordid', Status: 'INSYNC' } }), { 'Content-Type': 'application/xml' });
|
|
||||||
|
|
||||||
awsHockServer = http.createServer(awsHockInstance.handler).listen(5353, callback);
|
|
||||||
}
|
|
||||||
], done);
|
|
||||||
});
|
|
||||||
|
|
||||||
after(function (done) {
|
|
||||||
APP_ID = null;
|
|
||||||
async.series([
|
|
||||||
apiHockServer.close.bind(apiHockServer),
|
|
||||||
awsHockServer.close.bind(awsHockServer)
|
|
||||||
], done);
|
|
||||||
});
|
|
||||||
|
|
||||||
var appResult = null, appEntry = null;
|
|
||||||
|
|
||||||
it('can install test app', function (done) {
|
|
||||||
var fake1 = nock(config.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST });
|
|
||||||
var fake2 = nock(config.apiServerOrigin()).post('/api/v1/exchangeBoxTokenWithUserToken?token=APPSTORE_TOKEN').reply(201, { userId: 'USER_ID', cloudronId: 'CLOUDRON_ID', token: 'ACCESS_TOKEN' });
|
|
||||||
var fake3 = nock(config.apiServerOrigin()).post(function (uri) { return uri.indexOf('/api/v1/users/USER_ID/cloudrons/CLOUDRON_ID/apps/') >= 0; }, { 'appstoreId': APP_STORE_ID }).reply(201, { });
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
function checkInstallStatus() {
|
|
||||||
superagent.get(SERVER_URL + '/api/v1/apps/' + APP_ID)
|
|
||||||
.query({ access_token: token })
|
|
||||||
.end(function (err, res) {
|
|
||||||
expect(res.statusCode).to.equal(200);
|
|
||||||
if (res.body.installationState === appdb.ISTATE_INSTALLED) { appResult = res.body; return done(null); }
|
|
||||||
if (res.body.installationState === appdb.ISTATE_ERROR) return done(new Error('Install error'));
|
|
||||||
if (++count > 50) return done(new Error('Timedout'));
|
|
||||||
setTimeout(checkInstallStatus, 1000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
superagent.post(SERVER_URL + '/api/v1/apps/install')
|
|
||||||
.query({ access_token: token })
|
|
||||||
.send({ appStoreId: APP_STORE_ID, password: PASSWORD, location: APP_LOCATION, portBindings: { ECHO_SERVER_PORT: 7171 }, accessRestriction: null })
|
|
||||||
.end(function (err, res) {
|
|
||||||
expect(res.statusCode).to.equal(202);
|
|
||||||
expect(fake1.isDone()).to.be.ok();
|
|
||||||
APP_ID = res.body.id;
|
|
||||||
checkInstallStatus();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - image created', function (done) {
|
|
||||||
expect(imageCreated).to.be.ok();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - 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;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - 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('ECHO_SERVER_PORT=7171');
|
|
||||||
expect(data.HostConfig.PortBindings['7778/tcp'][0].HostPort).to.eql('7171');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - nginx config', function (done) {
|
|
||||||
expect(fs.existsSync(paths.NGINX_APPCONFIG_DIR + '/' + APP_LOCATION + '.conf'));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - registered subdomain', function (done) {
|
|
||||||
// this is checked in unregister subdomain testcase
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - volume created', function (done) {
|
|
||||||
expect(fs.existsSync(paths.DATA_DIR + '/' + APP_ID));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - http is up and running', function (done) {
|
|
||||||
var tryCount = 20;
|
|
||||||
expect(appResult.httpPort).to.be(undefined);
|
|
||||||
(function healthCheck() {
|
|
||||||
superagent.get('http://localhost:' + appEntry.httpPort + appResult.manifest.healthCheckPath)
|
|
||||||
.end(function (err, res) {
|
|
||||||
if (err || res.statusCode !== 200) {
|
|
||||||
if (--tryCount === 0) return done(new Error('Timedout'));
|
|
||||||
return setTimeout(healthCheck, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(!err).to.be.ok();
|
|
||||||
expect(res.statusCode).to.equal(200);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - 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();
|
|
||||||
});
|
|
||||||
client.on('error', done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - running container has volume mounted', function (done) {
|
|
||||||
docker.getContainer(appEntry.containerId).inspect(function (error, data) {
|
|
||||||
expect(error).to.not.be.ok();
|
|
||||||
|
|
||||||
// support newer docker versions
|
|
||||||
if (data.Volumes) {
|
|
||||||
expect(data.Volumes['/app/data']).to.eql(paths.DATA_DIR + '/' + APP_ID + '/data');
|
|
||||||
} else {
|
|
||||||
expect(data.Mounts.filter(function (mount) { return mount.Destination === '/app/data'; })[0].Source).to.eql(paths.DATA_DIR + '/' + APP_ID + '/data');
|
|
||||||
}
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('installation - app can populate addons', function (done) {
|
|
||||||
superagent.get('http://localhost:' + appEntry.httpPort + '/populate_addons').end(function (err, res) {
|
|
||||||
expect(!err).to.be.ok();
|
|
||||||
expect(res.statusCode).to.equal(200);
|
|
||||||
for (var key in res.body) {
|
|
||||||
expect(res.body[key]).to.be('OK');
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - app can check addons', function (done) {
|
|
||||||
this.timeout(120000);
|
|
||||||
console.log('This test can take a while as it waits for scheduler addon to tick 3');
|
|
||||||
checkAddons(appEntry, done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installation - redis addon created', function (done) {
|
|
||||||
checkRedis('redis-' + APP_ID, done);
|
|
||||||
});
|
|
||||||
|
|
||||||
function checkConfigureStatus(count, done) {
|
function checkConfigureStatus(count, done) {
|
||||||
assert.strictEqual(typeof count, 'number');
|
assert.strictEqual(typeof count, 'number');
|
||||||
assert.strictEqual(typeof done, 'function');
|
assert.strictEqual(typeof done, 'function');
|
||||||
@@ -1340,45 +1104,6 @@ describe('Apps', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
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);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// osx: if this test is failing, it is probably because of a stray port binding in boot2docker
|
|
||||||
it('did stop the app', function (done) {
|
|
||||||
var timer1, timer2;
|
|
||||||
|
|
||||||
function finished() {
|
|
||||||
clearTimeout(timer1);
|
|
||||||
clearTimeout(timer2);
|
|
||||||
|
|
||||||
if (done) done();
|
|
||||||
|
|
||||||
// avoid double callbacks
|
|
||||||
done = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function waitForAppToDie() {
|
|
||||||
var client = net.connect(7171);
|
|
||||||
client.setTimeout(2000);
|
|
||||||
client.on('connect', function () {
|
|
||||||
timer1 = setTimeout(waitForAppToDie, 1000);
|
|
||||||
});
|
|
||||||
client.on('timeout', function () { finished(); });
|
|
||||||
client.on('error', function (error) { finished(); });
|
|
||||||
client.on('data', function (data) {
|
|
||||||
timer2 = setTimeout(waitForAppToDie, 1000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForAppToDie();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can uninstall app', function (done) {
|
it('can uninstall app', function (done) {
|
||||||
var fake1 = nock(config.apiServerOrigin()).post('/api/v1/exchangeBoxTokenWithUserToken?token=APPSTORE_TOKEN').reply(201, { userId: 'USER_ID', cloudronId: 'CLOUDRON_ID', token: 'ACCESS_TOKEN' });
|
var fake1 = nock(config.apiServerOrigin()).post('/api/v1/exchangeBoxTokenWithUserToken?token=APPSTORE_TOKEN').reply(201, { userId: 'USER_ID', cloudronId: 'CLOUDRON_ID', token: 'ACCESS_TOKEN' });
|
||||||
var fake2 = nock(config.apiServerOrigin()).get(function (uri) { return uri.indexOf('/api/v1/users/USER_ID/cloudrons/CLOUDRON_ID/apps/') >= 0; }).reply(200, { });
|
var fake2 = nock(config.apiServerOrigin()).get(function (uri) { return uri.indexOf('/api/v1/users/USER_ID/cloudrons/CLOUDRON_ID/apps/') >= 0; }).reply(200, { });
|
||||||
@@ -1444,5 +1169,4 @@ describe('Apps', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -271,7 +271,7 @@ function getEmailDnsRecords(callback) {
|
|||||||
function ignoreError(what, func) {
|
function ignoreError(what, func) {
|
||||||
return function (callback) {
|
return function (callback) {
|
||||||
func(function (error) {
|
func(function (error) {
|
||||||
if (error && process.env.BOX_ENV !== 'test') console.error('Ignored error - ' + what + ':', error);
|
if (error) debug('Ignored error - ' + what + ':', error);
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user