UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

674 lines (671 loc) 20.6 kB
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'); }); }); }); }); });