noflo
Version:
Flow-Based Programming environment for JavaScript
1,645 lines (1,642 loc) • 66.7 kB
JavaScript
var Substream, chai, component, helpers, socket;
if (typeof process !== 'undefined' && process.execPath && process.execPath.match(/node|iojs/)) {
if (!chai) {
chai = require('chai');
}
helpers = require('../src/lib/Helpers');
component = require('../src/lib/Component');
socket = require('../src/lib/InternalSocket');
Substream = require('../src/lib/Streams').Substream;
} else {
helpers = require('noflo/src/lib/Helpers');
component = require('noflo/src/lib/Component');
socket = require('noflo/src/lib/InternalSocket');
Substream = require('noflo/src/lib/Streams').Substream;
}
describe('Component traits', function() {
describe('MapComponent', function() {
var c;
c = null;
it('should pass data to the callback', function() {
var s;
c = new component.Component;
c.inPorts.add('in');
c.outPorts.add('out', {
required: false
});
helpers.MapComponent(c, function(data) {
return chai.expect(data).to.equal(1);
});
s = new socket.createSocket();
c.inPorts["in"].attach(s);
return s.send(1);
});
it('should pass groups to the callback', function() {
var s;
c = new component.Component;
c.inPorts.add('in');
c.outPorts.add('out', {
required: false
});
helpers.MapComponent(c, function(data, groups) {
chai.expect(groups).to.eql(['one', 'two']);
return chai.expect(data).to.equal(1);
});
s = new socket.createSocket();
c.inPorts["in"].attach(s);
s.beginGroup('one');
s.beginGroup('two');
return s.send(1);
});
return it('should send groups and disconnect through', function(done) {
var groups, s, s2;
c = new component.Component;
c.inPorts.add('in');
c.outPorts.add('out', {
required: false
});
helpers.MapComponent(c, function(data, groups, out) {
return out.send(data * 2);
});
s = new socket.createSocket();
c.inPorts["in"].attach(s);
s2 = new socket.createSocket();
c.outPorts.out.attach(s2);
groups = [];
s2.on('begingroup', function(group) {
return groups.push(group);
});
s2.on('data', function(data) {
chai.expect(groups.length).to.equal(2);
return chai.expect(data).to.equal(6);
});
s2.on('endgroup', function() {
return groups.pop();
});
s2.on('disconnect', function() {
chai.expect(groups.length).to.equal(0);
return done();
});
s.beginGroup('one');
s.beginGroup('two');
s.send(3);
s.endGroup();
s.endGroup();
return s.disconnect();
});
});
describe('WirePattern', function() {
describe('when grouping by packet groups', function() {
var c, p, x, y, z;
c = new component.Component;
c.inPorts.add('x', {
required: true,
datatype: 'int'
}).add('y', {
required: true,
datatype: 'int'
}).add('z', {
required: true,
datatype: 'int'
});
c.outPorts.add('point');
x = new socket.createSocket();
y = new socket.createSocket();
z = new socket.createSocket();
p = new socket.createSocket();
c.inPorts.x.attach(x);
c.inPorts.y.attach(y);
c.inPorts.z.attach(z);
c.outPorts.point.attach(p);
it('should pass data and groups to the callback', function(done) {
var count, groups, grp, key, src, _results;
src = {
111: {
x: 1,
y: 2,
z: 3
},
222: {
x: 4,
y: 5,
z: 6
},
333: {
x: 7,
y: 8,
z: 9
}
};
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point',
group: true,
forwardGroups: true
}, function(data, groups, out) {
chai.expect(groups.length).to.be.above(0);
chai.expect(data).to.deep.equal(src[groups[0]]);
return out.send(data);
});
groups = [];
count = 0;
p.on('begingroup', function(grp) {
return groups.push(grp);
});
p.on('endgroup', function() {
return groups.pop();
});
p.on('data', function(data) {
return count++;
});
p.on('disconnect', function() {
if (count === 3 && groups.length === 0) {
return done();
}
});
_results = [];
for (key in src) {
grp = src[key];
x.beginGroup(key);
y.beginGroup(key);
z.beginGroup(key);
x.send(grp.x);
y.send(grp.y);
z.send(grp.z);
x.endGroup();
y.endGroup();
z.endGroup();
x.disconnect();
y.disconnect();
_results.push(z.disconnect());
}
return _results;
});
it('should work without a group provided', function(done) {
p.removeAllListeners();
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point'
}, function(data, groups, out) {
chai.expect(groups.length).to.equal(0);
return out.send({
x: data.x,
y: data.y,
z: data.z
});
});
p.once('data', function(data) {
chai.expect(data).to.deep.equal({
x: 123,
y: 456,
z: 789
});
return done();
});
x.send(123);
x.disconnect();
y.send(456);
y.disconnect();
z.send(789);
return z.disconnect();
});
it('should process inputs for different groups independently with group: true', function(done) {
var groups, inOrder, input, outOrder, src, tuple, _i, _len, _results;
src = {
1: {
x: 1,
y: 2,
z: 3
},
2: {
x: 4,
y: 5,
z: 6
},
3: {
x: 7,
y: 8,
z: 9
}
};
inOrder = [[1, 'x'], [3, 'z'], [2, 'y'], [2, 'x'], [1, 'z'], [2, 'z'], [3, 'x'], [1, 'y'], [3, 'y']];
outOrder = [2, 1, 3];
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point',
group: true,
forwardGroups: true
}, function(data, groups, out) {
return out.send({
x: data.x,
y: data.y,
z: data.z
});
});
groups = [];
p.on('begingroup', function(grp) {
return groups.push(grp);
});
p.on('endgroup', function(grp) {
return groups.pop();
});
p.on('data', function(data) {
chai.expect(groups.length).to.equal(1);
chai.expect(groups[0]).to.equal(outOrder[0]);
chai.expect(data).to.deep.equal(src[outOrder[0]]);
outOrder.shift();
if (!outOrder.length) {
return done();
}
});
_results = [];
for (_i = 0, _len = inOrder.length; _i < _len; _i++) {
tuple = inOrder[_i];
input = null;
switch (tuple[1]) {
case 'x':
input = x;
break;
case 'y':
input = y;
break;
case 'z':
input = z;
}
input.beginGroup(tuple[0]);
input.send(src[tuple[0]][tuple[1]]);
input.endGroup();
_results.push(input.disconnect());
}
return _results;
});
it('should support asynchronous handlers', function(done) {
var counter, hadData, point;
point = {
x: 123,
y: 456,
z: 789
};
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point',
async: true,
group: true,
forwardGroups: true
}, function(data, groups, out, callback) {
return setTimeout(function() {
out.send({
x: data.x,
y: data.y,
z: data.z
});
return callback();
}, 100);
});
p.removeAllListeners();
counter = 0;
hadData = false;
p.on('begingroup', function(grp) {
return counter++;
});
p.on('endgroup', function() {
return counter--;
});
p.once('data', function(data) {
chai.expect(data).to.deep.equal(point);
return hadData = true;
});
p.once('disconnect', function() {
chai.expect(counter).to.equal(0);
chai.expect(hadData).to.be["true"];
return done();
});
x.beginGroup('async');
y.beginGroup('async');
z.beginGroup('async');
x.send(point.x);
y.send(point.y);
z.send(point.z);
x.endGroup();
y.endGroup();
z.endGroup();
x.disconnect();
y.disconnect();
return z.disconnect();
});
it('should not forward groups if forwarding is off', function(done) {
var counter, hadData, point;
point = {
x: 123,
y: 456
};
helpers.WirePattern(c, {
"in": ['x', 'y'],
out: 'point'
}, function(data, groups, out) {
return out.send({
x: data.x,
y: data.y
});
});
p.removeAllListeners();
counter = 0;
hadData = false;
p.on('begingroup', function(grp) {
return counter++;
});
p.on('data', function(data) {
chai.expect(data).to.deep.equal(point);
return hadData = true;
});
p.once('disconnect', function() {
chai.expect(counter).to.equal(0);
chai.expect(hadData).to.be["true"];
return done();
});
x.beginGroup('doNotForwardMe');
y.beginGroup('doNotForwardMe');
x.send(point.x);
y.send(point.y);
x.endGroup();
y.endGroup();
x.disconnect();
return y.disconnect();
});
it('should forward groups from a specific port only', function(done) {
var groups, point, refGroups;
point = {
x: 123,
y: 456,
z: 789
};
refGroups = ['boo'];
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point',
forwardGroups: 'y'
}, function(data, groups, out) {
return out.send({
x: data.x,
y: data.y,
z: data.z
});
});
p.removeAllListeners();
groups = [];
p.on('begingroup', function(grp) {
return groups.push(grp);
});
p.on('data', function(data) {
return chai.expect(data).to.deep.equal(point);
});
p.once('disconnect', function() {
chai.expect(groups).to.deep.equal(refGroups);
return done();
});
x.beginGroup('foo');
y.beginGroup('boo');
z.beginGroup('bar');
x.send(point.x);
y.send(point.y);
z.send(point.z);
x.endGroup();
y.endGroup();
z.endGroup();
x.disconnect();
y.disconnect();
return z.disconnect();
});
return it('should forward groups from selected ports only', function(done) {
var groups, point, refGroups;
point = {
x: 123,
y: 456,
z: 789
};
refGroups = ['foo', 'bar'];
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point',
forwardGroups: ['x', 'z']
}, function(data, groups, out) {
return out.send({
x: data.x,
y: data.y,
z: data.z
});
});
p.removeAllListeners();
groups = [];
p.on('begingroup', function(grp) {
return groups.push(grp);
});
p.on('data', function(data) {
return chai.expect(data).to.deep.equal(point);
});
p.once('disconnect', function() {
chai.expect(groups).to.deep.equal(refGroups);
return done();
});
x.beginGroup('foo');
y.beginGroup('boo');
z.beginGroup('bar');
x.send(point.x);
y.send(point.y);
z.send(point.z);
x.endGroup();
y.endGroup();
z.endGroup();
x.disconnect();
y.disconnect();
return z.disconnect();
});
});
describe('when `this` context is important', function() {
var c, p, x, y, z;
c = new component.Component;
c.inPorts.add('x', {
required: true,
datatype: 'int'
}).add('y', {
required: true,
datatype: 'int'
}).add('z', {
required: true,
datatype: 'int'
});
c.outPorts.add('point');
x = new socket.createSocket();
y = new socket.createSocket();
z = new socket.createSocket();
p = new socket.createSocket();
c.inPorts.x.attach(x);
c.inPorts.y.attach(y);
c.inPorts.z.attach(z);
c.outPorts.point.attach(p);
it('should correctly bind component to `this` context', function(done) {
p.removeAllListeners();
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
out: 'point'
}, function(data, groups, out) {
chai.expect(this).to.deep.equal(c);
return out.send({
x: data.x,
y: data.y,
z: data.z
});
});
p.once('data', function(data) {
chai.expect(data).to.deep.equal({
x: 123,
y: 456,
z: 789
});
return done();
});
x.send(123);
x.disconnect();
y.send(456);
y.disconnect();
z.send(789);
return z.disconnect();
});
return it('should correctly bind component to `this` context in async mode', function(done) {
p.removeAllListeners();
helpers.WirePattern(c, {
"in": ['x', 'y', 'z'],
async: true,
out: 'point'
}, function(data, groups, out, callback) {
chai.expect(this).to.deep.equal(c);
out.send({
x: data.x,
y: data.y,
z: data.z
});
return callback();
});
p.once('data', function(data) {
return done();
});
x.send(123);
x.disconnect();
y.send(456);
y.disconnect();
z.send(789);
return z.disconnect();
});
});
describe('when in async mode and packet order matters', function() {
var c, delay, load, msg, out;
c = new component.Component;
c.inPorts.add('delay', {
datatype: 'int'
}).add('msg', {
datatype: 'string'
});
c.outPorts.add('out', {
datatype: 'object'
}).add('load', {
datatype: 'int'
});
delay = new socket.createSocket();
msg = new socket.createSocket();
out = new socket.createSocket();
load = new socket.createSocket();
c.inPorts.delay.attach(delay);
c.inPorts.msg.attach(msg);
c.outPorts.out.attach(out);
c.outPorts.load.attach(load);
it('should preserve input order at the output', function(done) {
var expected, idx, ip, sample, _i, _len, _results;
helpers.WirePattern(c, {
"in": ['delay', 'msg'],
async: true,
ordered: true,
group: false
}, function(data, groups, res, callback) {
return setTimeout(function() {
res.send({
delay: data.delay,
msg: data.msg
});
return callback();
}, data.delay);
});
sample = [
{
delay: 30,
msg: "one"
}, {
delay: 0,
msg: "two"
}, {
delay: 20,
msg: "three"
}, {
delay: 10,
msg: "four"
}
];
out.on('data', function(data) {
return chai.expect(data).to.deep.equal(sample.shift());
});
out.on('disconnect', function() {
if (sample.length === 0) {
return done();
}
});
expected = [1, 2, 3, 4, 3, 2, 1, 0];
load.on('data', function(data) {
return chai.expect(data).to.equal(expected.shift());
});
idx = 0;
_results = [];
for (_i = 0, _len = sample.length; _i < _len; _i++) {
ip = sample[_i];
delay.beginGroup(idx);
delay.send(ip.delay);
delay.endGroup();
msg.beginGroup(idx);
msg.send(ip.msg);
msg.endGroup();
delay.disconnect();
msg.disconnect();
_results.push(idx++);
}
return _results;
});
return it('should support complex substreams', function(done) {
var expected, i, sample, _i, _results;
out.removeAllListeners();
load.removeAllListeners();
c.cntr = 0;
helpers.WirePattern(c, {
"in": ['delay', 'msg'],
async: true,
ordered: true,
group: false,
receiveStreams: ['delay', 'msg']
}, function(data, groups, res, callback) {
var delayData, delayObj, index0, index1, msgData, msgObj, subDelay, subMsg;
chai.expect(data.delay instanceof Substream).to.be["true"];
chai.expect(data.msg instanceof Substream).to.be["true"];
delayObj = data.delay.toObject();
msgObj = data.msg.toObject();
index0 = this.cntr.toString();
chai.expect(Object.keys(delayObj)[0]).to.equal(index0);
chai.expect(Object.keys(msgObj)[0]).to.equal(index0);
subDelay = delayObj[index0];
subMsg = msgObj[index0];
index1 = (10 + this.cntr).toString();
chai.expect(Object.keys(subDelay)[0]).to.equal(index1);
chai.expect(Object.keys(subMsg)[0]).to.equal(index1);
delayData = subDelay[index1];
msgData = subMsg[index1];
chai.expect(delayData).to.equal(sample[c.cntr].delay);
chai.expect(msgData).to.equal(sample[c.cntr].msg);
this.cntr++;
return setTimeout(function() {
var k0, k1, v0, v1;
for (k0 in msgObj) {
v0 = msgObj[k0];
res.beginGroup(k0);
res.send(k0);
for (k1 in v0) {
v1 = v0[k1];
res.beginGroup(k1);
res.send({
delay: delayObj[k0][k1],
msg: msgObj[k0][k1]
});
res.endGroup();
res.send(k1);
}
res.endGroup();
}
return callback();
}, data.delay);
});
sample = [
{
delay: 30,
msg: "one"
}, {
delay: 0,
msg: "two"
}, {
delay: 20,
msg: "three"
}, {
delay: 10,
msg: "four"
}
];
expected = ['0', '0', '10', sample[0], '10', '1', '1', '11', sample[1], '11', '2', '2', '12', sample[2], '12', '3', '3', '13', sample[3], '13'];
out.on('begingroup', function(grp) {
return chai.expect(grp).to.equal(expected.shift());
});
out.on('data', function(data) {
return chai.expect(data).to.deep.equal(expected.shift());
});
out.on('disconnect', function() {
if (expected.length === 0) {
return done();
}
});
_results = [];
for (i = _i = 0; _i <= 3; i = ++_i) {
delay.beginGroup(i);
delay.beginGroup(10 + i);
delay.send(sample[i].delay);
delay.endGroup();
delay.endGroup();
msg.beginGroup(i);
msg.beginGroup(10 + i);
msg.send(sample[i].msg);
msg.endGroup();
msg.endGroup();
delay.disconnect();
_results.push(msg.disconnect());
}
return _results;
});
});
describe('when grouping by field', function() {
var c, msg, umsg, usr;
c = new component.Component;
c.inPorts.add('user', {
datatype: 'object'
}).add('message', {
datatype: 'object'
});
c.outPorts.add('signedmessage');
usr = new socket.createSocket();
msg = new socket.createSocket();
umsg = new socket.createSocket();
c.inPorts.user.attach(usr);
c.inPorts.message.attach(msg);
c.outPorts.signedmessage.attach(umsg);
return it('should match objects by specific field', function(done) {
var counter, mesg, messages, req, user, users, _fn, _results;
helpers.WirePattern(c, {
"in": ['user', 'message'],
out: 'signedmessage',
async: true,
field: 'request'
}, function(data, groups, out, callback) {
return setTimeout(function() {
out.send({
request: data.request,
user: data.user.name,
text: data.message.text
});
return callback();
}, 10);
});
users = {
14: {
request: 14,
id: 21,
name: 'Josh'
},
12: {
request: 12,
id: 25,
name: 'Leo'
},
34: {
request: 34,
id: 84,
name: 'Anica'
}
};
messages = {
34: {
request: 34,
id: 234,
text: 'Hello world'
},
12: {
request: 12,
id: 82,
text: 'Aloha amigos'
},
14: {
request: 14,
id: 249,
text: 'Node.js ftw'
}
};
counter = 0;
umsg.on('data', function(data) {
chai.expect(data).to.be.an('object');
chai.expect(data.request).to.be.ok;
chai.expect(data.user).to.equal(users[data.request].name);
chai.expect(data.text).to.equal(messages[data.request].text);
counter++;
if (counter === 3) {
return done();
}
});
_fn = function(req, user) {
return setTimeout(function() {
usr.send(user);
return usr.disconnect();
}, req);
};
for (req in users) {
user = users[req];
_fn(req, user);
}
_results = [];
for (req in messages) {
mesg = messages[req];
_results.push((function(req, mesg) {
return setTimeout(function() {
msg.send(mesg);
return msg.disconnect();
}, req);
})(req, mesg));
}
return _results;
});
});
describe('when there are multiple output routes', function() {
var c, even, num, odd, str;
c = new component.Component;
c.inPorts.add('num', {
datatype: 'int'
}).add('str', {
datatype: 'string'
});
c.outPorts.add('odd', {
datatype: 'object'
}).add('even', {
datatype: 'object'
});
num = new socket.createSocket();
str = new socket.createSocket();
odd = new socket.createSocket();
even = new socket.createSocket();
c.inPorts.num.attach(num);
c.inPorts.str.attach(str);
c.outPorts.odd.attach(odd);
c.outPorts.even.attach(even);
return it('should send output to one or more of them', function(done) {
var dataCounter, grpCounter, i, numbers, _i, _results;
numbers = ['cero', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve'];
helpers.WirePattern(c, {
"in": ['num', 'str'],
out: ['odd', 'even'],
async: true,
ordered: true
}, function(data, groups, outs, callback) {
return setTimeout(function() {
var grp, _i, _j, _k, _l, _len, _len1, _len2, _len3;
if (data.num % 2 === 1) {
for (_i = 0, _len = groups.length; _i < _len; _i++) {
grp = groups[_i];
outs.odd.beginGroup(grp);
}
outs.odd.send(data);
for (_j = 0, _len1 = groups.length; _j < _len1; _j++) {
grp = groups[_j];
outs.odd.endGroup();
}
} else {
for (_k = 0, _len2 = groups.length; _k < _len2; _k++) {
grp = groups[_k];
outs.even.beginGroup(grp);
}
outs.even.send(data);
for (_l = 0, _len3 = groups.length; _l < _len3; _l++) {
grp = groups[_l];
outs.even.endGroup();
}
}
return callback();
}, 0);
});
grpCounter = 0;
dataCounter = 0;
odd.on('begingroup', function(grp) {
return grpCounter++;
});
odd.on('data', function(data) {
chai.expect(data.num % 2).to.equal(1);
chai.expect(data.str).to.equal(numbers[data.num]);
return dataCounter++;
});
odd.on('disconnect', function() {
if (dataCounter === 10 && grpCounter === 10) {
return done();
}
});
even.on('begingroup', function(grp) {
return grpCounter++;
});
even.on('data', function(data) {
chai.expect(data.num % 2).to.equal(0);
chai.expect(data.str).to.equal(numbers[data.num]);
return dataCounter++;
});
even.on('disconnect', function() {
if (dataCounter === 10 && grpCounter === 10) {
return done();
}
});
_results = [];
for (i = _i = 0; _i < 10; i = ++_i) {
num.beginGroup(i);
num.send(i);
num.endGroup(i);
num.disconnect();
str.beginGroup(i);
str.send(numbers[i]);
str.endGroup(i);
_results.push(str.disconnect());
}
return _results;
});
});
describe('when there are parameter ports', function() {
var c, d1, d2, err, out, p1, p2, p3;
c = null;
p1 = p2 = p3 = d1 = d2 = out = err = 0;
beforeEach(function() {
c = new component.Component;
c.inPorts.add('param1', {
datatype: 'string',
required: true
}).add('param2', {
datatype: 'int',
required: false
}).add('param3', {
datatype: 'int',
required: true,
"default": 0
}).add('data1', {
datatype: 'string'
}).add('data2', {
datatype: 'int'
});
c.outPorts.add('out', {
datatype: 'object'
}).add('error', {
datatype: 'object'
});
p1 = new socket.createSocket();
p2 = new socket.createSocket();
p3 = new socket.createSocket();
d1 = new socket.createSocket();
d2 = new socket.createSocket();
out = new socket.createSocket();
err = new socket.createSocket();
c.inPorts.param1.attach(p1);
c.inPorts.param2.attach(p2);
c.inPorts.param3.attach(p3);
c.inPorts.data1.attach(d1);
c.inPorts.data2.attach(d2);
c.outPorts.out.attach(out);
return c.outPorts.error.attach(err);
});
it('should wait for required params without default value', function(done) {
helpers.WirePattern(c, {
"in": ['data1', 'data2'],
out: 'out',
params: ['param1', 'param2', 'param3']
}, function(input, groups, out) {
var res;
res = {
p1: c.params.param1,
p2: c.params.param2,
p3: c.params.param3,
d1: input.data1,
d2: input.data2
};
return out.send(res);
});
out.once('data', function(data) {
chai.expect(data).to.be.an('object');
chai.expect(data.p1).to.equal('req');
chai.expect(data.p2).to.be.undefined;
chai.expect(data.p3).to.equal(0);
chai.expect(data.d1).to.equal('foo');
chai.expect(data.d2).to.equal(123);
return out.once('data', function(data) {
chai.expect(data).to.be.an('object');
chai.expect(data.p1).to.equal('req');
chai.expect(data.p2).to.equal(568);
chai.expect(data.p3).to.equal(800);
chai.expect(data.d1).to.equal('bar');
chai.expect(data.d2).to.equal(456);
return done();
});
});
d1.send('foo');
d1.disconnect();
d2.send(123);
d2.disconnect();
c.sendDefaults();
p1.send('req');
p1.disconnect();
return setTimeout(function() {
p2.send(568);
p2.disconnect();
p3.send(800);
p3.disconnect();
d1.send('bar');
d1.disconnect();
d2.send(456);
return d2.disconnect();
}, 10);
});
it('should work for async procs too', function(done) {
helpers.WirePattern(c, {
"in": ['data1', 'data2'],
out: 'out',
params: ['param1', 'param2', 'param3']
}, function(input, groups, out) {
var delay;
delay = c.params.param2 ? c.params.param2 : 10;
return setTimeout(function() {
var res;
res = {
p1: c.params.param1,
p2: c.params.param2,
p3: c.params.param3,
d1: input.data1,
d2: input.data2
};
return out.send(res);
}, delay);
});
out.once('data', function(data) {
chai.expect(data).to.be.an('object');
chai.expect(data.p1).to.equal('req');
chai.expect(data.p2).to.equal(56);
chai.expect(data.p3).to.equal(0);
chai.expect(data.d1).to.equal('foo');
chai.expect(data.d2).to.equal(123);
return done();
});
p2.send(56);
p2.disconnect();
d1.send('foo');
d1.disconnect();
d2.send(123);
d2.disconnect();
c.sendDefaults();
p1.send('req');
return p1.disconnect();
});
it('should reset state if shutdown() is called', function(done) {
helpers.WirePattern(c, {
"in": ['data1', 'data2'],
out: 'out',
params: ['param1', 'param2', 'param3']
}, function(input, groups, out) {
return out.send({
p1: c.params.param1,
p2: c.params.param2,
p3: c.params.param3,
d1: input.data1,
d2: input.data2
});
});
d1.send('boo');
d1.disconnect();
p2.send(73);
p2.disconnect();
chai.expect(Object.keys(c.groupedData)).to.have.length.above(0);
chai.expect(Object.keys(c.params)).to.have.length.above(0);
c.shutdown();
chai.expect(c.groupedData).to.deep.equal({});
chai.expect(c.params).to.deep.equal({});
chai.expect(c.taskQ).to.deep.equal([]);
return done();
});
return it('should drop premature data if configured to do so', function(done) {
helpers.WirePattern(c, {
"in": ['data1', 'data2'],
out: 'out',
params: ['param1', 'param2', 'param3'],
dropInput: true
}, function(input, groups, out) {
var res;
res = {
p1: c.params.param1,
p2: c.params.param2,
p3: c.params.param3,
d1: input.data1,
d2: input.data2
};
return out.send(res);
});
out.once('data', function(data) {
chai.expect(data).to.be.an('object');
chai.expect(data.p1).to.equal('req');
chai.expect(data.p2).to.equal(568);
chai.expect(data.p3).to.equal(800);
chai.expect(data.d1).to.equal('bar');
chai.expect(data.d2).to.equal(456);
return done();
});
c.sendDefaults();
p2.send(568);
p2.disconnect();
p3.send(800);
p3.disconnect();
d1.send('foo');
d1.disconnect();
d2.send(123);
d2.disconnect();
return setTimeout(function() {
p1.send('req');
p1.disconnect();
d1.send('bar');
d1.disconnect();
d2.send(456);
return d2.disconnect();
}, 10);
});
});
describe('without output ports', function() {
var c, foo, sig;
c = new component.Component;
c.inPorts.add('foo');
foo = socket.createSocket();
sig = socket.createSocket();
c.inPorts.foo.attach(foo);
helpers.WirePattern(c, {
"in": 'foo',
out: [],
async: true
}, function(foo, grp, out, callback) {
return setTimeout(function() {
sig.send(foo);
return callback();
}, 20);
});
return it('should be fine still', function(done) {
sig.on('data', function(data) {
chai.expect(data).to.equal('foo');
return done();
});
foo.send('foo');
return foo.disconnect();
});
});
describe('when data processing is not possible at the moment', function() {
var c, err, line, res, rpt, tryAgain, whn;
c = new component.Component;
c.inPorts.add('line', {
datatype: 'string'
}).add('repeat', {
datatype: 'int'
}).add('when', {
datatype: 'string',
"default": 'later'
});
c.outPorts.add('res', {
datatype: 'string'
}).add('error', {
datatype: 'object'
});
line = socket.createSocket();
rpt = socket.createSocket();
whn = socket.createSocket();
res = socket.createSocket();
err = socket.createSocket();
c.inPorts.line.attach(line);
c.inPorts.repeat.attach(rpt);
c.inPorts.when.attach(whn);
c.outPorts.res.attach(res);
c.outPorts.error.attach(err);
c.invCount = 0;
tryAgain = null;
helpers.WirePattern(c, {
"in": ['line', 'repeat'],
params: 'when',
out: 'res',
async: true
}, function(input, groups, out, completed, postpone, resume) {
var i, repeated, _i, _ref;
this.invCount++;
if (this.invCount > 100) {
return;
}
switch (this.params.when) {
case 'now':
repeated = '';
for (i = _i = 0, _ref = input.repeat; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
repeated += input.line;
}
out.send(repeated);
return completed();
case 'later':
return postpone();
case 'afterTimeout':
postpone(false);
this.params.when = 'now';
return setTimeout(function() {
return resume();
}, 10);
case 'whenItell':
postpone(false);
this.params.when = 'now';
return tryAgain = resume;
}
});
it('should be able to postpone it until next tuple of data', function(done) {
res.once('data', function(data) {
chai.expect(data).to.equal('opopopopopopopopopop');
chai.expect(c.invCount).to.equal(2);
return res.once('data', function(data) {
chai.expect(data).to.equal('gogogo');
chai.expect(c.invCount).to.equal(3);
return done();
});
});
c.sendDefaults();
line.send('op');
rpt.send(10);
line.disconnect();
rpt.disconnect();
whn.send('now');
whn.disconnect();
line.send('go');
rpt.send(3);
line.disconnect();
return rpt.disconnect();
});
it('should be able to postpone and retry after timeout', function(done) {
c.invCount = 0;
res.once('data', function(data) {
chai.expect(data).to.equal('dododo');
chai.expect(c.invCount).to.equal(2);
return done();
});
whn.send('afterTimeout');
whn.disconnect();
line.send('do');
rpt.send(3);
line.disconnect();
return rpt.disconnect();
});
return it('should be able to postpone it and resume when needed', function(done) {
c.invCount = 0;
res.once('data', function(data) {
chai.expect(data).to.equal('yoyo');
chai.expect(c.invCount).to.equal(2);
return done();
});
whn.send('whenItell');
whn.disconnect();
line.send('yo');
rpt.send(2);
line.disconnect();
rpt.disconnect();
return setTimeout(function() {
return tryAgain();
}, 30);
});
});
describe('with many inputs and groups', function() {
var c, err, ins, msg, out, pth, rep, tkn;
c = new component.Component;
c.token = null;
c.inPorts.add('in', {
datatype: 'string'
}).add('message', {
datatype: 'string'
}).add('repository', {
datatype: 'string'
}).add('path', {
datatype: 'string'
}).add('token', {
datatype: 'string'
}, function(event, payload) {
if (event === 'data') {
return c.token = payload;
}
});
c.outPorts.add('out', {
datatype: 'string'
}).add('error', {
datatype: 'object'
});
helpers.WirePattern(c, {
"in": ['in', 'message', 'repository', 'path'],
out: 'out',
async: true,
forwardGroups: true
}, function(data, groups, out, callback) {
return setTimeout(function() {
out.beginGroup(data.path);
out.send(data.message);
out.endGroup();
return callback();
}, 300);
});
ins = socket.createSocket();
msg = socket.createSocket();
rep = socket.createSocket();
pth = socket.createSocket();
tkn = socket.createSocket();
out = socket.createSocket();
err = socket.createSocket();
c.inPorts["in"].attach(ins);
c.inPorts.message.attach(msg);
c.inPorts.repository.attach(rep);
c.inPorts.path.attach(pth);
c.inPorts.token.attach(tkn);
c.outPorts.out.attach(out);
c.outPorts.error.attach(err);
return it('should handle mixed flow well', function(done) {
var ends, groups, packets, refData, refGroups;
groups = [];
refGroups = ['foo', 'http://techcrunch.com/2013/03/26/embedly-now/', 'path data'];
ends = 0;
packets = [];
refData = ['message data'];
out.on('begingroup', function(grp) {
return groups.push(grp);
});
out.on('endgroup', function() {
return ends++;
});
out.on('data', function(data) {
return packets.push(data);
});
out.on('disconnect', function() {
chai.expect(groups).to.deep.equal(refGroups);
chai.expect(ends).to.equal(3);
chai.expect(packets).to.deep.equal(refData);
return done();
});
err.on('data', function(data) {
return done(data);
});
rep.beginGroup('foo');
rep.beginGroup('http://techcrunch.com/2013/03/26/embedly-now/');
rep.send('repo data');
rep.endGroup();
rep.endGroup();
ins.beginGroup('foo');
ins.beginGroup('http://techcrunch.com/2013/03/26/embedly-now/');
ins.send('ins data');
msg.beginGroup('foo');
msg.beginGroup('http://techcrunch.com/2013/03/26/embedly-now/');
msg.send('message data');
msg.endGroup();
msg.endGroup();
ins.endGroup();
ins.endGroup();
ins.disconnect();
msg.disconnect();
pth.beginGroup('foo');
pth.beginGroup('http://techcrunch.com/2013/03/26/embedly-now/');
pth.send('path data');
pth.endGroup();
pth.endGroup();
pth.disconnect();
return rep.disconnect();
});
});
describe('for batch processing', function() {
var addr, addr2sum, cntA, cntB, dblA, dblA2add, dblB, dblB2add, gen2dblA, gen2dblB, genA, genB, newAdder, newDoubler, newGenerator, newSeqsum, sum, sumr;
newGenerator = function(name) {
var generator;
generator = new component.Component;
generator.inPorts.add('count', {
datatype: 'int'
});
generator.outPorts.add('seq', {
datatype: 'int'
});
return helpers.WirePattern(generator, {
"in": 'count',
out: 'seq',
async: true,
forwardGroups: true,
ordered: true
}, function(count, groups, seq, callback) {
var i, sentCount, _i, _results;
sentCount = 0;
_results = [];
for (i = _i = 1; 1 <= count ? _i <= count : _i >= count; i = 1 <= count ? ++_i : --_i) {
_results.push((function(i) {
var delay;
delay = i > 10 ? i % 10 : i;
return setTimeout(function() {
seq.send(i);
sentCount++;
if (sentCount === count) {
return callback();
}
}, delay);
})(i));
}
return _results;
});
};
newDoubler = function(name) {
var doubler;
doubler = new component.Component;
doubler.inPorts.add('num', {
datatype: 'int'
});
doubler.outPorts.add('out', {
datatype: 'int'
});
return helpers.WirePattern(doubler, {
"in": 'num',
out: 'out',
forwardGroups: true
}, function(num, groups, out) {
var dbl;
dbl = 2 * num;
return out.send(dbl);
});
};
newAdder = function() {
var adder;
adder = new component.Component;
adder.inPorts.add('num1', {
datatype: 'int'
});
adder.inPorts.add('num2', {
datatype: 'int'
});
adder.outPorts.add('sum', {
datatype: 'int'
});
return helpers.WirePattern(adder, {
"in": ['num1', 'num2'],
out: 'sum',
forwardGroups: true,
async: true,
ordered: true
}, function(args, groups, out, callback) {
var sum;
sum = args.num1 + args.num2;
return setTimeout(function() {
out.send(sum);
return callback();
}, sum % 10);
});
};
newSeqsum = function() {
var seqsum;
seqsum = new component.Component;
seqsum.sum = 0;
seqsum.inPorts.add('seq', {
datatype: 'int'
}, function(event, payload) {
switch (event) {
case 'data':
return seqsum.sum += payload;
case 'disconnect':
seqsum.outPorts.sum.send(seqsum.sum);
seqsum.sum = 0;
return seqsum.outPorts.sum.disconnect();
}
});
seqsum.outPorts.add('sum', {
datatype: 'int'
});
return seqsum;
};
genA = newGenerator('A');
genB = newGenerator('B');
dblA = newDoubler('A');
dblB = newDoubler('B');
addr = newAdder();
sumr = newSeqsum();
cntA = socket.createSocket();
cntB = socket.createSocket();
gen2dblA = socket.createSocket();
gen2dblB = socket.createSocket();
dblA2add = socket.createSocket();
dblB2add = socket.createSocket();
addr2sum = socket.createSocket();
sum = socket.createSocket();
genA.inPorts.count.attach(cntA);
genB.inPorts.count.attach(cntB);
genA.outPorts.seq.attach(gen2dblA);
genB.outPorts.seq.attach(gen2dblB);
dblA.inPorts.num.attach(gen2dblA);
dblB.inPorts.num.attach(gen2dblB);
dblA.outPorts.out.attach(dblA2add);
dblB.outPorts.out.attach(dblB2add);
addr.inPorts.num1.attach(dblA2add);
addr.inPorts.num2.attach(dblB2add);
addr.outPorts.sum.attach(addr2sum);
sumr.inPorts.seq.attach(addr2sum);
sumr.outPorts.sum.attach(sum);
return it('should process sequences of packets separated by disconnects', function(done) {
var actual, expected;
expected = [24, 40];
actual = [];
sum.on('data', function(data) {
return actual.push(data);
});
sum.on('disconnect', function() {
var act, exp;
chai.expect(actual).to.have.length.above(0);
chai.expect(expected).to.have.length.above(0);
act = actual.shift();
exp = expected.shift();
chai.expect(act).to.equal(exp);
if (expected.length === 0) {
return done();
}
});
cntA.send(3);
cntA.disconnect();
cntB.send(3);
cntB.disconnect();
cntA.send(4);
cntB.send(4);
cntA.disconnect();
return cntB.disconnect();
});
});
describe('for batch processing with groups', function() {
var c1, c1c2, c2, cnt, out;
c1 = new component.Component;
c1.inPorts.add('count', {
datatype: 'int'
});
c1.outPorts.add('seq', {
datatype: 'int'
});
c2 = new component.Component;
c2.inPorts.add('num', {
datatype: 'int'
});
c2.outPorts.add('out', {
datatype: 'int'
});
cnt = socket.createSocket();
c1c2 = socket.createSocket();
out = socket.createSocket();
c1.inPorts.count.attach(cnt);
c1.outPorts.seq.attach(c1c2);
c2.inPorts.num.attach(c1c2);
c2.outPorts.out.attach(out);
return it('should wrap entire sequence with groups', function(done) {
var actual, expected;
helpers.WirePattern(c1, {
"in": 'count',
out: 'seq',
async: true,
forwardGroups: true
}, function(count, groups, out, callback) {
var i, _fn, _i;
_fn = function(i) {
return setTimeout(function() {
return out.send(i);
}, 0);
};
for (i = _i = 0; 0 <= count ? _i < count : _i > count; i = 0 <= count ? ++_i : --_i) {
_fn(i);
}
return setTimeout(function() {
return callback();
}, 3);
});
helpers.WirePattern(c2, {
"in": 'num',
out: 'out',
forwardGroups: true
}, function(num, groups, out) {
chai.expect(groups).to.deep.equal(['foo', 'bar']);
return out.send(num);
});
expected = ['<foo>', '<bar>', 0, 1, 2, '</bar>', '</foo>'];
actual = [];
out.on('begingroup', function(grp) {
return actual.push("<" + grp + ">");
});
out.on('endgroup', function(grp) {
return actual.push("</" + grp + ">");
});
out.on('data', function(data) {
return actual.push(data);
});
out.on('disconnect', function() {
chai.expect(actual).to.deep.equal(expected);
return done();
});
cnt.beginGroup('foo');
cnt.beginGroup('bar');
cnt.send(3);
cnt.endGroup();
cnt.endGroup();
return cnt.disconnect();
});
});
describe('with addressable ports', function() {
var c, d11, d12, d13, d2, err, out, p11, p12, p13;
c = new component.Component;
c.inPorts.add('p1', {
datatype: 'int',
addressable: true,
required: true
}).add('d1', {
datatype: 'int',
addressable: true
}).add('d2', {
datatype: 'string'
});
c.outPorts.add('out', {
datatype: 'object'
}).add('error', {
datatype: 'object'
});
p11 = socket.createSocket();
p12 = socket.createSocket();
p13 = socket.createSocket();
d11 = socket.createSocket();
d12 = socket.createSocket();
d13 = socket.createSocket();
d2 = socket.createSocket();
out = socket.createSocket();
err = socket.createSocket();
c.inPorts.p1.attach(p11);
c.inPorts.p1.attach(p12);
c.inPorts.p1.attach(p13);
c.inPorts.d1.attach(d11);
c.inPorts.d1.attach(d12);
c.inPorts.d1.attach(d13);
c.inPorts.d2.attach(d2);
c.outPorts.out.attach(out);
c.outPorts.error.attach(err);
it('should wait for all param and any data port values (default)', function(done) {
helpers.WirePattern(c, {
"in": ['d1', 'd2'],
params: 'p1',
out: 'out',
arrayPolicy: {
"in": 'any',
params: 'all'
}
}, function(input, groups, out) {
chai.expect(c.params.p1).to.deep.equal({
0: 1,
1: 2,
2: 3
});
chai.expect(input.d1).to.deep.equal({
0: 1
});
chai.expect(input.d2).to.equal('foo');
return done();
});
d2.send('foo');
d2.disconnect();
d11.send(1);