win-backbone
Version:
The control backbone for WIN, handles message passing between modules in an experiment. Allows for somewhat generic module swapping
411 lines (311 loc) • 9.77 kB
JavaScript
var winBB = require('../');
var should = require("should");
//lets create some sample modules
var sample = require("./sampleEvo");
var path =require('path');
var colors =require('colors');
var util =require('util');
var backbone = new winBB(__dirname + "/");
var saveMod = require('./sampleSave')(backbone);
var traverse = require('traverse');
backLog = backbone.getLogger({winFunction:"mocha"});
backbone.logLevel = backbone.testing;
backLog.logLevel = backLog.testing;
var backLog, evoEmitter,backEmitter, rModules, sampleJSON;
var wFunToModule;
var mochaModule = {
winFunction : "mocha",
requiredEvents : function(){
return [
"save:batchSave",
"save:manyArgumentCallback",
"save:errorCallback"
];
}
// ,eventCallbacks : function(){return {}}
}
// var homePath = path.resolve(__dirname, "..");
describe('Testing win-backbone',function(){
before(function(done)
{
var evoModule = new sample(backbone);
//modules functions yo
rModules = [evoModule.winFunction, saveMod.winFunction, mochaModule.winFunction];
wFunToModule = {};
//not necessarily the real modules
wFunToModule[evoModule.winFunction] = evoModule;
wFunToModule[saveMod.winFunction] = saveMod;
wFunToModule[mochaModule.winFunction] = mochaModule;
sampleJSON =
{
"evo" : evoModule,
"save" : "./sampleSave.js",
"mocha" : mochaModule
};
//now load in our module file
backbone.loadModules(sampleJSON);
// backbone.mute("backbone");
backbone.muteLogger(backLog);
// backbone.mute("evo");
// backbone.mute("save");
// backbone.mute("mocha");
evoEmitter = backbone.getEmitter(evoModule);
backEmitter = backbone.getEmitter(mochaModule);
backbone.initializeModules(function()
{
backLog("Finished Module Init");
done();
});
})
it('should have proper modules and events',function(done)
{
//backwards compat, but more consistent with getters
var callerEvents = backbone.getRegisteredEvents();
var requiredEvents = backbone.getModuleRequirements();
backLog('All req functions: '.green, requiredEvents);
backLog('All callback functions: '.green, callerEvents);
// backLog("Bckbone:", backbone.getModuleCount);
// backLog("bb mod:".red, backbone.getModuleCount());
//check modules -- shoud have enough
backbone.getModuleCount().should.equal(rModules.length);
var allModules = backbone.getModules();
for(var key in sampleJSON)
{
//these are the module names -- check they have been loaded
//make sure it exists in the modules we retrieved
should.exist(allModules[key]);
}
//now make sure all the required events are correct
for(var wFun in wFunToModule)
{
//what do we require?
var mod = wFunToModule[wFun];
if(!mod.requiredEvents)
continue;
var actualRequired = mod.requiredEvents();
//shouldn't exist if we don't have any required events
if(!actualRequired.length)
{
should.not.exist(requiredEvents[wFun]);
continue;
}
//grab the inner version
var bModRequired = requiredEvents[wFun];
should.exist(bModRequired);
var all = {};
for(var i=0; i < actualRequired.length; i++)
{
var split = actualRequired[i].split(':');
var n = split[0];
if(!all[n])
all[n] = {};
all[n][split[1]] = actualRequired[i];
}
backLog("Bb required: ".yellow, bModRequired);
backLog('Test req functions: '.magenta, actualRequired);
backLog("Checking req against: ".magenta, all);
//catch all the required
for(var mReqFunc in all)
{
var actual = all[mReqFunc];
var gen = bModRequired[mReqFunc];
backLog("inner test: ".magenta, actual)
backLog("inner backbone: ".yellow, gen)
//exists, and has same nubmer of keys
should.exist(gen);
Object.keys(actual).length.should.equal(Object.keys(gen).length);
for(var k in actual)
actual[k].should.equal(gen[k]);
}
}
//lets squish callbacks to do this quicker
var squishCallbackNames = [];
traverse(callerEvents).forEach(function(node)
{
if(this.isLeaf)
squishCallbackNames.push(this.node);
});
var squishActual = [];
for(var modFunc in wFunToModule)
{
//now lets pull all callbacks
var mod = wFunToModule[modFunc];
if(!mod.eventCallbacks)
continue;
//get callbacks
var cbs = mod.eventCallbacks();
//if you don't have cbs dont add please
if(Object.keys(cbs).length)
squishActual = squishActual.concat(Object.keys(cbs));
}
var noDups = {};
traverse(squishActual).forEach(function(){
if(this.isLeaf)
{
//no more you
if(noDups[this.node])
this.remove();
noDups[this.node] = true;
}
});
backLog("Test calbacks : ".magenta, squishActual);
backLog("Registered callbacks :".yellow, squishCallbackNames);
squishActual.length.should.equal(squishCallbackNames.length);
squishActual.sort();
squishCallbackNames.sort();
squishActual.join(',').should.equal(squishCallbackNames.join(','));
//all done with registered stuff
done();
});
it('Should emit from eveolution module without issue',function(done){
//call from "inside" another module
evoEmitter.emit('save:batchSave', ["stuffywuffy"], function()
{
backLog('Batch save test returned: ', arguments);
done();
});
});
it('Should used q callback to return function call', function(done){
//shoudl call qfunction
var incomingArgs = ["stuffywuffy"];
var eMessage = "error";
backLog("Making many arg callback: ".magenta, incomingArgs);
backEmitter.qCall('save:manyArgumentCallback', incomingArgs[0])
.then(function(repeat)
{
backLog("Many call return: ".yellow, repeat);
//this is a single return call
incomingArgs[0].should.equal(repeat);
incomingArgs.push("new arg");
return backEmitter.qCall('save:manyArgumentCallback', incomingArgs[0], incomingArgs[1])
})
.then(function(multi)
{
incomingArgs[0].should.equal(multi[0]);
incomingArgs[1].should.equal(multi[1]);
return backEmitter.qCall('save:errorCallback', incomingArgs[0]);
})
.fail(function(err)
{
backLog("Err: ", err);
//should catch this error -- if it isn't the error we purposefully threw, it will also cause an error here too
err.message.should.equal(eMessage);
//survied the test
backLog("Finised Q flow function tests");
})
.done(function()
{
backLog("it's finally over");
done();
})
})
it('Should emit error due to lack of event permission',function(done){
backLog('Test invalid callback');
try
{
evoEmitter('evolution:createIndividual', 0, function()
{
log('invalid callback');
});
done("Should have thrown an error in individual");
}
catch(e)
{
done();
}
});
it('Should make multiple requests at the same time through backbone',function(done){
//this represents how many concurrent requests to make
var maCount = 2 + Math.floor(Math.random()*10);
var mirrorArgs = {}, advancedQuery = [];
//making a random number of concurrent requests! Systematically create arguments for testing
for(var i=0; i < maCount; i++){
var aQuery = ["save:manyArgumentCallback"];
//1 - 6 args
var addArgs = 1 + Math.floor(Math.random()*4);
var mArg = [];
for(var a=0; a < addArgs; a++)
{
var theArg = "argument-" + a;
//addditional arguments
aQuery.push(theArg);
mArg.push(theArg);
}
//we save the arguments we should be mirrored for this callback
mirrorArgs[i] = mArg;
//add the query
advancedQuery.push(aQuery);
}
backLog("Advanced query: ".rainbow, advancedQuery);
var failIndex = Math.floor(Math.random()*advancedQuery.length);
//really it works?
backEmitter.qConcurrent(advancedQuery)
.then(function(allResults)
{
backLog("Many concurrent call return: ".yellow, allResults);
//this is a single return call
for(var i=0; i < allResults.length; i++)
{
var result = allResults[i];
var mirArgs = mirrorArgs[i];
backLog("Desired: ".magenta, mirArgs)
backLog("Resulting: ".yellow, result)
//if we only sent a single argument, it gets mirrored directly (no array stuff)
if(mirArgs.length == 1)
mirArgs[0].should.equal(result);
else
{
//otherwise, we have multiples
//we make the arg
mirArgs.length.should.equal(result.length);
//loop through results
for(var l=0; l < mirArgs; l++)
{
mirArgs[l].should.equal(result[l]);
}
}
}
//replace a calback with a certified fail!
//don't need any arguments
advancedQuery[failIndex] = ["save:errorCallback"];
return backEmitter.qConcurrent(advancedQuery, {endOnError: true});
})
.then(function()
{
//this shouldn't be reached
done(new Error("Error was never called"));
}, function(err)
{
backLog("Honk town!!!!".rainbow);
//we have an error, but only length 1 -- endOnError is advanced stuff
err.length.should.equal(1);
"error".should.equal(err[0].message);
//do the same thing, but wihtout end on error
return backEmitter.qConcurrent(advancedQuery);
})
.then(function()
{
//this shouldn't be reached
done(new Error("Error was never called"));
}, function(err)
{
//somebody should have failed!
for(var i=0; i < err.length; i++)
{
if(i != failIndex)
should.not.exist(err[i]);
else{
should.exist(err[i]);
"error".should.equal(err[i].message);
}
}
//survied the test
backLog("Finised Q concurrent flow function tests");
})
.done(function()
{
backLog("it's finally multiply over");
done();
})
});
});