nebulous_stomp 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,575 @@
1
+ require 'stomp'
2
+
3
+ require 'spec_helper'
4
+ require 'nebulous/message'
5
+
6
+ require_relative 'helpers'
7
+
8
+ require 'pry'
9
+
10
+ include Nebulous
11
+
12
+
13
+ RSpec.configure do |c|
14
+ c.include Helpers
15
+ end
16
+
17
+
18
+
19
+ describe Message do
20
+
21
+ # the cacheing process can't preserve the symbol-or-text-ness of the
22
+ # headers; we're stuck with that. So for comparison purposes this helper
23
+ # function deep-converts all keys in a hash to symbols.
24
+ def symbolise(hash)
25
+
26
+ hash.each_with_object({}) do |(k,v),m|
27
+ m[k.to_sym] = v.kind_of?(Hash) ? symbolise(v) : v
28
+ end
29
+
30
+ end
31
+
32
+
33
+ let(:msg_pts) do
34
+ x = Message.from_parts('Daphne', 'Fred', 'Velma', 'Shaggy', 'Scooby')
35
+ x.reply_id = 42
36
+ x
37
+ end
38
+
39
+ let(:smess) { stomp_message('application/text', 'foo') }
40
+ let(:msg_stomp) { Message.from_stomp(smess) }
41
+
42
+ let(:json_hash) do
43
+
44
+ b = { verb: 'tom',
45
+ params: 'dick',
46
+ desc: 'harry' }.to_json
47
+
48
+ x = Message.from_stomp( stomp_message('application/json', b) )
49
+
50
+ { stompHeaders: x.stomp_headers,
51
+ stompBody: x.stomp_body,
52
+ verb: 'tom',
53
+ params: 'dick',
54
+ desc: 'harry',
55
+ replyTo: '/queue/thing',
56
+ replyId: '1234',
57
+ inReplyTo: '4321',
58
+ contentType: 'application/json' }
59
+
60
+ end
61
+
62
+ let(:msg_cache) { Message.from_cache( json_hash.to_json ) }
63
+
64
+
65
+ describe 'Message.from_parts' do
66
+
67
+ it 'returns a Message object' do
68
+ expect( msg_pts ).to be_a_kind_of(Message)
69
+ end
70
+
71
+ it 'sets protocol attributes if it can, raises hell otherwise' do
72
+ expect{ Message.from_parts }.to raise_exception ArgumentError
73
+
74
+ expect{ Message.from_parts(nil, nil, nil, nil, nil) }.
75
+ to raise_exception ArgumentError
76
+
77
+ expect( msg_pts.reply_to ).to eq 'Daphne'
78
+ expect( msg_pts.in_reply_to ).to eq 'Fred'
79
+ expect( msg_pts.verb ).to eq 'Velma'
80
+ expect( msg_pts.params ).to eq 'Shaggy'
81
+ expect( msg_pts.desc ).to eq 'Scooby'
82
+ end
83
+
84
+ it "assumes a content type of JSON" do
85
+ expect( msg_pts.content_type ).to match(/json$/i)
86
+ end
87
+
88
+ end
89
+ ##
90
+
91
+
92
+ describe 'Message.in_reply_to' do
93
+
94
+ let(:msg) do
95
+ Message.in_reply_to(msg_pts, 'Buffy', 'Willow', 'Xander', 'Ripper')
96
+ end
97
+
98
+
99
+ it 'requires another Message object and a verb' do
100
+ expect{ Message.in_reply_to('foo') }.to raise_exception ArgumentError
101
+
102
+ expect{ Message.in_reply_to('foo', 'bar') }.
103
+ to raise_exception ArgumentError
104
+
105
+ expect{ Message.in_reply_to(msg_pts, 'bar') }.not_to raise_exception
106
+ end
107
+
108
+ it 'returns a fresh Message object' do
109
+ expect( msg ).to be_a_kind_of(Message)
110
+ expect( msg ).not_to eq(msg_pts)
111
+ end
112
+
113
+ it 'sets Protocol attributes' do
114
+ expect( msg.verb ).to eq 'Buffy'
115
+ expect( msg.params ).to eq 'Willow'
116
+ expect( msg.desc ).to eq 'Xander'
117
+ expect( msg.reply_to ).to eq 'Ripper'
118
+
119
+ # NB the reply_id (message ID) not the reply_to (the queue)
120
+ expect( msg.in_reply_to ).to eq 42
121
+ end
122
+
123
+ it 'sets the content type from the source message' do
124
+ expect( msg.content_type ).to eq msg_pts.content_type
125
+ end
126
+
127
+ end
128
+ ##
129
+
130
+
131
+ describe 'Message.from_stomp' do
132
+
133
+ it 'requires a Stomp::Message' do
134
+ expect{ Message.from_stomp }.to raise_exception ArgumentError
135
+ expect{ Message.from_stomp('foo') }.to raise_exception ArgumentError
136
+ expect{ Message.from_stomp(smess) }.not_to raise_exception
137
+ end
138
+
139
+ it 'sets stomp attributes' do
140
+ expect( msg_stomp.stomp_headers ).to include smess.headers
141
+ expect( msg_stomp.stomp_body ).to eq smess.body
142
+ end
143
+
144
+ it 'still works if there are no Protocol attributes to set' do
145
+ expect( msg_stomp.verb ).to eq nil
146
+ expect( msg_stomp.params ).to eq nil
147
+ expect( msg_stomp.desc ).to eq nil
148
+ expect( msg_stomp.reply_to ).to eq nil
149
+ expect( msg_stomp.in_reply_to ).to eq nil
150
+ end
151
+
152
+
153
+ context "when the message body is text" do
154
+
155
+ it 'returns a Message object' do
156
+ expect( msg_stomp ).to be_a_kind_of Message
157
+ end
158
+
159
+ it 'sets Protocol attributes if it can' do
160
+ body = {verb: 'Dougal', params: 'Florence', desc: 'Ermintrude'}
161
+ mess = stomp_message('application/json', body.to_json, '23')
162
+ msg = Message.from_stomp(mess)
163
+ expect( msg.verb ).to eq 'Dougal'
164
+ expect( msg.params ).to eq 'Florence'
165
+ expect( msg.desc ).to eq 'Ermintrude'
166
+ expect( msg.in_reply_to ).to eq '23'
167
+ end
168
+
169
+ end
170
+
171
+
172
+ context "when the message body is JSON" do
173
+
174
+ let(:msg_stomp_json) do
175
+ m = {verb: 'one', params: 'two', desc: 'three'}.to_json
176
+ x = stomp_message('application/json', m, '19')
177
+ Message.from_stomp(x)
178
+ end
179
+
180
+ it 'returns a Message object' do
181
+ expect( msg_stomp_json ).to be_a_kind_of Message
182
+ end
183
+
184
+ it 'sets Protocol attributes if it can' do
185
+ expect( msg_stomp_json.verb ).to eq 'one'
186
+ expect( msg_stomp_json.params ).to eq 'two'
187
+ expect( msg_stomp_json.desc ).to eq 'three'
188
+ expect( msg_stomp_json.in_reply_to ).to eq '19'
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+ ##
195
+
196
+
197
+ describe 'Message.from_cache' do
198
+
199
+ let(:msg2) do
200
+ x = { replyId: '1234',
201
+ contentType: 'application/json' }.to_json
202
+
203
+ Message.from_cache(x)
204
+ end
205
+
206
+
207
+ it 'requires some json in the right format' do
208
+ expect{ Message.from_cache }.to raise_exception ArgumentError
209
+ expect{ Message.from_cache('foo') }.to raise_exception ArgumentError
210
+ expect{ Message.from_cache({}) }.to raise_exception ArgumentError
211
+ expect{ Message.from_cache({foo:'bar'}) }.to raise_exception ArgumentError
212
+
213
+ expect{ Message.from_cache(json_hash.to_json) }.not_to raise_exception
214
+ end
215
+
216
+ it "copes with some loon passing header and not body or vice versa" do
217
+ # I know because ... I was that soldier.
218
+
219
+ loony1 = { stompHeader: 'foo' }
220
+ loony2 = { stompBody: 'bar' }
221
+
222
+ expect{ Message.from_cache(loony1.to_json) }.not_to raise_exception
223
+ expect{ Message.from_cache(loony2.to_json) }.not_to raise_exception
224
+ end
225
+
226
+ it 'still works if there are no Protocol attributes to set' do
227
+ expect( msg2.verb ).to eq nil
228
+ expect( msg2.params ).to eq nil
229
+ expect( msg2.desc ).to eq nil
230
+ expect( msg2.reply_to ).to eq nil
231
+ expect( msg2.in_reply_to ).to eq nil
232
+ end
233
+
234
+ it 'sets Protocol attributes if it can' do
235
+ expect( msg_cache.verb ).to eq 'tom'
236
+ expect( msg_cache.params ).to eq 'dick'
237
+ expect( msg_cache.desc ).to eq 'harry'
238
+ expect( msg_cache.reply_to ).to eq '/queue/thing'
239
+ expect( msg_cache.in_reply_to ).to eq '4321'
240
+ end
241
+
242
+
243
+ context "when the message body is JSON" do
244
+ # msg_cache has a json body
245
+
246
+ it 'returns a Message object' do
247
+ expect( msg_cache ).to be_a_kind_of Message
248
+ end
249
+
250
+ it 'sets the stomp attributes' do
251
+ expect( msg_cache.stomp_headers ).
252
+ to eq symbolise( json_hash[:stompHeaders] )
253
+
254
+ expect( msg_cache.stomp_body ).to eq json_hash[:stompBody]
255
+ end
256
+
257
+ it 'sets the content type' do
258
+ expect( msg_cache.content_type ).to eq json_hash[:contentType]
259
+ end
260
+
261
+ end
262
+
263
+
264
+ context "when the message body is text" do
265
+
266
+ let(:msg3_cache) do
267
+ { stompHeaders: msg_stomp.stomp_headers,
268
+ stompBody: msg_stomp.stomp_body,
269
+ verb: 'alice',
270
+ params: 'karen',
271
+ desc: 'jessica',
272
+ replyTo: '/queue/thing',
273
+ replyId: '9876',
274
+ inReplyTo: '6789',
275
+ contentType: 'application/text' }
276
+
277
+ end
278
+
279
+ let(:msg3) { Message.from_cache( msg3_cache.to_json ) }
280
+
281
+
282
+ it 'returns a Message object' do
283
+ expect( msg3 ).to be_a_kind_of Message
284
+ end
285
+
286
+ it 'sets the stomp attributes' do
287
+ heads = msg3_cache[:stompHeaders].each_with_object({}) do |(k,v),m|
288
+ m[k.to_sym] = v
289
+ end
290
+
291
+ expect( msg3.stomp_headers ).to eq heads
292
+ expect( msg3.stomp_body ).to eq msg3_cache[:stompBody]
293
+ end
294
+
295
+ it 'sets the content type' do
296
+ expect( msg3.content_type ).to eq msg3_cache[:contentType]
297
+ end
298
+
299
+ end
300
+
301
+
302
+ end
303
+ ##
304
+
305
+
306
+ describe '#parameters' do
307
+ it 'returns the same as @param' do
308
+ expect(msg_pts.parameters).to eq msg_pts.params
309
+ end
310
+ end
311
+ ##
312
+
313
+
314
+ describe '#description' do
315
+ it 'returns the same as @desc' do
316
+ expect(msg_pts.description).to eq msg_pts.desc
317
+ end
318
+ end
319
+ ##
320
+
321
+
322
+ describe '#content_is_json?' do
323
+
324
+ it 'returns true if the body is supposed to be JSON' do
325
+ expect( msg_pts.content_is_json? ).to be true
326
+ end
327
+
328
+ it 'returns false unless the body is supposed to be JSON' do
329
+ smess = stomp_message('application/text', 'foo')
330
+ mess = Message.from_stomp(smess)
331
+ expect( mess.content_is_json? ).to be false
332
+
333
+ mess = Message.from_cache( {contentType: 'dunno'}.to_json )
334
+ expect( mess.content_is_json? ).to be false
335
+
336
+ mess = Message.from_cache( {horse: 'badger'}.to_json )
337
+ expect( mess.content_is_json? ).to be false
338
+ end
339
+
340
+ end
341
+ ##
342
+
343
+
344
+ describe '#to_cache' do
345
+
346
+ it 'returns the message as a hash' do
347
+ hash = msg_pts.to_cache
348
+
349
+ expect( hash ).to be_a_kind_of Hash
350
+ expect( hash ).to include( replyTo: 'Daphne',
351
+ inReplyTo: 'Fred',
352
+ verb: 'Velma',
353
+ params: 'Shaggy',
354
+ desc: 'Scooby' )
355
+
356
+ expect( hash[:contentType] ).to match /json$/i
357
+ end
358
+
359
+ it 'always returns all the keys' do
360
+ expect( msg_stomp.to_cache.keys ).to include(*json_hash.keys)
361
+ end
362
+
363
+ it "returns a hash that Message.from_cache doesn''t freak out over" do
364
+ expect{ Message.from_cache(msg_cache.to_cache.to_json) }.
365
+ not_to raise_exception
366
+
367
+ mess = Message.from_cache(msg_cache.to_cache.to_json)
368
+ expect(mess.to_cache).to eq symbolise(json_hash)
369
+ end
370
+
371
+
372
+ end
373
+ ##
374
+
375
+
376
+ describe '#protocol_json' do
377
+ it "returns the Protocol as a JSON string" do
378
+ hash = JSON.parse( msg_pts.protocol_json, symbolize_names: true )
379
+
380
+ expect( hash ).to include(verb: 'Velma')
381
+
382
+ expect( hash ).to include(params: 'Shaggy').
383
+ or include(parameters: 'Shaggy')
384
+
385
+ expect( hash ).to include(desc: 'Scooby').
386
+ or include(description: 'Scooby')
387
+
388
+ end
389
+ end
390
+ ##
391
+
392
+
393
+ describe "#body_to_h" do
394
+
395
+ context "if the body is in JSON" do
396
+
397
+ it "returns a hash" do
398
+ x = {}
399
+ x[:stompHeaders] = {}
400
+ x[:stompBody] = @datH.to_json # JSONd twice?
401
+ x[:contentType] = "JSON"
402
+
403
+ nr = Message.from_cache(x.to_json)
404
+ expect( nr.body_to_h ).to eq @datH
405
+ end
406
+
407
+ end
408
+
409
+ context "If the body is not in JSON" do
410
+ it "returns nil" do
411
+
412
+ x = {}
413
+ x["body"] = @datS
414
+ x["content-type"] = "text"
415
+
416
+ nr = Message.from_cache(x.to_json)
417
+ expect( nr.body_to_h ).to be_nil
418
+
419
+ end
420
+ end
421
+
422
+ context "If the body is nil(!)" do
423
+ it "returns nil" do
424
+ x = {}
425
+ x["body"] = nil
426
+ x["content-type"] = "JSON"
427
+
428
+ nr = Message.from_cache(x.to_json)
429
+
430
+ expect{ nr.body_to_h }.to_not raise_exception
431
+ expect( nr.body_to_h ).to be_nil
432
+ end
433
+ end
434
+
435
+ end
436
+ ##
437
+
438
+
439
+ describe '#headers_for_stomp' do
440
+
441
+ it 'always returns a Hash' do
442
+ expect( msg_pts.headers_for_stomp ).to be_a_kind_of Hash
443
+ expect( msg_stomp.headers_for_stomp ).to be_a_kind_of Hash
444
+ expect( msg_cache.headers_for_stomp ).to be_a_kind_of Hash
445
+ end
446
+
447
+ it "returns the custom headers for the Stomp gem" do
448
+ hdrs = msg_pts.headers_for_stomp
449
+ expect( hdrs ).to include("content-type" => 'application/json')
450
+ expect( hdrs ).to include("neb-reply-id" => 42)
451
+ expect( hdrs ).to include("neb-reply-to" => 'Daphne')
452
+ expect( hdrs ).to include("neb-in-reply-to" => 'Fred')
453
+
454
+ hdrs = msg_stomp.headers_for_stomp
455
+ expect( hdrs ).to include("content-type" => 'application/text')
456
+ expect( hdrs ).to include("neb-reply-id" => nil)
457
+ end
458
+
459
+ end
460
+ ##
461
+
462
+
463
+ describe '#body_for_stomp' do
464
+
465
+ it "returns a JSON string for content type JSON" do
466
+ expect{ JSON.parse(msg_cache.body_for_stomp) }.not_to raise_exception
467
+
468
+ hash = JSON.parse(msg_cache.body_for_stomp)
469
+
470
+ expect( hash ).to include('verb' => 'tom')
471
+
472
+ expect( hash ).to include('params' => 'dick').
473
+ or include('parameters' => 'dick')
474
+
475
+ expect( hash ).to include('desc' => 'harry').
476
+ or include('description' => 'harry')
477
+
478
+ end
479
+
480
+ it "returns a header-style string for non-JSON" do
481
+ hash1 = { verb: 'tom',
482
+ params: 'dick',
483
+ desc: 'harry',
484
+ contentType: 'supposedly/boris' }
485
+
486
+ msg = Message.from_cache( hash1.to_json )
487
+
488
+ expect( msg.body_for_stomp ).to be_a_kind_of String
489
+
490
+ hash2 = msg.body_for_stomp.
491
+ split("\n").
492
+ each_with_object({}) {|e,m| k,v = e.split(/:\s*/); m[k] = v }
493
+
494
+ expect( hash2 ).to include('verb' => 'tom')
495
+
496
+ expect( hash2 ).to include('params' => 'dick').
497
+ or include('parameters' => 'dick')
498
+
499
+ expect( hash2 ).to include('desc' => 'harry').
500
+ or include('description' => 'harry')
501
+
502
+ end
503
+
504
+ end
505
+ ##
506
+
507
+
508
+ describe '#respond_success' do
509
+
510
+ it "raises an error if we have no @reply_to" do
511
+ expect{ msg_stomp.respond_success }.to raise_exception NebulousError
512
+ end
513
+
514
+ it "returns the queue to respond on" do
515
+ q,_ = msg_cache.respond_success
516
+ expect( q ).to eq '/queue/thing'
517
+ end
518
+
519
+ it "returns a new message that has the success verb" do
520
+ _,m = msg_cache.respond_success
521
+ expect( m ).to be_a_kind_of Message
522
+ expect( m.verb ).to eq 'success'
523
+ end
524
+
525
+ end
526
+ ##
527
+
528
+
529
+ describe '#respond_error' do
530
+ let(:err) { NebulousError.new("test error") }
531
+
532
+ it "raises an error if we have no @reply_to" do
533
+ expect{ msg_stomp.respond_error('foo') }.to raise_exception NebulousError
534
+ end
535
+
536
+ it "requires an error parameter" do
537
+ expect{ msg_cache.respond_error() }.to raise_exception ArgumentError
538
+ expect{ msg_cache.respond_error('foo') }.not_to raise_exception
539
+ end
540
+
541
+ it "accepts an exception object" do
542
+ expect{ msg_cache.respond_error(err) }.not_to raise_exception
543
+ end
544
+
545
+ it "accepts an optional error field" do
546
+ expect{ msg_cache.respond_error('foo', :bar) }.not_to raise_exception
547
+ end
548
+
549
+ it "returns the queue to respond on" do
550
+ q,_ = msg_cache.respond_error('foo')
551
+ expect( q ).to eq '/queue/thing'
552
+
553
+ q,_ = msg_cache.respond_error(err, :foo)
554
+ expect( q ).to eq '/queue/thing'
555
+ end
556
+
557
+ it "returns a new message with the failure verb and details" do
558
+ _,m = msg_cache.respond_error('foo')
559
+ expect( m ).to be_a_kind_of Message
560
+ expect( m.verb ).to eq 'error'
561
+ expect( m.params ).to eq []
562
+ expect( m.desc ).to eq 'foo'
563
+
564
+ _,m = msg_cache.respond_error(err, :foo)
565
+ expect( m ).to be_a_kind_of Message
566
+ expect( m.verb ).to eq 'error'
567
+ expect( m.params ).to eq "foo"
568
+ expect( m.desc ).to eq err.message
569
+ end
570
+
571
+ end
572
+ ##
573
+
574
+ end
575
+