UNPKG

11.4 kBtext/coffeescriptView Raw
1should = require 'should'
2_ = require 'lodash'
3logger = require 'torch'
4{focus} = require 'qi'
5{join} = require 'path'
6
7bus = require '../lib/bus'
8core = require '../lib/core'
9
10mockRetriever = require './helpers/mockRetriever'
11
12describe 'core.request', ->
13 beforeEach (done) ->
14 core.reset =>
15
16 core.init {timeout: 20}, mockRetriever()
17 @moduleName = 'server'
18 @serviceName = 'start'
19 @channel = "#{@moduleName}.#{@serviceName}"
20 @data =
21 x: 2
22 y: 'hello'
23
24 done()
25
26 it 'should receive exactly one valid response', (done) ->
27 core.respond @channel, (message, done) ->
28 done null, message
29
30 core.request @channel, @data, (err, message) =>
31 should.not.exist err
32
33 should.exist message
34 message.should.eql @data
35
36 done()
37
38 it 'should pass an error to the callback', (done) ->
39 testError = new Error 'testError'
40 core.respond @channel, (args, fin) ->
41 fin testError
42
43 core.request @channel, @data, (err, message) =>
44 should.exist err
45 should.exist message
46 message.should.eql {}
47
48 err.should.eql testError
49
50 done()
51
52 it 'should invoke the success callback exactly once, then discard all', (done) ->
53 core.respond @channel, (message, finished) =>
54 finished()
55
56 test = (err, data) ->
57 bus.publish
58 channel: @channel
59 topic: replyTo.topic.err
60 data: new Error 'should not see'
61 done()
62
63 replyTo = core.request @channel, @data, test
64
65 it 'should return a timeout error when it times out', (done) ->
66 {RequestTimeoutError} = require '../lib/errorTypes'
67 core.respond @channel, -> # I can't hear you
68 core.request @channel, @data, (err, result) =>
69 should.exist err
70 err.message.should.eql "Request timed out after 20ms on channel: '#{@channel}'"
71 err.should.be.instanceOf RequestTimeoutError
72 should.exist result
73 result.should.eql {}
74 done()
75
76 it 'should return immediately if there are no listeners', (done) ->
77 core.request @channel, @data, (err, result) =>
78 should.exist err
79 expectedMsg = "No responders for request: '#{@channel}'"
80 err.message.should.eql expectedMsg
81
82 should.exist result
83 result.should.eql {}
84 done()
85
86 it 'should return an "ambiguous" error when there are multiple responders', (done) ->
87 core.respond @channel, ->
88 core.respond @channel, ->
89 core.request @channel, @data, (err, result) =>
90 should.exist err
91 err.message.should.eql "Ambiguous: 2 responders for request: '#{@channel}'"
92 should.exist result
93 result.should.eql {}
94 done()
95
96
97describe 'core.response', ->
98 beforeEach (done) ->
99 core.reset =>
100 core.init {timeout: 20}, mockRetriever()
101 @channel = 'testChannel'
102 @data =
103 x: 2
104 y: 'hello'
105 done()
106
107 it 'should send exactly one valid response', (done) ->
108 echo = (message, next) -> next null, message
109 core.respond @channel, echo
110
111 bus.subscribe
112 channel: @channel
113 topic: "success.123"
114 callback: (message) =>
115 should.exist message
116 message.should.eql @data
117 done()
118
119 bus.publish
120 channel: @channel
121 topic: "request.123"
122 data: @data
123 replyTo:
124 channel: @channel
125 topic:
126 success: "success.123"
127
128
129describe 'core.delegate', ->
130 beforeEach (done) ->
131 core.reset =>
132 core.init {timeout: 20}, mockRetriever()
133 done()
134
135 it 'should should return if there are no responders', (done) ->
136 channel = 'testChannel'
137
138 core.delegate channel, {}, (err, results) ->
139 should.not.exist err
140 done()
141
142 it 'responders on another channel should not interfere', (done) ->
143 channel = 'testChannel'
144
145 core.respond 'fooChannel', (message, next) ->
146 next null, {helloFrom: 'fooChannel'}
147
148 core.delegate channel, {}, (err, results) ->
149 should.not.exist err
150 done()
151
152 it 'should should receive multiple responses', (done) ->
153 channel = 'testChannel'
154
155 sub = core.respond channel, (message, next) ->
156 next null, {helloFrom: 'responderA'}
157
158 res1 = sub.responderId
159
160 sub = core.respond channel, (message, next) ->
161 next null, {helloFrom: 'responderB'}
162
163 res2 = sub.responderId
164
165 core.delegate channel, {}, (err, results) ->
166 should.not.exist err
167 should.exist results
168
169 results[res1].should.eql { helloFrom: 'responderA' }
170 results[res2].should.eql { helloFrom: 'responderB' }
171 done()
172
173 it 'should return an err when a responder returns one', (done) ->
174 channel = 'testChannel'
175
176 testResponse = {message: 'this works'}
177 core.respond channel, (message, next) ->
178 next null, testResponse
179
180 testError = new Error 'Expect this error'
181 core.respond channel, (message, next) ->
182 next testError, {}
183
184 core.delegate channel, {}, (err, results) ->
185 should.exist err
186 expectedMsg = "Received errors from channel '#{channel}':\nError: #{testError.message}"
187 err.message.should.startWith expectedMsg
188
189 should.exist err.errors, 'expected errors'
190 subErrors = _.values err.errors
191 should.exist subErrors, 'expected subErrors'
192 [subErr] = subErrors
193 should.exist subErr, 'expected subErr'
194 subErr.should.eql testError
195
196 should.exist results, 'expected results'
197 values = _.values results
198 should.exist values, 'expected values'
199 [result] = values
200 should.exist result, 'expected result'
201 result.should.eql testResponse
202
203 done()
204
205 it 'should return a timeout err when an implied request times out', (done) ->
206 channel = 'testChannel'
207
208 wontTimeOutMsg = {message: "I won't time out"}
209 sub = core.respond channel, (message, next) ->
210 next null, wontTimeOutMsg
211
212 successId = sub.responderId
213
214 # This WILL time out
215 sub = core.respond channel, (message, next) ->
216 # next() will never get called.
217
218 errId = sub.responderId
219
220 core.delegate channel, {}, (err, results) ->
221 should.exist err
222
223 expectedMsg = "Received errors from channel '#{channel}':\nAxiomError/RequestTimeoutError: Responder with id '#{errId}' timed out after 20ms on channel: '#{channel}'"
224 err.message.should.startWith expectedMsg
225
226 should.exist err.errors
227
228 subErr = err.errors[errId]
229 should.exist subErr, 'expected subErr'
230
231 errMsg = "Responder with id '#{errId}' timed out after 20ms on channel: '#{channel}'"
232 subErr.message.should.eql errMsg
233
234 should.exist results
235 result = results[successId]
236 should.exist result
237 result.should.eql wontTimeOutMsg
238
239 done()
240
241 it 'should collect args', (done) ->
242
243 # Given a pitch function
244 pitch = (args, fin) ->
245 fin null, {foo: 1}
246 pitch.extension = 'sandbox'
247
248 # And I attach the endpoints
249 responderId = core.respond 'pitch', pitch
250
251 # When I delegate
252 core.delegate 'pitch', {input: 2}, (err, result) ->
253 should.not.exist err
254 should.exist result?.sandbox, 'expected responder data'
255 should.exist result.__delegation_result, 'expected __delegation_result'
256 result.__delegation_result.should.eql true
257 should.exist result.__input, 'expected __input'
258 result.__input.should.eql {input: 2}
259 result.sandbox.should.eql {input: 2, foo: 1}
260 done()
261
262 it 'should collect errors', (done) ->
263
264 # Given an error service
265 error = (args, fin) ->
266 fin(new Error 'oops')
267 error.extension = 'sandbox'
268
269 # And I attach the endpoints
270 responderId = core.respond 'error', error
271
272 # When I delegate
273 core.delegate 'error', {something: 1}, (err, result) ->
274 should.exist err?.errors?.sandbox, 'expected err for responder'
275 should.exist result, 'expected result'
276 result.should.eql
277 __delegation_result: true
278 __input: {something: 1}
279 done()
280
281 it 'should distribute args', (done) ->
282
283 # Given a sandbox extension
284 responderId = core.load 'sandbox',
285 services:
286 pitch: (args, fin) ->
287 args.should.eql {bar: 2, foo: 1}
288 fin null, args
289
290 args =
291 __delegation_result: true
292 __input: {bar: 2}
293 sandbox: {foo: 1}
294 other: {value: "shouldn't see"}
295
296 # When I delegate
297 core.delegate 'sandbox.pitch', args, (err, result) ->
298 should.not.exist err
299 should.exist result?.sandbox, 'expected responder data'
300 result.sandbox.should.eql {bar: 2, foo: 1}
301 done()
302
303 it 'should use input args', (done) ->
304
305 # Given a sandbox extension
306 responderId = core.load 'sandbox',
307 services:
308 pitch: (args, fin) ->
309 args.should.eql {bar: 2}
310 fin null, args
311
312 args =
313 __delegation_result: true
314 __input: {bar: 2}
315 other: {value: "shouldn't see"}
316
317 # When I delegate
318 core.delegate 'sandbox.pitch', args, (err, result) ->
319 should.not.exist err
320 should.exist result?.sandbox, 'expected responder data'
321 result.sandbox.should.eql {bar: 2}
322 done()
323
324describe 'core.listen', ->
325 beforeEach (done) ->
326 core.reset =>
327 core.init {timeout: 20}, mockRetriever()
328 @channelA = 'testChannelA'
329 @channelB = 'testChannelB'
330 @dataA =
331 x: 2
332 y: 'hello'
333 @dataB =
334 x: 111
335 y: 'goodbye'
336 @topicA = 'info.A'
337 @topicB = 'info.B'
338
339 done()
340
341 it 'should listen with a standard-signature callback', (done) ->
342 core.listen @channelA, @topicA, (err, result) =>
343 should.not.exist err
344 should.exist result
345 {data} = result
346 should.exist data
347 data.should.eql @dataA
348 done()
349
350 bus.publish
351 channel: @channelA
352 data: @dataA
353 topic: @topicA
354
355 it 'should listen to two topics on one channel', (done) ->
356 cb = focus (err, results) =>
357 should.not.exist err
358
359 should.exist results
360
361 [resultA, resultB] = results
362 should.exist resultA
363 should.exist resultB
364
365 dataA = resultA.data
366 should.exist dataA
367 dataA.should.eql @dataA
368
369 dataB = resultB.data
370 should.exist dataB
371 dataB.should.eql @dataB
372
373 done()
374
375 core.listen @channelA, @topicA, cb()
376
377 core.listen @channelA, @topicB, cb()
378
379 bus.publish
380 channel: @channelA
381 data: @dataA
382 topic: @topicA
383
384 bus.publish
385 channel: @channelA
386 data: @dataB
387 topic: @topicB
388
389 it 'should listen to two topics on two channels', (done) ->
390 cb = focus (err, results) =>
391 should.not.exist err
392
393 should.exist results
394
395 [resultA, resultB] = results
396 should.exist resultA
397 should.exist resultB
398
399 dataA = resultA.data
400 should.exist dataA
401 dataA.should.eql @dataA
402
403 dataB = resultB.data
404 should.exist dataB
405 dataB.should.eql @dataB
406
407 done()
408
409 core.listen @channelA, @topicA, cb()
410
411 core.listen @channelB, @topicB, cb()
412
413 bus.publish
414 channel: @channelA
415 data: @dataA
416 topic: @topicA
417
418 bus.publish
419 channel: @channelB
420 data: @dataB
421 topic: @topicB
422
423 it 'should listen to any topic on one channel', (done) ->
424 core.listen @channelA, '#', (err, result) =>
425 should.not.exist err
426 should.exist result
427
428 {data} = result
429 should.exist data
430 data.should.eql @dataA
431
432 done()
433
434 bus.publish
435 channel: @channelA
436 data: @dataA
437 topic: @topicA