noflo
Version:
Flow-Based Programming environment for JavaScript
674 lines (671 loc) • 20.6 kB
JavaScript
var chai, noflo, path, root, urlPrefix;
if (typeof process !== 'undefined' && process.execPath && process.execPath.match(/node|iojs/)) {
if (!chai) {
chai = require('chai');
}
noflo = require('../src/lib/NoFlo.coffee');
path = require('path');
root = path.resolve(__dirname, '../');
urlPrefix = './';
} else {
noflo = require('noflo');
root = 'noflo';
urlPrefix = '/';
}
describe('NoFlo Graph component', function() {
var Split, SubgraphMerge, c, g, loader;
c = null;
g = null;
loader = null;
before(function(done) {
loader = new noflo.ComponentLoader(root);
loader.listComponents(done);
return done;
});
beforeEach(function(done) {
loader.load('Graph', function(err, instance) {
if (err) {
return done(err);
}
c = instance;
g = noflo.internalSocket.createSocket();
c.inPorts.graph.attach(g);
return done();
});
});
Split = function() {
var inst;
inst = new noflo.Component;
inst.inPorts.add('in', {
datatype: 'all'
});
inst.outPorts.add('out', {
datatype: 'all'
});
return inst.process(function(input, output) {
var data;
data = input.getData('in');
return output.sendDone({
out: data
});
});
};
SubgraphMerge = function() {
var inst;
inst = new noflo.Component;
inst.inPorts.add('in', {
datatype: 'all'
});
inst.outPorts.add('out', {
datatype: 'all'
});
inst.forwardBrackets = {};
return inst.process(function(input, output) {
var packet;
packet = input.get('in');
if (packet.type !== 'data') {
return output.done();
}
return output.sendDone({
out: packet.data
});
});
};
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 have a baseDir', function() {
return chai.expect(c.baseDir).to.equal(root);
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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(function(err) {
if (err) {
return done(err);
}
});
});
return g.send({
outports: {
out: {
process: 'Split',
port: '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(function(err) {
if (err) {
return done(err);
}
});
});
return g.send({
inports: {
"in": {
process: 'Merge',
port: 'in'
}
},
outports: {
out: {
process: 'Split',
port: '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 noflo.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.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() {
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(function(err) {
if (err) {
return done(err);
}
});
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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.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() {
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(function(err) {
if (err) {
return done(err);
}
});
});
g.send(file);
return chai.expect(c.ready).to.be["false"];
});
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', '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(function(err) {
if (err) {
return done(err);
}
});
});
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, received;
ins = noflo.internalSocket.createSocket();
out = noflo.internalSocket.createSocket();
c.inPorts['in'].attach(ins);
c.outPorts['out'].attach(out);
received = false;
out.on('data', function(data) {
chai.expect(data).to.equal('Foo');
return received = true;
});
out.on('disconnect', function() {
chai.expect(received, 'should have transmitted data').to.equal(true);
return done();
});
ins.connect();
ins.send('Foo');
return ins.disconnect();
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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.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() {
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(function(err) {
if (err) {
return done(err);
}
});
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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, received;
ins = noflo.internalSocket.createSocket();
out = noflo.internalSocket.createSocket();
c.inPorts['in'].attach(ins);
c.outPorts['out'].attach(out);
received = false;
out.on('data', function(data) {
chai.expect(data).to.equal('Foo');
return received = true;
});
out.on('disconnect', function() {
chai.expect(received, 'should have transmitted data').to.equal(true);
return done();
});
ins.connect();
ins.send('Foo');
return ins.disconnect();
});
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(function(err) {
if (err) {
return done(err);
}
});
});
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'
});
c.outPorts.add('out', {
datatype: 'string'
});
return c.process(function(input, output) {
var data;
data = input.getData('in');
return output.sendDone({
out: data
});
});
};
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);
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);
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);
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');
});
});
});
});
});