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