analytics tests, reduce bcrypt rouds for tests

v1.18.x
barisusakli 8 years ago
parent e3616ab0f9
commit 9796f54580

@ -6,192 +6,194 @@ var winston = require('winston');
var db = require('./database');
(function (Analytics) {
var counters = {};
var Analytics = module.exports;
var pageViews = 0;
var uniqueIPCount = 0;
var uniquevisitors = 0;
var counters = {};
var isCategory = /^(?:\/api)?\/category\/(\d+)/;
var pageViews = 0;
var uniqueIPCount = 0;
var uniquevisitors = 0;
new cronJob('*/10 * * * *', function () {
Analytics.writeData();
}, null, true);
var isCategory = /^(?:\/api)?\/category\/(\d+)/;
Analytics.increment = function (keys) {
keys = Array.isArray(keys) ? keys : [keys];
new cronJob('*/10 * * * *', function () {
Analytics.writeData();
}, null, true);
keys.forEach(function (key) {
counters[key] = counters[key] || 0;
++counters[key];
});
};
Analytics.pageView = function (payload) {
++pageViews;
if (payload.ip) {
db.sortedSetScore('ip:recent', payload.ip, function (err, score) {
if (err) {
return;
}
if (!score) {
++uniqueIPCount;
}
var today = new Date();
today.setHours(today.getHours(), 0, 0, 0);
if (!score || score < today.getTime()) {
++uniquevisitors;
db.sortedSetAdd('ip:recent', Date.now(), payload.ip);
}
});
}
Analytics.increment = function (keys) {
keys = Array.isArray(keys) ? keys : [keys];
if (payload.path) {
var categoryMatch = payload.path.match(isCategory),
cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null;
keys.forEach(function (key) {
counters[key] = counters[key] || 0;
++counters[key];
});
};
if (cid) {
Analytics.increment(['pageviews:byCid:' + cid]);
}
}
};
Analytics.pageView = function (payload) {
++pageViews;
Analytics.writeData = function () {
var today = new Date();
var month = new Date();
var dbQueue = [];
today.setHours(today.getHours(), 0, 0, 0);
month.setMonth(month.getMonth(), 1);
month.setHours(0, 0, 0, 0);
if (payload.ip) {
db.sortedSetScore('ip:recent', payload.ip, function (err, score) {
if (err) {
return;
}
if (!score) {
++uniqueIPCount;
}
var today = new Date();
today.setHours(today.getHours(), 0, 0, 0);
if (!score || score < today.getTime()) {
++uniquevisitors;
db.sortedSetAdd('ip:recent', Date.now(), payload.ip);
}
});
}
if (pageViews > 0) {
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:pageviews', pageViews, today.getTime()));
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:pageviews:month', pageViews, month.getTime()));
pageViews = 0;
}
if (payload.path) {
var categoryMatch = payload.path.match(isCategory),
cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null;
if (uniquevisitors > 0) {
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:uniquevisitors', uniquevisitors, today.getTime()));
uniquevisitors = 0;
if (cid) {
Analytics.increment(['pageviews:byCid:' + cid]);
}
if (uniqueIPCount > 0) {
dbQueue.push(async.apply(db.incrObjectFieldBy, 'global', 'uniqueIPCount', uniqueIPCount));
uniqueIPCount = 0;
}
};
Analytics.writeData = function (callback) {
callback = callback || function () {};
var today = new Date();
var month = new Date();
var dbQueue = [];
today.setHours(today.getHours(), 0, 0, 0);
month.setMonth(month.getMonth(), 1);
month.setHours(0, 0, 0, 0);
if (pageViews > 0) {
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:pageviews', pageViews, today.getTime()));
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:pageviews:month', pageViews, month.getTime()));
pageViews = 0;
}
if (uniquevisitors > 0) {
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:uniquevisitors', uniquevisitors, today.getTime()));
uniquevisitors = 0;
}
if (uniqueIPCount > 0) {
dbQueue.push(async.apply(db.incrObjectFieldBy, 'global', 'uniqueIPCount', uniqueIPCount));
uniqueIPCount = 0;
}
if (Object.keys(counters).length > 0) {
for(var key in counters) {
if (counters.hasOwnProperty(key)) {
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:' + key, counters[key], today.getTime()));
delete counters[key];
}
}
}
if (Object.keys(counters).length > 0) {
for(var key in counters) {
if (counters.hasOwnProperty(key)) {
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:' + key, counters[key], today.getTime()));
delete counters[key];
}
}
async.parallel(dbQueue, function (err) {
if (err) {
winston.error('[analytics] Encountered error while writing analytics to data store: ' + err.message);
}
callback(err);
});
};
async.parallel(dbQueue, function (err) {
if (err) {
winston.error('[analytics] Encountered error while writing analytics to data store: ' + err.message);
}
});
};
Analytics.getHourlyStatsForSet = function (set, hour, numHours, callback) {
var terms = {},
hoursArr = [];
Analytics.getHourlyStatsForSet = function (set, hour, numHours, callback) {
var terms = {},
hoursArr = [];
hour = new Date(hour);
hour.setHours(hour.getHours(), 0, 0, 0);
hour = new Date(hour);
hour.setHours(hour.getHours(), 0, 0, 0);
for (var i = 0, ii = numHours; i < ii; i++) {
hoursArr.push(hour.getTime());
hour.setHours(hour.getHours() - 1, 0, 0, 0);
}
for (var i = 0, ii = numHours; i < ii; i++) {
hoursArr.push(hour.getTime());
hour.setHours(hour.getHours() - 1, 0, 0, 0);
db.sortedSetScores(set, hoursArr, function (err, counts) {
if (err) {
return callback(err);
}
db.sortedSetScores(set, hoursArr, function (err, counts) {
if (err) {
return callback(err);
}
hoursArr.forEach(function (term, index) {
terms[term] = parseInt(counts[index], 10) || 0;
});
var termsArr = [];
hoursArr.forEach(function (term, index) {
terms[term] = parseInt(counts[index], 10) || 0;
});
hoursArr.reverse();
hoursArr.forEach(function (hour) {
termsArr.push(terms[hour]);
});
var termsArr = [];
callback(null, termsArr);
});
};
Analytics.getDailyStatsForSet = function (set, day, numDays, callback) {
var daysArr = [];
day = new Date(day);
day.setDate(day.getDate() + 1); // set the date to tomorrow, because getHourlyStatsForSet steps *backwards* 24 hours to sum up the values
day.setHours(0, 0, 0, 0);
async.whilst(function () {
return numDays--;
}, function (next) {
Analytics.getHourlyStatsForSet(set, day.getTime() - (1000 * 60 * 60 * 24 * numDays), 24, function (err, day) {
if (err) {
return next(err);
}
daysArr.push(day.reduce(function (cur, next) {
return cur + next;
}));
next();
});
}, function (err) {
callback(err, daysArr);
hoursArr.reverse();
hoursArr.forEach(function (hour) {
termsArr.push(terms[hour]);
});
};
Analytics.getUnwrittenPageviews = function () {
return pageViews;
};
callback(null, termsArr);
});
};
Analytics.getMonthlyPageViews = function (callback) {
var thisMonth = new Date();
var lastMonth = new Date();
thisMonth.setMonth(thisMonth.getMonth(), 1);
thisMonth.setHours(0, 0, 0, 0);
lastMonth.setMonth(thisMonth.getMonth() - 1, 1);
lastMonth.setHours(0, 0, 0, 0);
Analytics.getDailyStatsForSet = function (set, day, numDays, callback) {
var daysArr = [];
var values = [thisMonth.getTime(), lastMonth.getTime()];
day = new Date(day);
day.setDate(day.getDate() + 1); // set the date to tomorrow, because getHourlyStatsForSet steps *backwards* 24 hours to sum up the values
day.setHours(0, 0, 0, 0);
db.sortedSetScores('analytics:pageviews:month', values, function (err, scores) {
async.whilst(function () {
return numDays--;
}, function (next) {
Analytics.getHourlyStatsForSet(set, day.getTime() - (1000 * 60 * 60 * 24 * numDays), 24, function (err, day) {
if (err) {
return callback(err);
return next(err);
}
callback(null, {thisMonth: scores[0] || 0, lastMonth: scores[1] || 0});
daysArr.push(day.reduce(function (cur, next) {
return cur + next;
}));
next();
});
};
Analytics.getCategoryAnalytics = function (cid, callback) {
async.parallel({
'pageviews:hourly': async.apply(Analytics.getHourlyStatsForSet, 'analytics:pageviews:byCid:' + cid, Date.now(), 24),
'pageviews:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:pageviews:byCid:' + cid, Date.now(), 30),
'topics:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:topics:byCid:' + cid, Date.now(), 7),
'posts:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:posts:byCid:' + cid, Date.now(), 7),
}, callback);
};
Analytics.getErrorAnalytics = function (callback) {
async.parallel({
'not-found': async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:404', Date.now(), 7),
'toobusy': async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:503', Date.now(), 7)
}, callback);
};
}(exports));
}, function (err) {
callback(err, daysArr);
});
};
Analytics.getUnwrittenPageviews = function () {
return pageViews;
};
Analytics.getMonthlyPageViews = function (callback) {
var thisMonth = new Date();
var lastMonth = new Date();
thisMonth.setMonth(thisMonth.getMonth(), 1);
thisMonth.setHours(0, 0, 0, 0);
lastMonth.setMonth(thisMonth.getMonth() - 1, 1);
lastMonth.setHours(0, 0, 0, 0);
var values = [thisMonth.getTime(), lastMonth.getTime()];
db.sortedSetScores('analytics:pageviews:month', values, function (err, scores) {
if (err) {
return callback(err);
}
callback(null, {thisMonth: scores[0] || 0, lastMonth: scores[1] || 0});
});
};
Analytics.getCategoryAnalytics = function (cid, callback) {
async.parallel({
'pageviews:hourly': async.apply(Analytics.getHourlyStatsForSet, 'analytics:pageviews:byCid:' + cid, Date.now(), 24),
'pageviews:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:pageviews:byCid:' + cid, Date.now(), 30),
'topics:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:topics:byCid:' + cid, Date.now(), 7),
'posts:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:posts:byCid:' + cid, Date.now(), 7),
}, callback);
};
Analytics.getErrorAnalytics = function (callback) {
async.parallel({
'not-found': async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:404', Date.now(), 7),
'toobusy': async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:503', Date.now(), 7)
}, callback);
};

@ -45,6 +45,8 @@ describe('Controllers', function () {
});
});
it('should load default home route', function (done) {
request(nconf.get('url'), function (err, res, body) {
assert.ifError(err);
@ -615,6 +617,10 @@ describe('Controllers', function () {
after(function (done) {
db.emptydb(done);
var analytics = require('../src/analytics');
analytics.writeData(function (err) {
assert.ifError(err);
db.emptydb(done);
});
});
});

@ -129,6 +129,7 @@
nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates'));
nconf.set('theme_templates_path', meta.config['theme:templates'] ? path.join(nconf.get('themes_path'), meta.config['theme:id'], meta.config['theme:templates']) : nconf.get('base_templates_path'));
nconf.set('theme_config', path.join(nconf.get('themes_path'), 'nodebb-theme-persona', 'theme.json'));
nconf.set('bcrypt_rounds', 6);
require('../../build').buildTargets(['js', 'clientCSS', 'acpCSS', 'tpl'], next);
},

@ -322,6 +322,24 @@ describe('socket.io', function () {
});
});
it('should get daily analytics', function (done) {
io.emit('admin.analytics.get', {graph: 'traffic', units: 'days'}, function (err, data) {
assert.ifError(err);
assert(data);
assert(data.monthlyPageViews);
done();
});
});
it('should get hourly analytics', function (done) {
io.emit('admin.analytics.get', {graph: 'traffic', units: 'hours'}, function (err, data) {
assert.ifError(err);
assert(data);
assert(data.monthlyPageViews);
done();
});
});
after(function (done) {
db.emptydb(done);
});

Loading…
Cancel
Save