noflo
Version:
Flow-Based Programming environment for JavaScript
553 lines (545 loc) • 16.2 kB
JavaScript
var chai, noflo, path, processAsync, processMerge, processMergeA, root, urlPrefix, wirePatternAsync, wirePatternMerge;
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 = '/';
}
wirePatternAsync = function() {
var c;
c = new noflo.Component;
c.inPorts.add('in', {
datatype: 'string'
});
c.outPorts.add('out', {
datatype: 'string'
});
return noflo.helpers.WirePattern(c, {
"in": 'in',
out: 'out',
async: true,
forwardGroups: true
}, function(data, groups, out, callback) {
return setTimeout(function() {
out.send(data + c.nodeId);
return callback();
}, 1);
});
};
wirePatternMerge = function() {
var c;
c = new noflo.Component;
c.inPorts.add('in1', {
datatype: 'string'
});
c.inPorts.add('in2', {
datatype: 'string'
});
c.outPorts.add('out', {
datatype: 'string'
});
return noflo.helpers.WirePattern(c, {
"in": ['in1', 'in2'],
out: 'out',
async: true,
forwardGroups: true
}, function(data, groups, out, callback) {
out.send("1" + data['in1'] + c.nodeId + "2" + data['in2'] + c.nodeId);
return callback();
});
};
processAsync = function() {
var c;
c = new noflo.Component;
c.inPorts.add('in', {
datatype: 'string'
});
c.outPorts.add('out', {
datatype: 'string'
});
return c.process(function(input, output) {
var data;
data = input.getData('in');
return setTimeout(function() {
return output.sendDone(data + c.nodeId);
}, 1);
});
};
processMerge = function() {
var c;
c = new noflo.Component;
c.inPorts.add('in1', {
datatype: 'string'
});
c.inPorts.add('in2', {
datatype: 'string'
});
c.outPorts.add('out', {
datatype: 'string'
});
c.forwardBrackets = {
'in1': ['out']
};
return c.process(function(input, output) {
var first, second;
if (!input.has('in1', 'in2', function(ip) {
return ip.type === 'data';
})) {
return;
}
first = input.getData('in1');
second = input.getData('in2');
return output.sendDone({
out: "1" + first + ":2" + second + ":" + c.nodeId
});
});
};
processMergeA = function() {
var c;
c = new noflo.Component;
c.inPorts.add('in1', {
datatype: 'string'
});
c.inPorts.add('in2', {
datatype: 'string',
addressable: true
});
c.outPorts.add('out', {
datatype: 'string'
});
c.forwardBrackets = {
'in1': ['out']
};
return c.process(function(input, output) {
var first, second0, second1;
if (!input.hasData('in1', ['in2', 0], ['in2', 1])) {
return;
}
first = input.getData('in1');
second0 = input.getData(['in2', 0]);
second1 = input.getData(['in2', 1]);
return output.sendDone({
out: "1" + first + ":2" + second0 + ":2" + second1 + ":" + c.nodeId
});
});
};
describe('Scope isolation', function() {
var loader;
loader = null;
before(function(done) {
loader = new noflo.ComponentLoader(root);
return loader.listComponents(function(err) {
if (err) {
return done(err);
}
loader.registerComponent('wirepattern', 'Async', wirePatternAsync);
loader.registerComponent('wirepattern', 'Merge', wirePatternMerge);
loader.registerComponent('process', 'Async', processAsync);
loader.registerComponent('process', 'Merge', processMerge);
loader.registerComponent('process', 'MergeA', processMergeA);
return done();
});
});
describe('with WirePattern sending to Process API', function() {
var c, ins, out;
c = null;
ins = null;
out = null;
before(function(done) {
var fbpData;
fbpData = "INPORT=Wp.IN:IN OUTPORT=Pc.OUT:OUT Wp(wirepattern/Async) OUT -> IN Pc(process/Async)";
return noflo.graph.loadFBP(fbpData, function(err, g) {
if (err) {
return done(err);
}
loader.registerComponent('scope', 'Connected', g);
return loader.load('scope/Connected', function(err, instance) {
if (err) {
return done(err);
}
c = instance;
ins = noflo.internalSocket.createSocket();
c.inPorts["in"].attach(ins);
return done();
});
});
});
beforeEach(function() {
out = noflo.internalSocket.createSocket();
return c.outPorts.out.attach(out);
});
afterEach(function() {
c.outPorts.out.detach(out);
return out = null;
});
it('should forward old-style groups as expected', function(done) {
var expected, received;
expected = ['CONN', '< 1', '< a', 'DATA bazWpPc', '>', '>', 'DISC'];
received = [];
out.on('connect', function() {
return received.push('CONN');
});
out.on('begingroup', function(group) {
return received.push("< " + group);
});
out.on('data', function(data) {
return received.push("DATA " + data);
});
out.on('endgroup', function() {
return received.push('>');
});
out.on('disconnect', function() {
received.push('DISC');
chai.expect(received).to.eql(expected);
return done();
});
ins.connect();
ins.beginGroup(1);
ins.beginGroup('a');
ins.send('baz');
ins.endGroup();
ins.endGroup();
return ins.disconnect();
});
it('should forward new-style brackets as expected', function(done) {
var brackets, expected, received;
expected = ['< 1', '< a', 'DATA fooWpPc', '>', '>'];
received = [];
brackets = [];
out.on('ip', function(ip) {
switch (ip.type) {
case 'openBracket':
received.push("< " + ip.data);
return brackets.push(ip.data);
case 'data':
return received.push("DATA " + ip.data);
case 'closeBracket':
received.push('>');
brackets.pop();
if (brackets.length) {
return;
}
chai.expect(received).to.eql(expected);
return done();
}
});
ins.post(new noflo.IP('openBracket', 1));
ins.post(new noflo.IP('openBracket', 'a'));
ins.post(new noflo.IP('data', 'foo'));
ins.post(new noflo.IP('closeBracket', 'a'));
return ins.post(new noflo.IP('closeBracket', 1));
});
return it('should forward scopes as expected', function(done) {
var brackets, expected, received;
expected = ['x < 1', 'x < a', 'x DATA barWpPc', 'x >', 'x >'];
received = [];
brackets = [];
out.on('ip', function(ip) {
switch (ip.type) {
case 'openBracket':
received.push(ip.scope + " < " + ip.data);
return brackets.push(ip.data);
case 'data':
return received.push(ip.scope + " DATA " + ip.data);
case 'closeBracket':
received.push(ip.scope + " >");
brackets.pop();
if (brackets.length) {
return;
}
chai.expect(received).to.eql(expected);
return done();
}
});
ins.post(new noflo.IP('openBracket', 1, {
scope: 'x'
}));
ins.post(new noflo.IP('openBracket', 'a', {
scope: 'x'
}));
ins.post(new noflo.IP('data', 'bar', {
scope: 'x'
}));
ins.post(new noflo.IP('closeBracket', 'a', {
scope: 'x'
}));
return ins.post(new noflo.IP('closeBracket', 1, {
scope: 'x'
}));
});
});
describe('pure Process API merging two inputs', function() {
var c, in1, in2, out;
c = null;
in1 = null;
in2 = null;
out = null;
before(function(done) {
var fbpData;
fbpData = "INPORT=Pc1.IN:IN1 INPORT=Pc2.IN:IN2 OUTPORT=PcMerge.OUT:OUT Pc1(process/Async) OUT -> IN1 PcMerge(process/Merge) Pc2(process/Async) OUT -> IN2 PcMerge(process/Merge)";
return noflo.graph.loadFBP(fbpData, function(err, g) {
if (err) {
return done(err);
}
loader.registerComponent('scope', 'Merge', g);
return loader.load('scope/Merge', function(err, instance) {
if (err) {
return done(err);
}
c = instance;
in1 = noflo.internalSocket.createSocket();
c.inPorts.in1.attach(in1);
in2 = noflo.internalSocket.createSocket();
c.inPorts.in2.attach(in2);
return done();
});
});
});
beforeEach(function() {
out = noflo.internalSocket.createSocket();
return c.outPorts.out.attach(out);
});
afterEach(function() {
c.outPorts.out.detach(out);
return out = null;
});
it('should forward new-style brackets as expected', function(done) {
var expected, received;
expected = ['CONN', '< 1', '< a', 'DATA 1bazPc1:2fooPc2:PcMerge', '>', '>', 'DISC'];
received = [];
out.on('connect', function() {
return received.push('CONN');
});
out.on('begingroup', function(group) {
return received.push("< " + group);
});
out.on('data', function(data) {
return received.push("DATA " + data);
});
out.on('endgroup', function() {
return received.push('>');
});
out.on('disconnect', function() {
received.push('DISC');
chai.expect(received).to.eql(expected);
return done();
});
in2.connect();
in2.send('foo');
in2.disconnect();
in1.connect();
in1.beginGroup(1);
in1.beginGroup('a');
in1.send('baz');
in1.endGroup();
in1.endGroup();
return in1.disconnect();
});
it('should forward new-style brackets as expected regardless of sending order', function(done) {
var expected, received;
expected = ['CONN', '< 1', '< a', 'DATA 1bazPc1:2fooPc2:PcMerge', '>', '>', 'DISC'];
received = [];
out.on('connect', function() {
return received.push('CONN');
});
out.on('begingroup', function(group) {
return received.push("< " + group);
});
out.on('data', function(data) {
return received.push("DATA " + data);
});
out.on('endgroup', function() {
return received.push('>');
});
out.on('disconnect', function() {
received.push('DISC');
chai.expect(received).to.eql(expected);
return done();
});
in1.connect();
in1.beginGroup(1);
in1.beginGroup('a');
in1.send('baz');
in1.endGroup();
in1.endGroup();
in1.disconnect();
in2.connect();
in2.send('foo');
return in2.disconnect();
});
return it('should forward scopes as expected', function(done) {
var brackets, expected, received;
expected = ['x < 1', 'x DATA 1onePc1:2twoPc2:PcMerge', 'x >'];
received = [];
brackets = [];
out.on('ip', function(ip) {
switch (ip.type) {
case 'openBracket':
received.push(ip.scope + " < " + ip.data);
return brackets.push(ip.data);
case 'data':
return received.push(ip.scope + " DATA " + ip.data);
case 'closeBracket':
received.push(ip.scope + " >");
brackets.pop();
if (brackets.length) {
return;
}
chai.expect(received).to.eql(expected);
return done();
}
});
in2.post(new noflo.IP('data', 'two', {
scope: 'x'
}));
in1.post(new noflo.IP('openBracket', 1, {
scope: 'x'
}));
in1.post(new noflo.IP('data', 'one', {
scope: 'x'
}));
return in1.post(new noflo.IP('closeBracket', 1, {
scope: 'x'
}));
});
});
describe('Process API with IIPs and scopes', function() {
var c, in1, in2, out;
c = null;
in1 = null;
in2 = null;
out = null;
before(function(done) {
var fbpData;
fbpData = "INPORT=Pc1.IN:IN1 OUTPORT=PcMerge.OUT:OUT Pc1(process/Async) -> IN1 PcMerge(process/Merge) 'twoIIP' -> IN2 PcMerge(process/Merge)";
return noflo.graph.loadFBP(fbpData, function(err, g) {
if (err) {
return done(err);
}
loader.registerComponent('scope', 'MergeIIP', g);
return loader.load('scope/MergeIIP', function(err, instance) {
if (err) {
return done(err);
}
c = instance;
in1 = noflo.internalSocket.createSocket();
c.inPorts.in1.attach(in1);
return done();
});
});
});
beforeEach(function() {
out = noflo.internalSocket.createSocket();
return c.outPorts.out.attach(out);
});
afterEach(function() {
c.outPorts.out.detach(out);
return out = null;
});
return it('should forward scopes as expected', function(done) {
var brackets, expected, received;
expected = ['x < 1', 'x DATA 1onePc1:2twoIIP:PcMerge', 'x >'];
received = [];
brackets = [];
out.on('ip', function(ip) {
switch (ip.type) {
case 'openBracket':
received.push(ip.scope + " < " + ip.data);
return brackets.push(ip.data);
case 'data':
return received.push(ip.scope + " DATA " + ip.data);
case 'closeBracket':
received.push(ip.scope + " >");
brackets.pop();
if (brackets.length) {
return;
}
chai.expect(received).to.eql(expected);
return done();
}
});
in1.post(new noflo.IP('openBracket', 1, {
scope: 'x'
}));
in1.post(new noflo.IP('data', 'one', {
scope: 'x'
}));
return in1.post(new noflo.IP('closeBracket', 1, {
scope: 'x'
}));
});
});
return describe('Process API with IIPs to addressable ports and scopes', function() {
var c, in1, in2, out;
c = null;
in1 = null;
in2 = null;
out = null;
before(function(done) {
var fbpData;
fbpData = "INPORT=Pc1.IN:IN1 OUTPORT=PcMergeA.OUT:OUT Pc1(process/Async) -> IN1 PcMergeA(process/MergeA) 'twoIIP0' -> IN2[0] PcMergeA 'twoIIP1' -> IN2[1] PcMergeA";
return noflo.graph.loadFBP(fbpData, function(err, g) {
if (err) {
return done(err);
}
loader.registerComponent('scope', 'MergeIIPA', g);
return loader.load('scope/MergeIIPA', function(err, instance) {
if (err) {
return done(err);
}
c = instance;
in1 = noflo.internalSocket.createSocket();
c.inPorts.in1.attach(in1);
return done();
});
});
});
beforeEach(function() {
out = noflo.internalSocket.createSocket();
return c.outPorts.out.attach(out);
});
afterEach(function() {
c.outPorts.out.detach(out);
return out = null;
});
return it('should forward scopes as expected', function(done) {
var brackets, expected, received;
expected = ['x < 1', 'x DATA 1onePc1:2twoIIP0:2twoIIP1:PcMergeA', 'x >'];
received = [];
brackets = [];
out.on('ip', function(ip) {
switch (ip.type) {
case 'openBracket':
received.push(ip.scope + " < " + ip.data);
return brackets.push(ip.data);
case 'data':
return received.push(ip.scope + " DATA " + ip.data);
case 'closeBracket':
received.push(ip.scope + " >");
brackets.pop();
if (brackets.length) {
return;
}
chai.expect(received).to.eql(expected);
return done();
}
});
in1.post(new noflo.IP('openBracket', 1, {
scope: 'x'
}));
in1.post(new noflo.IP('data', 'one', {
scope: 'x'
}));
return in1.post(new noflo.IP('closeBracket', 1, {
scope: 'x'
}));
});
});
});