nanocyte-deployer
Version:
Deploy flows to nanocyte
468 lines (390 loc) • 16.7 kB
text/coffeescript
_ = require 'lodash'
FlowDeployer = require '../src/flow-deployer'
describe 'FlowDeployer', ->
describe 'when constructed with a flow', ->
beforeEach ->
= get: sinon.stub()
= erik_is_happy: true
options =
flowUuid: 'the-flow-uuid'
flowToken: 'the-flow-token'
forwardUrl: 'http://www.zombo.com'
instanceId: 'an-instance-id'
userUuid: 'some-user-uuid'
userToken: 'some-user-token'
octobluUrl: 'https://api.octoblu.com'
deploymentUuid: 'the-deployment-uuid'
flowLoggerUuid: 'flow-logger-uuid'
=
configure: sinon.stub()
=
save: sinon.stub()
stop: sinon.stub()
=
message: sinon.stub()
updateDangerously: sinon.stub()
createSubscription: sinon.stub()
whoami: sinon.stub()
MeshbluHttp = sinon.spy =>
= new FlowDeployer options,
configurationGenerator:
configurationSaver:
MeshbluHttp: MeshbluHttp
request:
.get.withArgs('https://api.octoblu.com/api/flows/the-flow-uuid').yields null, {}, {a: 1, b: 5}
.get.withArgs('https://api.octoblu.com/api/user').yields null, {}, {api: {}}
describe 'when deploy is called', ->
beforeEach (done)->
flowConfig =
'some': 'thing'
'subscribe-devices':
config:
'broadcast.sent': ['subscribe-to-this-uuid']
.configure.yields null, flowConfig, {stop: 'config'}
.stop.yields null
.save.yields null
.setupDevice = sinon.stub().yields null
.deploy => done()
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.called
firstArg = .message.firstCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'begin'
message: undefined
it 'should call configuration generator with the flow', ->
expect(.configure).to.have.been.calledWith
flowData: { a: 1, b: 5 }
userData: {api: {}}
deploymentUuid: 'the-deployment-uuid'
flowToken: 'the-flow-token'
it 'should call configuration saver with the flow', ->
expect(.save).to.have.been.calledWith(
flowId: 'the-flow-uuid'
instanceId: 'an-instance-id'
flowData:
'some': 'thing'
'subscribe-devices':
config:
'broadcast.sent': ['subscribe-to-this-uuid']
)
expect(.save).to.have.been.calledWith(
flowId: 'the-flow-uuid-stop'
instanceId: 'an-instance-id'
flowData:
stop: 'config'
)
it 'should call request.get', ->
options =
json: true
auth :
user: 'some-user-uuid'
pass: 'some-user-token'
expect(.get).to.have.been.calledWith 'https://api.octoblu.com/api/flows/the-flow-uuid', options
expect(.get).to.have.been.calledWith 'https://api.octoblu.com/api/user', options
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.called
firstArg = .message.secondCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'end'
message: undefined
describe 'when deploy is called and user GET errored', ->
beforeEach (done) ->
userUrl = 'https://api.octoblu.com/api/user'
.get.withArgs(userUrl).yields new Error 'whoa, thats not a user', null
.deploy (, ) => done()
it 'should call request.get', ->
expect(.get).to.have.been.called
it 'should yield and error', ->
expect().to.exist
it 'should not give us a result', ->
expect().to.not.exist
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.calledTwice
firstArg = .message.secondCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'error'
message: 'whoa, thats not a user'
describe 'when deploy is called and flow get errored', ->
beforeEach (done) ->
userUrl = 'https://api.octoblu.com/api/user'
.get.withArgs(userUrl).yields null
flowUrl = 'https://api.octoblu.com/api/flows/the-flow-uuid'
.get.withArgs(flowUrl).yields new Error 'whoa, shoots bad', null
.deploy (, ) => done()
it 'should call request.get', ->
expect(.get).to.have.been.called
it 'should yield and error', ->
expect().to.exist
it 'should not give us a result', ->
expect().to.not.exist
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.calledTwice
firstArg = .message.secondCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'error'
message: 'whoa, shoots bad'
describe 'when deploy is called and the configuration generator returns an error', ->
beforeEach (done)->
.configure.yields new Error 'Oh noes'
.deploy (, )=> done()
it 'should return an error with an error', ->
expect().to.exist
it 'should not give us a result', ->
expect().to.not.exist
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.calledTwice
firstArg = .message.secondCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'error'
message: 'Oh noes'
describe 'when deploy is called and the configuration stop returns an error', ->
beforeEach (done)->
.configure.yields null, { erik_likes_me: true}
.stop.yields new Error 'Erik can never like me enough'
.deploy (, )=> done()
it 'should yield and error', ->
expect().to.exist
it 'should not give us a result', ->
expect().to.not.exist
it 'should not call save', ->
expect(.save).to.not.have.been.called
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.calledTwice
firstArg = .message.secondCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'error'
message: 'Erik can never like me enough'
describe 'when deploy is called and the configuration save returns an error', ->
beforeEach (done)->
.configure.yields null, { erik_likes_me: true}
.stop.yields null
.save.yields new Error 'Erik can never like me enough'
.deploy (, )=> done()
it 'should yield and error', ->
expect().to.exist
it 'should not give us a result', ->
expect().to.not.exist
it 'should message the FLOW_LOGGER_UUID', ->
expect(.message).to.have.been.calledTwice
firstArg = .message.secondCall.args[0]
delete firstArg.payload.date
expect(firstArg).to.deep.equal
devices: ['flow-logger-uuid']
payload:
application: 'flow-deploy-service'
deploymentUuid: 'the-deployment-uuid'
flowUuid: 'the-flow-uuid'
userUuid: 'some-user-uuid'
workflow: 'flow-start'
state: 'error'
message: 'Erik can never like me enough'
describe 'when deploy is called and the generator and saver actually worked', ->
beforeEach (done) ->
.configure.yields null, { erik_likes_me: 'more than you know'}
.stop.yields null
.save.yields null, {finally_i_am_happy: true}
.setupDevice = sinon.stub().yields null
.deploy (, ) => done()
it 'should call setupDeviceForwarding', ->
expect(.setupDevice).to.have.been.called
describe 'createSubscriptions', ->
beforeEach (done) ->
.createSubscription.yields null
flowConfig =
'subscribe-devices':
config:
'broadcast.sent': ['subscribe-to-this-uuid']
.createSubscriptions flowConfig, done
it "should create the subscription to the device's", ->
subscriberUuid = 'the-flow-uuid'
emitterUuid = 'subscribe-to-this-uuid'
type = 'broadcast.sent'
expect(.createSubscription).to.have.been.calledWith {subscriberUuid, emitterUuid, type}
describe 'setupDeviceForwarding', ->
beforeEach (done) ->
=
$addToSet:
'meshblu.forwarders.broadcast.received':
signRequest: true
url: 'http://www.zombo.com'
method: 'POST'
name: 'nanocyte-flow-deploy'
type: 'webhook'
'meshblu.forwarders.message.received':
signRequest: true
url: 'http://www.zombo.com'
method: 'POST'
name: 'nanocyte-flow-deploy'
type: 'webhook'
=
$pull:
'meshblu.forwarders.received':
name: 'nanocyte-flow-deploy'
'meshblu.messageHooks':
name: 'nanocyte-flow-deploy'
'meshblu.forwarders.broadcast.received':
name: 'nanocyte-flow-deploy'
'meshblu.forwarders.message.received':
name: 'nanocyte-flow-deploy'
=
$unset:
'meshblu.forwarders.broadcast': ''
=
uuid: 1
flow: {a: 1, b: 5}
meshblu:
messageHooks: [
generateAndForwardMeshbluCredentials: true
url: 'http://www.neopets.com'
method: 'DELETE'
name: 'nanocyte-flow-deploy'
]
.whoami.yields null, meshblu: forwarders: broadcast: []
.updateDangerously.yields null, null
.setupDeviceForwarding (, ) => done()
it "should update a meshblu device with the webhook to wherever it's going", ->
expect(.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
expect(.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
expect(.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
describe 'setupMessageSchema', ->
beforeEach (done) ->
= $set:
messageSchema:
type: "object"
properties:
from:
type: "string"
title: 'Trigger'
required: true
enum: [ 'a', 'c' ]
messageFormSchema: [
key: "from"
titleMap: {
'a' : 'multiply (a)'
'c' : 'rabbits (c)'
}
]
nodes = [
{
class: 'trigger'
id: 'a'
name: 'multiply'
},
{
class: 'not-a-trigger'
id: 'b'
name: 'like'
},
{
class: 'trigger'
id: 'c'
name: 'rabbits'
}
]
.meshbluHttp.updateDangerously.yields null, null
.setupMessageSchema nodes, (, ) => done()
it "should update a meshblu device with message schema for triggers", ->
expect(.meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
describe 'startFlow', ->
describe 'when called and there is no errors', ->
beforeEach (done) ->
.updateDangerously.yields null
.message.yields null, null
.startFlow (, ) => done()
it 'should update meshblu device status', ->
expect(.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
$set:
online: true
deploying: false
stopping: false
it 'should message meshblu with the a flow start message', ->
expect(.message).to.have.been.calledWith
devices: ['the-flow-uuid']
payload:
from: "engine-start"
it 'should message meshblu with a subscribe:pulse message', ->
expect(.message).to.have.been.calledWith
devices: ['the-flow-uuid']
topic: 'subscribe:pulse'
describe 'when called and meshblu returns an error', ->
beforeEach (done) ->
=
payload:
from: "engine-start"
.updateDangerously.yields null
.message.yields new Error 'duck army', null
.startFlow (, ) => done()
it 'should call the callback with the error', ->
expect().to.exist
describe 'stopFlow', ->
describe 'when called and there is no error', ->
beforeEach (done) ->
.updateDangerously.yields null
.message.yields null, null
.stopFlow (, ) => done()
it 'should update the meshblu device with as offline', ->
expect(.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
$set:
online: false
deploying: false
stopping: false
it 'should message meshblu with the a flow stop message', ->
expect(.meshbluHttp.message).to.have.been.calledWith
devices: ['the-flow-uuid']
payload:
from: "engine-stop"
describe 'when called and meshblu returns an error', ->
beforeEach (done) ->
.updateDangerously.yields null
.message.yields new Error 'look at meeeeee', null
.stopFlow (, ) => done()
it 'should call the callback with the error', ->
expect().to.exist