Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0a397ad
commit 9eb3beb
Showing
5 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
var Ping = require('../models/ping'); | ||
var CheckEvent = require('../models/checkEvent'); | ||
|
||
var UptimeCalculator = function(check) { | ||
this.check = check; | ||
} | ||
|
||
UptimeCalculator.prototype.getUptimePeriods = function(begin, end, callback) { | ||
var self = this; | ||
this.getPingBeforeTime(begin, function(err1, ping) { | ||
if (err1) return callback(err1); | ||
if (!ping) return callback(null, []); | ||
CheckEvent.find() | ||
.where('check').equals(self.check) | ||
.where('timestamp').gte(begin).lte(end) | ||
.sort({ timestamp: 1 }) | ||
.find(function(err2, checkEvents) { | ||
if (err2) return callback(err2); | ||
var periods = []; | ||
var isUp = ping.isUp; // initial state | ||
var currentPeriod = isUp ? [begin] : []; | ||
checkEvents.forEach(function(checkEvent) { | ||
switch (checkEvent.message) { | ||
case 'up': | ||
if (isUp) break; // check passes up while it was already up: ignore | ||
// beginning of an uptime period | ||
currentPeriod.push(checkEvent.timestamp.getTime()); | ||
isUp = true; | ||
break; | ||
case 'down': | ||
if (!isUp) break; // check passes down while it was already down: ignore | ||
// end of an uptime period | ||
currentPeriod.push(checkEvent.timestamp.getTime()); | ||
periods.push(currentPeriod); | ||
currentPeriod = []; | ||
isUp = false; | ||
break; | ||
} | ||
}) | ||
if (isUp) { | ||
// check was up until the end | ||
currentPeriod.push(end); | ||
periods.push(currentPeriod); | ||
}; | ||
callback(null, periods); | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Get the last ping preceding a given timestamp | ||
* | ||
* This determines the state of a check at a given time. | ||
* | ||
* @api public | ||
*/ | ||
UptimeCalculator.prototype.getPingBeforeTime = function(timestamp, callback) { | ||
Ping.find() | ||
.where('check').equals(this.check) | ||
.where('timestamp').lte(timestamp) | ||
.sort({ timestamp: -1 }) | ||
.findOne(callback); | ||
} | ||
|
||
module.exports = UptimeCalculator; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
test: | ||
NODE_ENV=test mocha test/*/*.js | ||
|
||
.PHONY: test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
var should = require('should'); | ||
var async = require('async'); | ||
var mongoose = require('../../bootstrap'); | ||
var UptimeCalculator = require('../../lib/uptimeCalculator'); | ||
var Check = require('../../models/check'); | ||
var CheckEvent = require('../../models/checkEvent'); | ||
var Ping = require('../../models/ping'); | ||
|
||
var check1, check2, now; // fixtures | ||
|
||
describe('uptimeCalculator', function() { | ||
|
||
before(function(done) { | ||
async.parallel([ | ||
function(cb) { Ping.collection.drop(cb) }, | ||
function(cb) { Check.collection.drop(cb) }, | ||
function(cb) { CheckEvent.collection.drop(cb) }, | ||
], done); | ||
}); | ||
|
||
before(function() { | ||
now = Date.now(); | ||
}); | ||
|
||
before(function(done) { | ||
check1 = new Check(); | ||
check1.save(function(err) { | ||
if (err) throw (err); | ||
async.series([ | ||
function(cb) { Ping.createForCheck(false, now - 3000, 100, check1, 'dummy1', '', cb); }, | ||
function(cb) { Ping.createForCheck(false, now - 2000, 100, check1, 'dummy2', '', cb); }, | ||
function(cb) { Ping.createForCheck(true, now - 1000, 100, check1, 'dummy3', '', cb); }, | ||
function(cb) { Ping.createForCheck(true, now, 100, check1, 'dummy4', '', cb); }, | ||
function(cb) { Ping.createForCheck(true, now + 1000, 100, check1, 'dummy5', '', cb); }, | ||
function(cb) { Ping.createForCheck(false, now + 2000, 100, check1, 'dummy6', '', cb); }, | ||
function(cb) { Ping.createForCheck(true, now + 3000, 100, check1, 'dummy7', '', cb); }, | ||
], done); | ||
}); | ||
}); | ||
|
||
before(function(done) { | ||
check2 = new Check(); | ||
check2.save(done); | ||
}); | ||
|
||
describe('#getPingBeforeTime', function() { | ||
|
||
it('should return nothing for new Checks', function(done) { | ||
var calculator = new UptimeCalculator(check2); | ||
calculator.getPingBeforeTime(now, function(err, ping) { | ||
if (err) throw (err); | ||
should.not.exist(ping); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should return the latest ping', function(done) { | ||
var calculator = new UptimeCalculator(check1); | ||
calculator.getPingBeforeTime(now, function(err, ping) { | ||
if (err) throw (err); | ||
ping.monitorName.should.eql('dummy4'); | ||
done(); | ||
}); | ||
}); | ||
|
||
}); | ||
|
||
describe('#getUptimePeriods', function() { | ||
|
||
it('should return empty array when there is no ping', function(done) { | ||
var calculator = new UptimeCalculator(check2); | ||
calculator.getUptimePeriods(Date.now(), Date.now() + 1000, function(err, periods) { | ||
if (err) throw (err); | ||
periods.should.eql([]); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should return the correct period for not finished check', function(done) { | ||
var calculator = new UptimeCalculator(check1); | ||
calculator.getUptimePeriods(now + 3000, now + 6000, function(err, periods) { | ||
if (err) throw (err); | ||
periods.should.eql([ [now + 3000, now + 6000] ]); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should return the correct period for not started check', function(done) { | ||
var calculator = new UptimeCalculator(check1); | ||
calculator.getUptimePeriods(now - 6000, now - 3000, function(err, periods) { | ||
if (err) throw (err); | ||
periods.should.eql([ ]); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should return the correct period for crossing checks', function(done) { | ||
var calculator = new UptimeCalculator(check1); | ||
calculator.getUptimePeriods(now - 6000, now, function(err, periods) { | ||
if (err) throw (err); | ||
periods.should.eql([ [ now - 1000, now ]]); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should return the correct periods', function(done) { | ||
var calculator = new UptimeCalculator(check1); | ||
calculator.getUptimePeriods(now - 3000, now + 3000, function(err, periods) { | ||
if (err) throw (err); | ||
periods.should.eql([ [now - 1000, now + 2000], [now + 3000, now + 3000] ]); | ||
done(); | ||
}); | ||
}); | ||
|
||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
--reporter spec | ||
--slow 20ms |