noflo
Version:
Flow-Based Programming environment for JavaScript
616 lines (610 loc) • 19.9 kB
JavaScript
var chai, graph, noflo, path, root, subgraph, urlPrefix,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
if (typeof process !== 'undefined' && process.execPath && process.execPath.match(/node|iojs/)) {
if (!chai) {
chai = require('chai');
}
subgraph = require('../src/components/Graph.coffee');
graph = require('../src/lib/Graph.coffee');
noflo = require('../src/lib/NoFlo.coffee');
path = require('path');
root = path.resolve(__dirname, '../');
urlPrefix = './';
} else {
subgraph = require('noflo/src/components/Graph.js');
graph = require('noflo/src/lib/Graph.js');
noflo = require('noflo/src/lib/NoFlo.js');
root = 'noflo';
urlPrefix = '/';
}
describe('Graph component', function() {
var Split, SubgraphMerge, c, g;
c = null;
g = null;
beforeEach(function() {
c = subgraph.getComponent();
g = noflo.internalSocket.createSocket();
return c.inPorts.graph.attach(g);
});
Split = (function(_super) {
__extends(Split, _super);
function Split() {
this.inPorts = {
"in": new noflo.Port
};
this.outPorts = {
out: new noflo.ArrayPort
};
this.inPorts["in"].on('connect', (function(_this) {
return function(data) {
return _this.outPorts.out.connect();
};
})(this));
this.inPorts["in"].on('data', (function(_this) {
return function(data) {
return _this.outPorts.out.send(data);
};
})(this));
this.inPorts["in"].on('disconnect', (function(_this) {
return function() {
return _this.outPorts.out.disconnect();
};
})(this));
}
return Split;
})(noflo.Component);
Split.getComponent = function() {
return new Split;
};
SubgraphMerge = function() {
var inst;
inst = new noflo.Component;
inst.inPorts.add('in', function(event, payload, instance) {
var method;
method = event;
if (event === 'data') {
method = 'send';
}
return instance.outPorts[method]('out', payload);
});
inst.outPorts.add('out');
return inst;
};
describe('initially', function() {
it('should be ready', function() {
return chai.expect(c.ready).to.be["true"];
});
it('should not contain a network', function() {
return chai.expect(c.network).to.be["null"];
});
it('should not have a baseDir', function() {
return chai.expect(c.baseDir).to.be["null"];
});
return it('should only have the graph inport', function() {
chai.expect(c.inPorts.ports).to.have.keys(['graph']);
return chai.expect(c.outPorts.ports).to.be.empty;
});
});
describe('with JSON graph definition', function() {
it('should emit a ready event after network has been loaded', function(done) {
this.timeout(6000);
c.baseDir = root;
c.once('ready', function() {
chai.expect(c.network).not.to.be["null"];
chai.expect(c.ready).to.be["true"];
return done();
});
c.once('network', function(network) {
network.loader.components.Split = Split;
network.loader.registerComponent('', 'Merge', SubgraphMerge);
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
return c.start();
});
return g.send({
processes: {
Split: {
component: 'Split'
},
Merge: {
component: 'Merge'
}
}
});
});
it('should expose available ports', function(done) {
this.timeout(6000);
c.baseDir = root;
c.once('ready', function() {
chai.expect(c.inPorts.ports).to.have.keys(['graph']);
chai.expect(c.outPorts.ports).to.be.empty;
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send({
processes: {
Split: {
component: 'Split'
},
Merge: {
component: 'Merge'
}
},
connections: [
{
src: {
process: 'Merge',
port: 'out'
},
tgt: {
process: 'Split',
port: 'in'
}
}
]
});
});
it('should update description from the graph', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.network).not.to.be["null"];
chai.expect(c.ready).to.be["true"];
chai.expect(c.description).to.equal('Hello, World!');
return done();
});
c.once('network', function(network) {
network.loader.components.Split = Split;
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
chai.expect(c.description).to.equal('Hello, World!');
return c.start();
});
return g.send({
properties: {
description: 'Hello, World!'
},
processes: {
Split: {
component: 'Split'
}
}
});
});
it('should expose only exported ports when they exist', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.inPorts.ports).to.have.keys(['graph']);
chai.expect(c.outPorts.ports).to.have.keys(['out']);
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send({
exports: [
{
"public": 'out',
"private": 'split.out'
}
],
processes: {
Split: {
component: 'Split'
},
Merge: {
component: 'Merge'
}
},
connections: [
{
src: {
process: 'Merge',
port: 'out'
},
tgt: {
process: 'Split',
port: 'in'
}
}
]
});
});
return it('should be able to run the graph', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
var ins, out;
ins = noflo.internalSocket.createSocket();
out = noflo.internalSocket.createSocket();
c.inPorts['in'].attach(ins);
c.outPorts['out'].attach(out);
out.on('data', function(data) {
chai.expect(data).to.equal('Foo');
return done();
});
return ins.send('Foo');
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send({
exports: [
{
"public": 'in',
"private": 'merge.in'
}, {
"public": 'out',
"private": 'split.out'
}
],
processes: {
Split: {
component: 'Split'
},
Merge: {
component: 'Merge'
}
},
connections: [
{
src: {
process: 'Merge',
port: 'out'
},
tgt: {
process: 'Split',
port: 'in'
}
}
]
});
});
});
describe('with a Graph instance', function() {
var gr;
gr = new graph.Graph('Hello, world');
gr.baseDir = root;
gr.addNode('Split', 'Split');
gr.addNode('Merge', 'Merge');
gr.addEdge('Merge', 'out', 'Split', 'in');
gr.addInport('in', 'Merge', 'in');
gr.addOutport('out', 'Split', 'out');
it('should emit a ready event after network has been loaded', function(done) {
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.network).not.to.be["null"];
chai.expect(c.ready).to.be["true"];
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
g.send(gr);
return chai.expect(c.ready).to.be["false"];
});
it('should expose available ports', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.inPorts.ports).to.have.keys(['graph', 'in']);
chai.expect(c.outPorts.ports).to.have.keys(['out']);
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send(gr);
});
return it('should be able to run the graph', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
var ins, out;
ins = noflo.internalSocket.createSocket();
out = noflo.internalSocket.createSocket();
c.inPorts['in'].attach(ins);
c.outPorts['out'].attach(out);
out.on('data', function(data) {
chai.expect(data).to.equal('Foo');
return done();
});
return ins.send('Foo');
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send(gr);
});
});
describe('with a FBP file with INPORTs and OUTPORTs', function() {
var file;
file = "" + urlPrefix + "spec/fixtures/subgraph.fbp";
it('should emit a ready event after network has been loaded', function(done) {
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.network).not.to.be["null"];
chai.expect(c.ready).to.be["true"];
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
g.send(file);
return chai.expect(c.ready).to.be["false"];
});
it('should expose available ports', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.inPorts.ports).to.have.keys(['graph', 'in']);
chai.expect(c.outPorts.ports).to.have.keys(['out']);
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send(file);
});
return it('should be able to run the graph', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
var ins, out;
ins = noflo.internalSocket.createSocket();
out = noflo.internalSocket.createSocket();
c.inPorts['in'].attach(ins);
c.outPorts['out'].attach(out);
out.on('connect', function() {
return ins.send('Foo');
});
out.on('data', function(data) {
chai.expect(data).to.equal('Foo');
return ins.disconnect();
});
out.on('disconnect', function() {
return done();
});
return ins.connect();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send(file);
});
});
describe('with a FBP file with legacy EXPORTS', function() {
var file;
file = "" + urlPrefix + "spec/fixtures/subgraph_legacy.fbp";
it('should emit a ready event after network has been loaded', function(done) {
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.network).not.to.be["null"];
chai.expect(c.ready).to.be["true"];
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
g.send(file);
return chai.expect(c.ready).to.be["false"];
});
it('should expose available ports', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.inPorts.ports).to.have.keys(['graph', 'in']);
chai.expect(c.outPorts.ports).to.have.keys(['out']);
return done();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send(file);
});
it('should have disambiguated the exported ports', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
chai.expect(c.network.graph.exports).to.be.empty;
chai.expect(c.network.graph.inports).to.be.not.empty;
chai.expect(c.network.graph.inports["in"]).to.be.an('object');
chai.expect(c.network.graph.outports).to.be.not.empty;
chai.expect(c.network.graph.outports.out).to.be.an('object');
return done();
});
c.once('network', function() {
c.network.loader.components.Split = Split;
return c.network.loader.components.Merge = SubgraphMerge;
});
return g.send(file);
});
return it('should be able to run the graph', function(done) {
c.baseDir = root;
this.timeout(6000);
c.once('ready', function() {
var ins, out;
ins = noflo.internalSocket.createSocket();
out = noflo.internalSocket.createSocket();
c.inPorts['in'].attach(ins);
c.outPorts['out'].attach(out);
out.on('connect', function() {
return ins.send('Foo');
});
out.on('data', function(data) {
chai.expect(data).to.equal('Foo');
return ins.disconnect();
});
out.on('disconnect', function() {
return done();
});
return ins.connect();
});
c.once('network', function() {
chai.expect(c.ready).to.be["false"];
chai.expect(c.network).not.to.be["null"];
c.network.loader.components.Split = Split;
c.network.loader.components.Merge = SubgraphMerge;
return c.start();
});
return g.send(file);
});
});
return describe('when a subgraph is used as a component', function() {
var createSplit, grDefaults, grInitials;
createSplit = function() {
c = new noflo.Component;
c.inPorts.add('in', {
required: true,
datatype: 'string',
"default": 'default-value'
}, (function(_this) {
return function(e, data) {
switch (e) {
case 'connect':
return c.outPorts.out.connect();
case 'data':
return c.outPorts.out.send(data);
case 'disconnect':
return c.outPorts.out.disconnect();
}
};
})(this));
c.outPorts.add('out');
return c;
};
grDefaults = new noflo.Graph('Child Graph Using Defaults');
grDefaults.addNode('SplitIn', 'Split');
grDefaults.addNode('SplitOut', 'Split');
grDefaults.addInport('in', 'SplitIn', 'in');
grDefaults.addOutport('out', 'SplitOut', 'out');
grDefaults.addEdge('SplitIn', 'out', 'SplitOut', 'in');
grInitials = new noflo.Graph('Child Graph Using Initials');
grInitials.addNode('SplitIn', 'Split');
grInitials.addNode('SplitOut', 'Split');
grInitials.addInport('in', 'SplitIn', 'in');
grInitials.addOutport('out', 'SplitOut', 'out');
grInitials.addInitial('initial-value', 'SplitIn', 'in');
grInitials.addEdge('SplitIn', 'out', 'SplitOut', 'in');
it('should send defaults', function(done) {
var cl;
this.timeout(6000);
cl = new noflo.ComponentLoader(root);
return cl.listComponents(function(err, components) {
if (err) {
return done(err);
}
cl.components.Split = createSplit;
cl.components.Defaults = grDefaults;
cl.components.Initials = grInitials;
return cl.load('Defaults', function(err, inst) {
var o;
o = noflo.internalSocket.createSocket();
inst.outPorts.out.attach(o);
o.once('data', function(data) {
chai.expect(data).to.equal('default-value');
return done();
});
return inst.start();
});
});
});
it('should send initials', function(done) {
var cl;
this.timeout(6000);
cl = new noflo.ComponentLoader(root);
return cl.listComponents(function(err, components) {
if (err) {
return done(err);
}
cl.components.Split = createSplit;
cl.components.Defaults = grDefaults;
cl.components.Initials = grInitials;
return cl.load('Initials', function(err, inst) {
var o;
o = noflo.internalSocket.createSocket();
inst.outPorts.out.attach(o);
o.once('data', function(data) {
chai.expect(data).to.equal('initial-value');
return done();
});
return inst.start();
});
});
});
return it('should not send defaults when an inport is attached externally', function(done) {
var cl;
this.timeout(6000);
cl = new noflo.ComponentLoader(root);
return cl.listComponents(function(err, components) {
if (err) {
return done(err);
}
cl.components.Split = createSplit;
cl.components.Defaults = grDefaults;
cl.components.Initials = grInitials;
return cl.load('Defaults', function(err, inst) {
var i, o;
i = noflo.internalSocket.createSocket();
o = noflo.internalSocket.createSocket();
inst.inPorts["in"].attach(i);
inst.outPorts.out.attach(o);
o.once('data', function(data) {
chai.expect(data).to.equal('Foo');
return done();
});
inst.start();
return i.send('Foo');
});
});
});
});
});