UNPKG

17 kBtext/coffeescriptView Raw
1_ = require 'lodash'
2FlowDeployer = require '../src/flow-deployer'
3
4
5describe 'FlowDeployer', ->
6 describe 'when constructed with a flow', ->
7 beforeEach ->
8 @request = get: sinon.stub()
9 @configuration = erik_is_happy: true
10
11 options =
12 flowUuid: 'the-flow-uuid'
13 flowToken: 'the-flow-token'
14 forwardUrl: 'http://www.zombo.com'
15 instanceId: 'an-instance-id'
16 userUuid: 'some-user-uuid'
17 userToken: 'some-user-token'
18 octobluUrl: 'https://api.octoblu.com'
19 deploymentUuid: 'the-deployment-uuid'
20 flowLoggerUuid: 'flow-logger-uuid'
21
22 @configurationGenerator =
23 configure: sinon.stub()
24
25 @configurationSaver =
26 save: sinon.stub()
27 stop: sinon.stub()
28
29 @meshbluHttp =
30 message: sinon.stub()
31 updateDangerously: sinon.stub()
32 createSubscription: sinon.stub()
33 search: sinon.stub()
34
35 MeshbluHttp = sinon.spy => @meshbluHttp
36
37 @sut = new FlowDeployer options,
38 configurationGenerator: @configurationGenerator
39 configurationSaver: @configurationSaver
40 MeshbluHttp: MeshbluHttp
41 request: @request
42
43 @request.get.withArgs('https://api.octoblu.com/api/flows/the-flow-uuid').yields null, {}, {a: 1, b: 5}
44 @request.get.withArgs('https://api.octoblu.com/api/user').yields null, {}, {api: {}}
45
46 describe 'when deploy is called', ->
47 beforeEach (done)->
48 flowConfig =
49 'some': 'thing'
50 'subscribe-devices':
51 config:
52 'broadcast.sent': ['subscribe-to-this-uuid']
53
54 @configurationGenerator.configure.yields null, flowConfig, {stop: 'config'}
55 @configurationSaver.stop.yields null
56 @configurationSaver.save.yields null
57 @sut.setupDevice = sinon.stub().yields null
58 @sut.deploy => done()
59
60 it 'should message the FLOW_LOGGER_UUID', ->
61 expect(@meshbluHttp.message).to.have.been.called
62 firstArg = @meshbluHttp.message.firstCall.args[0]
63 delete firstArg.payload.date
64
65 expect(firstArg).to.deep.equal
66 devices: ['flow-logger-uuid']
67 payload:
68 application: 'flow-deploy-service'
69 deploymentUuid: 'the-deployment-uuid'
70 flowUuid: 'the-flow-uuid'
71 userUuid: 'some-user-uuid'
72 workflow: 'flow-start'
73 state: 'begin'
74 message: undefined
75
76 it 'should call configuration generator with the flow', ->
77 expect(@configurationGenerator.configure).to.have.been.calledWith
78 flowData: { a: 1, b: 5 }
79 userData: {api: {}}
80 deploymentUuid: 'the-deployment-uuid'
81 flowToken: 'the-flow-token'
82
83 it 'should call configuration saver with the flow', ->
84 expect(@configurationSaver.save).to.have.been.calledWith(
85 flowId: 'the-flow-uuid'
86 instanceId: 'an-instance-id'
87 flowData:
88 'some': 'thing'
89 'subscribe-devices':
90 config:
91 'broadcast.sent': ['subscribe-to-this-uuid']
92 )
93 expect(@configurationSaver.save).to.have.been.calledWith(
94 flowId: 'the-flow-uuid-stop'
95 instanceId: 'an-instance-id'
96 flowData:
97 stop: 'config'
98 )
99
100 it 'should call request.get', ->
101 options =
102 json: true
103 auth :
104 user: 'some-user-uuid'
105 pass: 'some-user-token'
106
107 expect(@request.get).to.have.been.calledWith 'https://api.octoblu.com/api/flows/the-flow-uuid', options
108 expect(@request.get).to.have.been.calledWith 'https://api.octoblu.com/api/user', options
109
110 it 'should message the FLOW_LOGGER_UUID', ->
111 expect(@meshbluHttp.message).to.have.been.called
112 firstArg = @meshbluHttp.message.secondCall.args[0]
113 delete firstArg.payload.date
114
115 expect(firstArg).to.deep.equal
116 devices: ['flow-logger-uuid']
117 payload:
118 application: 'flow-deploy-service'
119 deploymentUuid: 'the-deployment-uuid'
120 flowUuid: 'the-flow-uuid'
121 userUuid: 'some-user-uuid'
122 workflow: 'flow-start'
123 state: 'end'
124 message: undefined
125
126 describe 'when deploy is called and user GET errored', ->
127 beforeEach (done) ->
128 userUrl = 'https://api.octoblu.com/api/user'
129 @request.get.withArgs(userUrl).yields new Error 'whoa, thats not a user', null
130 @sut.deploy (@error, @result) => done()
131
132 it 'should call request.get', ->
133 expect(@request.get).to.have.been.called
134
135 it 'should yield and error', ->
136 expect(@error).to.exist
137
138 it 'should not give us a result', ->
139 expect(@result).to.not.exist
140
141 it 'should message the FLOW_LOGGER_UUID', ->
142 expect(@meshbluHttp.message).to.have.been.calledTwice
143 firstArg = @meshbluHttp.message.secondCall.args[0]
144 delete firstArg.payload.date
145
146 expect(firstArg).to.deep.equal
147 devices: ['flow-logger-uuid']
148 payload:
149 application: 'flow-deploy-service'
150 deploymentUuid: 'the-deployment-uuid'
151 flowUuid: 'the-flow-uuid'
152 userUuid: 'some-user-uuid'
153 workflow: 'flow-start'
154 state: 'error'
155 message: 'whoa, thats not a user'
156
157 describe 'when deploy is called and flow get errored', ->
158 beforeEach (done) ->
159 userUrl = 'https://api.octoblu.com/api/user'
160 @request.get.withArgs(userUrl).yields null
161
162 flowUrl = 'https://api.octoblu.com/api/flows/the-flow-uuid'
163 @request.get.withArgs(flowUrl).yields new Error 'whoa, shoots bad', null
164 @sut.deploy (@error, @result) => done()
165
166 it 'should call request.get', ->
167 expect(@request.get).to.have.been.called
168
169 it 'should yield and error', ->
170 expect(@error).to.exist
171
172 it 'should not give us a result', ->
173 expect(@result).to.not.exist
174
175 it 'should message the FLOW_LOGGER_UUID', ->
176 expect(@meshbluHttp.message).to.have.been.calledTwice
177 firstArg = @meshbluHttp.message.secondCall.args[0]
178 delete firstArg.payload.date
179
180 expect(firstArg).to.deep.equal
181 devices: ['flow-logger-uuid']
182 payload:
183 application: 'flow-deploy-service'
184 deploymentUuid: 'the-deployment-uuid'
185 flowUuid: 'the-flow-uuid'
186 userUuid: 'some-user-uuid'
187 workflow: 'flow-start'
188 state: 'error'
189 message: 'whoa, shoots bad'
190
191 describe 'when deploy is called and the configuration generator returns an error', ->
192 beforeEach (done)->
193 @configurationGenerator.configure.yields new Error 'Oh noes'
194 @sut.deploy (@error, @result)=> done()
195
196 it 'should return an error with an error', ->
197 expect(@error).to.exist
198
199 it 'should not give us a result', ->
200 expect(@result).to.not.exist
201
202 it 'should message the FLOW_LOGGER_UUID', ->
203 expect(@meshbluHttp.message).to.have.been.calledTwice
204 firstArg = @meshbluHttp.message.secondCall.args[0]
205 delete firstArg.payload.date
206
207 expect(firstArg).to.deep.equal
208 devices: ['flow-logger-uuid']
209 payload:
210 application: 'flow-deploy-service'
211 deploymentUuid: 'the-deployment-uuid'
212 flowUuid: 'the-flow-uuid'
213 userUuid: 'some-user-uuid'
214 workflow: 'flow-start'
215 state: 'error'
216 message: 'Oh noes'
217
218 describe 'when deploy is called and the configuration stop returns an error', ->
219 beforeEach (done)->
220 @configurationGenerator.configure.yields null, { erik_likes_me: true}
221 @configurationSaver.stop.yields new Error 'Erik can never like me enough'
222 @sut.deploy (@error, @result)=> done()
223
224 it 'should yield and error', ->
225 expect(@error).to.exist
226
227 it 'should not give us a result', ->
228 expect(@result).to.not.exist
229
230 it 'should not call save', ->
231 expect(@configurationSaver.save).to.not.have.been.called
232
233 it 'should message the FLOW_LOGGER_UUID', ->
234 expect(@meshbluHttp.message).to.have.been.calledTwice
235 firstArg = @meshbluHttp.message.secondCall.args[0]
236 delete firstArg.payload.date
237
238 expect(firstArg).to.deep.equal
239 devices: ['flow-logger-uuid']
240 payload:
241 application: 'flow-deploy-service'
242 deploymentUuid: 'the-deployment-uuid'
243 flowUuid: 'the-flow-uuid'
244 userUuid: 'some-user-uuid'
245 workflow: 'flow-start'
246 state: 'error'
247 message: 'Erik can never like me enough'
248
249 describe 'when deploy is called and the configuration save returns an error', ->
250 beforeEach (done)->
251 @configurationGenerator.configure.yields null, { erik_likes_me: true}
252 @configurationSaver.stop.yields null
253 @configurationSaver.save.yields new Error 'Erik can never like me enough'
254 @sut.deploy (@error, @result)=> done()
255
256 it 'should yield and error', ->
257 expect(@error).to.exist
258
259 it 'should not give us a result', ->
260 expect(@result).to.not.exist
261
262 it 'should message the FLOW_LOGGER_UUID', ->
263 expect(@meshbluHttp.message).to.have.been.calledTwice
264 firstArg = @meshbluHttp.message.secondCall.args[0]
265 delete firstArg.payload.date
266
267 expect(firstArg).to.deep.equal
268 devices: ['flow-logger-uuid']
269 payload:
270 application: 'flow-deploy-service'
271 deploymentUuid: 'the-deployment-uuid'
272 flowUuid: 'the-flow-uuid'
273 userUuid: 'some-user-uuid'
274 workflow: 'flow-start'
275 state: 'error'
276 message: 'Erik can never like me enough'
277
278 describe 'when deploy is called and the generator and saver actually worked', ->
279 beforeEach (done) ->
280 @configurationGenerator.configure.yields null, { erik_likes_me: 'more than you know'}
281 @configurationSaver.stop.yields null
282 @configurationSaver.save.yields null, {finally_i_am_happy: true}
283 @sut.setupDevice = sinon.stub().yields null
284
285 @sut.deploy (@error, @result) => done()
286
287 it 'should call setupDeviceForwarding', ->
288 expect(@sut.setupDevice).to.have.been.called
289
290
291 describe 'createSubscriptions', ->
292 beforeEach (done) ->
293 @meshbluHttp.createSubscription.yields null
294 flowConfig =
295 'subscribe-devices':
296 config:
297 'broadcast.sent': ['subscribe-to-this-uuid']
298 @sut.createSubscriptions flowConfig, done
299
300 it "should create the subscription to the device's", ->
301 subscriberUuid = 'the-flow-uuid'
302 emitterUuid = 'subscribe-to-this-uuid'
303 type = 'broadcast.sent'
304 expect(@meshbluHttp.createSubscription).to.have.been.calledWith {subscriberUuid, emitterUuid, type}
305
306 describe 'setupDeviceForwarding', ->
307 beforeEach (done) ->
308 @updateMessageHooks =
309 $addToSet:
310 'meshblu.forwarders.broadcast.received':
311 signRequest: true
312 url: 'http://www.zombo.com'
313 method: 'POST'
314 name: 'nanocyte-flow-deploy'
315 type: 'webhook'
316 'meshblu.forwarders.message.received':
317 signRequest: true
318 url: 'http://www.zombo.com'
319 method: 'POST'
320 name: 'nanocyte-flow-deploy'
321 type: 'webhook'
322
323 @pullMessageHooks =
324 $pull:
325 'meshblu.forwarders.received':
326 name: 'nanocyte-flow-deploy'
327 'meshblu.messageHooks':
328 name: 'nanocyte-flow-deploy'
329 'meshblu.forwarders.broadcast.received':
330 name: 'nanocyte-flow-deploy'
331 'meshblu.forwarders.message.received':
332 name: 'nanocyte-flow-deploy'
333
334 @removeOldMessageHooks =
335 $unset:
336 'meshblu.forwarders.broadcast': ''
337
338 @device =
339 uuid: 1
340 flow: {a: 1, b: 5}
341 meshblu:
342 messageHooks: [
343 generateAndForwardMeshbluCredentials: true
344 url: 'http://www.neopets.com'
345 method: 'DELETE'
346 name: 'nanocyte-flow-deploy'
347 ]
348
349 @meshbluHttp.search.yields null, [meshblu: forwarders: broadcast: []]
350 @meshbluHttp.updateDangerously.yields null, null
351 @sut.setupDeviceForwarding (@error, @result) => done()
352
353 it "should update a meshblu device with the webhook to wherever it's going", ->
354 expect(@meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid', @removeOldMessageHooks
355 expect(@meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid', @pullMessageHooks
356 expect(@meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid', @updateMessageHooks
357
358 describe 'setupMessageSchema', ->
359 beforeEach (done) ->
360 @updateDevice = $set:
361 messageSchema:
362 type: 'object'
363 properties:
364 from:
365 type: 'string'
366 title: 'Trigger'
367 required: true
368 enum: [ 'a', 'c' ]
369 payload:
370 title: "payload"
371 description: "Use {{msg}} to send the entire message"
372 replacePayload:
373 type: 'string'
374 default: 'payload'
375
376 messageFormSchema: [
377 {
378 key: 'from'
379 titleMap:
380 'a' : 'multiply (a)'
381 'c' : 'rabbits (c)'
382 }
383 { key: 'payload', 'type': 'input', title: "Payload", description: "Use {{msg}} to send the entire message"}
384 ]
385
386 nodes = [
387 {
388 class: 'trigger'
389 id: 'a'
390 name: 'multiply'
391 },
392 {
393 class: 'not-a-trigger'
394 id: 'b'
395 name: 'like'
396 },
397 {
398 class: 'trigger'
399 id: 'c'
400 name: 'rabbits'
401 }
402 ]
403
404 @sut.meshbluHttp.updateDangerously.yields null, null
405 @sut.setupMessageSchema nodes, (@error, @result) => done()
406
407 it "should update a meshblu device with message schema for triggers", ->
408 expect(@sut.meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid', @updateDevice
409
410 describe 'startFlow', ->
411 describe 'when called and there is no errors', ->
412 beforeEach (done) ->
413 @meshbluHttp.updateDangerously.yields null
414 @meshbluHttp.message.yields null, null
415 @sut.startFlow (@error, @result) => done()
416
417 it 'should update meshblu device status', ->
418 expect(@meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
419 $set:
420 online: true
421 deploying: false
422 stopping: false
423
424 it 'should message meshblu with the a flow start message', ->
425 expect(@meshbluHttp.message).to.have.been.calledWith
426 devices: ['the-flow-uuid']
427 payload:
428 from: "engine-start"
429
430 it 'should message meshblu with a subscribe:pulse message', ->
431 expect(@meshbluHttp.message).to.have.been.calledWith
432 devices: ['the-flow-uuid']
433 topic: 'subscribe:pulse'
434
435 describe 'when called and meshblu returns an error', ->
436 beforeEach (done) ->
437 @message =
438 payload:
439 from: "engine-start"
440
441 @meshbluHttp.updateDangerously.yields null
442 @meshbluHttp.message.yields new Error 'duck army', null
443 @sut.startFlow (@error, @result) => done()
444
445 it 'should call the callback with the error', ->
446 expect(@error).to.exist
447
448 describe 'stopFlow', ->
449 describe 'when called and there is no error', ->
450 beforeEach (done) ->
451 @meshbluHttp.updateDangerously.yields null
452 @meshbluHttp.message.yields null, null
453 @sut.stopFlow (@error, @result) => done()
454
455 it 'should update the meshblu device with as offline', ->
456 expect(@meshbluHttp.updateDangerously).to.have.been.calledWith 'the-flow-uuid',
457 $set:
458 online: false
459 deploying: false
460 stopping: false
461
462 it 'should message meshblu with the a flow stop message', ->
463 expect(@sut.meshbluHttp.message).to.have.been.calledWith
464 devices: ['the-flow-uuid']
465 payload:
466 from: "engine-stop"
467
468 describe 'when called and meshblu returns an error', ->
469 beforeEach (done) ->
470 @meshbluHttp.updateDangerously.yields null
471 @meshbluHttp.message.yields new Error 'look at meeeeee', null
472 @sut.stopFlow (@error, @result) => done()
473
474 it 'should call the callback with the error', ->
475 expect(@error).to.exist