mqtt 0.0.9 → 0.1.0

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,30 @@
1
+ # Monkey patch to add stubbed string encoding functions to Ruby 1.8
2
+
3
+ class String
4
+ def force_encoding(encoding)
5
+ @encoding = encoding
6
+ self
7
+ end
8
+
9
+ def encoding
10
+ @encoding ||= Encoding::ASCII_8BIT
11
+ end
12
+
13
+ def encode(encoding)
14
+ new = self.dup
15
+ new.force_encoding(encoding)
16
+ end
17
+ end
18
+
19
+ class Encoding
20
+ def initialize(name)
21
+ @name = name
22
+ end
23
+
24
+ def to_s
25
+ @name
26
+ end
27
+
28
+ UTF_8 = Encoding.new("UTF-8")
29
+ ASCII_8BIT = Encoding.new("ASCII-8BIT")
30
+ end
@@ -1,3 +1,3 @@
1
1
  module MQTT
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -63,7 +63,7 @@ describe MQTT::Client do
63
63
  end
64
64
  end
65
65
 
66
- describe "when calling the 'connect' method" do
66
+ describe "when calling the 'connect' method on a client" do
67
67
  before(:each) do
68
68
  TCPSocket.stub(:new).and_return(@socket)
69
69
  Thread.stub(:new)
@@ -160,6 +160,30 @@ describe MQTT::Client do
160
160
 
161
161
  end
162
162
 
163
+ describe "calling 'connect' on the class" do
164
+ before(:each) do
165
+ TCPSocket.stub(:new).and_return(@socket)
166
+ MQTT::Client.stub(:new).and_return(@client)
167
+ Thread.stub(:new)
168
+ @client.stub(:receive_connack)
169
+ end
170
+
171
+ it "should create a new client object" do
172
+ MQTT::Client.should_receive(:new).once
173
+ MQTT::Client.connect
174
+ end
175
+
176
+ it "should call connect new client object" do
177
+ @client.should_receive(:connect).once
178
+ MQTT::Client.connect
179
+ end
180
+
181
+ it "should return the new client object" do
182
+ client = MQTT::Client.connect
183
+ client.class.should == MQTT::Client
184
+ end
185
+ end
186
+
163
187
  describe "when calling the 'receive_connack' method" do
164
188
  before(:each) do
165
189
  @client.instance_variable_set(:@socket, @socket)
@@ -302,7 +326,7 @@ describe MQTT::Client do
302
326
  @socket.string.should == "\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x01"
303
327
  end
304
328
  end
305
-
329
+
306
330
  describe "when calling the 'queue_length' method" do
307
331
  it "should return 0 if there are no incoming messages waiting" do
308
332
  @client.queue_length.should == 0
@@ -320,7 +344,6 @@ describe MQTT::Client do
320
344
  end
321
345
  end
322
346
 
323
-
324
347
  describe "when calling the 'queue_emtpy?' method" do
325
348
  it "should return return true if there no incoming messages waiting" do
326
349
  @client.queue_empty?.should be_true
@@ -351,6 +374,59 @@ describe MQTT::Client do
351
374
  payload.should == 'payload1'
352
375
  @client.queue_empty?.should be_true
353
376
  end
377
+
378
+ context "with a block" do
379
+ it "should successfull receive a more than 1 message" do
380
+ inject_packet(:topic => 'topic0', :payload => 'payload0')
381
+ inject_packet(:topic => 'topic1', :payload => 'payload1')
382
+ payloads = []
383
+ @client.get do |topic,payload|
384
+ payloads << payload
385
+ break if payloads.size > 1
386
+ end
387
+ payloads.size.should == 2
388
+ payloads.should == ['payload0', 'payload1']
389
+ end
390
+ end
391
+ end
392
+
393
+ describe "when calling the 'get_packet' method" do
394
+ before(:each) do
395
+ @client.instance_variable_set(:@socket, @socket)
396
+ end
397
+
398
+ it "should successfull receive a valid PUBLISH packet with a QoS 0" do
399
+ inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
400
+ packet = @client.get_packet
401
+ packet.class.should == MQTT::Packet::Publish
402
+ packet.qos.should == 0
403
+ packet.topic.should == 'topic0'
404
+ packet.payload.should == 'payload0'
405
+ end
406
+
407
+ it "should successfull receive a valid PUBLISH packet with a QoS 1" do
408
+ inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1)
409
+ packet = @client.get_packet
410
+ packet.class.should == MQTT::Packet::Publish
411
+ packet.qos.should == 1
412
+ packet.topic.should == 'topic1'
413
+ packet.payload.should == 'payload1'
414
+ @client.queue_empty?.should be_true
415
+ end
416
+
417
+ context "with a block" do
418
+ it "should successfull receive a more than 1 packet" do
419
+ inject_packet(:topic => 'topic0', :payload => 'payload0')
420
+ inject_packet(:topic => 'topic1', :payload => 'payload1')
421
+ packets = []
422
+ @client.get_packet do |packet|
423
+ packets << packet
424
+ break if packets.size > 1
425
+ end
426
+ packets.size.should == 2
427
+ packets.map{|p| p.payload}.should == ['payload0', 'payload1']
428
+ end
429
+ end
354
430
  end
355
431
 
356
432
  describe "when calling the 'unsubscribe' method" do
@@ -1,3 +1,6 @@
1
+ # encoding: BINARY
2
+ # Encoding is set to binary, so that the binary packets aren't validated as UTF-8
3
+
1
4
  $:.unshift(File.dirname(__FILE__))
2
5
 
3
6
  require 'spec_helper'
@@ -20,6 +23,27 @@ describe MQTT::Packet do
20
23
  packet = MQTT::Packet.new( :retain => true )
21
24
  packet.retain.should be_true
22
25
  end
26
+
27
+ it "should have a custom inspect method" do
28
+ packet = MQTT::Packet.new
29
+ packet.inspect.should == '#<MQTT::Packet>'
30
+ end
31
+
32
+ it "should throw an exception the QoS is greater than 2" do
33
+ lambda {
34
+ packet = MQTT::Packet.new( :qos => 3 )
35
+ }.should raise_error(
36
+ 'Invalid QoS value: 3'
37
+ )
38
+ end
39
+
40
+ it "should throw an exception the QoS is less than 0" do
41
+ lambda {
42
+ packet = MQTT::Packet.new( :qos => -1 )
43
+ }.should raise_error(
44
+ 'Invalid QoS value: -1'
45
+ )
46
+ end
23
47
  end
24
48
 
25
49
  describe "when setting packet parameters" do
@@ -76,11 +100,13 @@ describe MQTT::Packet do
76
100
  it "should provide a add_short method to get a big-endian unsigned 16-bit integer" do
77
101
  data = @packet.send(:encode_short, 1024)
78
102
  data.should == "\x04\x00"
103
+ data.encoding.to_s.should == "ASCII-8BIT"
79
104
  end
80
105
 
81
106
  it "should provide a add_string method to get a string preceeded by its length" do
82
107
  data = @packet.send(:encode_string, 'quack')
83
108
  data.should == "\x00\x05quack"
109
+ data.encoding.to_s.should == "ASCII-8BIT"
84
110
  end
85
111
 
86
112
  it "should provide a shift_short method to get a 16-bit unsigned integer" do
@@ -125,6 +151,16 @@ describe MQTT::Packet::Publish do
125
151
  packet.to_s.should == "\x3C\x12\x00\x03c/d\x00\x05hello world"
126
152
  end
127
153
 
154
+ it "should output a string as binary / 8-bit ASCII" do
155
+ packet = MQTT::Packet::Publish.new( :topic => 'test', :payload => 'hello world' )
156
+ packet.to_s.encoding.to_s.should == "ASCII-8BIT"
157
+ end
158
+
159
+ it "should support passing in non-strings to the topic and payload" do
160
+ packet = MQTT::Packet::Publish.new( :topic => :symbol, :payload => 1234 )
161
+ packet.to_s.should == "\x30\x0c\x00\x06symbol1234"
162
+ end
163
+
128
164
  it "should throw an exception when there is no topic name" do
129
165
  lambda {
130
166
  MQTT::Packet::Publish.new.to_s
@@ -132,6 +168,25 @@ describe MQTT::Packet::Publish do
132
168
  'Invalid topic name when serialising packet'
133
169
  )
134
170
  end
171
+
172
+ it "should throw an exception when there is an empty topic name" do
173
+ lambda {
174
+ MQTT::Packet::Publish.new( :topic => '' ).to_s
175
+ }.should raise_error(
176
+ 'Invalid topic name when serialising packet'
177
+ )
178
+ end
179
+ end
180
+
181
+ describe "when serialising an oversized packet" do
182
+ it "should throw an exception when body is bigger than 256MB" do
183
+ lambda {
184
+ packet = MQTT::Packet::Publish.new( :topic => 'test', :payload => 'x'*268435455 )
185
+ packet.to_s
186
+ }.should raise_error(
187
+ 'Error serialising packet: body is more than 256MB'
188
+ )
189
+ end
135
190
  end
136
191
 
137
192
  describe "when parsing a packet with QOS 0" do
@@ -157,10 +212,12 @@ describe MQTT::Packet::Publish do
157
212
 
158
213
  it "should set the topic name correctly" do
159
214
  @packet.topic.should == 'test'
215
+ @packet.topic.encoding.to_s.should == 'UTF-8'
160
216
  end
161
217
 
162
218
  it "should set the payload correctly" do
163
219
  @packet.payload.should == 'hello world'
220
+ @packet.payload.encoding.to_s.should == 'ASCII-8BIT'
164
221
  end
165
222
  end
166
223
 
@@ -187,10 +244,22 @@ describe MQTT::Packet::Publish do
187
244
 
188
245
  it "should set the topic name correctly" do
189
246
  @packet.topic.should == 'c/d'
247
+ @packet.topic.encoding.to_s.should == 'UTF-8'
190
248
  end
191
249
 
192
250
  it "should set the payload correctly" do
193
251
  @packet.payload.should == 'hello world'
252
+ @packet.payload.encoding.to_s.should == 'ASCII-8BIT'
253
+ end
254
+ end
255
+
256
+ describe "when parsing a packet with a invalid QoS value" do
257
+ it "should throw an exception" do
258
+ lambda {
259
+ packet = MQTT::Packet.parse( "\x36\x12\x00\x03a/b\x00\x05hello world" )
260
+ }.should raise_error(
261
+ 'Invalid QoS value: 3'
262
+ )
194
263
  end
195
264
  end
196
265
 
@@ -211,7 +280,7 @@ describe MQTT::Packet::Publish do
211
280
  end
212
281
 
213
282
  it "should get the body length correctly" do
214
- @packet.payload.size.should == 314
283
+ @packet.payload.bytesize.should == 314
215
284
  end
216
285
  end
217
286
 
@@ -233,10 +302,95 @@ describe MQTT::Packet::Publish do
233
302
  end
234
303
 
235
304
  it "should get the body length correctly" do
236
- @packet.payload.size.should == 16384
305
+ @packet.payload.bytesize.should == 16384
306
+ end
307
+ end
308
+
309
+ describe "processing a packet containing UTF-8 character" do
310
+ before(:each) do
311
+ @packet = MQTT::Packet::Publish.new(
312
+ :topic => "Test ①".force_encoding("UTF-8"),
313
+ :payload => "Snowman: ☃".force_encoding("UTF-8")
314
+ )
315
+ end
316
+
317
+ it "should have the correct topic byte length" do
318
+ @packet.topic.bytesize.should == 8
319
+ end
320
+
321
+ it "should have the correct topic string length", :unless => RUBY_VERSION =~ /^1\.8/ do
322
+ # Ruby 1.8 doesn't support UTF-8 properly
323
+ @packet.topic.length.should == 6
324
+ end
325
+
326
+ it "should have the correct payload byte length" do
327
+ @packet.payload.bytesize.should == 12
328
+ end
329
+
330
+ it "should have the correct payload string length", :unless => RUBY_VERSION =~ /^1\.8/ do
331
+ # Ruby 1.8 doesn't support UTF-8 properly
332
+ @packet.payload.length.should == 10
333
+ end
334
+
335
+ it "should encode to MQTT packet correctly" do
336
+ @packet.to_s.should == "\x30\x16\x00\x08Test \xE2\x91\xA0Snowman: \xE2\x98\x83".force_encoding('BINARY')
337
+ end
338
+
339
+ it "should parse the serialised packet" do
340
+ packet2 = MQTT::Packet.parse( @packet.to_s )
341
+ packet2.topic.should == "Test ①".force_encoding('UTF-8')
342
+ packet2.payload.should == "Snowman: ☃".force_encoding('BINARY')
343
+ end
344
+ end
345
+
346
+ describe "reading a packet from a socket" do
347
+ before(:each) do
348
+ @socket = StringIO.new("\x30\x11\x00\x04testhello world")
349
+ @packet = MQTT::Packet.read(@socket)
350
+ end
351
+
352
+ it "should correctly create the right type of packet object" do
353
+ @packet.class.should == MQTT::Packet::Publish
354
+ end
355
+
356
+ it "should set the body length is read correctly" do
357
+ @packet.body_length.should == 17
358
+ end
359
+
360
+ it "should set the QOS level correctly" do
361
+ @packet.qos.should == 0
362
+ end
363
+
364
+ it "should set the RETAIN flag correctly" do
365
+ @packet.retain.should be_false
366
+ end
367
+
368
+ it "should set the DUP flag correctly" do
369
+ @packet.duplicate.should be_false
370
+ end
371
+
372
+ it "should set the topic name correctly" do
373
+ @packet.topic.should == 'test'
374
+ @packet.topic.encoding.to_s.should == 'UTF-8'
375
+ end
376
+
377
+ it "should set the payload correctly" do
378
+ @packet.payload.should == 'hello world'
379
+ @packet.payload.encoding.to_s.should == 'ASCII-8BIT'
237
380
  end
238
381
  end
239
382
 
383
+ describe "when calling the inspect method" do
384
+ it "should output the payload, if it is less than 16 bytes" do
385
+ packet = MQTT::Packet::Publish.new( :topic => "topic", :payload => "payload" )
386
+ packet.inspect.should == "#<MQTT::Packet::Publish: d0, q0, r0, m0, 'topic', 'payload'>"
387
+ end
388
+
389
+ it "should output the length of the payload, if it is more than 16 bytes" do
390
+ packet = MQTT::Packet::Publish.new( :topic => "topic", :payload => 'x'*32 )
391
+ packet.inspect.should == "#<MQTT::Packet::Publish: d0, q0, r0, m0, 'topic', ... (32 bytes)>"
392
+ end
393
+ end
240
394
  end
241
395
 
242
396
  describe MQTT::Packet::Connect do
@@ -262,6 +416,14 @@ describe MQTT::Packet::Connect do
262
416
  )
263
417
  end
264
418
 
419
+ it "should throw an exception if the keep alive value is less than 0" do
420
+ lambda {
421
+ MQTT::Packet::Connect.new(:client_id => 'test', :keep_alive => -2).to_s
422
+ }.should raise_error(
423
+ 'Invalid keep-alive value: cannot be less than 0'
424
+ )
425
+ end
426
+
265
427
  it "should output the correct bytes for a packet with a Will" do
266
428
  packet = MQTT::Packet::Connect.new(
267
429
  :client_id => 'myclient',
@@ -337,6 +499,7 @@ describe MQTT::Packet::Connect do
337
499
 
338
500
  it "should set the Protocol Name of the packet correctly" do
339
501
  @packet.protocol_name.should == 'MQIsdp'
502
+ @packet.protocol_name.encoding.to_s.should == 'UTF-8'
340
503
  end
341
504
 
342
505
  it "should set the Protocol Version of the packet correctly" do
@@ -345,6 +508,7 @@ describe MQTT::Packet::Connect do
345
508
 
346
509
  it "should set the Client Identifier of the packet correctly" do
347
510
  @packet.client_id.should == 'myclient'
511
+ @packet.client_id.encoding.to_s.should == 'UTF-8'
348
512
  end
349
513
 
350
514
  it "should set the Keep Alive timer of the packet correctly" do
@@ -393,6 +557,7 @@ describe MQTT::Packet::Connect do
393
557
 
394
558
  it "should set the Protocol Name of the packet correctly" do
395
559
  @packet.protocol_name.should == 'MQIsdp'
560
+ @packet.protocol_name.encoding.to_s.should == 'UTF-8'
396
561
  end
397
562
 
398
563
  it "should set the Protocol Version of the packet correctly" do
@@ -401,6 +566,7 @@ describe MQTT::Packet::Connect do
401
566
 
402
567
  it "should set the Client Identifier of the packet correctly" do
403
568
  @packet.client_id.should == 'myclient'
569
+ @packet.client_id.encoding.to_s.should == 'UTF-8'
404
570
  end
405
571
 
406
572
  it "should set the clean session flag should be set" do
@@ -417,10 +583,12 @@ describe MQTT::Packet::Connect do
417
583
 
418
584
  it "should set the Will topic of the packet correctly" do
419
585
  @packet.will_topic.should == 'topic'
586
+ @packet.will_topic.encoding.to_s.should == 'UTF-8'
420
587
  end
421
588
 
422
589
  it "should set the Will payload of the packet correctly" do
423
590
  @packet.will_payload.should == 'hello'
591
+ @packet.will_payload.encoding.to_s.should == 'UTF-8'
424
592
  end
425
593
  end
426
594
 
@@ -446,6 +614,7 @@ describe MQTT::Packet::Connect do
446
614
 
447
615
  it "should set the Protocol Name of the packet correctly" do
448
616
  @packet.protocol_name.should == 'MQIsdp'
617
+ @packet.protocol_name.encoding.to_s.should == 'UTF-8'
449
618
  end
450
619
 
451
620
  it "should set the Protocol Version of the packet correctly" do
@@ -454,7 +623,8 @@ describe MQTT::Packet::Connect do
454
623
 
455
624
  it "should set the Client Identifier of the packet correctly" do
456
625
  @packet.client_id.should == 'myclient'
457
- end
626
+ @packet.client_id.encoding.to_s.should == 'UTF-8'
627
+ end
458
628
 
459
629
  it "should set the Keep Alive Timer of the packet correctly" do
460
630
  @packet.keep_alive.should == 10
@@ -462,10 +632,12 @@ describe MQTT::Packet::Connect do
462
632
 
463
633
  it "should set the Username of the packet correctly" do
464
634
  @packet.username.should == 'username'
635
+ @packet.username.encoding.to_s.should == 'UTF-8'
465
636
  end
466
637
 
467
638
  it "should set the Username of the packet correctly" do
468
639
  @packet.password.should == 'password'
640
+ @packet.password.encoding.to_s.should == 'UTF-8'
469
641
  end
470
642
  end
471
643
 
@@ -478,6 +650,7 @@ describe MQTT::Packet::Connect do
478
650
 
479
651
  it "should set the Username of the packet correctly" do
480
652
  @packet.username.should == 'username'
653
+ @packet.username.encoding.to_s.should == 'UTF-8'
481
654
  end
482
655
 
483
656
  it "should set the Username of the packet correctly" do
@@ -498,6 +671,7 @@ describe MQTT::Packet::Connect do
498
671
 
499
672
  it "should set the Username of the packet correctly" do
500
673
  @packet.password.should == 'password'
674
+ @packet.password.encoding.to_s.should == 'UTF-8'
501
675
  end
502
676
  end
503
677
 
@@ -542,6 +716,7 @@ describe MQTT::Packet::Connect do
542
716
 
543
717
  it "should set the Protocol Name of the packet correctly" do
544
718
  @packet.protocol_name.should == 'MQIsdp'
719
+ @packet.protocol_name.encoding.to_s.should == 'UTF-8'
545
720
  end
546
721
 
547
722
  it "should set the Protocol Version of the packet correctly" do
@@ -554,6 +729,7 @@ describe MQTT::Packet::Connect do
554
729
 
555
730
  it "should set the Client Identifier of the packet correctly" do
556
731
  @packet.client_id.should == '12345678901234567890123'
732
+ @packet.client_id.encoding.to_s.should == 'UTF-8'
557
733
  end
558
734
 
559
735
  it "should set the Will QoS of the packet correctly" do
@@ -566,21 +742,67 @@ describe MQTT::Packet::Connect do
566
742
 
567
743
  it "should set the Will topic of the packet correctly" do
568
744
  @packet.will_topic.should == 'will_topic'
745
+ @packet.will_topic.encoding.to_s.should == 'UTF-8'
569
746
  end
570
747
 
571
748
  it "should set the Will payload of the packet correctly" do
572
749
  @packet.will_payload.should == 'will_message'
750
+ @packet.will_payload.encoding.to_s.should == 'UTF-8'
573
751
  end
574
752
 
575
753
  it "should set the Username of the packet correctly" do
576
754
  @packet.username.should == 'user0123456789'
755
+ @packet.username.encoding.to_s.should == 'UTF-8'
577
756
  end
578
757
 
579
758
  it "should set the Username of the packet correctly" do
580
759
  @packet.password.should == 'pass0123456789'
760
+ @packet.password.encoding.to_s.should == 'UTF-8'
761
+ end
762
+ end
763
+
764
+ describe "when parsing packet with an unknown protocol name" do
765
+ it "should throw a protocol exception" do
766
+ lambda {
767
+ packet = MQTT::Packet.parse(
768
+ "\x10\x16\x00\x06FooBar\x03\x00\x00\x0a\x00\x08myclient"
769
+ )
770
+ }.should raise_error(
771
+ MQTT::ProtocolException,
772
+ "Unsupported protocol name: FooBar"
773
+ )
581
774
  end
582
775
  end
583
776
 
777
+ describe "when parsing packet with an unknown protocol version" do
778
+ it "should throw a protocol exception" do
779
+ lambda {
780
+ packet = MQTT::Packet.parse(
781
+ "\x10\x16\x00\x06MQIsdp\x02\x00\x00\x0a\x00\x08myclient"
782
+ )
783
+ }.should raise_error(
784
+ MQTT::ProtocolException,
785
+ "Unsupported protocol version: 2"
786
+ )
787
+ end
788
+ end
789
+
790
+ describe "when calling the inspect method" do
791
+ it "should output correct string for the default options" do
792
+ packet = MQTT::Packet::Connect.new
793
+ packet.inspect.should == "#<MQTT::Packet::Connect: keep_alive=15, clean, client_id=''>"
794
+ end
795
+
796
+ it "should output correct string when parameters are given" do
797
+ packet = MQTT::Packet::Connect.new(
798
+ :keep_alive => 10,
799
+ :client_id => 'c123',
800
+ :clean_session => false,
801
+ :username => 'foo'
802
+ )
803
+ packet.inspect.should == "#<MQTT::Packet::Connect: keep_alive=10, client_id='c123', username='foo'>"
804
+ end
805
+ end
584
806
  end
585
807
 
586
808
  describe MQTT::Packet::Connack do
@@ -731,6 +953,17 @@ describe MQTT::Packet::Connack do
731
953
  )
732
954
  end
733
955
  end
956
+
957
+ describe "when calling the inspect method" do
958
+ it "should output the right string when the return code is 0" do
959
+ packet = MQTT::Packet::Connack.new( :return_code => 0x00 )
960
+ packet.inspect.should == "#<MQTT::Packet::Connack: 0x00>"
961
+ end
962
+ it "should output the right string when the return code is 0x0F" do
963
+ packet = MQTT::Packet::Connack.new( :return_code => 0x0F )
964
+ packet.inspect.should == "#<MQTT::Packet::Connack: 0x0F>"
965
+ end
966
+ end
734
967
  end
735
968
 
736
969
  describe MQTT::Packet::Puback do
@@ -765,6 +998,11 @@ describe MQTT::Packet::Puback do
765
998
  )
766
999
  end
767
1000
  end
1001
+
1002
+ it "should output the right string when calling inspect" do
1003
+ packet = MQTT::Packet::Puback.new( :message_id => 0x1234 )
1004
+ packet.inspect.should == "#<MQTT::Packet::Puback: 0x1234>"
1005
+ end
768
1006
  end
769
1007
 
770
1008
  describe MQTT::Packet::Pubrec do
@@ -799,6 +1037,11 @@ describe MQTT::Packet::Pubrec do
799
1037
  )
800
1038
  end
801
1039
  end
1040
+
1041
+ it "should output the right string when calling inspect" do
1042
+ packet = MQTT::Packet::Pubrec.new( :message_id => 0x1234 )
1043
+ packet.inspect.should == "#<MQTT::Packet::Pubrec: 0x1234>"
1044
+ end
802
1045
  end
803
1046
 
804
1047
  describe MQTT::Packet::Pubrel do
@@ -833,6 +1076,11 @@ describe MQTT::Packet::Pubrel do
833
1076
  )
834
1077
  end
835
1078
  end
1079
+
1080
+ it "should output the right string when calling inspect" do
1081
+ packet = MQTT::Packet::Pubrel.new( :message_id => 0x1234 )
1082
+ packet.inspect.should == "#<MQTT::Packet::Pubrel: 0x1234>"
1083
+ end
836
1084
  end
837
1085
 
838
1086
  describe MQTT::Packet::Pubcomp do
@@ -867,6 +1115,11 @@ describe MQTT::Packet::Pubcomp do
867
1115
  )
868
1116
  end
869
1117
  end
1118
+
1119
+ it "should output the right string when calling inspect" do
1120
+ packet = MQTT::Packet::Pubcomp.new( :message_id => 0x1234 )
1121
+ packet.inspect.should == "#<MQTT::Packet::Pubcomp: 0x1234>"
1122
+ end
870
1123
  end
871
1124
 
872
1125
  describe MQTT::Packet::Subscribe do
@@ -972,6 +1225,18 @@ describe MQTT::Packet::Subscribe do
972
1225
  @packet.topics.should == [['a/b',0],['c/d',1]]
973
1226
  end
974
1227
  end
1228
+
1229
+ describe "when calling the inspect method" do
1230
+ it "should output correct string for a single topic" do
1231
+ packet = MQTT::Packet::Subscribe.new(:topics => 'test')
1232
+ packet.inspect.should == "#<MQTT::Packet::Subscribe: 0x00, 'test':0>"
1233
+ end
1234
+
1235
+ it "should output correct string for multiple topics" do
1236
+ packet = MQTT::Packet::Subscribe.new(:topics => {'a' => 1, 'b' => 0, 'c' => 2})
1237
+ packet.inspect.should == "#<MQTT::Packet::Subscribe: 0x00, 'a':1, 'b':0, 'c':2>"
1238
+ end
1239
+ end
975
1240
  end
976
1241
 
977
1242
  describe MQTT::Packet::Suback do
@@ -1038,6 +1303,18 @@ describe MQTT::Packet::Suback do
1038
1303
  @packet.granted_qos.should == [1,1]
1039
1304
  end
1040
1305
  end
1306
+
1307
+ describe "when calling the inspect method" do
1308
+ it "should output correct string for a single granted qos" do
1309
+ packet = MQTT::Packet::Suback.new(:message_id => 0x1234, :granted_qos => 0)
1310
+ packet.inspect.should == "#<MQTT::Packet::Suback: 0x1234, qos=0>"
1311
+ end
1312
+
1313
+ it "should output correct string for multiple topics" do
1314
+ packet = MQTT::Packet::Suback.new(:message_id => 0x1235, :granted_qos => [0,1,2])
1315
+ packet.inspect.should == "#<MQTT::Packet::Suback: 0x1235, qos=0,1,2>"
1316
+ end
1317
+ end
1041
1318
  end
1042
1319
 
1043
1320
  describe MQTT::Packet::Unsubscribe do
@@ -1078,6 +1355,18 @@ describe MQTT::Packet::Unsubscribe do
1078
1355
  @packet.topics.should == ['a/b','c/d']
1079
1356
  end
1080
1357
  end
1358
+
1359
+ describe "when calling the inspect method" do
1360
+ it "should output correct string for a single topic" do
1361
+ packet = MQTT::Packet::Unsubscribe.new(:topics => 'test')
1362
+ packet.inspect.should == "#<MQTT::Packet::Unsubscribe: 0x00, 'test'>"
1363
+ end
1364
+
1365
+ it "should output correct string for multiple topics" do
1366
+ packet = MQTT::Packet::Unsubscribe.new(:message_id => 42, :topics => ['a', 'b', 'c'])
1367
+ packet.inspect.should == "#<MQTT::Packet::Unsubscribe: 0x2A, 'a', 'b', 'c'>"
1368
+ end
1369
+ end
1081
1370
  end
1082
1371
 
1083
1372
  describe MQTT::Packet::Unsuback do
@@ -1112,6 +1401,11 @@ describe MQTT::Packet::Unsuback do
1112
1401
  )
1113
1402
  end
1114
1403
  end
1404
+
1405
+ it "should output the right string when calling inspect" do
1406
+ packet = MQTT::Packet::Unsuback.new( :message_id => 0x1234 )
1407
+ packet.inspect.should == "#<MQTT::Packet::Unsuback: 0x1234>"
1408
+ end
1115
1409
  end
1116
1410
 
1117
1411
  describe MQTT::Packet::Pingreq do
@@ -1136,6 +1430,11 @@ describe MQTT::Packet::Pingreq do
1136
1430
  )
1137
1431
  end
1138
1432
  end
1433
+
1434
+ it "should output the right string when calling inspect" do
1435
+ packet = MQTT::Packet::Pingreq.new
1436
+ packet.inspect.should == "#<MQTT::Packet::Pingreq>"
1437
+ end
1139
1438
  end
1140
1439
 
1141
1440
  describe MQTT::Packet::Pingresp do
@@ -1160,6 +1459,11 @@ describe MQTT::Packet::Pingresp do
1160
1459
  )
1161
1460
  end
1162
1461
  end
1462
+
1463
+ it "should output the right string when calling inspect" do
1464
+ packet = MQTT::Packet::Pingresp.new
1465
+ packet.inspect.should == "#<MQTT::Packet::Pingresp>"
1466
+ end
1163
1467
  end
1164
1468
 
1165
1469
 
@@ -1185,6 +1489,11 @@ describe MQTT::Packet::Disconnect do
1185
1489
  )
1186
1490
  end
1187
1491
  end
1492
+
1493
+ it "should output the right string when calling inspect" do
1494
+ packet = MQTT::Packet::Disconnect.new
1495
+ packet.inspect.should == "#<MQTT::Packet::Disconnect>"
1496
+ end
1188
1497
  end
1189
1498
 
1190
1499
 
@@ -1201,24 +1510,60 @@ describe "Serialising an invalid packet" do
1201
1510
  end
1202
1511
  end
1203
1512
 
1204
- describe "Reading in an invalid packet" do
1513
+ describe "Reading in an invalid packet from a socket" do
1205
1514
  context "that has 0 length" do
1206
1515
  it "should throw an exception" do
1207
1516
  lambda {
1208
- data = StringIO.new
1209
- MQTT::Packet.read(data)
1517
+ socket = StringIO.new
1518
+ MQTT::Packet.read(socket)
1519
+ }.should raise_error(
1520
+ MQTT::ProtocolException,
1521
+ "Failed to read byte from socket"
1522
+ )
1523
+ end
1524
+ end
1525
+
1526
+ context "that has an incomplete packet length header" do
1527
+ it "should throw an exception" do
1528
+ lambda {
1529
+ socket = StringIO.new("\x30\xFF")
1530
+ MQTT::Packet.read(socket)
1531
+ }.should raise_error(
1532
+ MQTT::ProtocolException,
1533
+ "Failed to read byte from socket"
1534
+ )
1535
+ end
1536
+ end
1537
+
1538
+ context "that has the maximum number of bytes in the length header" do
1539
+ it "should throw an exception" do
1540
+ lambda {
1541
+ socket = StringIO.new("\x30\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF")
1542
+ MQTT::Packet.read(socket)
1210
1543
  }.should raise_error(
1211
- MQTT::ProtocolException
1544
+ MQTT::ProtocolException,
1545
+ "Failed to parse packet - input buffer (4) is not the same as the body length header (268435455)"
1212
1546
  )
1213
1547
  end
1214
1548
  end
1215
1549
  end
1216
1550
 
1217
1551
  describe "Parsing an invalid packet" do
1552
+ context "that has no length" do
1553
+ it "should throw an exception" do
1554
+ lambda {
1555
+ MQTT::Packet.parse( "" )
1556
+ }.should raise_error(
1557
+ MQTT::ProtocolException,
1558
+ "Invalid packet: less than 2 bytes long"
1559
+ )
1560
+ end
1561
+ end
1562
+
1218
1563
  context "that has an invalid type identifier" do
1219
1564
  it "should throw an exception" do
1220
1565
  lambda {
1221
- MQTT::Packet.parse( "\x00" )
1566
+ MQTT::Packet.parse( "\x00\x00" )
1222
1567
  }.should raise_error(
1223
1568
  MQTT::ProtocolException,
1224
1569
  "Invalid packet type identifier: 0"
@@ -1237,13 +1582,24 @@ describe "Parsing an invalid packet" do
1237
1582
  end
1238
1583
  end
1239
1584
 
1585
+ context "that has too many bytes in the length field" do
1586
+ it "should throw an exception" do
1587
+ lambda {
1588
+ MQTT::Packet.parse( "\x30\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" )
1589
+ }.should raise_error(
1590
+ MQTT::ProtocolException,
1591
+ 'Failed to parse packet - input buffer (4) is not the same as the body length header (268435455)'
1592
+ )
1593
+ end
1594
+ end
1595
+
1240
1596
  context "that has a bigger buffer than expected" do
1241
1597
  it "should throw an exception" do
1242
1598
  lambda {
1243
1599
  MQTT::Packet.parse( "\x30\x11\x00\x04testhello big world" )
1244
1600
  }.should raise_error(
1245
1601
  MQTT::ProtocolException,
1246
- "Failed to parse packet - input buffer (21) is not the same as the body length buffer (17)"
1602
+ "Failed to parse packet - input buffer (21) is not the same as the body length header (17)"
1247
1603
  )
1248
1604
  end
1249
1605
  end
@@ -1254,7 +1610,7 @@ describe "Parsing an invalid packet" do
1254
1610
  MQTT::Packet.parse( "\x30\x11\x00\x04testhello" )
1255
1611
  }.should raise_error(
1256
1612
  MQTT::ProtocolException,
1257
- "Failed to parse packet - input buffer (11) is not the same as the body length buffer (17)"
1613
+ "Failed to parse packet - input buffer (11) is not the same as the body length header (17)"
1258
1614
  )
1259
1615
  end
1260
1616
  end