From 9796f545803d04b8ba134f030447faeb0de1e677 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 18 Nov 2016 15:57:53 +0300 Subject: [PATCH] analytics tests, reduce bcrypt rouds for tests --- src/analytics.js | 326 +++++++++++++++++++------------------ test/controllers.js | 8 +- test/mocks/databasemock.js | 1 + test/socket.io.js | 18 ++ 4 files changed, 190 insertions(+), 163 deletions(-) diff --git a/src/analytics.js b/src/analytics.js index ab834b75b2..6b248057da 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -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.increment = function (keys) { + keys = Array.isArray(keys) ? keys : [keys]; - Analytics.pageView = function (payload) { - ++pageViews; + keys.forEach(function (key) { + counters[key] = counters[key] || 0; + ++counters[key]; + }); +}; - 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.pageView = function (payload) { + ++pageViews; - if (payload.path) { - var categoryMatch = payload.path.match(isCategory), - cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null; - - if (cid) { - Analytics.increment(['pageviews:byCid:' + cid]); - } - } - }; - - 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 (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]; - } - } - } - - async.parallel(dbQueue, function (err) { + if (payload.ip) { + db.sortedSetScore('ip:recent', payload.ip, function (err, score) { if (err) { - winston.error('[analytics] Encountered error while writing analytics to data store: ' + err.message); + 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.getHourlyStatsForSet = function (set, hour, numHours, callback) { - var terms = {}, - hoursArr = []; + if (payload.path) { + var categoryMatch = payload.path.match(isCategory), + cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null; - hour = new Date(hour); - hour.setHours(hour.getHours(), 0, 0, 0); + if (cid) { + Analytics.increment(['pageviews:byCid:' + cid]); + } + } +}; - for (var i = 0, ii = numHours; i < ii; i++) { - hoursArr.push(hour.getTime()); - hour.setHours(hour.getHours() - 1, 0, 0, 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]; + } + } + } + + async.parallel(dbQueue, function (err) { + if (err) { + winston.error('[analytics] Encountered error while writing analytics to data store: ' + err.message); + } + callback(err); + }); +}; + +Analytics.getHourlyStatsForSet = function (set, hour, numHours, callback) { + var terms = {}, + hoursArr = []; + + 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); + } + + db.sortedSetScores(set, hoursArr, function (err, counts) { + if (err) { + return callback(err); } - db.sortedSetScores(set, hoursArr, function (err, counts) { + hoursArr.forEach(function (term, index) { + terms[term] = parseInt(counts[index], 10) || 0; + }); + + var termsArr = []; + + hoursArr.reverse(); + hoursArr.forEach(function (hour) { + termsArr.push(terms[hour]); + }); + + 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 callback(err); + return next(err); } - hoursArr.forEach(function (term, index) { - terms[term] = parseInt(counts[index], 10) || 0; - }); - - var termsArr = []; - - hoursArr.reverse(); - hoursArr.forEach(function (hour) { - termsArr.push(terms[hour]); - }); - - callback(null, termsArr); + daysArr.push(day.reduce(function (cur, next) { + return cur + next; + })); + next(); }); - }; + }, function (err) { + callback(err, daysArr); + }); +}; - Analytics.getDailyStatsForSet = function (set, day, numDays, callback) { - var daysArr = []; +Analytics.getUnwrittenPageviews = function () { + return pageViews; +}; - 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); +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); - 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); - } + var values = [thisMonth.getTime(), lastMonth.getTime()]; - daysArr.push(day.reduce(function (cur, next) { - return cur + next; - })); - next(); - }); - }, function (err) { - callback(err, daysArr); - }); - }; + 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.getUnwrittenPageviews = function () { - return pageViews; - }; +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.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.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); +}; - 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); - }; - -}(exports)); \ No newline at end of file diff --git a/test/controllers.js b/test/controllers.js index fb80b5a3dc..2ec3c896ce 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -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); + }); }); }); diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 42c14ed2f7..61ab8b2bbe 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -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); }, diff --git a/test/socket.io.js b/test/socket.io.js index ff255a0208..b03753f362 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -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); });