implement and test a complex constrained scheduler
This commit is contained in:
220
scripts/tests/test-scheduler.js
Normal file
220
scripts/tests/test-scheduler.js
Normal file
@@ -0,0 +1,220 @@
|
||||
/* three types of actions:
|
||||
* read
|
||||
* write
|
||||
* append
|
||||
each of which take a random amount of time
|
||||
|
||||
*/
|
||||
var Util = require("../../lib/common-util");
|
||||
var schedule = require("../../lib/schedule")();
|
||||
var nThen = require("nthen");
|
||||
|
||||
var rand = function (n) {
|
||||
return Math.floor(Math.random() * n);
|
||||
};
|
||||
|
||||
var rand_time = function () {
|
||||
// between 51 and 151
|
||||
return rand(300) + 25;
|
||||
};
|
||||
|
||||
var makeAction = function (type) {
|
||||
var i = 0;
|
||||
return function (time) {
|
||||
var j = i++;
|
||||
return function (next) {
|
||||
console.log(" Beginning action: %s#%s", type, j);
|
||||
setTimeout(function () {
|
||||
console.log(" Completed action: %s#%s", type, j);
|
||||
next();
|
||||
}, time);
|
||||
return j;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
var TYPES = ['WRITE', 'READ', 'APPEND'];
|
||||
var chooseAction = function () {
|
||||
var n = rand(100);
|
||||
|
||||
if (n < 50) { return 'APPEND'; }
|
||||
if (n < 90) { return 'READ'; }
|
||||
return 'WRITE';
|
||||
|
||||
//return TYPES[rand(3)];
|
||||
};
|
||||
|
||||
var test = function (script, cb) {
|
||||
var uid = Util.uid();
|
||||
|
||||
var TO_RUN = script.length;
|
||||
var total_run = 0;
|
||||
|
||||
var parallel = 0;
|
||||
var last_run_ordered = -1;
|
||||
//var i = 0;
|
||||
|
||||
var ACTIONS = {};
|
||||
TYPES.forEach(function (type) {
|
||||
ACTIONS[type] = makeAction(type);
|
||||
});
|
||||
|
||||
nThen(function (w) {
|
||||
setTimeout(w(), 3000);
|
||||
// run scripted actions with assertions
|
||||
script.forEach(function (scene) {
|
||||
var type = scene[0];
|
||||
var time = typeof(scene[1]) === 'number'? scene[1]: rand_time();
|
||||
|
||||
var action = ACTIONS[type](time);
|
||||
console.log("Queuing action of type: %s(%s)", type, time);
|
||||
|
||||
var proceed = w();
|
||||
|
||||
switch (type) {
|
||||
case 'APPEND':
|
||||
return schedule.ordered(uid, w(function (next) {
|
||||
parallel++;
|
||||
var temp = action(function () {
|
||||
parallel--;
|
||||
total_run++;
|
||||
proceed();
|
||||
next();
|
||||
});
|
||||
if (temp !== (last_run_ordered + 1)) {
|
||||
throw new Error("out of order");
|
||||
}
|
||||
last_run_ordered = temp;
|
||||
}));
|
||||
case 'WRITE':
|
||||
return schedule.blocking(uid, w(function (next) {
|
||||
parallel++;
|
||||
action(function () {
|
||||
parallel--;
|
||||
total_run++;
|
||||
proceed();
|
||||
next();
|
||||
});
|
||||
if (parallel > 1) {
|
||||
console.log("parallelism === %s", parallel);
|
||||
throw new Error("too much parallel");
|
||||
}
|
||||
}));
|
||||
case 'READ':
|
||||
return schedule.unordered(uid, w(function (next) {
|
||||
parallel++;
|
||||
action(function () {
|
||||
parallel--;
|
||||
total_run++;
|
||||
proceed();
|
||||
next();
|
||||
});
|
||||
}));
|
||||
default:
|
||||
throw new Error("wut");
|
||||
}
|
||||
});
|
||||
}).nThen(function () {
|
||||
// make assertions about the whole script
|
||||
if (total_run !== TO_RUN) {
|
||||
console.log("Ran %s / %s", total_run, TO_RUN);
|
||||
throw new Error("skipped tasks");
|
||||
}
|
||||
console.log("total_run === %s", total_run);
|
||||
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var randomScript = function () {
|
||||
var len = rand(15) + 10;
|
||||
var script = [];
|
||||
while (len--) {
|
||||
script.push([
|
||||
chooseAction(),
|
||||
rand_time(),
|
||||
]);
|
||||
}
|
||||
return script;
|
||||
};
|
||||
|
||||
var WRITE = function (t) {
|
||||
return ['WRITE', t];
|
||||
};
|
||||
var READ = function (t) {
|
||||
return ['READ', t];
|
||||
};
|
||||
|
||||
var APPEND = function (t) {
|
||||
return ['APPEND', t];
|
||||
};
|
||||
|
||||
nThen(function (w) {
|
||||
test([
|
||||
['READ', 150],
|
||||
['APPEND', 200],
|
||||
['APPEND', 100],
|
||||
['READ', 350],
|
||||
['WRITE', 400],
|
||||
['APPEND', 275],
|
||||
['APPEND', 187],
|
||||
['WRITE', 330],
|
||||
['WRITE', 264],
|
||||
['WRITE', 256],
|
||||
], w(function () {
|
||||
console.log("finished pre-scripted test\n");
|
||||
}));
|
||||
}).nThen(function (w) {
|
||||
test([
|
||||
WRITE(289),
|
||||
APPEND(281),
|
||||
READ(207),
|
||||
WRITE(225),
|
||||
READ(279),
|
||||
WRITE(300),
|
||||
READ(331),
|
||||
APPEND(341),
|
||||
APPEND(385),
|
||||
READ(313),
|
||||
WRITE(285),
|
||||
READ(304),
|
||||
APPEND(273),
|
||||
APPEND(150),
|
||||
WRITE(246),
|
||||
READ(244),
|
||||
WRITE(172),
|
||||
APPEND(253),
|
||||
READ(215),
|
||||
READ(296),
|
||||
APPEND(281),
|
||||
APPEND(296),
|
||||
WRITE(168),
|
||||
], w(function () {
|
||||
console.log("finished 2nd pre-scripted test\n");
|
||||
}));
|
||||
}).nThen(function () {
|
||||
var totalTests = 50;
|
||||
var randomTests = 1;
|
||||
|
||||
var last = nThen(function () {
|
||||
console.log("beginning randomized tests");
|
||||
});
|
||||
|
||||
var queueRandomTest = function (i) {
|
||||
last = last.nThen(function (w) {
|
||||
console.log("running random test script #%s\n", i);
|
||||
test(randomScript(), w(function () {
|
||||
console.log("finished random test #%s\n", i);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
while (randomTests <=totalTests) { queueRandomTest(randomTests++); }
|
||||
|
||||
last.nThen(function () {
|
||||
console.log("finished %s random tests", totalTests);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user