mqtt 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1230 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'spec_helper'
4
+ require 'mqtt'
5
+
6
+ describe MQTT::Packet do
7
+
8
+ describe "when creating a new packet" do
9
+ it "should allow you to set the packet dup flag as a hash parameter" do
10
+ packet = MQTT::Packet.new( :dup => true )
11
+ packet.dup.should be_true
12
+ end
13
+
14
+ it "should allow you to set the packet QOS level as a hash parameter" do
15
+ packet = MQTT::Packet.new( :qos => 2 )
16
+ packet.qos.should == 2
17
+ end
18
+
19
+ it "should allow you to set the packet retain flag as a hash parameter" do
20
+ packet = MQTT::Packet.new( :retain => true )
21
+ packet.retain.should be_true
22
+ end
23
+ end
24
+
25
+ describe "when setting packet parameters" do
26
+ before(:each) do
27
+ @packet = MQTT::Packet.new(
28
+ :dup => false,
29
+ :qos => 0,
30
+ :retain => false
31
+ )
32
+ end
33
+
34
+ it "should have a type_id method to get the integer ID of the packet type" do
35
+ @packet = MQTT::Packet::Pingreq.new
36
+ @packet.type_id.should == 12
37
+ end
38
+
39
+ it "should let you change the dup flag of a packet" do
40
+ @packet.dup = true
41
+ @packet.dup.should be_true
42
+ end
43
+
44
+ it "should let you change the dup flag of a packet using an integer" do
45
+ @packet.dup = 1
46
+ @packet.dup.should be_true
47
+ end
48
+
49
+ it "should let you change the retain flag of a packet" do
50
+ @packet.retain = true
51
+ @packet.retain.should be_true
52
+ end
53
+
54
+ it "should let you change the retain flag of a packet using an integer" do
55
+ @packet.retain = 1
56
+ @packet.retain.should be_true
57
+ end
58
+ end
59
+
60
+ it "should let you attributes using the update_attributes method" do
61
+ @packet = MQTT::Packet.new(:qos => 1)
62
+ @packet.update_attributes(:qos => 2)
63
+ @packet.qos.should == 2
64
+ end
65
+
66
+ describe "protected methods" do
67
+ before(:each) do
68
+ @packet = MQTT::Packet.new
69
+ end
70
+
71
+ it "should provide a encode_bytes method to get some bytes as Integers" do
72
+ data = @packet.send(:encode_bytes, 0x48, 0x65, 0x6c, 0x6c, ?o)
73
+ data.should == 'Hello'
74
+ end
75
+
76
+ it "should provide a add_short method to get a big-endian unsigned 16-bit integer" do
77
+ data = @packet.send(:encode_short, 1024)
78
+ data.should == "\x04\x00"
79
+ end
80
+
81
+ it "should provide a add_string method to get a string preceeded by its length" do
82
+ data = @packet.send(:encode_string, 'quack')
83
+ data.should == "\x00\x05quack"
84
+ end
85
+
86
+ it "should provide a shift_short method to get a 16-bit unsigned integer" do
87
+ buffer = "\x22\x8Bblahblah"
88
+ @packet.send(:shift_short,buffer).should == 8843
89
+ buffer.should == 'blahblah'
90
+ end
91
+
92
+ it "should provide a shift_byte method to get one byte as integers" do
93
+ buffer = "\x01blahblah"
94
+ @packet.send(:shift_byte,buffer).should == 1
95
+ buffer.should == 'blahblah'
96
+ end
97
+
98
+ it "should provide a shift_string method to get a string preceeded by its length" do
99
+ buffer = "\x00\x05Hello World"
100
+ @packet.send(:shift_string,buffer).should == "Hello"
101
+ buffer.should == ' World'
102
+ end
103
+ end
104
+ end
105
+
106
+ describe MQTT::Packet::Publish do
107
+ describe "when serialising a packet" do
108
+ it "should output the correct bytes for a packet with default QOS and no flags" do
109
+ packet = MQTT::Packet::Publish.new( :topic => 'test', :payload => 'hello world' )
110
+ packet.to_s.should == "\x30\x11\x00\x04testhello world"
111
+ end
112
+
113
+ it "should output the correct bytes for a packet with QOS 1 and no flags" do
114
+ packet = MQTT::Packet::Publish.new( :qos => 1, :message_id => 5, :topic => 'a/b', :payload => 'hello world' )
115
+ packet.to_s.should == "\x32\x12\x00\x03a/b\x00\x05hello world"
116
+ end
117
+
118
+ it "should output the correct bytes for a packet with QOS 2 and retain flag set" do
119
+ packet = MQTT::Packet::Publish.new( :qos => 2, :retain => true, :message_id => 5, :topic => 'c/d', :payload => 'hello world' )
120
+ packet.to_s.should == "\x35\x12\x00\x03c/d\x00\x05hello world"
121
+ end
122
+
123
+ it "should output the correct bytes for a packet with QOS 2 and dup flag set" do
124
+ packet = MQTT::Packet::Publish.new( :qos => 2, :dup => true, :message_id => 5, :topic => 'c/d', :payload => 'hello world' )
125
+ packet.to_s.should == "\x3C\x12\x00\x03c/d\x00\x05hello world"
126
+ end
127
+
128
+ it "should throw an exception when there is no topic name" do
129
+ lambda {
130
+ MQTT::Packet::Publish.new.to_s
131
+ }.should raise_error(
132
+ 'Invalid topic name when serialising packet'
133
+ )
134
+ end
135
+ end
136
+
137
+ describe "when parsing a packet with QOS 0" do
138
+ before(:each) do
139
+ @packet = MQTT::Packet.parse( "\x30\x11\x00\x04testhello world" )
140
+ end
141
+
142
+ it "should correctly create the right type of packet object" do
143
+ @packet.class.should == MQTT::Packet::Publish
144
+ end
145
+
146
+ it "should set the QOS level correctly" do
147
+ @packet.qos.should == 0
148
+ end
149
+
150
+ it "should set the RETAIN flag correctly" do
151
+ @packet.retain.should be_false
152
+ end
153
+
154
+ it "should set the DUP flag correctly" do
155
+ @packet.dup.should be_false
156
+ end
157
+
158
+ it "should set the topic name correctly" do
159
+ @packet.topic.should == 'test'
160
+ end
161
+
162
+ it "should set the payload correctly" do
163
+ @packet.payload.should == 'hello world'
164
+ end
165
+ end
166
+
167
+ describe "when parsing a packet with QOS 2 and retain and dup flags set" do
168
+ before(:each) do
169
+ @packet = MQTT::Packet.parse( "\x3D\x12\x00\x03c/d\x00\x05hello world" )
170
+ end
171
+
172
+ it "should correctly create the right type of packet object" do
173
+ @packet.class.should == MQTT::Packet::Publish
174
+ end
175
+
176
+ it "should set the QOS level correctly" do
177
+ @packet.qos.should == 2
178
+ end
179
+
180
+ it "should set the RETAIN flag correctly" do
181
+ @packet.retain.should be_true
182
+ end
183
+
184
+ it "should set the DUP flag correctly" do
185
+ @packet.dup.should be_true
186
+ end
187
+
188
+ it "should set the topic name correctly" do
189
+ @packet.topic.should == 'c/d'
190
+ end
191
+
192
+ it "should set the payload correctly" do
193
+ @packet.payload.should == 'hello world'
194
+ end
195
+ end
196
+
197
+ describe "when parsing a packet with a body of 314 bytes" do
198
+ before(:each) do
199
+ # 0x30 = publish
200
+ # 0xC1 = (65 * 1)
201
+ # 0x02 = (2 * 128)
202
+ @packet = MQTT::Packet.parse( "\x30\xC1\x02\x00\x05topic" + ('x' * 314) )
203
+ end
204
+
205
+ it "should parse the packet type correctly" do
206
+ @packet.class.should == MQTT::Packet::Publish
207
+ end
208
+
209
+ it "should get the topic name correctly" do
210
+ @packet.topic.should == 'topic'
211
+ end
212
+
213
+ it "should get the body length correctly" do
214
+ @packet.payload.size.should == 314
215
+ end
216
+ end
217
+
218
+ describe "when parsing a packet with a body of 16kbytes" do
219
+ before(:each) do
220
+ # 0x30 = publish
221
+ # 0x87 = (7 * 1)
222
+ # 0x80 = (0 * 128)
223
+ # 0x01 = (1 * 16384)
224
+ @packet = MQTT::Packet.parse( "\x30\x87\x80\x01\x00\x05topic" + ('x'*16384) )
225
+ end
226
+
227
+ it "should parse the packet type correctly" do
228
+ @packet.class.should == MQTT::Packet::Publish
229
+ end
230
+
231
+ it "should get the topic name correctly" do
232
+ @packet.topic.should == 'topic'
233
+ end
234
+
235
+ it "should get the body length correctly" do
236
+ @packet.payload.size.should == 16384
237
+ end
238
+ end
239
+
240
+ end
241
+
242
+ describe MQTT::Packet::Connect do
243
+ describe "when serialising a packet" do
244
+ it "should output the correct bytes for a packet with no flags" do
245
+ packet = MQTT::Packet::Connect.new( :client_id => 'myclient' )
246
+ packet.to_s.should == "\020\026\x00\x06MQIsdp\x03\x02\x00\x0a\x00\x08myclient"
247
+ end
248
+
249
+ it "should output the correct bytes for a packet with clean session turned off" do
250
+ packet = MQTT::Packet::Connect.new(
251
+ :client_id => 'myclient',
252
+ :clean_session => false
253
+ )
254
+ packet.to_s.should == "\020\026\x00\x06MQIsdp\x03\x00\x00\x0a\x00\x08myclient"
255
+ end
256
+
257
+ it "should throw an exception when there is no client identifier" do
258
+ lambda {
259
+ MQTT::Packet::Connect.new.to_s
260
+ }.should raise_error(
261
+ 'Invalid client identifier when serialising packet'
262
+ )
263
+ end
264
+
265
+ it "should output the correct bytes for a packet with a Will" do
266
+ packet = MQTT::Packet::Connect.new(
267
+ :client_id => 'myclient',
268
+ :clean_session => true,
269
+ :will_qos => 1,
270
+ :will_retain => false,
271
+ :will_topic => 'topic',
272
+ :will_payload => 'hello'
273
+ )
274
+ packet.to_s.should ==
275
+ "\x10\x24"+
276
+ "\x00\x06MQIsdp"+
277
+ "\x03\x0e\x00\x0a"+
278
+ "\x00\x08myclient"+
279
+ "\x00\x05topic\x00\x05hello"
280
+ end
281
+
282
+ it "should output the correct bytes for a packet with a username and password" do
283
+ packet = MQTT::Packet::Connect.new(
284
+ :client_id => 'myclient',
285
+ :username => 'username',
286
+ :password => 'password'
287
+ )
288
+ packet.to_s.should ==
289
+ "\x10\x2A"+
290
+ "\x00\x06MQIsdp"+
291
+ "\x03\xC2\x00\x0a\x00"+
292
+ "\x08myclient"+
293
+ "\x00\x08username"+
294
+ "\x00\x08password"
295
+ end
296
+
297
+ it "should output the correct bytes for a packet with everything" do
298
+ packet = MQTT::Packet::Connect.new(
299
+ :client_id => '12345678901234567890123',
300
+ :clean_session => true,
301
+ :keep_alive => 65535,
302
+ :will_qos => 2,
303
+ :will_retain => true,
304
+ :will_topic => 'will_topic',
305
+ :will_payload => 'will_message',
306
+ :username => 'user0123456789',
307
+ :password => 'pass0123456789'
308
+ )
309
+ packet.to_s.should ==
310
+ "\x10\x5F"+ # fixed header (2)
311
+ "\x00\x06MQIsdp"+ # protocol name (8)
312
+ "\x03\xf6"+ # protocol version + flags (2)
313
+ "\xff\xff"+ # keep alive (2)
314
+ "\x00\x1712345678901234567890123"+ # client identifier (25)
315
+ "\x00\x0Awill_topic"+ # will topic (12)
316
+ "\x00\x0Cwill_message"+ # will message (14)
317
+ "\x00\x0Euser0123456789"+ # username (16)
318
+ "\x00\x0Epass0123456789" # password (16)
319
+ end
320
+
321
+ end
322
+
323
+ describe "when parsing a simple Connect packet" do
324
+ before(:each) do
325
+ @packet = MQTT::Packet.parse(
326
+ "\x10\x16\x00\x06MQIsdp\x03\x00\x00\x0a\x00\x08myclient"
327
+ )
328
+ end
329
+
330
+ it "should correctly create the right type of packet object" do
331
+ @packet.class.should == MQTT::Packet::Connect
332
+ end
333
+
334
+ it "should set the QOS of the packet correctly" do
335
+ @packet.qos.should == 0
336
+ end
337
+
338
+ it "should set the Protocol Name of the packet correctly" do
339
+ @packet.protocol_name.should == 'MQIsdp'
340
+ end
341
+
342
+ it "should set the Protocol Version of the packet correctly" do
343
+ @packet.protocol_version.should == 3
344
+ end
345
+
346
+ it "should set the Client Identifier of the packet correctly" do
347
+ @packet.client_id.should == 'myclient'
348
+ end
349
+
350
+ it "should set the Keep Alive timer of the packet correctly" do
351
+ @packet.keep_alive.should == 10
352
+ end
353
+
354
+ it "should set not have the clean session flag set" do
355
+ @packet.clean_session.should be_false
356
+ end
357
+
358
+ it "should set the the username field of the packet to nil" do
359
+ @packet.username.should be_nil
360
+ end
361
+
362
+ it "should set the the password field of the packet to nil" do
363
+ @packet.password.should be_nil
364
+ end
365
+ end
366
+
367
+ describe "when parsing a Connect packet with the clean session flag set" do
368
+ before(:each) do
369
+ @packet = MQTT::Packet.parse(
370
+ "\x10\x16\x00\x06MQIsdp\x03\x02\x00\x0a\x00\x08myclient"
371
+ )
372
+ end
373
+
374
+ it "should set the clean session flag" do
375
+ @packet.clean_session.should be_true
376
+ end
377
+ end
378
+
379
+ describe "when parsing a Connect packet with a Will and Testament" do
380
+ before(:each) do
381
+ @packet = MQTT::Packet.parse(
382
+ "\x10\x24\x00\x06MQIsdp\x03\x0e\x00\x0a\x00\x08myclient\x00\x05topic\x00\x05hello"
383
+ )
384
+ end
385
+
386
+ it "should correctly create the right type of packet object" do
387
+ @packet.class.should == MQTT::Packet::Connect
388
+ end
389
+
390
+ it "should set the QOS of the packet correctly" do
391
+ @packet.qos.should == 0
392
+ end
393
+
394
+ it "should set the Protocol Name of the packet correctly" do
395
+ @packet.protocol_name.should == 'MQIsdp'
396
+ end
397
+
398
+ it "should set the Protocol Version of the packet correctly" do
399
+ @packet.protocol_version.should == 3
400
+ end
401
+
402
+ it "should set the Client Identifier of the packet correctly" do
403
+ @packet.client_id.should == 'myclient'
404
+ end
405
+
406
+ it "should set the clean session flag should be set" do
407
+ @packet.clean_session.should be_true
408
+ end
409
+
410
+ it "should set the QOS of the Will should be 1" do
411
+ @packet.will_qos.should == 1
412
+ end
413
+
414
+ it "should set the Will retain flag should be false" do
415
+ @packet.will_retain.should be_false
416
+ end
417
+
418
+ it "should set the Will topic of the packet correctly" do
419
+ @packet.will_topic.should == 'topic'
420
+ end
421
+
422
+ it "should set the Will payload of the packet correctly" do
423
+ @packet.will_payload.should == 'hello'
424
+ end
425
+ end
426
+
427
+ describe "when parsing a Connect packet with a username and password" do
428
+ before(:each) do
429
+ @packet = MQTT::Packet.parse(
430
+ "\x10\x2A"+
431
+ "\x00\x06MQIsdp"+
432
+ "\x03\xC0\x00\x0a\x00"+
433
+ "\x08myclient"+
434
+ "\x00\x08username"+
435
+ "\x00\x08password"
436
+ )
437
+ end
438
+
439
+ it "should correctly create the right type of packet object" do
440
+ @packet.class.should == MQTT::Packet::Connect
441
+ end
442
+
443
+ it "should set the QOS of the packet correctly" do
444
+ @packet.qos.should == 0
445
+ end
446
+
447
+ it "should set the Protocol Name of the packet correctly" do
448
+ @packet.protocol_name.should == 'MQIsdp'
449
+ end
450
+
451
+ it "should set the Protocol Version of the packet correctly" do
452
+ @packet.protocol_version.should == 3
453
+ end
454
+
455
+ it "should set the Client Identifier of the packet correctly" do
456
+ @packet.client_id.should == 'myclient'
457
+ end
458
+
459
+ it "should set the Keep Alive Timer of the packet correctly" do
460
+ @packet.keep_alive.should == 10
461
+ end
462
+
463
+ it "should set the Username of the packet correctly" do
464
+ @packet.username.should == 'username'
465
+ end
466
+
467
+ it "should set the Username of the packet correctly" do
468
+ @packet.password.should == 'password'
469
+ end
470
+ end
471
+
472
+ describe "when parsing a Connect that has a username but no password" do
473
+ before(:each) do
474
+ @packet = MQTT::Packet.parse(
475
+ "\x10\x20\x00\x06MQIsdp\x03\x80\x00\x0a\x00\x08myclient\x00\x08username"
476
+ )
477
+ end
478
+
479
+ it "should set the Username of the packet correctly" do
480
+ @packet.username.should == 'username'
481
+ end
482
+
483
+ it "should set the Username of the packet correctly" do
484
+ @packet.password.should be_nil
485
+ end
486
+ end
487
+
488
+ describe "when parsing a Connect that has a password but no username" do
489
+ before(:each) do
490
+ @packet = MQTT::Packet.parse(
491
+ "\x10\x20\x00\x06MQIsdp\x03\x40\x00\x0a\x00\x08myclient\x00\x08password"
492
+ )
493
+ end
494
+
495
+ it "should set the Username of the packet correctly" do
496
+ @packet.username.should be_nil
497
+ end
498
+
499
+ it "should set the Username of the packet correctly" do
500
+ @packet.password.should == 'password'
501
+ end
502
+ end
503
+
504
+ describe "when parsing a Connect packet has the username and password flags set but doesn't have the fields" do
505
+ before(:each) do
506
+ @packet = MQTT::Packet.parse(
507
+ "\x10\x16\x00\x06MQIsdp\x03\xC0\x00\x0a\x00\x08myclient"
508
+ )
509
+ end
510
+
511
+ it "should set the Username of the packet correctly" do
512
+ @packet.username.should be_nil
513
+ end
514
+
515
+ it "should set the Username of the packet correctly" do
516
+ @packet.password.should be_nil
517
+ end
518
+ end
519
+
520
+ describe "when parsing a Connect packet with every option set" do
521
+ before(:each) do
522
+ @packet = MQTT::Packet.parse(
523
+ "\x10\x5F"+ # fixed header (2)
524
+ "\x00\x06MQIsdp"+ # protocol name (8)
525
+ "\x03\xf6"+ # protocol version + flags (2)
526
+ "\xff\xff"+ # keep alive (2)
527
+ "\x00\x1712345678901234567890123"+ # client identifier (25)
528
+ "\x00\x0Awill_topic"+ # will topic (12)
529
+ "\x00\x0Cwill_message"+ # will message (14)
530
+ "\x00\x0Euser0123456789"+ # username (16)
531
+ "\x00\x0Epass0123456789" # password (16)
532
+ )
533
+ end
534
+
535
+ it "should correctly create the right type of packet object" do
536
+ @packet.class.should == MQTT::Packet::Connect
537
+ end
538
+
539
+ it "should set the QOS of the packet correctly" do
540
+ @packet.qos.should == 0
541
+ end
542
+
543
+ it "should set the Protocol Name of the packet correctly" do
544
+ @packet.protocol_name.should == 'MQIsdp'
545
+ end
546
+
547
+ it "should set the Protocol Version of the packet correctly" do
548
+ @packet.protocol_version.should == 3
549
+ end
550
+
551
+ it "should set the Keep Alive Timer of the packet correctly" do
552
+ @packet.keep_alive.should == 65535
553
+ end
554
+
555
+ it "should set the Client Identifier of the packet correctly" do
556
+ @packet.client_id.should == '12345678901234567890123'
557
+ end
558
+
559
+ it "should set the Will QoS of the packet correctly" do
560
+ @packet.will_qos.should == 2
561
+ end
562
+
563
+ it "should set the Will retain flag of the packet correctly" do
564
+ @packet.will_retain.should be_true
565
+ end
566
+
567
+ it "should set the Will topic of the packet correctly" do
568
+ @packet.will_topic.should == 'will_topic'
569
+ end
570
+
571
+ it "should set the Will payload of the packet correctly" do
572
+ @packet.will_payload.should == 'will_message'
573
+ end
574
+
575
+ it "should set the Username of the packet correctly" do
576
+ @packet.username.should == 'user0123456789'
577
+ end
578
+
579
+ it "should set the Username of the packet correctly" do
580
+ @packet.password.should == 'pass0123456789'
581
+ end
582
+ end
583
+
584
+ end
585
+
586
+ describe MQTT::Packet::Connack do
587
+ describe "when serialising a packet" do
588
+ it "should output the correct bytes for a sucessful connection acknowledgement packet" do
589
+ packet = MQTT::Packet::Connack.new( :return_code => 0x00 )
590
+ packet.to_s.should == "\x20\x02\x00\x00"
591
+ end
592
+ end
593
+
594
+ describe "when parsing a successful Connection Accepted packet" do
595
+ before(:each) do
596
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x00" )
597
+ end
598
+
599
+ it "should correctly create the right type of packet object" do
600
+ @packet.class.should == MQTT::Packet::Connack
601
+ end
602
+
603
+ it "should set the QOS of the packet correctly" do
604
+ @packet.qos.should == 0
605
+ end
606
+
607
+ it "should set the return code of the packet correctly" do
608
+ @packet.return_code.should == 0x00
609
+ end
610
+
611
+ it "should set the return message of the packet correctly" do
612
+ @packet.return_msg.should match(/Connection Accepted/i)
613
+ end
614
+ end
615
+
616
+ describe "when parsing a unacceptable protocol version packet" do
617
+ before(:each) do
618
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x01" )
619
+ end
620
+
621
+ it "should correctly create the right type of packet object" do
622
+ @packet.class.should == MQTT::Packet::Connack
623
+ end
624
+
625
+ it "should set the return code of the packet correctly" do
626
+ @packet.return_code.should == 0x01
627
+ end
628
+
629
+ it "should set the return message of the packet correctly" do
630
+ @packet.return_msg.should match(/unacceptable protocol version/i)
631
+ end
632
+ end
633
+
634
+ describe "when parsing a client identifier rejected packet" do
635
+ before(:each) do
636
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x02" )
637
+ end
638
+
639
+ it "should correctly create the right type of packet object" do
640
+ @packet.class.should == MQTT::Packet::Connack
641
+ end
642
+
643
+ it "should set the return code of the packet correctly" do
644
+ @packet.return_code.should == 0x02
645
+ end
646
+
647
+ it "should set the return message of the packet correctly" do
648
+ @packet.return_msg.should match(/client identifier rejected/i)
649
+ end
650
+ end
651
+
652
+ describe "when parsing a broker unavailable packet" do
653
+ before(:each) do
654
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x03" )
655
+ end
656
+
657
+ it "should correctly create the right type of packet object" do
658
+ @packet.class.should == MQTT::Packet::Connack
659
+ end
660
+
661
+ it "should set the return code of the packet correctly" do
662
+ @packet.return_code.should == 0x03
663
+ end
664
+
665
+ it "should set the return message of the packet correctly" do
666
+ @packet.return_msg.should match(/broker unavailable/i)
667
+ end
668
+ end
669
+
670
+ describe "when parsing a broker unavailable packet" do
671
+ before(:each) do
672
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x04" )
673
+ end
674
+
675
+ it "should correctly create the right type of packet object" do
676
+ @packet.class.should == MQTT::Packet::Connack
677
+ end
678
+
679
+ it "should set the return code of the packet correctly" do
680
+ @packet.return_code.should == 0x04
681
+ end
682
+
683
+ it "should set the return message of the packet correctly" do
684
+ @packet.return_msg.should match(/bad user name or password/i)
685
+ end
686
+ end
687
+
688
+ describe "when parsing a broker unavailable packet" do
689
+ before(:each) do
690
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x05" )
691
+ end
692
+
693
+ it "should correctly create the right type of packet object" do
694
+ @packet.class.should == MQTT::Packet::Connack
695
+ end
696
+
697
+ it "should set the return code of the packet correctly" do
698
+ @packet.return_code.should == 0x05
699
+ end
700
+
701
+ it "should set the return message of the packet correctly" do
702
+ @packet.return_msg.should match(/not authorised/i)
703
+ end
704
+ end
705
+
706
+ describe "when parsing an unknown connection refused packet" do
707
+ before(:each) do
708
+ @packet = MQTT::Packet.parse( "\x20\x02\x00\x10" )
709
+ end
710
+
711
+ it "should correctly create the right type of packet object" do
712
+ @packet.class.should == MQTT::Packet::Connack
713
+ end
714
+
715
+ it "should set the return code of the packet correctly" do
716
+ @packet.return_code.should == 0x10
717
+ end
718
+
719
+ it "should set the return message of the packet correctly" do
720
+ @packet.return_msg.should match(/Connection refused: error code 16/i)
721
+ end
722
+ end
723
+
724
+ describe "when parsing packet with extra bytes on the end" do
725
+ it "should throw an exception" do
726
+ lambda {
727
+ @packet = MQTT::Packet.parse( "\x20\x03\x00\x00\x00" )
728
+ }.should raise_error(
729
+ MQTT::ProtocolException,
730
+ "Extra bytes at end of Connect Acknowledgment packet"
731
+ )
732
+ end
733
+ end
734
+ end
735
+
736
+ describe MQTT::Packet::Puback do
737
+ describe "when serialising a packet" do
738
+ it "should output the correct bytes for a packet with no flags" do
739
+ packet = MQTT::Packet::Puback.new( :message_id => 0x1234 )
740
+ packet.to_s.should == "\x40\x02\x12\x34"
741
+ end
742
+ end
743
+
744
+ describe "when parsing a packet" do
745
+ before(:each) do
746
+ @packet = MQTT::Packet.parse( "\x40\x02\x12\x34" )
747
+ end
748
+
749
+ it "should correctly create the right type of packet object" do
750
+ @packet.class.should == MQTT::Packet::Puback
751
+ end
752
+
753
+ it "should set the message id of the packet correctly" do
754
+ @packet.message_id.should == 0x1234
755
+ end
756
+ end
757
+
758
+ describe "when parsing packet with extra bytes on the end" do
759
+ it "should throw an exception" do
760
+ lambda {
761
+ @packet = MQTT::Packet.parse( "\x40\x03\x12\x34\x00" )
762
+ }.should raise_error(
763
+ MQTT::ProtocolException,
764
+ "Extra bytes at end of Publish Acknowledgment packet"
765
+ )
766
+ end
767
+ end
768
+ end
769
+
770
+ describe MQTT::Packet::Pubrec do
771
+ describe "when serialising a packet" do
772
+ it "should output the correct bytes for a packet with no flags" do
773
+ packet = MQTT::Packet::Pubrec.new( :message_id => 0x1234 )
774
+ packet.to_s.should == "\x50\x02\x12\x34"
775
+ end
776
+ end
777
+
778
+ describe "when parsing a packet" do
779
+ before(:each) do
780
+ @packet = MQTT::Packet.parse( "\x50\x02\x12\x34" )
781
+ end
782
+
783
+ it "should correctly create the right type of packet object" do
784
+ @packet.class.should == MQTT::Packet::Pubrec
785
+ end
786
+
787
+ it "should set the message id of the packet correctly" do
788
+ @packet.message_id.should == 0x1234
789
+ end
790
+ end
791
+
792
+ describe "when parsing packet with extra bytes on the end" do
793
+ it "should throw an exception" do
794
+ lambda {
795
+ @packet = MQTT::Packet.parse( "\x50\x03\x12\x34\x00" )
796
+ }.should raise_error(
797
+ MQTT::ProtocolException,
798
+ "Extra bytes at end of Publish Received packet"
799
+ )
800
+ end
801
+ end
802
+ end
803
+
804
+ describe MQTT::Packet::Pubrel do
805
+ describe "when serialising a packet" do
806
+ it "should output the correct bytes for a packet with no flags" do
807
+ packet = MQTT::Packet::Pubrel.new( :message_id => 0x1234 )
808
+ packet.to_s.should == "\x60\x02\x12\x34"
809
+ end
810
+ end
811
+
812
+ describe "when parsing a packet" do
813
+ before(:each) do
814
+ @packet = MQTT::Packet.parse( "\x60\x02\x12\x34" )
815
+ end
816
+
817
+ it "should correctly create the right type of packet object" do
818
+ @packet.class.should == MQTT::Packet::Pubrel
819
+ end
820
+
821
+ it "should set the message id of the packet correctly" do
822
+ @packet.message_id.should == 0x1234
823
+ end
824
+ end
825
+
826
+ describe "when parsing packet with extra bytes on the end" do
827
+ it "should throw an exception" do
828
+ lambda {
829
+ @packet = MQTT::Packet.parse( "\x60\x03\x12\x34\x00" )
830
+ }.should raise_error(
831
+ MQTT::ProtocolException,
832
+ "Extra bytes at end of Publish Release packet"
833
+ )
834
+ end
835
+ end
836
+ end
837
+
838
+ describe MQTT::Packet::Pubcomp do
839
+ describe "when serialising a packet" do
840
+ it "should output the correct bytes for a packet with no flags" do
841
+ packet = MQTT::Packet::Pubcomp.new( :message_id => 0x1234 )
842
+ packet.to_s.should == "\x70\x02\x12\x34"
843
+ end
844
+ end
845
+
846
+ describe "when parsing a packet" do
847
+ before(:each) do
848
+ @packet = MQTT::Packet.parse( "\x70\x02\x12\x34" )
849
+ end
850
+
851
+ it "should correctly create the right type of packet object" do
852
+ @packet.class.should == MQTT::Packet::Pubcomp
853
+ end
854
+
855
+ it "should set the message id of the packet correctly" do
856
+ @packet.message_id.should == 0x1234
857
+ end
858
+ end
859
+
860
+ describe "when parsing packet with extra bytes on the end" do
861
+ it "should throw an exception" do
862
+ lambda {
863
+ @packet = MQTT::Packet.parse( "\x70\x03\x12\x34\x00" )
864
+ }.should raise_error(
865
+ MQTT::ProtocolException,
866
+ "Extra bytes at end of Publish Complete packet"
867
+ )
868
+ end
869
+ end
870
+ end
871
+
872
+ describe MQTT::Packet::Subscribe do
873
+ describe "setting the packet's topics" do
874
+ before(:each) do
875
+ @packet = MQTT::Packet::Subscribe.new
876
+ end
877
+
878
+ it "should be able to set the topics from a String 'a/b'" do
879
+ @packet.topics = 'a/b'
880
+ @packet.topics.should == [["a/b", 0]]
881
+ end
882
+
883
+ it "should be able to set the multiple topics from an array ['a/b', 'b/c']" do
884
+ @packet.topics = ['a/b', 'b/c']
885
+ @packet.topics.should == [["a/b", 0], ['b/c', 0]]
886
+ end
887
+
888
+ it "should be able to set the topics from a Hash {'a/b' => 0, 'b/c' => 1}" do
889
+ @packet.topics = {'a/b' => 0, 'b/c' => 1}
890
+ @packet.topics.should == [["a/b", 0], ["b/c", 1]]
891
+ end
892
+
893
+ it "should be able to set the topics from a single level array ['a/b', 0]" do
894
+ @packet.topics = ['a/b', 0]
895
+ @packet.topics.should == [["a/b", 0]]
896
+ end
897
+
898
+ it "should be able to set the topics from a two level array [['a/b' => 0], ['b/c' => 1]]" do
899
+ @packet.topics = [['a/b', 0], ['b/c', 1]]
900
+ @packet.topics.should == [['a/b', 0], ['b/c', 1]]
901
+ end
902
+
903
+ it "should throw an exception when setting topic with a non-string" do
904
+ lambda {
905
+ @packet.topics = 56
906
+ }.should raise_error(
907
+ 'Invalid topics input: 56'
908
+ )
909
+ end
910
+ end
911
+
912
+ describe "when serialising a packet" do
913
+ it "should output the correct bytes for a packet with a single topic" do
914
+ packet = MQTT::Packet::Subscribe.new( :topics => 'a/b', :message_id => 1 )
915
+ packet.to_s.should == "\x82\x08\x00\x01\x00\x03a/b\x00"
916
+ end
917
+
918
+ it "should output the correct bytes for a packet with multiple topics" do
919
+ packet = MQTT::Packet::Subscribe.new( :topics => [['a/b', 0], ['c/d', 1]], :message_id => 6 )
920
+ packet.to_s.should == "\x82\x0e\000\x06\x00\x03a/b\x00\x00\x03c/d\x01"
921
+ end
922
+
923
+ it "should throw an exception when no topics are given" do
924
+ lambda {
925
+ MQTT::Packet::Subscribe.new.to_s
926
+ }.should raise_error(
927
+ 'no topics given when serialising packet'
928
+ )
929
+ end
930
+ end
931
+
932
+ describe "when parsing a packet with a single topic" do
933
+ before(:each) do
934
+ @packet = MQTT::Packet.parse( "\x82\x08\x00\x01\x00\x03a/b\x00" )
935
+ end
936
+
937
+ it "should correctly create the right type of packet object" do
938
+ @packet.class.should == MQTT::Packet::Subscribe
939
+ end
940
+
941
+ it "should set the QOS level correctly" do
942
+ @packet.qos.should == 1
943
+ end
944
+
945
+ it "should set the Message ID correctly" do
946
+ @packet.message_id.should == 1
947
+ end
948
+
949
+ it "should set the topic name correctly" do
950
+ @packet.topics.should == [['a/b',0]]
951
+ end
952
+ end
953
+
954
+ describe "when parsing a packet with a two topics" do
955
+ before(:each) do
956
+ @packet = MQTT::Packet.parse( "\x82\x0e\000\x06\x00\x03a/b\x00\x00\x03c/d\x01" )
957
+ end
958
+
959
+ it "should correctly create the right type of packet object" do
960
+ @packet.class.should == MQTT::Packet::Subscribe
961
+ end
962
+
963
+ it "should set the QOS level correctly" do
964
+ @packet.qos.should == 1
965
+ end
966
+
967
+ it "should set the Message ID correctly" do
968
+ @packet.message_id.should == 6
969
+ end
970
+
971
+ it "should set the topic name correctly" do
972
+ @packet.topics.should == [['a/b',0],['c/d',1]]
973
+ end
974
+ end
975
+ end
976
+
977
+ describe MQTT::Packet::Suback do
978
+ describe "when serialising a packet" do
979
+ it "should output the correct bytes for an acknowledgement to a single topic" do
980
+ packet = MQTT::Packet::Suback.new( :granted_qos => [0,1], :message_id => 5 )
981
+ packet.to_s.should == "\x90\x04\x00\x05\x00\x01"
982
+ end
983
+
984
+ it "should output the correct bytes for an acknowledgement to a two topics" do
985
+ packet = MQTT::Packet::Suback.new( :granted_qos => [[0,0],[1,0]], :message_id => 6 )
986
+ packet.to_s.should == "\x90\x06\x00\x06\x00\x00\x01\x00"
987
+ end
988
+
989
+ it "should throw an exception when no granted QOSs are given" do
990
+ lambda {
991
+ MQTT::Packet::Suback.new(:message_id => 7).to_s
992
+ }.should raise_error(
993
+ 'no granted QOS given when serialising packet'
994
+ )
995
+ end
996
+
997
+ it "should throw an exception if the granted QOSs are not an array" do
998
+ lambda {
999
+ MQTT::Packet::Suback.new(:message_id => 8, :granted_qos => :foo).to_s
1000
+ }.should raise_error(
1001
+ 'granted QOS should be an array of arrays'
1002
+ )
1003
+ end
1004
+ end
1005
+
1006
+ describe "when parsing a packet" do
1007
+ before(:each) do
1008
+ @packet = MQTT::Packet.parse( "\x90\x04\x12\x34\x01\x01" )
1009
+ end
1010
+
1011
+ it "should correctly create the right type of packet object" do
1012
+ @packet.class.should == MQTT::Packet::Suback
1013
+ end
1014
+
1015
+ it "should set the message id of the packet correctly" do
1016
+ @packet.message_id.should == 0x1234
1017
+ end
1018
+
1019
+ it "should set the Granted QOS of the packet correctly" do
1020
+ @packet.granted_qos.should == [[1,1]]
1021
+ end
1022
+ end
1023
+ end
1024
+
1025
+ describe MQTT::Packet::Unsubscribe do
1026
+ describe "when serialising a packet" do
1027
+ it "should output the correct bytes for a packet with single topic" do
1028
+ packet = MQTT::Packet::Unsubscribe.new( :topics => 'a/b', :message_id => 5 )
1029
+ packet.to_s.should == "\xa2\x07\x00\x05\x00\x03a/b"
1030
+ end
1031
+
1032
+ it "should output the correct bytes for a packet with multiple topics" do
1033
+ packet = MQTT::Packet::Unsubscribe.new( :topics => ['a/b','c/d'], :message_id => 6 )
1034
+ packet.to_s.should == "\xa2\x0c\000\006\000\003a/b\000\003c/d"
1035
+ end
1036
+
1037
+ it "should throw an exception when no topics are given" do
1038
+ lambda {
1039
+ MQTT::Packet::Unsubscribe.new.to_s
1040
+ }.should raise_error(
1041
+ 'no topics given when serialising packet'
1042
+ )
1043
+ end
1044
+ end
1045
+
1046
+ describe "when parsing a packet" do
1047
+ before(:each) do
1048
+ @packet = MQTT::Packet.parse( "\xa2\f\000\005\000\003a/b\000\003c/d" )
1049
+ end
1050
+
1051
+ it "should correctly create the right type of packet object" do
1052
+ @packet.class.should == MQTT::Packet::Unsubscribe
1053
+ end
1054
+
1055
+ it "should set the QOS level correctly" do
1056
+ @packet.qos.should == 1
1057
+ end
1058
+
1059
+ it "should set the topic name correctly" do
1060
+ @packet.topics.should == ['a/b','c/d']
1061
+ end
1062
+ end
1063
+ end
1064
+
1065
+ describe MQTT::Packet::Unsuback do
1066
+ describe "when serialising a packet" do
1067
+ it "should output the correct bytes for a packet with no flags" do
1068
+ packet = MQTT::Packet::Unsuback.new( :message_id => 0x1234 )
1069
+ packet.to_s.should == "\xB0\x02\x12\x34"
1070
+ end
1071
+ end
1072
+
1073
+ describe "when parsing a packet" do
1074
+ before(:each) do
1075
+ @packet = MQTT::Packet.parse( "\xB0\x02\x12\x34" )
1076
+ end
1077
+
1078
+ it "should correctly create the right type of packet object" do
1079
+ @packet.class.should == MQTT::Packet::Unsuback
1080
+ end
1081
+
1082
+ it "should set the message id of the packet correctly" do
1083
+ @packet.message_id.should == 0x1234
1084
+ end
1085
+ end
1086
+
1087
+ describe "when parsing packet with extra bytes on the end" do
1088
+ it "should throw an exception" do
1089
+ lambda {
1090
+ @packet = MQTT::Packet.parse( "\xB0\x03\x12\x34\x00" )
1091
+ }.should raise_error(
1092
+ MQTT::ProtocolException,
1093
+ "Extra bytes at end of Unsubscribe Acknowledgment packet"
1094
+ )
1095
+ end
1096
+ end
1097
+ end
1098
+
1099
+ describe MQTT::Packet::Pingreq do
1100
+ describe "when serialising a packet" do
1101
+ it "should output the correct bytes for a packet with no flags" do
1102
+ packet = MQTT::Packet::Pingreq.new
1103
+ packet.to_s.should == "\xC0\x00"
1104
+ end
1105
+ end
1106
+
1107
+ describe "when parsing a packet" do
1108
+ it "should correctly create the right type of packet object" do
1109
+ packet = MQTT::Packet.parse( "\xC0\x00" )
1110
+ packet.class.should == MQTT::Packet::Pingreq
1111
+ end
1112
+
1113
+ it "should throw an exception if the packet has a payload" do
1114
+ lambda {
1115
+ MQTT::Packet.parse( "\xC0\x05hello" )
1116
+ }.should raise_error(
1117
+ 'Extra bytes at end of Ping Request packet'
1118
+ )
1119
+ end
1120
+ end
1121
+ end
1122
+
1123
+ describe MQTT::Packet::Pingresp do
1124
+ describe "when serialising a packet" do
1125
+ it "should output the correct bytes for a packet with no flags" do
1126
+ packet = MQTT::Packet::Pingresp.new
1127
+ packet.to_s.should == "\xD0\x00"
1128
+ end
1129
+ end
1130
+
1131
+ describe "when parsing a packet" do
1132
+ it "should correctly create the right type of packet object" do
1133
+ packet = MQTT::Packet.parse( "\xD0\x00" )
1134
+ packet.class.should == MQTT::Packet::Pingresp
1135
+ end
1136
+
1137
+ it "should throw an exception if the packet has a payload" do
1138
+ lambda {
1139
+ MQTT::Packet.parse( "\xD0\x05hello" )
1140
+ }.should raise_error(
1141
+ 'Extra bytes at end of Ping Response packet'
1142
+ )
1143
+ end
1144
+ end
1145
+ end
1146
+
1147
+
1148
+ describe MQTT::Packet::Disconnect do
1149
+ describe "when serialising a packet" do
1150
+ it "should output the correct bytes for a packet with no flags" do
1151
+ packet = MQTT::Packet::Disconnect.new
1152
+ packet.to_s.should == "\xE0\x00"
1153
+ end
1154
+ end
1155
+
1156
+ describe "when parsing a packet" do
1157
+ it "should correctly create the right type of packet object" do
1158
+ packet = MQTT::Packet.parse( "\xE0\x00" )
1159
+ packet.class.should == MQTT::Packet::Disconnect
1160
+ end
1161
+
1162
+ it "should throw an exception if the packet has a payload" do
1163
+ lambda {
1164
+ MQTT::Packet.parse( "\xE0\x05hello" )
1165
+ }.should raise_error(
1166
+ 'Extra bytes at end of Disconnect packet'
1167
+ )
1168
+ end
1169
+ end
1170
+ end
1171
+
1172
+
1173
+ describe "Serialising an invalid packet" do
1174
+ context "that has a no type" do
1175
+ it "should throw an exception" do
1176
+ lambda {
1177
+ MQTT::Packet.new.to_s
1178
+ }.should raise_error(
1179
+ RuntimeError,
1180
+ "Invalid packet type: MQTT::Packet"
1181
+ )
1182
+ end
1183
+ end
1184
+ end
1185
+
1186
+ describe "Parsing an invalid packet" do
1187
+ context "that has an invalid type identifier" do
1188
+ it "should throw an exception" do
1189
+ lambda {
1190
+ MQTT::Packet.parse( "\x00" )
1191
+ }.should raise_error(
1192
+ MQTT::ProtocolException,
1193
+ "Invalid packet type identifier: 0"
1194
+ )
1195
+ end
1196
+ end
1197
+
1198
+ context "that has an incomplete packet length header" do
1199
+ it "should throw an exception" do
1200
+ lambda {
1201
+ MQTT::Packet.parse( "\x30\xFF" )
1202
+ }.should raise_error(
1203
+ MQTT::ProtocolException,
1204
+ "The packet length header is incomplete"
1205
+ )
1206
+ end
1207
+ end
1208
+
1209
+ context "that has a bigger buffer than expected" do
1210
+ it "should throw an exception" do
1211
+ lambda {
1212
+ MQTT::Packet.parse( "\x30\x11\x00\x04testhello big world" )
1213
+ }.should raise_error(
1214
+ MQTT::ProtocolException,
1215
+ "Failed to parse packet - input buffer (21) is not the same as the body length buffer (17)"
1216
+ )
1217
+ end
1218
+ end
1219
+
1220
+ context "that has a smaller buffer than expected" do
1221
+ it "should throw an exception" do
1222
+ lambda {
1223
+ MQTT::Packet.parse( "\x30\x11\x00\x04testhello" )
1224
+ }.should raise_error(
1225
+ MQTT::ProtocolException,
1226
+ "Failed to parse packet - input buffer (11) is not the same as the body length buffer (17)"
1227
+ )
1228
+ end
1229
+ end
1230
+ end