Skip to content

Commit

Permalink
Guard against clock manipulation by fake timer libraries. Fixes avajs…
Browse files Browse the repository at this point in the history
  • Loading branch information
jamestalmage committed Nov 25, 2015
1 parent 21cac95 commit b88c2ba
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 11 deletions.
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';
var setImmediate = require('set-immediate-shim');
var relative = require('path').relative;
var hasFlag = require('has-flag');
var chalk = require('chalk');
var serializeError = require('serialize-error');
var globals = require('./lib/globals');
var Runner = require('./lib/runner');
var send = require('./lib/send');
var log = require('./lib/logger');
Expand Down Expand Up @@ -65,7 +65,7 @@ function exit() {
});
}

setImmediate(function () {
globals.setImmediate(function () {
runner.on('test', test);
runner.run().then(exit);
});
Expand Down
8 changes: 6 additions & 2 deletions lib/babel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
'use strict';

// Bind globals first, before anything has a chance to interfere.
var globals = require('./globals');

var sourceMapCache = Object.create(null);

var sourceMapSupport = require('source-map-support');
Expand Down Expand Up @@ -79,7 +83,7 @@ process.on('ava-exit', function () {
// use a little delay when running on AppVeyor (because it's shit)
var delay = process.env.AVA_APPVEYOR ? 100 : 0;

setTimeout(function () {
globals.setTimeout(function () {
process.exit(0);
}, delay);
});
Expand All @@ -96,7 +100,7 @@ process.on('ava-teardown', function () {
});

send('unhandledRejections', {rejections: rejections});
setTimeout(exit, 100);
globals.setTimeout(exit, 100);
});

function exit() {
Expand Down
13 changes: 13 additions & 0 deletions lib/globals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

// Global objects / functions to be bound before requiring test file, so tests do not interfere.

var x = module.exports;

x.now = Date.now;

x.setTimeout = setTimeout;

x.clearTimeout = clearTimeout;

x.setImmediate = require('set-immediate-shim');
14 changes: 7 additions & 7 deletions lib/test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'use strict';
var isGeneratorFn = require('is-generator-fn');
var setImmediate = require('set-immediate-shim');
var maxTimeout = require('max-timeout');
var Promise = require('bluebird');
var fnName = require('fn-name');
var co = require('co-with-promise');
var observableToPromise = require('observable-to-promise');
var isPromise = require('is-promise');
var assert = require('./assert');
var globals = require('./globals');

function Test(title, fn) {
if (!(this instanceof Test)) {
Expand Down Expand Up @@ -48,7 +48,7 @@ Test.prototype._assert = function () {
this.assertCount++;

if (this.assertCount === this.planCount) {
setImmediate(this.exit.bind(this));
globals.setImmediate(this.exit.bind(this));
}
};

Expand Down Expand Up @@ -118,10 +118,10 @@ Test.prototype.run = function () {
return this.exit();
}

this._timeStart = Date.now();
this._timeStart = globals.now();

// wait until all assertions are complete
this._timeout = setTimeout(function () {}, maxTimeout);
this._timeout = globals.setTimeout(function () {}, maxTimeout);

var ret;

Expand Down Expand Up @@ -179,10 +179,10 @@ Test.prototype.exit = function () {
var self = this;

// calculate total time spent in test
this.duration = Date.now() - this._timeStart;
this.duration = globals.now() - this._timeStart;

// stop infinite timer
clearTimeout(this._timeout);
globals.clearTimeout(this._timeout);

if (this.assertError === undefined && this.planCount !== null && this.planCount !== this.assertCount) {
this._setAssertError(new assert.AssertionError({
Expand All @@ -198,7 +198,7 @@ Test.prototype.exit = function () {
if (!this.ended) {
this.ended = true;

setImmediate(function () {
globals.setImmediate(function () {
if (self.assertError !== undefined) {
self.promise.reject(self.assertError);
return;
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
"devDependencies": {
"coveralls": "^2.11.4",
"signal-exit": "^2.1.2",
"sinon": "^1.17.2",
"tap": "^2.2.1",
"xo": "*",
"zen-observable": "^0.1.6"
Expand Down
8 changes: 8 additions & 0 deletions test/fixture/fake-timers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import test from '../../';
import sinon from 'sinon';

test(t => {
sinon.useFakeTimers(Date.now() + 10000);
t.pass();
t.end();
});
9 changes: 9 additions & 0 deletions test/fork.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,12 @@ test('exit after tests are finished', function (t) {
cleanupCompleted = event.completed;
});
});

test('fake timers do not break duration', function (t) {
fork(fixture('fake-timers.js'))
.then(function (info) {
var duration = info.tests[0].duration;
t.true(duration < 1000, duration + ' < 1000');
t.end();
});
});

0 comments on commit b88c2ba

Please sign in to comment.