global.TEST = true var Bottleneck = require('./bottleneck') var assert = require('assert') module.exports = function (options={}) { var mustEqual = function (a, b) { var strA = JSON.stringify(a) var strB = JSON.stringify(b) if (strA !== strB) { console.log(strA + ' !== ' + strB, (new Error('').stack)) assert(strA === strB) } } var start var calls = [] // set options.datastore var setRedisClientOptions = function (options) { options.clearDatastore = true if (options.clientOptions == null) { options.clientOptions = { host: process.env.REDIS_HOST, port: process.env.REDIS_PORT, } } } if (options.datastore == null && process.env.DATASTORE === 'redis') { options.datastore = 'redis' setRedisClientOptions(options) } else if (options.datastore == null && process.env.DATASTORE === 'ioredis') { options.datastore = 'ioredis' setRedisClientOptions(options) } else { options.datastore = 'local' } var limiter = new Bottleneck(options) // limiter.on("debug", function (str, args) { console.log(`${Date.now()-start} ${str} ${JSON.stringify(args)}`) }) if (!options.errorEventsExpected) { limiter.on("error", function (err) { console.log('(CONTEXT) ERROR EVENT', err) }) } limiter.ready().then(function (client) { start = Date.now() }) var getResults = function () { return { elapsed: Date.now() - start, callsDuration: calls.length > 0 ? calls[calls.length - 1].time : null, calls: calls } } var context = { job: function (err, ...result) { var cb = result.pop() calls.push({err: err, result: result, time: Date.now()-start}) if (process.env.DEBUG) console.log(result, calls) cb.apply({}, [err].concat(result)) }, slowJob: function (duration, err, ...result) { setTimeout(function () { var cb = result.pop() calls.push({err: err, result: result, time: Date.now()-start}) if (process.env.DEBUG) console.log(result, calls) cb.apply({}, [err].concat(result)) }, duration) }, promise: function (err, ...result) { return new Promise(function (resolve, reject) { if (process.env.DEBUG) console.log('In c.promise. Result: ', result) calls.push({err: err, result: result, time: Date.now()-start}) if (process.env.DEBUG) console.log(result, calls) if (err === null) { return resolve(result) } else { return reject(err) } }) }, slowPromise: function (duration, err, ...result) { return new Promise(function (resolve, reject) { setTimeout(function () { if (process.env.DEBUG) console.log('In c.slowPromise. Result: ', result) calls.push({err: err, result: result, time: Date.now()-start}) if (process.env.DEBUG) console.log(result, calls) if (err === null) { return resolve(result) } else { return reject(err) } }, duration) }) }, pNoErrVal: function (promise, ...expected) { if (process.env.DEBUG) console.log('In c.pNoErrVal. Expected:', expected) return promise.then(function (actual) { mustEqual(actual, expected) }) }, noErrVal: function (...expected) { return function (err, ...actual) { mustEqual(err, null) mustEqual(actual, expected) } }, last: function (options) { var opt = options != null ? options : {} return limiter.schedule(opt, function () { return Promise.resolve(getResults()) }) .catch(function (err) { console.error("Error in context.last:", err)}) }, wait: function (wait) { return new Promise(function (resolve, reject) { setTimeout(resolve, wait) }) }, limiter: limiter, mustEqual: mustEqual, mustExist: function (a) { assert(a != null) }, results: getResults, checkResultsOrder: function (order) { mustEqual(order.length, calls.length) for (var i = 0; i < Math.max(calls.length, order.length); i++) { mustEqual(order[i], calls[i].result) } }, checkDuration: function (shouldBe, minBound = 10) { var results = getResults() var min = shouldBe - minBound var max = shouldBe + 50 if (!(results.callsDuration > min && results.callsDuration < max)) { console.error('Duration not around ' + shouldBe + '. Was ' + results.callsDuration) } assert(results.callsDuration > min && results.callsDuration < max) } } return context }