UNPKG

msgflo

Version:

Polyglot FBP runtime based on message queues

187 lines (161 loc) 6.54 kB
chai = require 'chai' EventEmitter = require('events').EventEmitter websocket = require 'websocket' fbp = require 'fbp' fs = require 'fs' participants = require './fixtures/participants' Runtime = require('../src/runtime').Runtime class MockUi extends EventEmitter constructor: -> @connection = null @client = new websocket.client() @client.on 'connect', (connection) => @connection = connection @connection.on 'error', (error) => throw error @connection.on 'close', (error) => @emit 'disconnected' @connection.on 'message', (message) => @handleMessage message @emit 'connected', connection connect: (port) -> @client.connect "ws://localhost:#{port}/", "noflo" disconnect: -> @connection.close() if @connection @emit 'disconnected' send: (protocol, command, payload) -> msg = protocol: protocol command: command payload: payload || {} @sendMsg msg sendMsg: (msg) -> @connection.sendUTF JSON.stringify msg handleMessage: (message) -> if not message.type == 'utf8' throw new Error "Received non-UTF8 message: " + message d = JSON.parse message.utf8Data @emit 'message', d, d.protocol, d.command, d.payload describe 'FBP runtime protocol', () -> runtime = null ui = new MockUi options = broker: 'direct://broker111' port: 3333 host: 'localhost' componentdir: 'spec/protocoltemp' before (done) -> fs.rmdirSync options.componentdir if fs.existsSync options.componentdir fs.mkdirSync options.componentdir runtime = new Runtime options runtime.start (err, url) -> chai.expect(err).to.be.a 'null' ui.once 'connected', () -> done() ui.connect options.port after (done) -> ui.once 'disconnected', () -> runtime.stop () -> runtime = null done() ui.disconnect() describe 'runtime info', -> info = null it 'should be returned on getruntime', (done) -> ui.send "runtime", "getruntime" ui.once 'message', (d, protocol, command, payload) -> info = payload chai.expect(info).to.be.an 'object' done() it 'type should be "msgflo"', -> chai.expect(info.type).to.equal "msgflo" it 'protocol version should be "0.4"', -> chai.expect(info.version).to.be.a "string" chai.expect(info.version).to.equal "0.4" describe 'capabilities"', -> it 'should be an array', -> chai.expect(info.capabilities).to.be.an "array" it 'should include "protocol:component"', -> chai.expect(info.capabilities).to.include "protocol:component" it 'should include "protocol:graph"', -> chai.expect(info.capabilities).to.include "protocol:graph" it 'should include "protocol:network"', -> chai.expect(info.capabilities).to.include "protocol:network" it 'should include "component:getsource"', -> chai.expect(info.capabilities).to.include "component:getsource" it 'should include "component:setsource"', -> chai.expect(info.capabilities).to.include "component:setsource" describe 'participant queues already connected', -> # TODO: move IIP sending into Participant class? sendGraphIIPs = (part, graph) -> processIsParticipant = (name) -> process = graph.processes[name] return name == part.definition.id processes = Object.keys(graph.processes).filter processIsParticipant iips = graph.connections.filter (c) -> return c.data? and c.tgt.process in processes for iip in iips part.send iip.tgt.port, iip.data it 'should show as connected edges', (done) -> graph = fbp.parse " 'world' -> NAME say(Hello) OUT -> DROP sink(DevNullSink) " source = participants.Hello options.broker, 'say' sink = participants.DevNullSink options.broker, 'sink' source.connectGraphEdges graph sink.connectGraphEdges graph sink.start (err) -> chai.expect(err).to.be.a 'null' source.start (err) -> chai.expect(err).to.be.a 'null' ui.send 'component', 'getsource', { name: 'default/main' } ui.once 'message', (d, protocol, command, payload) -> chai.expect(payload).to.be.an 'object' chai.expect(payload).to.include.keys ['name', 'code', 'language'] chai.expect(payload.language).to.equal 'json' graph = JSON.parse payload.code chai.expect(graph).to.include.keys ['connections', 'processes'] chai.expect(graph.connections).to.have.length 1 conn = graph.connections[0] chai.expect(conn.src.process).to.contain 'say' chai.expect(conn.src.port).to.equal 'out' chai.expect(conn.tgt.process).to.contain 'sink' chai.expect(conn.tgt.port).to.equal 'drop' done() # TODO: automatically represent multiple participants of same class as subgraph describe 'stopping a running network', -> it 'should succeed' it 'network:getstatus shows not running' it 'should not respond to messages' describe 'starting a stopped network', -> it 'should succeed' it 'network:getstatus should show running' it 'should respond to messages again' describe 'adding an edge', -> it 'should succeed' it 'data should now be forwarded' describe 'removing a connected edge', -> it 'should succeed' it 'data should now be forwarded' describe 'adding a node', -> it 'should succeed' it 'node should produce data' describe 'removing a node', -> it 'should succeed' it 'node should not produce data anymore' describe 'adding a component', -> componentName = 'foo/SetSource' componentCode = fs.readFileSync(__dirname+'/fixtures/ProduceFoo.coffee', 'utf-8') it 'should become available', (done) -> ui.once 'message', (d, protocol, command, payload) -> chai.expect(payload).to.be.an 'object' chai.expect(payload).to.include.keys ['name', 'code', 'language'] chai.expect(payload.language).to.equal 'coffeescript' chai.expect(payload.code).to.include "component: 'ProduceFoo'" chai.expect(payload.code).to.include "module.exports = ProduceFoo" done() source = name: componentName language: 'coffeescript' library: undefined code: componentCode ui.send 'component', 'source', source it 'should be returned on getsource' it 'should be instantiable as new node'