pull-drain-gently
Version:
Like pull.drain, but respects CPU load
191 lines (164 loc) • 4.17 kB
JavaScript
var pull = require('pull-stream');
var test = require('tape');
var usage = require('cpu-percentage');
var fs = require('fs');
var drainGently = require('./index');
function delay() {
return pull.asyncMap(function (e, cb) {
setTimeout(function () {
cb(null, e);
});
});
}
test('like pull.drain: abort on drain', function (t) {
var c = 100;
var drain = drainGently(
function () {
if (c < 0) throw new Error('stream should have aborted');
if (!--c) return false; //drain.abort()
},
function () {
t.end();
},
);
pull(pull.infinite(), drain);
});
test('like pull.drain: abort on drain - async', function (t) {
var c = 100;
var drain = drainGently(
function () {
if (c < 0) throw new Error('stream should have aborted');
if (!--c) return drain.abort();
},
function () {
t.end();
},
);
pull(pull.infinite(), delay(), drain);
});
test('like pull.drain: abort on drain - sync', function (t) {
var c = 100;
var drain = drainGently(
function () {
if (c < 0) throw new Error('stream should have aborted');
if (!--c) return drain.abort();
},
function () {
t.end();
},
);
pull(pull.infinite(), drain);
});
test('like pull.drain: abort on drain - async, out of cb', function (t) {
t.plan(2);
var c = 0,
ERR = new Error('test ABORT');
var drain = drainGently(
function () {
--c;
},
function (err) {
t.ok(c < 0);
t.equal(err, ERR);
t.end();
},
);
pull(pull.infinite(), delay(), drain);
setTimeout(function () {
drain.abort(ERR);
}, 100);
});
test('supports drainGently()', function (t) {
pull(pull.count(7), drainGently());
setTimeout(() => {
t.end();
}, 50);
});
test('supports drainGently(null, done)', function (t) {
t.plan(1);
pull(
pull.count(7),
drainGently(null, () => {
t.pass('all good');
t.end();
}),
);
});
test('supports drainGently(opts)', function (t) {
pull(pull.count(7), drainGently({ceiling: 90, wait: 90}));
setTimeout(() => {
t.end();
}, 50);
});
test('supports drainGently(opts, null)', function (t) {
pull(pull.count(7), drainGently({ceiling: 90, wait: 90}, null));
setTimeout(() => {
t.end();
}, 50);
});
test('respects `maxPause` opt', function (t) {
t.plan(1);
t.timeoutAfter(8000);
const ceiling = 0.01; // super low threshold, most likely never met
const maxPause = 50; // ms
pull(
pull.count(200),
pull.asyncMap((x, cb) => fs.readFile('./package.json', cb)),
pull.map((contents) =>
Buffer.from(contents.toString('hex').toUpperCase())
.toString('base64')
.toLowerCase()
.substr(0, 20),
),
drainGently({ceiling, maxPause, wait: 16}, null, () => {
t.pass('all data points processed');
t.end();
}),
);
});
test('heavy processing is below the prescribed CPU 90% ceiling', function (t) {
t.plan(1);
const ceiling = 90;
const start = usage();
pull(
pull.count(20000),
pull.asyncMap((x, cb) => fs.readFile('./package.json', cb)),
pull.map((contents) =>
Buffer.from(contents.toString('hex').toUpperCase())
.toString('base64')
.toLowerCase()
.substr(0, 20),
),
drainGently(
{ceiling, wait: 40},
() => {},
() => {
const stats = usage(start);
console.log(usage(start));
t.true(stats.percent < ceiling + 3, 'CPU usage was approx. 90%');
t.end();
},
),
);
});
test('heavy processing is below the prescribed CPU 50% ceiling', function (t) {
t.plan(1);
const ceiling = 50;
const start = usage();
pull(
pull.count(8000),
pull.asyncMap((x, cb) => fs.readFile('./package.json', cb)),
pull.map((contents) =>
Buffer.from(contents.toString('hex').toUpperCase())
.toString('base64')
.toLowerCase()
.substr(0, 20),
),
drainGently({ceiling, wait: 40}, null, () => {
const stats = usage(start);
console.log(usage(start));
t.true(stats.percent < ceiling + 3, 'CPU usage was approx. 50%');
t.end();
}),
);
});