Permalink
Browse files

Merge pull request #150 from kenhkan/port-api

Port API specs
  • Loading branch information...
2 parents 671afe1 + 1c1bc5b commit 4eb1a2bc670fdf80f5e818340aa4122c0704a610 @bergie bergie committed Mar 2, 2014
Showing with 289 additions and 0 deletions.
  1. +76 −0 spec/Component.coffee
  2. +155 −0 spec/InPort.coffee
  3. +58 −0 spec/OutPort.coffee
View
@@ -0,0 +1,76 @@
+if typeof process isnt 'undefined' and process.execPath and process.execPath.indexOf('node') isnt -1
+ chai = require 'chai' unless chai
+ component = require '../src/lib/Component.coffee'
+ port = require '../src/lib/Port.coffee'
+ socket = require '../src/lib/InternalSocket.coffee'
+else
+ component = require 'noflo/src/lib/Component.js'
+ port = require 'noflo/src/lib/Port.js'
+ socket = require 'noflo/src/lib/InternalSocket.js'
+
+describe 'Component', ->
+ describe 'with required ports', ->
+ it 'should throw an error upon receiving packet with an unattached required port', ->
+ s1 = new socket
+ s2 = new socket
+ c = new component
+ inPorts:
+ requiredPort: new port
+ required: true
+ optionalPort: new port
+ c.inPorts.optionalPort.attach s2
+ run = ->
+ s2.send 'some-data'
+ chai.expect(run).to.throw()
+
+ it 'should be cool with an attached port', ->
+ s1 = new socket
+ s2 = new socket
+ c = new component
+ inPorts:
+ requiredPort: new port
+ required: true
+ optionalPort: new port
+ c.inPorts.requiredPort.attach s1
+ c.inPorts.optionalPort.attach s2
+ f = ->
+ s2.send 'some-data'
+ chai.expect(f).to.not.throw()
+
+ it 'should simply forward error if error port is attached', (done) ->
+ s1 = new socket
+ s2 = new socket
+ s3 = new socket
+ c = new component
+ inPorts:
+ requiredPort: new port
+ required: true
+ optionalPort: new port
+ outPorts:
+ error: new.port
+ c.inPorts.optionalPort.attach s2
+ c.outPorts.error.attach s3
+ s3.on 'connect', ->
+ chai.assert true
+ done()
+ f = ->
+ s2.send 'some-data'
+ chai.expect(f).to.not.throw()
+
+ describe 'with component creation shorthand', ->
+ it 'should make component creation easy', ->
+ c = new component
+ inPorts:
+ in:
+ datatype: 'string'
+ required: true
+ processor: (packet, component) ->
+ chai.expect(packet).toEqual 'some-data'
+ chai.expect(component).toBe c
+
+ justProcessor: (packet, component) ->
+ chai.expect(packet).toEqual 'some-data'
+ chai.expect(component).toBe c
+
+ c.inPorts.in.send 'some-data'
+ c.inPorts.justProcessor.send 'some-data'
View
@@ -1,10 +1,14 @@
chai = require 'chai' unless chai
if typeof process isnt 'undefined' and process.execPath and process.execPath.indexOf('node') isnt -1
inport = require '../src/lib/InPort'
+ outport = require '../src/lib/OutPort'
socket = require '../src/lib/InternalSocket'
+ ports = require '../src/lib/Ports'
else
inport = require 'noflo/src/lib/InPort.js'
+ outport = require 'noflo/src/lib/OutPort'
socket = require 'noflo/src/lib/InternalSocket.js'
+ ports = require 'noflo/src/lib/Ports'
describe 'Inport Port', ->
describe 'with default options', ->
@@ -35,3 +39,154 @@ describe 'Inport Port', ->
chai.expect(p.isConnected()).to.equal false
it 'should not contain a socket initially', ->
chai.expect(p.sockets.length).to.equal 0
+
+ describe 'with processing function called with port as context', ->
+ it 'should set context to port itself', ->
+ s = new socket
+ p = new inport
+ p.on 'data', (packet, component) ->
+ chai.expect(this).toBe p
+ chai.expect(packet).toEqual 'some-data'
+ p.attach s
+ s.send 'some-data'
+
+ describe 'with default value', ->
+ p = s = null
+ beforeEach ->
+ p = new inport
+ default: 'default-value'
+ s = new socket
+ p.attach s
+ it 'should send the default value as a packet, though on next tick after initialization', (done) ->
+ p.config.on 'data', (data) ->
+ chai.expect(data).toEqual 'default-value'
+ done()
+ it 'should send the default value before IIP', (done) ->
+ received = ['default-value', 'some-iip']
+ p.config.on 'data', (data) ->
+ chai.expect(data).toEqual received.shift()
+ done() if received.length is 0
+ s.send 'some-iip'
+
+ describe 'with options stored in port', ->
+ it 'should store all provided options in port, whether we expect it or not', ->
+ options =
+ datatype: 'string'
+ type: 'http://schema.org/Person'
+ description: 'Person'
+ required: true
+ weNeverExpectThis: 'butWeStoreItAnyway'
+ p = new inport options
+ for name, option of options
+ chai.expect(p.options[name]).toEqual option
+
+ describe 'with data type information', ->
+ right = 'all string number int object array'.split ' '
+ wrong = 'not valie data types'.split ' '
+ f = (datatype) ->
+ new inport
+ datatype: datatype
+ right.forEach (r) ->
+ it "should accept a '#{r}' data type", =>
+ chai.expect(-> f r).to.not.throw()
+ wrong.forEach (w) ->
+ it "should NOT accept a '#{w}' data type", =>
+ chai.expect(-> f w).to.throw()
+
+ describe 'with TYPE (i.e. ontology) information', ->
+ f = (type) ->
+ new inport
+ type: type
+ it 'should be a URL or MIME', ->
+ chai.expect(-> f 'http://schema.org/Person').to.not.throw()
+ chai.expect(-> f 'text/javascript').to.not.throw()
+ chai.expect(-> f 'neither-a-url-nor-mime').to.throw()
+
+ describe 'with buffering', ->
+ it 'should buffer incoming packets until `receive()`d', ->
+ p = new inport
+ buffered: true
+ s = new socket
+ p.attach s
+
+ p.once 'data', (data) ->
+ # We get notified with the packet as the parameter but it is not popped
+ # off the queue. We choose not to handle the packet for now.
+ chai.expect(data).toEqual 'buffered-data-1'
+ s.send 'buffered-data-1'
+
+ p.once 'data', (data) ->
+ # We should still get the queued up value because it doesn't make sense
+ # to "peek" into the latest packet until all preceding packets have
+ # been consumed.
+ chai.expect(data).toEqual 'buffered-data-1'
+ # Now we consume it. Note that the context should be the port itself.
+ _data = @receive()
+ chai.expect(data).toEqual _data
+ s.send 'buffered-data-2'
+
+ p.once 'data', (data) ->
+ # Now we see the second packet
+ chai.expect(data).toEqual 'buffered-data-2'
+ s.send 'buffered-data-3'
+
+ it 'should always return the immediate packet even without buffering', ->
+ p = new inport
+ # Specified here simply for illustrative purpose, otherwise implied
+ # `false`
+ buffered: false
+ s = new socket
+ p.attach s
+
+ p.once 'data', (data) ->
+ # `receive()` returns the same thing
+ _data = @receive()
+ chai.expect(data).toEqual 'data'
+ chai.expect(data).toEqual _data
+ s.send 'data'
+
+ describe 'with accepted enumerated values', (done) ->
+ it 'should accept certain values', ->
+ p = new inport
+ values: 'noflo is awesome'.split ''
+ s = new socket
+ p.attach s
+ p.on 'data', (data) ->
+ chai.expect(data).toEqual 'noflo is awesome'
+ done()
+ s.send 'awesome'
+
+ it 'should send to error port if value is not accepted', ->
+ p = new inport
+ values: 'noflo is awesome'.split ''
+ s = new socket
+ p.attach s
+ cb = jasmine.createSpy()
+ p.on 'data', cb
+ s.send 'terrific'
+ chai.expect(cb).not.toHaveBeenCalled()
+
+ describe 'with processing shorthand', ->
+ it 'should create a port with a callback', ->
+ s = new socket
+ ps = new ports
+ outPorts:
+ out: new outport
+ ps.add 'in', (packet, component) ->
+ chai.expect(packet).toEqual 'some-data'
+ chai.assert component.outPorts.out instanceof outport
+ chai.assert ps.inPorts.in instanceof inport
+ ps.inPorts.in.attach s
+ s.send 'some-data'
+
+ it 'should also accept metadata (i.e. options) when provided', (done) ->
+ s = new socket
+ ps = new ports
+ ps.add 'in',
+ datatype: 'string'
+ required: true
+ , (packet, component) ->
+ chai.expect(packet).toEqual 'some-data'
+ done()
+ ps.inPorts.in.attach s
+ s.send 'some-data'
View
@@ -0,0 +1,58 @@
+chai = require 'chai' unless chai
+if typeof process isnt 'undefined' and process.execPath and process.execPath.indexOf('node') isnt -1
+ outport = require '../src/lib/OutPort'
+ socket = require '../src/lib/InternalSocket'
+else
+ outport = require 'noflo/src/lib/OutPort.js'
+ socket = require 'noflo/src/lib/InternalSocket.js'
+
+describe 'Outport Port', ->
+ describe 'with addressable ports', ->
+ s1 = s2 = s3 = null
+ beforeEach ->
+ s1 = new socket
+ s2 = new socket
+ s3 = new socket
+
+ it 'should be able to send to a specific port', ->
+ p = new outport
+ addressable: true
+ p.attach s1
+ p.attach s2
+ p.attach s3
+ cb1 = jasmine.createSpy()
+ cb2 = jasmine.createSpy()
+ cb3 = jasmine.createSpy()
+ s1.on 'data', cb1
+ s2.on 'data', cb2
+ s3.on 'data', cb3
+ p.send 'some-data', 2
+ cb1.not.toHaveBeenCalled()
+ cb2.toHaveBeenCalled()
+ cb3.not.toHaveBeenCalled()
+
+ it 'should send to all with no specific port', ->
+ p = new outport
+ addressable: true
+ p.attach s1
+ p.attach s2
+ p.attach s3
+ cb1 = jasmine.createSpy()
+ cb2 = jasmine.createSpy()
+ cb3 = jasmine.createSpy()
+ s1.on 'data', cb1
+ s2.on 'data', cb2
+ s3.on 'data', cb3
+ p.send 'some-data'
+ cb1.toHaveBeenCalled()
+ cb2.toHaveBeenCalled()
+ cb3.toHaveBeenCalled()
+
+ it 'should throw an error when a specific port is requested with non-addressable port', ->
+ p = new outport
+ p.attach s1
+ p.attach s2
+ p.attach s3
+ f ->
+ p.send 'some-data'
+ expect(f).toHaveThrown()

0 comments on commit 4eb1a2b

Please sign in to comment.