apostrophe
Version:
The Apostrophe Content Management System.
553 lines (524 loc) • 16.6 kB
JavaScript
var t = require('../test-lib/test.js');
var assert = require('assert');
var apos, apos2;
var request = require('request-promise');
var _ = require('@sailshq/lodash');
var Promise = require('bluebird');
describe('Global', function() {
this.timeout(t.timeout);
after(function(done) {
return t.destroy(apos, function() {
return t.destroy(apos2, done);
});
});
it('global should exist on the apos object', function(done) {
apos = require('../index.js')({
root: module,
shortName: 'test',
modules: {
'apostrophe-express': {
secret: 'xxx',
port: 7900
},
'products': {
alias: 'products',
extend: 'apostrophe-pieces',
name: 'product'
},
'apostrophe-global': {
whileBusyDelay: 0.5,
addFields: [
{
name: 'testString',
type: 'string',
def: 'populated def'
},
{
name: '_featuredProducts',
type: 'joinByArray',
withType: 'product'
}
]
}
},
afterInit: function(callback) {
assert(apos.global);
// In tests this will be the name of the test file,
// so override that in order to get apostrophe to
// listen normally and not try to run a task. -Tom
apos.argv._ = [];
return callback(null);
},
afterListen: function(err) {
assert(!err);
done();
}
});
});
it('should populate when global.addGlobalToData is used as middleware', function(done) {
var req = apos.tasks.getAnonReq();
req.res.status = function(n) {
assert(n <= 400);
return req.res;
};
req.res.send = function(m) {};
return apos.global.addGlobalToData(req, req.res, function() {
assert(req.data.global);
assert(req.data.global.type === 'apostrophe-global');
done();
});
});
it('should populate when global.addGlobalToData is used with a callback', function(done) {
var req = apos.tasks.getAnonReq();
return apos.global.addGlobalToData(req, function(err) {
assert(!err);
assert(req.data.global);
assert(req.data.global.type === 'apostrophe-global');
done();
});
});
it('should populate when global.addGlobalToData is used to return a promise', function() {
var req = apos.tasks.getAnonReq();
return apos.global.addGlobalToData(req).then(function() {
assert(req.data.global);
assert(req.data.global.type === 'apostrophe-global');
});
});
it('should populate def values of schema properties at insert time', function(done) {
var req = apos.tasks.getAnonReq();
return apos.global.addGlobalToData(req, function(err) {
assert(!err);
assert(req.data.global.testString === 'populated def');
done();
});
});
it('insert products via task', function() {
return apos.tasks.invoke('products:generate', [], {});
});
var product;
it('set a product join up in the global doc', function() {
var req = apos.tasks.getReq();
return apos.products.find(req).sort({ sortTitle: 1 }).limit(1).toObject().then(function(object) {
assert(object);
product = object;
}).then(function() {
return apos.docs.db.update({
slug: 'global'
}, {
$set: {
featuredProductsIds: [ product._id ]
}
});
});
});
it('fetch the global doc, verify join', function() {
var req = apos.tasks.getAnonReq();
return apos.global.addGlobalToData(req).then(function() {
assert(req.data.global);
assert(req.data.global._featuredProducts);
assert(req.data.global._featuredProducts.length === 1);
assert(req.data.global._featuredProducts[0].slug === product.slug);
});
});
it('give global doc a workflowLocale property to simulate use with workflow', function() {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$set: {
workflowLocale: 'en'
}
});
});
it('busy mechanism (global)', function() {
this.timeout(50000);
var retrieved = false;
return apos.global.whileBusy(function() {
// Intentional parallelism: start a request while
// we're busy, so we can verify it waits
request('http://localhost:7900/').then(function(content) {
// fn should complete before this is retrieved
assert(content.indexOf('counts: 10') !== -1);
retrieved = true;
});
return apos.docs.db.findOne({
type: 'apostrophe-global'
}).then(function(global) {
assert(global.globalBusy);
}).then(function() {
return Promise.mapSeries(_.range(0, 10), function(i) {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$inc: {
counts: 1
}
}).then(function() {
return Promise.delay(50);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(doc) {
assert(doc.counts === 10);
});
}).then(function() {
assert(!retrieved);
});
}).then(function() {
// Wait up to 1 second more for the delayed request to succeed
var start = Date.now();
return check();
function check() {
if (retrieved) {
return;
}
if (Date.now() - start > 1000) {
assert(false);
}
return Promise.delay(50).then(check);
}
}).then(function() {
// Now that we are no longer busy a new request should take less than a second
return request('http://localhost:7900/').then(function(content) {
assert(content.indexOf('counts: 10') !== -1);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(global) {
assert(!global.globalBusy);
});
});
it('reset counts', function() {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$set: {
counts: 0
}
});
});
it('busy mechanism (default locale)', function() {
this.timeout(50000);
var retrieved = false;
return apos.global.whileBusy(function() {
// Intentional parallelism: start a request while
// we're busy, so we can verify it waits
request('http://localhost:7900/').then(function(content) {
// fn should complete before this is retrieved
assert(content.indexOf('counts: 10') !== -1);
retrieved = true;
});
return apos.docs.db.findOne({
type: 'apostrophe-global'
}).then(function(global) {
assert(global.globalBusyen);
}).then(function() {
return Promise.mapSeries(_.range(0, 10), function(i) {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$inc: {
counts: 1
}
}).then(function() {
return Promise.delay(50);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(doc) {
assert(doc.counts === 10);
});
}).then(function() {
assert(!retrieved);
});
}, { locale: 'en' }).then(function() {
// Wait up to 1 second more for the delayed request to succeed
var start = Date.now();
return check();
function check() {
if (retrieved) {
return;
}
if (Date.now() - start > 1000) {
assert(false);
}
return Promise.delay(50).then(check);
}
}).then(function() {
// Now that we are no longer busy a new request should take less than a second
return request('http://localhost:7900/').then(function(content) {
assert(content.indexOf('counts: 10') !== -1);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(global) {
assert(!global.globalBusyen);
});
});
it('reset counts', function() {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$set: {
counts: 0
}
});
});
it('busy mechanism (some other locale)', function() {
this.timeout(50000);
var retrieved = false;
return apos.global.whileBusy(function() {
// Intentional parallelism: start a request while
// we're busy, so we can verify it doesn't wait
request('http://localhost:7900/').then(function(content) {
// Should not wait for all 10 additions because it is a request
// for the en locale and we locked fr
assert(content.indexOf('counts: 10') === -1);
retrieved = true;
});
return apos.docs.db.findOne({
type: 'apostrophe-global'
}).then(function(global) {
// This property would only appear on the global doc
// for the fr locale, if there were one, and we are simulating
// from the perspective of en
assert(!global.globalBusyfr);
}).then(function() {
return Promise.mapSeries(_.range(0, 10), function(i) {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$inc: {
counts: 1
}
}).then(function() {
return Promise.delay(50);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(doc) {
assert(doc.counts === 10);
});
}).then(function() {
// we locked fr, not en, so this should have got through already
assert(retrieved);
});
}, { locale: 'fr' }).then(function() {
// Wait up to 1 second more for the delayed request to succeed
var start = Date.now();
return check();
function check() {
if (retrieved) {
return;
}
if (Date.now() - start > 1000) {
assert(false);
}
return Promise.delay(50).then(check);
}
}).then(function() {
// Now that we are no longer busy a new request should take less than a second
return request('http://localhost:7900/').then(function(content) {
assert(content.indexOf('counts: 10') !== -1);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(global) {
assert(!global.globalBusyfr);
});
});
it('global should exist on the second apos object', function(done) {
apos2 = require('../index.js')({
root: module,
shortName: 'test',
modules: {
'apostrophe-express': {
secret: 'xxx',
port: 7901
},
'apostrophe-global': {
whileBusyDelay: 0.5,
addFields: [
{
name: 'anotherString',
type: 'string',
def: 'populated anotherString def'
}
]
}
},
afterInit: function(callback) {
assert(apos2.global);
// In tests this will be the name of the test file,
// so override that in order to get apostrophe to
// listen normally and not try to run a task. -Tom
apos2.argv._ = [];
return callback(null);
},
afterListen: function(err) {
assert(!err);
done();
}
});
});
it('should populate def values of schema properties at update time', function(done) {
var req = apos.tasks.getAnonReq();
return apos.global.addGlobalToData(req, function(err) {
assert(!err);
// First verify it's an update not an insert - apos2 schema doesn't contain this but it should
// still be hanging around in the db
assert(req.data.global.testString === 'populated def');
assert(req.data.global.anotherString === 'populated anotherString def');
done();
});
});
});
describe('Global with separateWhileBusyMiddleware', function() {
this.timeout(t.timeout);
after(function(done) {
return t.destroy(apos, done);
});
it('global should exist on the apos object', function(done) {
apos = require('../index.js')({
root: module,
shortName: 'test',
modules: {
'apostrophe-express': {
secret: 'xxx',
port: 7900
},
'apostrophe-global': {
separateWhileBusyMiddleware: true,
whileBusyDelay: 0.5,
construct: function(self, options) {
var superAddGlobalToData = self.addGlobalToData;
// For test purposes, use a simplified global middleware
// that does not implement the locking, to verify that
// the separateWhileBusyMiddleware successfully takes over
// this role
self.addGlobalToData = function(req, res, next) {
if (arguments.length === 3) {
return self.findGlobal(req, function(err, _global) {
assert(!err);
req.data.global = _global;
return next();
});
}
return superAddGlobalToData.apply(self, arguments);
};
}
}
},
afterInit: function(callback) {
assert(apos.global);
// In tests this will be the name of the test file,
// so override that in order to get apostrophe to
// listen normally and not try to run a task. -Tom
apos.argv._ = [];
return callback(null);
},
afterListen: function(err) {
assert(!err);
done();
}
});
});
it('test findGlobal with callback', function(done) {
var req = apos.tasks.getReq();
return apos.global.findGlobal(req, function(err, global) {
assert(!err);
assert(global);
assert(global.type === 'apostrophe-global');
done();
});
});
it('test findGlobal with promise', function() {
var req = apos.tasks.getReq();
return apos.global.findGlobal(req).then(function(global) {
assert(global);
assert(global.type === 'apostrophe-global');
});
});
it('give global doc a workflowLocale property to simulate use with workflow', function() {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$set: {
workflowLocale: 'en'
}
});
});
it('busy mechanism (global)', function() {
this.timeout(50000);
var retrieved = false;
return apos.global.whileBusy(function() {
// Intentional parallelism: start a request while
// we're busy, so we can verify it waits
request('http://localhost:7900/').then(function(content) {
// fn should complete before this is retrieved
assert(content.indexOf('counts: 10') !== -1);
retrieved = true;
});
return apos.docs.db.findOne({
type: 'apostrophe-global'
}).then(function(global) {
assert(global.globalBusy);
}).then(function() {
return Promise.mapSeries(_.range(0, 10), function(i) {
return apos.docs.db.update({
type: 'apostrophe-global'
}, {
$inc: {
counts: 1
}
}).then(function() {
return Promise.delay(50);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(doc) {
assert(doc.counts === 10);
});
}).then(function() {
assert(!retrieved);
});
}).then(function() {
// Wait up to 1 second more for the delayed request to succeed
var start = Date.now();
return check();
function check() {
if (retrieved) {
return;
}
if (Date.now() - start > 1000) {
assert(false);
}
return Promise.delay(50).then(check);
}
}).then(function() {
// Now that we are no longer busy a new request should take less than a second
return request('http://localhost:7900/').then(function(content) {
assert(content.indexOf('counts: 10') !== -1);
});
}).then(function() {
return apos.docs.db.findOne({
type: 'apostrophe-global'
});
}).then(function(global) {
assert(!global.globalBusy);
});
});
});