UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

1,633 lines (1,631 loc) 74.7 kB
var chai, noflo; if (typeof process !== 'undefined' && process.execPath && process.execPath.match(/node|iojs/)) { if (!chai) { chai = require('chai'); } noflo = require('../src/lib/NoFlo.coffee'); } else { noflo = require('noflo'); } describe('Component traits', function() { describe('MapComponent', function() { var c; c = null; it('should pass data to the callback', function() { var s; c = new noflo.Component; c.inPorts.add('in'); c.outPorts.add('out', { required: false }); noflo.helpers.MapComponent(c, function(data) { return chai.expect(data).to.equal(1); }); s = new noflo.internalSocket.createSocket(); c.inPorts["in"].attach(s); return s.send(1); }); it('should pass groups to the callback', function() { var s; c = new noflo.Component; c.inPorts.add('in'); c.outPorts.add('out', { required: false }); noflo.helpers.MapComponent(c, function(data, groups) { chai.expect(groups).to.eql(['one', 'two']); return chai.expect(data).to.equal(1); }); s = new noflo.internalSocket.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 noflo.Component; c.inPorts.add('in'); c.outPorts.add('out', { required: false }); noflo.helpers.MapComponent(c, function(data, groups, out) { return out.send(data * 2); }); s = new noflo.internalSocket.createSocket(); c.inPorts["in"].attach(s); s2 = new noflo.internalSocket.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 = null; x = null; y = null; z = null; p = null; beforeEach(function(done) { c = new noflo.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 noflo.internalSocket.createSocket(); y = new noflo.internalSocket.createSocket(); z = new noflo.internalSocket.createSocket(); p = new noflo.internalSocket.createSocket(); c.inPorts.x.attach(x); c.inPorts.y.attach(y); c.inPorts.z.attach(z); c.outPorts.point.attach(p); return done(); }); afterEach(function() { return c.outPorts.point.detach(p); }); it('should pass data and groups to the callback', function(done) { var count, groups, grp, key, results, src; src = { 111: { x: 1, y: 2, z: 3 }, 222: { x: 4, y: 5, z: 6 }, 333: { x: 7, y: 8, z: 9 } }; noflo.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) { noflo.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, j, len, outOrder, results, src, tuple; 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]; noflo.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 (j = 0, len = inOrder.length; j < len; j++) { tuple = inOrder[j]; 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 }; noflo.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); }); 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 support asynchronous handlers in legacy mode', function(done) { var counter, hadData, point; point = { x: 123, y: 456, z: 789 }; noflo.helpers.WirePattern(c, { "in": ['x', 'y', 'z'], out: 'point', async: true, group: true, forwardGroups: true, legacy: true }, function(data, groups, out, callback) { return setTimeout(function() { out.send({ x: data.x, y: data.y, z: data.z }); return callback(); }, 100); }); 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 }; noflo.helpers.WirePattern(c, { "in": ['x', 'y'], out: 'point' }, function(data, groups, out) { return out.send({ x: data.x, y: data.y }); }); 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']; noflo.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 }); }); 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']; noflo.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 }); }); 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 noflo.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 noflo.internalSocket.createSocket(); y = new noflo.internalSocket.createSocket(); z = new noflo.internalSocket.createSocket(); p = new noflo.internalSocket.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) { noflo.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) { noflo.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 noflo.Component; c.inPorts.add('delay', { datatype: 'int' }).add('msg', { datatype: 'string' }); c.outPorts.add('out', { datatype: 'object' }).add('load', { datatype: 'int' }); delay = new noflo.internalSocket.createSocket(); msg = new noflo.internalSocket.createSocket(); out = new noflo.internalSocket.createSocket(); load = new noflo.internalSocket.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, j, len, results, sample; noflo.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 (j = 0, len = sample.length; j < len; j++) { ip = sample[j]; 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; }); it('should throw if receiveStreams is used', function(done) { var f; f = function() { return noflo.helpers.WirePattern(c, { "in": ['delay', 'msg'], async: true, ordered: true, group: false, receiveStreams: ['delay', 'msg'] }, function(data, groups, res, callback) { return callback(); }); }; chai.expect(f).to["throw"](Error); return done(); }); return it('should throw if sendStreams is used', function(done) { var f; f = function() { return noflo.helpers.WirePattern(c, { "in": ['delay', 'msg'], async: true, ordered: true, group: false, sendStreams: ['out'] }, function(data, groups, res, callback) { return callback(); }); }; chai.expect(f).to["throw"](Error); return done(); }); }); describe('when grouping by field', function() { var c, msg, umsg, usr; c = new noflo.Component; c.inPorts.add('user', { datatype: 'object' }).add('message', { datatype: 'object' }); c.outPorts.add('signedmessage'); usr = new noflo.internalSocket.createSocket(); msg = new noflo.internalSocket.createSocket(); umsg = new noflo.internalSocket.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, fn, mesg, messages, req, results, user, users; noflo.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() { it('should send output to one or more of them', function(done) { var c, even, expected, i, j, num, numbers, odd, received, results, str; numbers = ['cero', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve']; c = new noflo.Component; c.inPorts.add('num', { datatype: 'int' }).add('str', { datatype: 'string' }); c.outPorts.add('odd', { datatype: 'object' }).add('even', { datatype: 'object' }); num = new noflo.internalSocket.createSocket(); str = new noflo.internalSocket.createSocket(); odd = new noflo.internalSocket.createSocket(); even = new noflo.internalSocket.createSocket(); c.inPorts.num.attach(num); c.inPorts.str.attach(str); c.outPorts.odd.attach(odd); c.outPorts.even.attach(even); noflo.helpers.WirePattern(c, { "in": ['num', 'str'], out: ['odd', 'even'], async: true, ordered: true, forwardGroups: true }, function(data, groups, outs, callback) { return setTimeout(function() { if (data.num % 2 === 1) { outs.odd.send(data); } else { outs.even.send(data); } return callback(); }, 0); }); expected = []; numbers.forEach(function(n, idx) { var port; if (idx % 2 === 1) { port = 'odd'; } else { port = 'even'; } expected.push(port + " < " + idx); expected.push(port + " DATA " + n); return expected.push(port + " > " + idx); }); received = []; odd.on('begingroup', function(grp) { return received.push("odd < " + grp); }); odd.on('data', function(data) { return received.push("odd DATA " + data.str); }); odd.on('endgroup', function(grp) { return received.push("odd > " + grp); }); odd.on('disconnect', function() { if (received.length !== expected.length) { return; } chai.expect(received).to.eql(expected); return done(); }); even.on('begingroup', function(grp) { return received.push("even < " + grp); }); even.on('data', function(data) { return received.push("even DATA " + data.str); }); even.on('endgroup', function(grp) { return received.push("even > " + grp); }); even.on('disconnect', function() { if (!(received.length >= expected.length)) { return; } chai.expect(received).to.eql(expected); return done(); }); results = []; for (i = j = 0; j < 10; i = ++j) { 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; }); return it('should send output to one or more of indexes', function(done) { var c, even, expected, i, j, num, numbers, odd, received, results, str; c = new noflo.Component; c.inPorts.add('num', { datatype: 'int' }).add('str', { datatype: 'string' }); c.outPorts.add('out', { datatype: 'object', addressable: true }); num = new noflo.internalSocket.createSocket(); str = new noflo.internalSocket.createSocket(); odd = new noflo.internalSocket.createSocket(); even = new noflo.internalSocket.createSocket(); c.inPorts.num.attach(num); c.inPorts.str.attach(str); c.outPorts.out.attach(odd); c.outPorts.out.attach(even); numbers = ['cero', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve']; noflo.helpers.WirePattern(c, { "in": ['num', 'str'], out: 'out', async: true, ordered: true, forwardGroups: true }, function(data, groups, outs, callback) { return setTimeout(function() { if (data.num % 2 === 1) { outs.send(data, 0); } else { outs.send(data, 1); } return callback(); }, 0); }); expected = []; numbers.forEach(function(n, idx) { var port; if (idx % 2 === 1) { port = 'odd'; } else { port = 'even'; } expected.push(port + " < " + idx); expected.push(port + " DATA " + n); return expected.push(port + " > " + idx); }); received = []; odd.on('begingroup', function(grp) { return received.push("odd < " + grp); }); odd.on('data', function(data) { return received.push("odd DATA " + data.str); }); odd.on('endgroup', function(grp) { return received.push("odd > " + grp); }); odd.on('disconnect', function() { if (received.length !== expected.length) { return; } chai.expect(received).to.eql(expected); return done(); }); even.on('begingroup', function(grp) { return received.push("even < " + grp); }); even.on('data', function(data) { return received.push("even DATA " + data.str); }); even.on('endgroup', function(grp) { return received.push("even > " + grp); }); even.on('disconnect', function() { if (!(received.length >= expected.length)) { return; } chai.expect(received).to.eql(expected); return done(); }); results = []; for (i = j = 0; j < 10; i = ++j) { 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 noflo.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 noflo.internalSocket.createSocket(); p2 = new noflo.internalSocket.createSocket(); p3 = new noflo.internalSocket.createSocket(); d1 = new noflo.internalSocket.createSocket(); d2 = new noflo.internalSocket.createSocket(); out = new noflo.internalSocket.createSocket(); err = new noflo.internalSocket.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) { noflo.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); }); err.on('data', function(data) { return done(data); }); 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) { noflo.helpers.WirePattern(c, { "in": ['data1', 'data2'], out: 'out', params: ['param1', 'param2', 'param3'], async: true }, function(input, groups, out, callback) { 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 }; out.send(res); return callback(); }, delay); }); err.on('data', function(data) { return done(data); }); 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) { noflo.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(c.inPorts.data1.getBuffer().length, 'data1 should have a packet').to.be.above(0); chai.expect(c.inPorts.param2.getBuffer().length, 'param2 should have a packet').to.be.above(0); return c.shutdown(function(err) { var j, len, port, portName, ref; if (err) { return done(err); } ref = c.inPorts.ports; for (port = j = 0, len = ref.length; j < len; port = ++j) { portName = ref[port]; chai.expect(port.getBuffer()).to.eql([]); chai.expect(c.load).to.equal(0); } return done(); }); }); return it('should drop premature data if configured to do so', function(done) { noflo.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); }); err.on('data', function(data) { return done(data); }); 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 foo, sig; foo = null; sig = null; before(function() { var c; c = new noflo.Component; c.inPorts.add('foo'); foo = noflo.internalSocket.createSocket(); sig = noflo.internalSocket.createSocket(); c.inPorts.foo.attach(foo); return noflo.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('with many inputs and groups in async mode', function() { var err, ins, msg, out, pth, rep, tkn; ins = noflo.internalSocket.createSocket(); msg = noflo.internalSocket.createSocket(); rep = noflo.internalSocket.createSocket(); pth = noflo.internalSocket.createSocket(); tkn = noflo.internalSocket.createSocket(); out = noflo.internalSocket.createSocket(); err = noflo.internalSocket.createSocket(); before(function() { var c; c = new noflo.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' }); noflo.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); }); 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); return 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('with many inputs and groups in sync mode', function() { var err, ins, msg, out, pth, rep, tkn; ins = noflo.internalSocket.createSocket(); msg = noflo.internalSocket.createSocket(); rep = noflo.internalSocket.createSocket(); pth = noflo.internalSocket.createSocket(); tkn = noflo.internalSocket.createSocket(); out = noflo.internalSocket.createSocket(); err = noflo.internalSocket.createSocket(); before(function() { var c; c = new noflo.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' }); noflo.helpers.WirePattern(c, { "in": ['in', 'message', 'repository', 'path'], out: 'out', async: false, forwardGroups: true }, function(data, groups, out) { out.beginGroup(data.path); out.send(data.message); return out.endGroup(); }); 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); return 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 addr2sum, cntA, cntB, dblA2add, dblB2add, gen2dblA, gen2dblB, newAdder, newDoubler, newGenerator, newSeqsum, sum; newGenerator = function(name) { var generator; generator = new noflo.Component; generator.inPorts.add('count', { datatype: 'int' }); generator.outPorts.add('seq', { datatype: 'int' }); return noflo.helpers.WirePattern(generator, { "in": 'count', out: 'seq', async: true, forwardGroups: true, ordered: true }, function(count, groups, seq, callback) { var i, j, ref, results, sentCount; sentCount = 0; results = []; for (i = j = 1, ref = count; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) { 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 noflo.Component; doubler.inPorts.add('num', { datatype: 'int' }); doubler.outPorts.add('out', { datatype: 'int' }); return noflo.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 noflo.Component; adder.inPorts.add('num1', { datatype: 'int' }); adder.inPorts.add('num2', { datatype: 'int' }); adder.outPorts.add('sum', { datatype: 'int' }); return noflo.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 noflo.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; }; cntA = noflo.internalSocket.createSocket(); cntB = noflo.internalSocket.createSocket(); gen2dblA = noflo.internalSocket.createSocket(); gen2dblB = noflo.internalSocket.createSocket(); dblA2add = noflo.internalSocket.createSocket(); dblB2add = noflo.internalSocket.createSocket(); addr2sum = noflo.internalSocket.createSocket(); sum = noflo.internalSocket.createSocket(); before(function() { var addr, dblA, dblB, genA, genB, sumr; genA = newGenerator('A'); genB = newGenerator('B'); dblA = newDoubler('A'); dblB = newDoubler('B'); addr = newAdder(); sumr = newSeqsum(); 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); return sumr.outPorts.sum.attach(sum); }); return it('should process sequences of packets separated by disconnects', function(done) { var actual, expected; return this.skip('WirePattern doesn\'t see disconnects because of IP objects'); 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 noflo.Component; c1.inPorts.add('count', { datatype: 'int' }); c1.outPorts.add('seq', { datatype: 'int' }); c2 = new noflo.Component; c2.inPorts.add('num', { datatype: 'int' }); c2.outPorts.add('out', { datatype: 'int' }); cnt = noflo.internalSocket.createSocket(); c1c2 = noflo.internalSocket.createSocket(); out = noflo.internalSocket.createSocket(); c1.inPorts.count.attach(cnt); c1.outPorts.seq.attach(c1c2); c2.inPo