UNPKG

8.53 kBtext/coffeescriptView Raw
1_ = require 'lodash'
2shmock = require 'shmock'
3MessageController = require '../src/message-controller'
4
5API_HOST_PORT = 0xdead
6TRIGGER_HOST_PORT = 0xbeef
7SLACK_HOST_PORT = 0xf00d
8
9describe 'Canary', ->
10 @timeout 30000
11
12 before ->
13 @DateMock =
14 now: => @time or 0
15 setTime: (@time) =>
16 inc: (delta) => @time += delta
17
18 @startTime = Date.now()
19 @DateMock.setTime @startTime
20
21 process.env.OCTOBLU_CANARY_UUID = 'canary_uuid'
22 process.env.OCTOBLU_CANARY_TOKEN = 'canary_token'
23 process.env.OCTOBLU_API_HOST = 'http://localhost:' + API_HOST_PORT
24 process.env.OCTOBLU_TRIGGER_HOST = 'http://localhost:' + TRIGGER_HOST_PORT
25 process.env.SLACK_CHANNEL_URL = 'http://localhost:' + SLACK_HOST_PORT + '/slackTest'
26
27 @CANARY_RESTART_FLOWS_MAX_TIME = process.env.CANARY_RESTART_FLOWS_MAX_TIME = 1000*60
28 @CANARY_UPDATE_INTERVAL = process.env.CANARY_UPDATE_INTERVAL = 1000*120
29 @CANARY_HEALTH_CHECK_MAX_DIFF = process.env.CANARY_HEALTH_CHECK_MAX_DIFF = 100
30 @CANARY_DATA_HISTORY_SIZE = process.env.CANARY_DATA_HISTORY_SIZE = 3
31
32 @apiHost = shmock API_HOST_PORT
33 @triggerHost = shmock TRIGGER_HOST_PORT
34 @slackHost = shmock SLACK_HOST_PORT
35
36 @flows = [
37 flowId: "flow-a"
38 name: "trigger flow a"
39 activated: true
40 nodes: [
41 id: "trigger-flow-a"
42 type: "operation:trigger"
43 ]
44 ,
45 flowId: "flow-b"
46 name: "trigger flow b"
47 nodes: [
48 id: "trigger-flow-b"
49 type: "operation:trigger"
50 ]
51 ,
52 flowId: "flow-c"
53 name: "something something"
54 ]
55
56 @sut = new MessageController Date: @DateMock
57
58 @resetFlowTime = (name, time) =>
59 (@sut.canary.stats.getFlows())[name] = {messageTime:[time]}
60
61 after (done) ->
62 @apiHost.close =>
63 @triggerHost.close =>
64 @slackHost.close done
65
66 describe '-> canary', ->
67 it 'should have a message endpoint', ->
68 expect(@sut.postMessage).to.exist
69
70 it 'should have a stats endpoint', ->
71 expect(@sut.getStats).to.exist
72
73 it 'should have a passing endpoint', ->
74 expect(@sut.getPassing).to.exist
75
76 it 'should have a postTriggers function', ->
77 expect(@sut.canary.postTriggers).to.exist
78
79 it 'should have a function for getting current stats', ->
80 expect(@sut.canary.getStats).to.exist
81
82 it 'should have an initial failing state', ->
83 expect(@sut.canary.getPassing().passing).to.equal false
84
85 describe 'when startAllFlows is called', ->
86 before (done) ->
87 @getFlows = @apiHost.get('/api/flows').reply(200, @flows)
88 @startFlowA = @apiHost.post('/api/flows/flow-a/instance').reply(201)
89 @startFlowB = @apiHost.post('/api/flows/flow-b/instance').reply(201)
90 @startFlowC = @apiHost.post('/api/flows/flow-c/instance').reply(201)
91 @sut.canary.startAllFlows =>
92 @DateMock.inc @CANARY_UPDATE_INTERVAL
93 done()
94
95 it 'should have fetched our flows and started them', ->
96 expect(@getFlows.isDone).to.be.true
97 expect(@startFlowA.isDone).to.be.true
98 expect(@startFlowB.isDone).to.be.true
99 expect(@startFlowC.isDone).to.be.true
100
101 it 'should be in a passing state', ->
102 expect(@sut.canary.getPassing().passing).to.equal true
103
104 describe 'when one of the flows hasn\'t been messaged in awhile', ->
105 before ->
106 @resetFlowTime 'flow-a', @DateMock.now() - @CANARY_UPDATE_INTERVAL*2
107
108 it 'should be in a failing state', ->
109 expect(@sut.canary.getPassing().passing).to.equal false
110
111 describe.only 'and we message them a bunch', ->
112 before ->
113 messageCanary = =>
114 @DateMock.inc @CANARY_UPDATE_INTERVAL
115 @sut.postMessage {body:fromUuid:'flow-a'}, {end:=>}
116 @sut.postMessage {body:fromUuid:'flow-b'}, {end:=>}
117 @sut.postMessage {body:fromUuid:'flow-c'}, {end:=>}
118 _.times @CANARY_DATA_HISTORY_SIZE+1, messageCanary
119
120 it 'should be in a passing state', ->
121 # console.log JSON.stringify @sut.canary.getCurrentStats(), null, 2
122 expect(@sut.canary.getPassing().passing).to.equal true
123
124 describe 'when postTriggers is called', ->
125 before (done) ->
126 @triggerAPost = @triggerHost.post('/flows/flow-a/triggers/trigger-flow-a').reply(201)
127 @triggerBPost = @triggerHost.post('/flows/flow-b/triggers/trigger-flow-b').reply(201)
128 @sut.canary.postTriggers done
129
130 it 'should have posted to both triggers', ->
131 expect(@triggerAPost.isDone).to.be.true
132 expect(@triggerBPost.isDone).to.be.true
133
134 describe 'when one of the other flows hasn\'t been messaged in awhile', ->
135 before ->
136 @resetFlowTime 'flow-c', @DateMock.now() - @CANARY_UPDATE_INTERVAL*2
137
138 it 'should be in a failing state', ->
139 # console.log JSON.stringify @sut.canary.getCurrentStats(), null, 2
140 expect(@sut.canary.getPassing().passing).to.equal false
141
142 xdescribe 'when processUpdateInterval is called', ->
143 before (done) ->
144 @getFlows = @apiHost.get('/api/flows').reply(200, @flows)
145 @startFlowC = @apiHost.post('/api/flows/flow-c/instance').reply(201)
146 @triggerAPost = @triggerHost.post('/flows/flow-a/triggers/trigger-flow-a').reply(201)
147 @triggerBPost = @triggerHost.post('/flows/flow-b/triggers/trigger-flow-b').reply(201)
148 @slackPost = @slackHost.post('/slackTest').reply(200)
149
150 @sut.canary.processUpdateInterval done
151
152 it 'should have fetched the flows, restarted the failed flow, and posted to triggers', ->
153 expect(@getFlows.isDone).to.be.true
154 expect(@startFlowC.isDone).to.be.true
155 expect(@triggerAPost.isDone).to.be.true
156 expect(@triggerBPost.isDone).to.be.true
157 expect(@slackPost.isDone).to.be.true
158
159 it 'should have no errors in stats', ->
160 # console.log JSON.stringify @sut.canary.getCurrentStats(), null, 2
161 expect(_.isEmpty(@sut.canary.getStats().errors)).to.be.true
162
163 xdescribe 'when processUpdateInterval and everything errors', ->
164 before (done) ->
165 @resetFlowTime 'flow-c', @DateMock.now() - @CANARY_UPDATE_INTERVAL*2
166 @getFlows = @apiHost.get('/api/flows').reply(401, @flows)
167 @startFlowC = @apiHost.post('/api/flows/flow-c/instance').reply(401)
168 @triggerAPost = @triggerHost.post('/flows/flow-a/triggers/trigger-flow-a').reply(401)
169 @triggerBPost = @triggerHost.post('/flows/flow-b/triggers/trigger-flow-b').reply(401)
170 @slackPost = @slackHost.post('/slackTest').reply(200)
171
172 @sut.canary.processUpdateInterval done
173
174 it 'should have tried to fetch the flows, restart the failed flow, and post to triggers', ->
175 expect(@getFlows.isDone).to.be.true
176 expect(@startFlowC.isDone).to.be.true
177 expect(@triggerAPost.isDone).to.be.true
178 expect(@triggerBPost.isDone).to.be.true
179 expect(@slackPost.isDone).to.be.true
180
181 it 'should have errors in stats', ->
182 # console.log JSON.stringify @sut.canary.getCurrentStats(), null, 2
183 expect(@sut.canary.getStats().errors?.length).to.equal 4
184
185 describe 'when one of the flows is messaged too often', ->
186 before ->
187 @resetFlowTime 'flow-a', @DateMock.now()
188 @resetFlowTime 'flow-b', @DateMock.now()
189 @resetFlowTime 'flow-c', @DateMock.now()
190 delete @sut.canary.stats.errors
191
192 it 'should initialy be in a passing state', ->
193 expect(@sut.canary.getPassing().passing).to.equal true
194
195 describe 'and we message a flow once', ->
196 before ->
197 @DateMock.inc @CANARY_UPDATE_INTERVAL - (@CANARY_HEALTH_CHECK_MAX_DIFF*1.1)
198 @sut.postMessage {body:fromUuid:'flow-a'}, {end:=>}
199
200 it 'should be in a failing state', ->
201 # console.log JSON.stringify @sut.canary.getCurrentStats(), null, 2
202 expect(@sut.canary.getPassing().passing).to.equal false