qubitro-mqtt 0.0.1

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,2014 @@
1
+ # encoding: BINARY
2
+ # Encoding is set to binary, so that the binary packets aren't validated as UTF-8
3
+
4
+ $:.unshift(File.dirname(__FILE__))
5
+
6
+ require 'spec_helper'
7
+
8
+ describe MQTT::Packet do
9
+
10
+ describe "when creating a new packet" do
11
+ it "should allow you to set the packet flags as a hash parameter" do
12
+ packet = MQTT::Packet.new( :flags => [true, false, true, false] )
13
+ expect(packet.flags).to eq([true, false, true, false])
14
+ end
15
+
16
+ it "should have a custom inspect method" do
17
+ packet = MQTT::Packet.new
18
+ expect(packet.inspect).to eq('#<MQTT::Packet>')
19
+ end
20
+
21
+ it "should have a type_id method to get the integer ID of the packet type" do
22
+ packet = MQTT::Packet::Pingreq.new
23
+ expect(packet.type_id).to eq(12)
24
+ end
25
+ end
26
+
27
+ it "should let you change attributes using the update_attributes method" do
28
+ packet = MQTT::Packet.new(:flags => [false, false, false, true])
29
+ packet.update_attributes(:flags => [false, false, true, true])
30
+ expect(packet.flags).to eq([false, false, true, true])
31
+ end
32
+
33
+ describe "protected methods" do
34
+ let(:packet) { MQTT::Packet.new }
35
+
36
+ it "should provide a encode_bytes method to get some bytes as Integers" do
37
+ data = packet.send(:encode_bytes, 0x48, 0x65, 0x6c, 0x6c, 'o'.unpack('C1')[0])
38
+ expect(data).to eq('Hello')
39
+ end
40
+
41
+ it "should provide a encode_bits method to encode an array of bits to a string" do
42
+ data = packet.send(:encode_bits, [false, true, true, false, true, false, true, false])
43
+ expect(data).to eq('V')
44
+ end
45
+
46
+ it "should provide a add_short method to get a big-endian unsigned 16-bit integer" do
47
+ data = packet.send(:encode_short, 1024)
48
+ expect(data).to eq("\x04\x00")
49
+ expect(data.encoding.to_s).to eq("ASCII-8BIT")
50
+ end
51
+
52
+ it "should raise an error if too big argument for encode_short" do
53
+ expect {
54
+ data = packet.send(:encode_short, 0x10000)
55
+ }.to raise_error(
56
+ 'Value too big for short'
57
+ )
58
+ end
59
+
60
+ it "should provide a add_string method to get a string preceeded by its length" do
61
+ data = packet.send(:encode_string, 'quack')
62
+ expect(data).to eq("\x00\x05quack")
63
+ expect(data.encoding.to_s).to eq("ASCII-8BIT")
64
+ end
65
+
66
+ it "should provide a shift_short method to get a 16-bit unsigned integer" do
67
+ buffer = "\x22\x8Bblahblah"
68
+ expect(packet.send(:shift_short,buffer)).to eq(8843)
69
+ expect(buffer).to eq('blahblah')
70
+ end
71
+
72
+ it "should provide a shift_byte method to get one byte as integers" do
73
+ buffer = "\x01blahblah"
74
+ expect(packet.send(:shift_byte,buffer)).to eq(1)
75
+ expect(buffer).to eq('blahblah')
76
+ end
77
+
78
+ it "should provide a shift_byte method to get one byte as integers" do
79
+ buffer = "Yblahblah"
80
+ expect(packet.send(:shift_bits, buffer)).to eq([true, false, false, true, true, false, true, false])
81
+ expect(buffer).to eq('blahblah')
82
+ end
83
+
84
+ it "should provide a shift_string method to get a string preceeded by its length" do
85
+ buffer = "\x00\x05Hello World"
86
+ expect(packet.send(:shift_string,buffer)).to eq("Hello")
87
+ expect(buffer).to eq(' World')
88
+ end
89
+ end
90
+
91
+ describe "deprecated attributes" do
92
+ it "should still have a message_id method that is that same as id" do
93
+ packet = MQTT::Packet.new
94
+ packet.message_id = 1234
95
+ expect(packet.message_id).to eq(1234)
96
+ expect(packet.id).to eq(1234)
97
+ packet.id = 4321
98
+ expect(packet.message_id).to eq(4321)
99
+ expect(packet.id).to eq(4321)
100
+ end
101
+ end
102
+ end
103
+
104
+ describe MQTT::Packet::Publish do
105
+ describe "when creating a packet" do
106
+ it "should allow you to set the packet QoS level as a hash parameter" do
107
+ packet = MQTT::Packet::Publish.new( :qos => 2 )
108
+ expect(packet.qos).to eq(2)
109
+ end
110
+
111
+ it "should allow you to set the packet retain flag as a hash parameter" do
112
+ packet = MQTT::Packet::Publish.new( :retain => true )
113
+ expect(packet.retain).to be_truthy
114
+ end
115
+
116
+ it "should raise an exception the QoS is greater than 2" do
117
+ expect {
118
+ packet = MQTT::Packet::Publish.new( :qos => 3 )
119
+ }.to raise_error(
120
+ 'Invalid QoS value: 3'
121
+ )
122
+ end
123
+
124
+ it "should raise an exception the QoS is less than 0" do
125
+ expect {
126
+ packet = MQTT::Packet::Publish.new( :qos => -1 )
127
+ }.to raise_error(
128
+ 'Invalid QoS value: -1'
129
+ )
130
+ end
131
+ end
132
+
133
+ describe "when setting attributes on a packet" do
134
+ let(:packet) {
135
+ MQTT::Packet::Publish.new(
136
+ :duplicate => false,
137
+ :qos => 0,
138
+ :retain => false
139
+ )
140
+ }
141
+
142
+ it "should let you change the dup flag of a packet" do
143
+ packet.duplicate = true
144
+ expect(packet.duplicate).to be_truthy
145
+ end
146
+
147
+ it "should let you change the dup flag of a packet using an integer" do
148
+ packet.duplicate = 1
149
+ expect(packet.duplicate).to be_truthy
150
+ end
151
+
152
+ it "should let you change the QoS value of a packet" do
153
+ packet.qos = 1
154
+ expect(packet.qos).to eq(1)
155
+ end
156
+
157
+ it "should let you change the retain flag of a packet" do
158
+ packet.retain = true
159
+ expect(packet.retain).to be_truthy
160
+ end
161
+
162
+ it "should let you change the retain flag of a packet using an integer" do
163
+ packet.retain = 1
164
+ expect(packet.retain).to be_truthy
165
+ end
166
+ end
167
+
168
+ describe "when serialising a packet" do
169
+ it "should output the correct bytes for a packet with default QoS and no flags" do
170
+ packet = MQTT::Packet::Publish.new( :topic => 'test', :payload => 'hello world' )
171
+ expect(packet.to_s).to eq("\x30\x11\x00\x04testhello world")
172
+ end
173
+
174
+ it "should output the correct bytes for a packet with QoS 1 and no flags" do
175
+ packet = MQTT::Packet::Publish.new( :id => 5, :qos => 1, :topic => 'a/b', :payload => 'hello world' )
176
+ expect(packet.to_s).to eq("\x32\x12\x00\x03a/b\x00\x05hello world")
177
+ end
178
+
179
+ it "should output the correct bytes for a packet with QoS 2 and retain flag set" do
180
+ packet = MQTT::Packet::Publish.new( :id => 5, :qos => 2, :retain => true, :topic => 'c/d', :payload => 'hello world' )
181
+ expect(packet.to_s).to eq("\x35\x12\x00\x03c/d\x00\x05hello world")
182
+ end
183
+
184
+ it "should output the correct bytes for a packet with QoS 2 and dup flag set" do
185
+ packet = MQTT::Packet::Publish.new( :id => 5, :qos => 2, :duplicate => true, :topic => 'c/d', :payload => 'hello world' )
186
+ expect(packet.to_s).to eq("\x3C\x12\x00\x03c/d\x00\x05hello world")
187
+ end
188
+
189
+ it "should output the correct bytes for a packet with an empty payload" do
190
+ packet = MQTT::Packet::Publish.new( :topic => 'test' )
191
+ expect(packet.to_s).to eq("\x30\x06\x00\x04test")
192
+ end
193
+
194
+ it "should output a string as binary / 8-bit ASCII" do
195
+ packet = MQTT::Packet::Publish.new( :topic => 'test', :payload => 'hello world' )
196
+ expect(packet.to_s.encoding.to_s).to eq("ASCII-8BIT")
197
+ end
198
+
199
+ it "should support passing in non-strings to the topic and payload" do
200
+ packet = MQTT::Packet::Publish.new( :topic => :symbol, :payload => 1234 )
201
+ expect(packet.to_s).to eq("\x30\x0c\x00\x06symbol1234")
202
+ end
203
+
204
+ it "should raise an exception when there is no topic name" do
205
+ expect {
206
+ MQTT::Packet::Publish.new.to_s
207
+ }.to raise_error(
208
+ 'Invalid topic name when serialising packet'
209
+ )
210
+ end
211
+
212
+ it "should raise an exception when there is an empty topic name" do
213
+ expect {
214
+ MQTT::Packet::Publish.new( :topic => '' ).to_s
215
+ }.to raise_error(
216
+ 'Invalid topic name when serialising packet'
217
+ )
218
+ end
219
+ end
220
+
221
+ describe "when serialising an oversized packet" do
222
+ it "should raise an exception when body is bigger than 256MB" do
223
+ expect {
224
+ packet = MQTT::Packet::Publish.new( :topic => 'test', :payload => 'x'*268435455 )
225
+ packet.to_s
226
+ }.to raise_error(
227
+ 'Error serialising packet: body is more than 256MB'
228
+ )
229
+ end
230
+ end
231
+
232
+ describe "when parsing a packet with QoS 0" do
233
+ let(:packet) { MQTT::Packet.parse( "\x30\x11\x00\x04testhello world" ) }
234
+
235
+ it "should correctly create the right type of packet object" do
236
+ expect(packet.class).to eq(MQTT::Packet::Publish)
237
+ end
238
+
239
+ it "should set the QoS level correctly" do
240
+ expect(packet.qos).to eq(0)
241
+ end
242
+
243
+ it "should set the RETAIN flag correctly" do
244
+ expect(packet.retain).to be_falsey
245
+ end
246
+
247
+ it "should set the DUP flag correctly" do
248
+ expect(packet.duplicate).to be_falsey
249
+ end
250
+
251
+ it "should set the topic name correctly" do
252
+ expect(packet.topic).to eq('test')
253
+ expect(packet.topic.encoding.to_s).to eq('UTF-8')
254
+ end
255
+
256
+ it "should set the payload correctly" do
257
+ expect(packet.payload).to eq('hello world')
258
+ expect(packet.payload.encoding.to_s).to eq('ASCII-8BIT')
259
+ end
260
+ end
261
+
262
+ describe "when parsing a packet with QoS 2 and retain and dup flags set" do
263
+ let(:packet) { MQTT::Packet.parse( "\x3D\x12\x00\x03c/d\x00\x05hello world" ) }
264
+
265
+ it "should correctly create the right type of packet object" do
266
+ expect(packet.class).to eq(MQTT::Packet::Publish)
267
+ end
268
+
269
+ it "should set the QoS level correctly" do
270
+ expect(packet.qos).to eq(2)
271
+ end
272
+
273
+ it "should set the RETAIN flag correctly" do
274
+ expect(packet.retain).to be_truthy
275
+ end
276
+
277
+ it "should set the DUP flag correctly" do
278
+ expect(packet.duplicate).to be_truthy
279
+ end
280
+
281
+ it "should set the topic name correctly" do
282
+ expect(packet.topic).to eq('c/d')
283
+ expect(packet.topic.encoding.to_s).to eq('UTF-8')
284
+ end
285
+
286
+ it "should set the payload correctly" do
287
+ expect(packet.payload).to eq('hello world')
288
+ expect(packet.payload.encoding.to_s).to eq('ASCII-8BIT')
289
+ end
290
+ end
291
+
292
+ describe "when parsing a packet with an empty payload" do
293
+ let(:packet) { MQTT::Packet.parse( "\x30\x06\x00\x04test" ) }
294
+
295
+ it "should correctly create the right type of packet object" do
296
+ expect(packet.class).to eq(MQTT::Packet::Publish)
297
+ end
298
+
299
+ it "should set the topic name correctly" do
300
+ expect(packet.topic).to eq('test')
301
+ end
302
+
303
+ it "should set the payload correctly" do
304
+ expect(packet.payload).to be_empty
305
+ end
306
+ end
307
+
308
+ describe "when parsing a packet with a QoS value of 3" do
309
+ it "should raise an exception" do
310
+ expect {
311
+ packet = MQTT::Packet.parse( "\x36\x12\x00\x03a/b\x00\x05hello world" )
312
+ }.to raise_error(
313
+ MQTT::ProtocolException,
314
+ 'Invalid packet: QoS value of 3 is not allowed'
315
+ )
316
+ end
317
+ end
318
+
319
+ describe "when parsing a packet with QoS value of 0 and DUP set" do
320
+ it "should raise an exception" do
321
+ expect {
322
+ packet = MQTT::Packet.parse( "\x38\x10\x00\x03a/bhello world" )
323
+ }.to raise_error(
324
+ MQTT::ProtocolException,
325
+ 'Invalid packet: DUP cannot be set for QoS 0'
326
+ )
327
+ end
328
+ end
329
+
330
+ describe "when parsing a packet with a body of 314 bytes" do
331
+ let(:packet) {
332
+ # 0x30 = publish
333
+ # 0xC1 = (65 * 1)
334
+ # 0x02 = (2 * 128)
335
+ MQTT::Packet.parse( "\x30\xC1\x02\x00\x05topic" + ('x' * 314) )
336
+ }
337
+
338
+ it "should parse the packet type correctly" do
339
+ expect(packet.class).to eq(MQTT::Packet::Publish)
340
+ end
341
+
342
+ it "should get the topic name correctly" do
343
+ expect(packet.topic).to eq('topic')
344
+ end
345
+
346
+ it "should get the body length correctly" do
347
+ expect(packet.payload.bytesize).to eq(314)
348
+ end
349
+ end
350
+
351
+ describe "when parsing a packet with a body of 16kbytes" do
352
+ let(:packet) do
353
+ # 0x30 = publish
354
+ # 0x87 = (7 * 1)
355
+ # 0x80 = (0 * 128)
356
+ # 0x01 = (1 * 16384)
357
+ MQTT::Packet.parse( "\x30\x87\x80\x01\x00\x05topic" + ('x'*16384) )
358
+ end
359
+
360
+ it "should parse the packet type correctly" do
361
+ expect(packet.class).to eq(MQTT::Packet::Publish)
362
+ end
363
+
364
+ it "should get the topic name correctly" do
365
+ expect(packet.topic).to eq('topic')
366
+ end
367
+
368
+ it "should get the body length correctly" do
369
+ expect(packet.payload.bytesize).to eq(16384)
370
+ end
371
+ end
372
+
373
+ describe "processing a packet containing UTF-8 character" do
374
+ let(:packet) do
375
+ MQTT::Packet::Publish.new(
376
+ :topic => "Test ①".force_encoding("UTF-8"),
377
+ :payload => "Snowman: ☃".force_encoding("UTF-8")
378
+ )
379
+ end
380
+
381
+ it "should have the correct topic byte length" do
382
+ expect(packet.topic.bytesize).to eq(8)
383
+ end
384
+
385
+ it "should have the correct topic string length", :unless => RUBY_VERSION =~ /^1\.8/ do
386
+ # Ruby 1.8 doesn't support UTF-8 properly
387
+ expect(packet.topic.length).to eq(6)
388
+ end
389
+
390
+ it "should have the correct payload byte length" do
391
+ expect(packet.payload.bytesize).to eq(12)
392
+ end
393
+
394
+ it "should have the correct payload string length", :unless => RUBY_VERSION =~ /^1\.8/ do
395
+ # Ruby 1.8 doesn't support UTF-8 properly
396
+ expect(packet.payload.length).to eq(10)
397
+ end
398
+
399
+ it "should encode to MQTT packet correctly" do
400
+ expect(packet.to_s).to eq("\x30\x16\x00\x08Test \xE2\x91\xA0Snowman: \xE2\x98\x83".force_encoding('BINARY'))
401
+ end
402
+
403
+ it "should parse the serialised packet" do
404
+ packet2 = MQTT::Packet.parse( packet.to_s )
405
+ expect(packet2.topic).to eq("Test ①".force_encoding('UTF-8'))
406
+ expect(packet2.payload).to eq("Snowman: ☃".force_encoding('BINARY'))
407
+ end
408
+ end
409
+
410
+ describe "reading a packet from a socket" do
411
+ let(:socket) { StringIO.new("\x30\x11\x00\x04testhello world") }
412
+ let(:packet) { MQTT::Packet.read(socket) }
413
+
414
+ it "should correctly create the right type of packet object" do
415
+ expect(packet.class).to eq(MQTT::Packet::Publish)
416
+ end
417
+
418
+ it "should set the body length is read correctly" do
419
+ expect(packet.body_length).to eq(17)
420
+ end
421
+
422
+ it "should set the QoS level correctly" do
423
+ expect(packet.qos).to eq(0)
424
+ end
425
+
426
+ it "should set the RETAIN flag correctly" do
427
+ expect(packet.retain).to be_falsey
428
+ end
429
+
430
+ it "should set the DUP flag correctly" do
431
+ expect(packet.duplicate).to be_falsey
432
+ end
433
+
434
+ it "should set the topic name correctly" do
435
+ expect(packet.topic).to eq('test')
436
+ expect(packet.topic.encoding.to_s).to eq('UTF-8')
437
+ end
438
+
439
+ it "should set the payload correctly" do
440
+ expect(packet.payload).to eq('hello world')
441
+ expect(packet.payload.encoding.to_s).to eq('ASCII-8BIT')
442
+ end
443
+ end
444
+
445
+ describe "when calling the inspect method" do
446
+ it "should output the payload, if it is less than 16 bytes" do
447
+ packet = MQTT::Packet::Publish.new( :topic => "topic", :payload => "payload" )
448
+ expect(packet.inspect).to eq("#<MQTT::Packet::Publish: d0, q0, r0, m0, 'topic', 'payload'>")
449
+ end
450
+
451
+ it "should output the length of the payload, if it is more than 16 bytes" do
452
+ packet = MQTT::Packet::Publish.new( :topic => "topic", :payload => 'x'*32 )
453
+ expect(packet.inspect).to eq("#<MQTT::Packet::Publish: d0, q0, r0, m0, 'topic', ... (32 bytes)>")
454
+ end
455
+
456
+ it "should only output the length of a binary payload" do
457
+ packet = MQTT::Packet.parse("\x31\x12\x00\x04test\x8D\xF8\x09\x40\xC4\xE7\x4f\xF0\xFF\x30\xE0\xE7")
458
+ expect(packet.inspect).to eq("#<MQTT::Packet::Publish: d0, q0, r1, m0, 'test', ... (12 bytes)>")
459
+ end
460
+ end
461
+ end
462
+
463
+ describe MQTT::Packet::Connect do
464
+ describe "when serialising a packet" do
465
+ it "should output the correct bytes for a packet with no flags" do
466
+ packet = MQTT::Packet::Connect.new( :client_id => 'myclient' )
467
+ expect(packet.to_s).to eq("\020\026\x00\x06MQIsdp\x03\x02\x00\x0f\x00\x08myclient")
468
+ end
469
+
470
+ it "should output the correct bytes for a packet with clean session turned off" do
471
+ packet = MQTT::Packet::Connect.new(
472
+ :client_id => 'myclient',
473
+ :clean_session => false
474
+ )
475
+ expect(packet.to_s).to eq("\020\026\x00\x06MQIsdp\x03\x00\x00\x0f\x00\x08myclient")
476
+ end
477
+
478
+ context "protocol version 3.1.0" do
479
+ it "should raise an exception when there is no client identifier" do
480
+ expect {
481
+ MQTT::Packet::Connect.new(:version => '3.1.0', :client_id => '').to_s
482
+ }.to raise_error(
483
+ 'Client identifier too short while serialising packet'
484
+ )
485
+ end
486
+
487
+ it "should raise an exception when the client identifier is too long" do
488
+ expect {
489
+ client_id = '0EB8D2FE7C254715B4467C5B2ECAD100'
490
+ MQTT::Packet::Connect.new(:version => '3.1.0', :client_id => client_id).to_s
491
+ }.to raise_error(
492
+ 'Client identifier too long when serialising packet'
493
+ )
494
+ end
495
+ end
496
+
497
+ context "protocol version 3.1.1" do
498
+ it "should allow no client identifier" do
499
+ packet = MQTT::Packet::Connect.new(
500
+ :version => '3.1.1',
501
+ :client_id => '',
502
+ :clean_session => true
503
+ )
504
+ expect(packet.to_s).to eq("\020\014\x00\x04MQTT\x04\x02\x00\x0f\x00\x00")
505
+ end
506
+
507
+ it "should allow a 32 character client identifier" do
508
+ client_id = '0EB8D2FE7C254715B4467C5B2ECAD100'
509
+ packet = MQTT::Packet::Connect.new(
510
+ :version => '3.1.1',
511
+ :client_id => client_id,
512
+ :clean_session => true
513
+ )
514
+ expect(packet.to_s).to eq("\x10,\x00\x04MQTT\x04\x02\x00\x0F\x00\x200EB8D2FE7C254715B4467C5B2ECAD100")
515
+ end
516
+ end
517
+
518
+ it "should raise an exception if the keep alive value is less than 0" do
519
+ expect {
520
+ MQTT::Packet::Connect.new(:client_id => 'test', :keep_alive => -2).to_s
521
+ }.to raise_error(
522
+ 'Invalid keep-alive value: cannot be less than 0'
523
+ )
524
+ end
525
+
526
+ it "should output the correct bytes for a packet with a Will" do
527
+ packet = MQTT::Packet::Connect.new(
528
+ :client_id => 'myclient',
529
+ :clean_session => true,
530
+ :will_qos => 1,
531
+ :will_retain => false,
532
+ :will_topic => 'topic',
533
+ :will_payload => 'hello'
534
+ )
535
+ expect(packet.to_s).to eq(
536
+ "\x10\x24"+
537
+ "\x00\x06MQIsdp"+
538
+ "\x03\x0e\x00\x0f"+
539
+ "\x00\x08myclient"+
540
+ "\x00\x05topic\x00\x05hello"
541
+ )
542
+ end
543
+
544
+ it "should output the correct bytes for a packet with a username and password" do
545
+ packet = MQTT::Packet::Connect.new(
546
+ :client_id => 'myclient',
547
+ :username => 'username',
548
+ :password => 'password'
549
+ )
550
+ expect(packet.to_s).to eq(
551
+ "\x10\x2A"+
552
+ "\x00\x06MQIsdp"+
553
+ "\x03\xC2\x00\x0f"+
554
+ "\x00\x08myclient"+
555
+ "\x00\x08username"+
556
+ "\x00\x08password"
557
+ )
558
+ end
559
+
560
+ it "should output the correct bytes for a packet with everything" do
561
+ packet = MQTT::Packet::Connect.new(
562
+ :client_id => '12345678901234567890123',
563
+ :clean_session => true,
564
+ :keep_alive => 65535,
565
+ :will_qos => 2,
566
+ :will_retain => true,
567
+ :will_topic => 'will_topic',
568
+ :will_payload => 'will_message',
569
+ :username => 'user0123456789',
570
+ :password => 'pass0123456789'
571
+ )
572
+ expect(packet.to_s).to eq(
573
+ "\x10\x5F"+ # fixed header (2)
574
+ "\x00\x06MQIsdp"+ # protocol name (8)
575
+ "\x03\xf6"+ # protocol level + flags (2)
576
+ "\xff\xff"+ # keep alive (2)
577
+ "\x00\x1712345678901234567890123"+ # client identifier (25)
578
+ "\x00\x0Awill_topic"+ # will topic (12)
579
+ "\x00\x0Cwill_message"+ # will message (14)
580
+ "\x00\x0Euser0123456789"+ # username (16)
581
+ "\x00\x0Epass0123456789"
582
+ ) # password (16)
583
+ end
584
+
585
+ context 'protocol version 3.1.1' do
586
+ it "should output the correct bytes for a packet with no flags" do
587
+ packet = MQTT::Packet::Connect.new( :version => '3.1.1', :client_id => 'myclient' )
588
+ expect(packet.to_s).to eq("\020\024\x00\x04MQTT\x04\x02\x00\x0f\x00\x08myclient")
589
+ end
590
+ end
591
+
592
+ context 'an invalid protocol version number' do
593
+ it "should raise a protocol exception" do
594
+ expect {
595
+ packet = MQTT::Packet::Connect.new( :version => 'x.x.x', :client_id => 'myclient' )
596
+ }.to raise_error(
597
+ ArgumentError,
598
+ "Unsupported protocol version: x.x.x"
599
+ )
600
+ end
601
+ end
602
+
603
+ end
604
+
605
+ describe "when parsing a simple 3.1.0 Connect packet" do
606
+ let(:packet) do
607
+ MQTT::Packet.parse(
608
+ "\x10\x16\x00\x06MQIsdp\x03\x00\x00\x0a\x00\x08myclient"
609
+ )
610
+ end
611
+
612
+ it "should correctly create the right type of packet object" do
613
+ expect(packet.class).to eq(MQTT::Packet::Connect)
614
+ end
615
+
616
+ it "should set the fixed header flags of the packet correctly" do
617
+ expect(packet.flags).to eq([false, false, false, false])
618
+ end
619
+
620
+ it "should set the Protocol Name of the packet correctly" do
621
+ expect(packet.protocol_name).to eq('MQIsdp')
622
+ expect(packet.protocol_name.encoding.to_s).to eq('UTF-8')
623
+ end
624
+
625
+ it "should set the Protocol Level of the packet correctly" do
626
+ expect(packet.protocol_level).to eq(3)
627
+ end
628
+
629
+ it "should set the Protocol version of the packet correctly" do
630
+ expect(packet.version).to eq('3.1.0')
631
+ end
632
+
633
+ it "should set the Client Identifier of the packet correctly" do
634
+ expect(packet.client_id).to eq('myclient')
635
+ expect(packet.client_id.encoding.to_s).to eq('UTF-8')
636
+ end
637
+
638
+ it "should set the Keep Alive timer of the packet correctly" do
639
+ expect(packet.keep_alive).to eq(10)
640
+ end
641
+
642
+ it "should set not have the clean session flag set" do
643
+ expect(packet.clean_session).to be_falsey
644
+ end
645
+
646
+ it "should set the the username field of the packet to nil" do
647
+ expect(packet.username).to be_nil
648
+ end
649
+
650
+ it "should set the the password field of the packet to nil" do
651
+ expect(packet.password).to be_nil
652
+ end
653
+ end
654
+
655
+ describe "when parsing a simple 3.1.1 Connect packet" do
656
+ let(:packet) do
657
+ MQTT::Packet.parse(
658
+ "\x10\x14\x00\x04MQTT\x04\x00\x00\x0a\x00\x08myclient"
659
+ )
660
+ end
661
+
662
+ it "should correctly create the right type of packet object" do
663
+ expect(packet.class).to eq(MQTT::Packet::Connect)
664
+ end
665
+
666
+ it "should set the fixed header flags of the packet correctly" do
667
+ expect(packet.flags).to eq([false, false, false, false])
668
+ end
669
+
670
+ it "should set the Protocol Name of the packet correctly" do
671
+ expect(packet.protocol_name).to eq('MQTT')
672
+ expect(packet.protocol_name.encoding.to_s).to eq('UTF-8')
673
+ end
674
+
675
+ it "should set the Protocol Level of the packet correctly" do
676
+ expect(packet.protocol_level).to eq(4)
677
+ end
678
+
679
+ it "should set the Protocol version of the packet correctly" do
680
+ expect(packet.version).to eq('3.1.1')
681
+ end
682
+
683
+ it "should set the Client Identifier of the packet correctly" do
684
+ expect(packet.client_id).to eq('myclient')
685
+ expect(packet.client_id.encoding.to_s).to eq('UTF-8')
686
+ end
687
+
688
+ it "should set the Keep Alive timer of the packet correctly" do
689
+ expect(packet.keep_alive).to eq(10)
690
+ end
691
+
692
+ it "should set not have the clean session flag set" do
693
+ expect(packet.clean_session).to be_falsey
694
+ end
695
+
696
+ it "should set the the username field of the packet to nil" do
697
+ expect(packet.username).to be_nil
698
+ end
699
+
700
+ it "should set the the password field of the packet to nil" do
701
+ expect(packet.password).to be_nil
702
+ end
703
+ end
704
+
705
+ describe "when parsing a Connect packet with the clean session flag set" do
706
+ let(:packet) do
707
+ MQTT::Packet.parse(
708
+ "\x10\x16\x00\x06MQIsdp\x03\x02\x00\x0a\x00\x08myclient"
709
+ )
710
+ end
711
+
712
+ it "should set the clean session flag" do
713
+ expect(packet.clean_session).to be_truthy
714
+ end
715
+ end
716
+
717
+ describe "when parsing a Connect packet with a Will and Testament" do
718
+ let(:packet) do
719
+ MQTT::Packet.parse(
720
+ "\x10\x24\x00\x06MQIsdp\x03\x0e\x00\x0a\x00\x08myclient\x00\x05topic\x00\x05hello"
721
+ )
722
+ end
723
+
724
+ it "should correctly create the right type of packet object" do
725
+ expect(packet.class).to eq(MQTT::Packet::Connect)
726
+ end
727
+
728
+ it "should set the fixed header flags of the packet correctly" do
729
+ expect(packet.flags).to eq([false, false, false, false])
730
+ end
731
+
732
+ it "should set the Protocol Name of the packet correctly" do
733
+ expect(packet.protocol_name).to eq('MQIsdp')
734
+ expect(packet.protocol_name.encoding.to_s).to eq('UTF-8')
735
+ end
736
+
737
+ it "should set the Protocol Level of the packet correctly" do
738
+ expect(packet.protocol_level).to eq(3)
739
+ end
740
+
741
+ it "should set the Protocol version of the packet correctly" do
742
+ expect(packet.version).to eq('3.1.0')
743
+ end
744
+
745
+ it "should set the Client Identifier of the packet correctly" do
746
+ expect(packet.client_id).to eq('myclient')
747
+ expect(packet.client_id.encoding.to_s).to eq('UTF-8')
748
+ end
749
+
750
+ it "should set the clean session flag should be set" do
751
+ expect(packet.clean_session).to be_truthy
752
+ end
753
+
754
+ it "should set the QoS of the Will should be 1" do
755
+ expect(packet.will_qos).to eq(1)
756
+ end
757
+
758
+ it "should set the Will retain flag should be false" do
759
+ expect(packet.will_retain).to be_falsey
760
+ end
761
+
762
+ it "should set the Will topic of the packet correctly" do
763
+ expect(packet.will_topic).to eq('topic')
764
+ expect(packet.will_topic.encoding.to_s).to eq('UTF-8')
765
+ end
766
+
767
+ it "should set the Will payload of the packet correctly" do
768
+ expect(packet.will_payload).to eq('hello')
769
+ expect(packet.will_payload.encoding.to_s).to eq('UTF-8')
770
+ end
771
+ end
772
+
773
+ describe "when parsing a Connect packet with a username and password" do
774
+ let(:packet) do
775
+ MQTT::Packet.parse(
776
+ "\x10\x2A"+
777
+ "\x00\x06MQIsdp"+
778
+ "\x03\xC0\x00\x0a"+
779
+ "\x00\x08myclient"+
780
+ "\x00\x08username"+
781
+ "\x00\x08password"
782
+ )
783
+ end
784
+
785
+ it "should correctly create the right type of packet object" do
786
+ expect(packet.class).to eq(MQTT::Packet::Connect)
787
+ end
788
+
789
+ it "should set the fixed header flags of the packet correctly" do
790
+ expect(packet.flags).to eq([false, false, false, false])
791
+ end
792
+
793
+ it "should set the Protocol Name of the packet correctly" do
794
+ expect(packet.protocol_name).to eq('MQIsdp')
795
+ expect(packet.protocol_name.encoding.to_s).to eq('UTF-8')
796
+ end
797
+
798
+ it "should set the Protocol Level of the packet correctly" do
799
+ expect(packet.protocol_level).to eq(3)
800
+ end
801
+
802
+ it "should set the Protocol version of the packet correctly" do
803
+ expect(packet.version).to eq('3.1.0')
804
+ end
805
+
806
+ it "should set the Client Identifier of the packet correctly" do
807
+ expect(packet.client_id).to eq('myclient')
808
+ expect(packet.client_id.encoding.to_s).to eq('UTF-8')
809
+ end
810
+
811
+ it "should set the Keep Alive Timer of the packet correctly" do
812
+ expect(packet.keep_alive).to eq(10)
813
+ end
814
+
815
+ it "should set the Username of the packet correctly" do
816
+ expect(packet.username).to eq('username')
817
+ expect(packet.username.encoding.to_s).to eq('UTF-8')
818
+ end
819
+
820
+ it "should set the Username of the packet correctly" do
821
+ expect(packet.password).to eq('password')
822
+ expect(packet.password.encoding.to_s).to eq('UTF-8')
823
+ end
824
+ end
825
+
826
+ describe "when parsing a Connect that has a username but no password" do
827
+ let(:packet) do
828
+ MQTT::Packet.parse(
829
+ "\x10\x20\x00\x06MQIsdp\x03\x80\x00\x0a\x00\x08myclient\x00\x08username"
830
+ )
831
+ end
832
+
833
+ it "should set the Username of the packet correctly" do
834
+ expect(packet.username).to eq('username')
835
+ expect(packet.username.encoding.to_s).to eq('UTF-8')
836
+ end
837
+
838
+ it "should set the Username of the packet correctly" do
839
+ expect(packet.password).to be_nil
840
+ end
841
+ end
842
+
843
+ describe "when parsing a Connect that has a password but no username" do
844
+ let(:packet) do
845
+ MQTT::Packet.parse(
846
+ "\x10\x20\x00\x06MQIsdp\x03\x40\x00\x0a\x00\x08myclient\x00\x08password"
847
+ )
848
+ end
849
+
850
+ it "should set the Username of the packet correctly" do
851
+ expect(packet.username).to be_nil
852
+ end
853
+
854
+ it "should set the Username of the packet correctly" do
855
+ expect(packet.password).to eq('password')
856
+ expect(packet.password.encoding.to_s).to eq('UTF-8')
857
+ end
858
+ end
859
+
860
+ describe "when parsing a Connect packet has the username and password flags set but doesn't have the fields" do
861
+ let(:packet) do
862
+ MQTT::Packet.parse(
863
+ "\x10\x16\x00\x06MQIsdp\x03\xC0\x00\x0a\x00\x08myclient"
864
+ )
865
+ end
866
+
867
+ it "should set the Username of the packet correctly" do
868
+ expect(packet.username).to be_nil
869
+ end
870
+
871
+ it "should set the Username of the packet correctly" do
872
+ expect(packet.password).to be_nil
873
+ end
874
+ end
875
+
876
+ describe "when parsing a Connect packet with every option set" do
877
+ let(:packet) do
878
+ MQTT::Packet.parse(
879
+ "\x10\x5F"+ # fixed header (2)
880
+ "\x00\x06MQIsdp"+ # protocol name (8)
881
+ "\x03\xf6"+ # protocol level + flags (2)
882
+ "\xff\xff"+ # keep alive (2)
883
+ "\x00\x1712345678901234567890123"+ # client identifier (25)
884
+ "\x00\x0Awill_topic"+ # will topic (12)
885
+ "\x00\x0Cwill_message"+ # will message (14)
886
+ "\x00\x0Euser0123456789"+ # username (16)
887
+ "\x00\x0Epass0123456789" # password (16)
888
+ )
889
+ end
890
+
891
+ it "should correctly create the right type of packet object" do
892
+ expect(packet.class).to eq(MQTT::Packet::Connect)
893
+ end
894
+
895
+ it "should set the fixed header flags of the packet correctly" do
896
+ expect(packet.flags).to eq([false, false, false, false])
897
+ end
898
+
899
+ it "should set the Protocol Name of the packet correctly" do
900
+ expect(packet.protocol_name).to eq('MQIsdp')
901
+ expect(packet.protocol_name.encoding.to_s).to eq('UTF-8')
902
+ end
903
+
904
+ it "should set the Protocol Level of the packet correctly" do
905
+ expect(packet.protocol_level).to eq(3)
906
+ end
907
+
908
+ it "should set the Protocol version of the packet correctly" do
909
+ expect(packet.version).to eq('3.1.0')
910
+ end
911
+
912
+ it "should set the Keep Alive Timer of the packet correctly" do
913
+ expect(packet.keep_alive).to eq(65535)
914
+ end
915
+
916
+ it "should set the Client Identifier of the packet correctly" do
917
+ expect(packet.client_id).to eq('12345678901234567890123')
918
+ expect(packet.client_id.encoding.to_s).to eq('UTF-8')
919
+ end
920
+
921
+ it "should set the Will QoS of the packet correctly" do
922
+ expect(packet.will_qos).to eq(2)
923
+ end
924
+
925
+ it "should set the Will retain flag of the packet correctly" do
926
+ expect(packet.will_retain).to be_truthy
927
+ end
928
+
929
+ it "should set the Will topic of the packet correctly" do
930
+ expect(packet.will_topic).to eq('will_topic')
931
+ expect(packet.will_topic.encoding.to_s).to eq('UTF-8')
932
+ end
933
+
934
+ it "should set the Will payload of the packet correctly" do
935
+ expect(packet.will_payload).to eq('will_message')
936
+ expect(packet.will_payload.encoding.to_s).to eq('UTF-8')
937
+ end
938
+
939
+ it "should set the Username of the packet correctly" do
940
+ expect(packet.username).to eq('user0123456789')
941
+ expect(packet.username.encoding.to_s).to eq('UTF-8')
942
+ end
943
+
944
+ it "should set the Username of the packet correctly" do
945
+ expect(packet.password).to eq('pass0123456789')
946
+ expect(packet.password.encoding.to_s).to eq('UTF-8')
947
+ end
948
+ end
949
+
950
+ describe "when parsing packet with an unknown protocol name" do
951
+ it "should raise a protocol exception" do
952
+ expect {
953
+ packet = MQTT::Packet.parse(
954
+ "\x10\x16\x00\x06FooBar\x03\x00\x00\x0a\x00\x08myclient"
955
+ )
956
+ }.to raise_error(
957
+ MQTT::ProtocolException,
958
+ "Unsupported protocol: FooBar/3"
959
+ )
960
+ end
961
+ end
962
+
963
+ describe "when parsing packet with an unknown protocol level" do
964
+ it "should raise a protocol exception" do
965
+ expect {
966
+ packet = MQTT::Packet.parse(
967
+ "\x10\x16\x00\x06MQIsdp\x02\x00\x00\x0a\x00\x08myclient"
968
+ )
969
+ }.to raise_error(
970
+ MQTT::ProtocolException,
971
+ "Unsupported protocol: MQIsdp/2"
972
+ )
973
+ end
974
+ end
975
+
976
+ describe "when parsing packet with invalid fixed header flags" do
977
+ it "should raise a protocol exception" do
978
+ expect {
979
+ MQTT::Packet.parse(
980
+ "\x13\x16\x00\x06MQIsdp\x03\x00\x00\x0a\x00\x08myclient"
981
+ )
982
+ }.to raise_error(
983
+ MQTT::ProtocolException,
984
+ "Invalid flags in CONNECT packet header"
985
+ )
986
+ end
987
+ end
988
+
989
+ describe "when calling the inspect method" do
990
+ it "should output correct string for the default options" do
991
+ packet = MQTT::Packet::Connect.new
992
+ expect(packet.inspect).to eq("#<MQTT::Packet::Connect: keep_alive=15, clean, client_id=''>")
993
+ end
994
+
995
+ it "should output correct string when parameters are given" do
996
+ packet = MQTT::Packet::Connect.new(
997
+ :keep_alive => 10,
998
+ :client_id => 'c123',
999
+ :clean_session => false,
1000
+ :username => 'foo'
1001
+ )
1002
+ expect(packet.inspect).to eq("#<MQTT::Packet::Connect: keep_alive=10, client_id='c123', username='foo'>")
1003
+ end
1004
+ end
1005
+
1006
+ describe "deprecated attributes" do
1007
+ it "should still have a protocol_version method that is that same as protocol_level" do
1008
+ packet = MQTT::Packet::Connect.new
1009
+ packet.protocol_version = 5
1010
+ expect(packet.protocol_version).to eq(5)
1011
+ expect(packet.protocol_level).to eq(5)
1012
+ packet.protocol_version = 4
1013
+ expect(packet.protocol_version).to eq(4)
1014
+ expect(packet.protocol_level).to eq(4)
1015
+ end
1016
+ end
1017
+ end
1018
+
1019
+ describe MQTT::Packet::Connack do
1020
+
1021
+ describe "when setting attributes on a packet" do
1022
+ let(:packet) { MQTT::Packet::Connack.new }
1023
+
1024
+ it "should let you change the session present flag of a packet" do
1025
+ packet.session_present = true
1026
+ expect(packet.session_present).to be_truthy
1027
+ end
1028
+
1029
+ it "should let you change the session present flag of a packet using an integer" do
1030
+ packet.session_present = 1
1031
+ expect(packet.session_present).to be_truthy
1032
+ end
1033
+
1034
+ it "should let you change the return code of a packet" do
1035
+ packet.return_code = 3
1036
+ expect(packet.return_code).to eq(3)
1037
+ end
1038
+ end
1039
+
1040
+ describe "when serialising a packet" do
1041
+ it "should output the correct bytes for a sucessful connection acknowledgement packet without Session Present set" do
1042
+ packet = MQTT::Packet::Connack.new( :return_code => 0x00, :session_present => false )
1043
+ expect(packet.to_s).to eq("\x20\x02\x00\x00")
1044
+ end
1045
+
1046
+ it "should output the correct bytes for a sucessful connection acknowledgement packet with Session Present set" do
1047
+ packet = MQTT::Packet::Connack.new( :return_code => 0x00, :session_present => true )
1048
+ expect(packet.to_s).to eq("\x20\x02\x01\x00")
1049
+ end
1050
+ end
1051
+
1052
+ describe "when parsing a successful Connection Accepted packet" do
1053
+ let(:packet) do
1054
+ MQTT::Packet.parse( "\x20\x02\x00\x00" )
1055
+ end
1056
+
1057
+ it "should correctly create the right type of packet object" do
1058
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1059
+ end
1060
+
1061
+ it "should set the fixed header flags of the packet correctly" do
1062
+ expect(packet.flags).to eq([false, false, false, false])
1063
+ end
1064
+
1065
+ it "should set the Session Pression flag of the packet correctly" do
1066
+ expect(packet.session_present).to eq(false)
1067
+ end
1068
+
1069
+ it "should set the return code of the packet correctly" do
1070
+ expect(packet.return_code).to eq(0x00)
1071
+ end
1072
+
1073
+ it "should set the return message of the packet correctly" do
1074
+ expect(packet.return_msg).to match(/Connection Accepted/i)
1075
+ end
1076
+ end
1077
+
1078
+ describe "when parsing a successful Connection Accepted packet with Session Present set" do
1079
+ let(:packet) do
1080
+ MQTT::Packet.parse( "\x20\x02\x01\x00" )
1081
+ end
1082
+
1083
+ it "should correctly create the right type of packet object" do
1084
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1085
+ end
1086
+
1087
+ it "should set the fixed header flags of the packet correctly" do
1088
+ expect(packet.flags).to eq([false, false, false, false])
1089
+ end
1090
+
1091
+ it "should set the Session Pression flag of the packet correctly" do
1092
+ expect(packet.session_present).to eq(true)
1093
+ end
1094
+
1095
+ it "should set the return code of the packet correctly" do
1096
+ expect(packet.return_code).to eq(0x00)
1097
+ end
1098
+
1099
+ it "should set the return message of the packet correctly" do
1100
+ expect(packet.return_msg).to match(/Connection Accepted/i)
1101
+ end
1102
+ end
1103
+
1104
+ describe "when parsing a unacceptable protocol version packet" do
1105
+ let(:packet) do
1106
+ MQTT::Packet.parse( "\x20\x02\x00\x01" )
1107
+ end
1108
+
1109
+ it "should correctly create the right type of packet object" do
1110
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1111
+ end
1112
+
1113
+ it "should set the return code of the packet correctly" do
1114
+ expect(packet.return_code).to eq(0x01)
1115
+ end
1116
+
1117
+ it "should set the return message of the packet correctly" do
1118
+ expect(packet.return_msg).to match(/unacceptable protocol version/i)
1119
+ end
1120
+ end
1121
+
1122
+ describe "when parsing a client identifier rejected packet" do
1123
+ let(:packet) { MQTT::Packet.parse( "\x20\x02\x00\x02" ) }
1124
+
1125
+ it "should correctly create the right type of packet object" do
1126
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1127
+ end
1128
+
1129
+ it "should set the return code of the packet correctly" do
1130
+ expect(packet.return_code).to eq(0x02)
1131
+ end
1132
+
1133
+ it "should set the return message of the packet correctly" do
1134
+ expect(packet.return_msg).to match(/client identifier rejected/i)
1135
+ end
1136
+ end
1137
+
1138
+ describe "when parsing a server unavailable packet" do
1139
+ let(:packet) do
1140
+ MQTT::Packet.parse( "\x20\x02\x00\x03" )
1141
+ end
1142
+
1143
+ it "should correctly create the right type of packet object" do
1144
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1145
+ end
1146
+
1147
+ it "should set the return code of the packet correctly" do
1148
+ expect(packet.return_code).to eq(0x03)
1149
+ end
1150
+
1151
+ it "should set the return message of the packet correctly" do
1152
+ expect(packet.return_msg).to match(/server unavailable/i)
1153
+ end
1154
+ end
1155
+
1156
+ describe "when parsing a server unavailable packet" do
1157
+ let(:packet) do
1158
+ MQTT::Packet.parse( "\x20\x02\x00\x04" )
1159
+ end
1160
+
1161
+ it "should correctly create the right type of packet object" do
1162
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1163
+ end
1164
+
1165
+ it "should set the return code of the packet correctly" do
1166
+ expect(packet.return_code).to eq(0x04)
1167
+ end
1168
+
1169
+ it "should set the return message of the packet correctly" do
1170
+ expect(packet.return_msg).to match(/bad user name or password/i)
1171
+ end
1172
+ end
1173
+
1174
+ describe "when parsing a server unavailable packet" do
1175
+ let(:packet) do
1176
+ MQTT::Packet.parse( "\x20\x02\x00\x05" )
1177
+ end
1178
+
1179
+ it "should correctly create the right type of packet object" do
1180
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1181
+ end
1182
+
1183
+ it "should set the return code of the packet correctly" do
1184
+ expect(packet.return_code).to eq(0x05)
1185
+ end
1186
+
1187
+ it "should set the return message of the packet correctly" do
1188
+ expect(packet.return_msg).to match(/not authorised/i)
1189
+ end
1190
+ end
1191
+
1192
+ describe "when parsing an unknown connection refused packet" do
1193
+ let(:packet) { MQTT::Packet.parse( "\x20\x02\x00\x10" ) }
1194
+
1195
+ it "should correctly create the right type of packet object" do
1196
+ expect(packet.class).to eq(MQTT::Packet::Connack)
1197
+ end
1198
+
1199
+ it "should set the return code of the packet correctly" do
1200
+ expect(packet.return_code).to eq(0x10)
1201
+ end
1202
+
1203
+ it "should set the return message of the packet correctly" do
1204
+ expect(packet.return_msg).to match(/Connection refused: error code 16/i)
1205
+ end
1206
+ end
1207
+
1208
+ describe "when parsing packet with invalid Connack flags set" do
1209
+ it "should raise an exception" do
1210
+ expect {
1211
+ packet = MQTT::Packet.parse( "\x20\x02\xff\x05" )
1212
+ }.to raise_error(
1213
+ MQTT::ProtocolException,
1214
+ "Invalid flags in Connack variable header"
1215
+ )
1216
+ end
1217
+ end
1218
+
1219
+ describe "when parsing packet with extra bytes on the end" do
1220
+ it "should raise an exception" do
1221
+ expect {
1222
+ packet = MQTT::Packet.parse( "\x20\x03\x00\x00\x00" )
1223
+ }.to raise_error(
1224
+ MQTT::ProtocolException,
1225
+ "Extra bytes at end of Connect Acknowledgment packet"
1226
+ )
1227
+ end
1228
+ end
1229
+
1230
+ describe "when parsing packet with invalid fixed header flags" do
1231
+ it "should raise a protocol exception" do
1232
+ expect {
1233
+ MQTT::Packet.parse( "\x23\x02\x00\x00" )
1234
+ }.to raise_error(
1235
+ MQTT::ProtocolException,
1236
+ "Invalid flags in CONNACK packet header"
1237
+ )
1238
+ end
1239
+ end
1240
+
1241
+ describe "when calling the inspect method" do
1242
+ it "should output the right string when the return code is 0" do
1243
+ packet = MQTT::Packet::Connack.new( :return_code => 0x00 )
1244
+ expect(packet.inspect).to eq("#<MQTT::Packet::Connack: 0x00>")
1245
+ end
1246
+ it "should output the right string when the return code is 0x0F" do
1247
+ packet = MQTT::Packet::Connack.new( :return_code => 0x0F )
1248
+ expect(packet.inspect).to eq("#<MQTT::Packet::Connack: 0x0F>")
1249
+ end
1250
+ end
1251
+ end
1252
+
1253
+ describe MQTT::Packet::Puback do
1254
+ describe "when serialising a packet" do
1255
+ it "should output the correct bytes for a packet with no flags" do
1256
+ packet = MQTT::Packet::Puback.new( :id => 0x1234 )
1257
+ expect(packet.to_s).to eq("\x40\x02\x12\x34")
1258
+ end
1259
+ end
1260
+
1261
+ describe "when parsing a packet" do
1262
+ let(:packet) { MQTT::Packet.parse( "\x40\x02\x12\x34" ) }
1263
+
1264
+ it "should correctly create the right type of packet object" do
1265
+ expect(packet.class).to eq(MQTT::Packet::Puback)
1266
+ end
1267
+
1268
+ it "should set the message id of the packet correctly" do
1269
+ expect(packet.id).to eq(0x1234)
1270
+ end
1271
+ end
1272
+
1273
+ describe "when parsing packet with extra bytes on the end" do
1274
+ it "should raise an exception" do
1275
+ expect {
1276
+ packet = MQTT::Packet.parse( "\x40\x03\x12\x34\x00" )
1277
+ }.to raise_error(
1278
+ MQTT::ProtocolException,
1279
+ "Extra bytes at end of Publish Acknowledgment packet"
1280
+ )
1281
+ end
1282
+ end
1283
+
1284
+ describe "when parsing packet with invalid fixed header flags" do
1285
+ it "should raise a protocol exception" do
1286
+ expect {
1287
+ MQTT::Packet.parse( "\x43\x02\x12\x34" )
1288
+ }.to raise_error(
1289
+ MQTT::ProtocolException,
1290
+ "Invalid flags in PUBACK packet header"
1291
+ )
1292
+ end
1293
+ end
1294
+
1295
+ it "should output the right string when calling inspect" do
1296
+ packet = MQTT::Packet::Puback.new( :id => 0x1234 )
1297
+ expect(packet.inspect).to eq("#<MQTT::Packet::Puback: 0x1234>")
1298
+ end
1299
+ end
1300
+
1301
+ describe MQTT::Packet::Pubrec do
1302
+ describe "when serialising a packet" do
1303
+ it "should output the correct bytes for a packet with no flags" do
1304
+ packet = MQTT::Packet::Pubrec.new( :id => 0x1234 )
1305
+ expect(packet.to_s).to eq("\x50\x02\x12\x34")
1306
+ end
1307
+ end
1308
+
1309
+ describe "when parsing a packet" do
1310
+ let(:packet) { MQTT::Packet.parse( "\x50\x02\x12\x34" ) }
1311
+
1312
+ it "should correctly create the right type of packet object" do
1313
+ expect(packet.class).to eq(MQTT::Packet::Pubrec)
1314
+ end
1315
+
1316
+ it "should set the message id of the packet correctly" do
1317
+ expect(packet.id).to eq(0x1234)
1318
+ end
1319
+ end
1320
+
1321
+ describe "when parsing packet with extra bytes on the end" do
1322
+ it "should raise an exception" do
1323
+ expect {
1324
+ packet = MQTT::Packet.parse( "\x50\x03\x12\x34\x00" )
1325
+ }.to raise_error(
1326
+ MQTT::ProtocolException,
1327
+ "Extra bytes at end of Publish Received packet"
1328
+ )
1329
+ end
1330
+ end
1331
+
1332
+ describe "when parsing packet with invalid fixed header flags" do
1333
+ it "should raise a protocol exception" do
1334
+ expect {
1335
+ MQTT::Packet.parse( "\x53\x02\x12\x34" )
1336
+ }.to raise_error(
1337
+ MQTT::ProtocolException,
1338
+ "Invalid flags in PUBREC packet header"
1339
+ )
1340
+ end
1341
+ end
1342
+
1343
+ it "should output the right string when calling inspect" do
1344
+ packet = MQTT::Packet::Pubrec.new( :id => 0x1234 )
1345
+ expect(packet.inspect).to eq("#<MQTT::Packet::Pubrec: 0x1234>")
1346
+ end
1347
+ end
1348
+
1349
+ describe MQTT::Packet::Pubrel do
1350
+ describe "when serialising a packet" do
1351
+ it "should output the correct bytes for a packet with no flags" do
1352
+ packet = MQTT::Packet::Pubrel.new( :id => 0x1234 )
1353
+ expect(packet.to_s).to eq("\x62\x02\x12\x34")
1354
+ end
1355
+ end
1356
+
1357
+ describe "when parsing a packet" do
1358
+ let(:packet) { MQTT::Packet.parse( "\x62\x02\x12\x34" ) }
1359
+
1360
+ it "should correctly create the right type of packet object" do
1361
+ expect(packet.class).to eq(MQTT::Packet::Pubrel)
1362
+ end
1363
+
1364
+ it "should set the message id of the packet correctly" do
1365
+ expect(packet.id).to eq(0x1234)
1366
+ end
1367
+ end
1368
+
1369
+ describe "when parsing packet with extra bytes on the end" do
1370
+ it "should raise an exception" do
1371
+ expect {
1372
+ packet = MQTT::Packet.parse( "\x62\x03\x12\x34\x00" )
1373
+ }.to raise_error(
1374
+ MQTT::ProtocolException,
1375
+ "Extra bytes at end of Publish Release packet"
1376
+ )
1377
+ end
1378
+ end
1379
+
1380
+ describe "when parsing packet with invalid fixed header flags" do
1381
+ it "should raise a protocol exception" do
1382
+ expect {
1383
+ MQTT::Packet.parse( "\x60\x02\x12\x34" )
1384
+ }.to raise_error(
1385
+ MQTT::ProtocolException,
1386
+ "Invalid flags in PUBREL packet header"
1387
+ )
1388
+ end
1389
+ end
1390
+
1391
+ it "should output the right string when calling inspect" do
1392
+ packet = MQTT::Packet::Pubrel.new( :id => 0x1234 )
1393
+ expect(packet.inspect).to eq("#<MQTT::Packet::Pubrel: 0x1234>")
1394
+ end
1395
+ end
1396
+
1397
+ describe MQTT::Packet::Pubcomp do
1398
+ describe "when serialising a packet" do
1399
+ it "should output the correct bytes for a packet with no flags" do
1400
+ packet = MQTT::Packet::Pubcomp.new( :id => 0x1234 )
1401
+ expect(packet.to_s).to eq("\x70\x02\x12\x34")
1402
+ end
1403
+ end
1404
+
1405
+ describe "when parsing a packet" do
1406
+ let(:packet) { MQTT::Packet.parse( "\x70\x02\x12\x34" ) }
1407
+
1408
+ it "should correctly create the right type of packet object" do
1409
+ expect(packet.class).to eq(MQTT::Packet::Pubcomp)
1410
+ end
1411
+
1412
+ it "should set the message id of the packet correctly" do
1413
+ expect(packet.id).to eq(0x1234)
1414
+ end
1415
+ end
1416
+
1417
+ describe "when parsing packet with extra bytes on the end" do
1418
+ it "should raise an exception" do
1419
+ expect {
1420
+ MQTT::Packet.parse( "\x70\x03\x12\x34\x00" )
1421
+ }.to raise_error(
1422
+ MQTT::ProtocolException,
1423
+ "Extra bytes at end of Publish Complete packet"
1424
+ )
1425
+ end
1426
+ end
1427
+
1428
+ describe "when parsing packet with invalid fixed header flags" do
1429
+ it "should raise a protocol exception" do
1430
+ expect {
1431
+ MQTT::Packet.parse( "\x72\x02\x12\x34" )
1432
+ }.to raise_error(
1433
+ MQTT::ProtocolException,
1434
+ "Invalid flags in PUBCOMP packet header"
1435
+ )
1436
+ end
1437
+ end
1438
+
1439
+ it "should output the right string when calling inspect" do
1440
+ packet = MQTT::Packet::Pubcomp.new( :id => 0x1234 )
1441
+ expect(packet.inspect).to eq("#<MQTT::Packet::Pubcomp: 0x1234>")
1442
+ end
1443
+ end
1444
+
1445
+ describe MQTT::Packet::Subscribe do
1446
+ describe "setting the packet's topics" do
1447
+ let(:packet) { MQTT::Packet::Subscribe.new }
1448
+
1449
+ it "should be able to set the topics from a String 'a/b'" do
1450
+ packet.topics = 'a/b'
1451
+ expect(packet.topics).to eq([["a/b", 0]])
1452
+ end
1453
+
1454
+ it "should be able to set the multiple topics from an array ['a/b', 'b/c']" do
1455
+ packet.topics = ['a/b', 'b/c']
1456
+ expect(packet.topics).to eq([["a/b", 0], ['b/c', 0]])
1457
+ end
1458
+
1459
+ it "should be able to set the topics from a Hash {'a/b' => 0, 'b/c' => 1}" do
1460
+ packet.topics = {'a/b' => 0, 'b/c' => 1}
1461
+ expect(packet.topics).to eq([["a/b", 0], ["b/c", 1]])
1462
+ end
1463
+
1464
+ it "should be able to set the topics from a single level array ['a/b', 0]" do
1465
+ packet.topics = ['a/b', 0]
1466
+ expect(packet.topics).to eq([["a/b", 0]])
1467
+ end
1468
+
1469
+ it "should be able to set the topics from a two level array [['a/b' => 0], ['b/c' => 1]]" do
1470
+ packet.topics = [['a/b', 0], ['b/c', 1]]
1471
+ expect(packet.topics).to eq([['a/b', 0], ['b/c', 1]])
1472
+ end
1473
+
1474
+ it "should raise an exception when setting topic with a non-string" do
1475
+ expect {
1476
+ packet.topics = 56
1477
+ }.to raise_error(
1478
+ 'Invalid topics input: 56'
1479
+ )
1480
+ end
1481
+ end
1482
+
1483
+ describe "when serialising a packet" do
1484
+ it "should output the correct bytes for a packet with a single topic" do
1485
+ packet = MQTT::Packet::Subscribe.new( :id => 1, :topics => 'a/b' )
1486
+ expect(packet.to_s).to eq("\x82\x08\x00\x01\x00\x03a/b\x00")
1487
+ end
1488
+
1489
+ it "should output the correct bytes for a packet with multiple topics" do
1490
+ packet = MQTT::Packet::Subscribe.new( :id => 6, :topics => [['a/b', 0], ['c/d', 1]] )
1491
+ expect(packet.to_s).to eq("\x82\x0e\000\x06\x00\x03a/b\x00\x00\x03c/d\x01")
1492
+ end
1493
+
1494
+ it "should raise an exception when no topics are given" do
1495
+ expect {
1496
+ MQTT::Packet::Subscribe.new.to_s
1497
+ }.to raise_error(
1498
+ 'no topics given when serialising packet'
1499
+ )
1500
+ end
1501
+ end
1502
+
1503
+ describe "when parsing a packet with a single topic" do
1504
+ let(:packet) { MQTT::Packet.parse( "\x82\x08\x00\x01\x00\x03a/b\x00" ) }
1505
+
1506
+ it "should correctly create the right type of packet object" do
1507
+ expect(packet.class).to eq(MQTT::Packet::Subscribe)
1508
+ end
1509
+
1510
+ it "should set the fixed header flags of the packet correctly" do
1511
+ expect(packet.flags).to eq([false, true, false, false])
1512
+ end
1513
+
1514
+ it "should set the Message ID correctly" do
1515
+ expect(packet.id).to eq(1)
1516
+ end
1517
+
1518
+ it "should set the topic name correctly" do
1519
+ expect(packet.topics).to eq([['a/b',0]])
1520
+ end
1521
+ end
1522
+
1523
+ describe "when parsing a packet with a two topics" do
1524
+ let(:packet) { MQTT::Packet.parse( "\x82\x0e\000\x06\x00\x03a/b\x00\x00\x03c/d\x01" ) }
1525
+
1526
+ it "should correctly create the right type of packet object" do
1527
+ expect(packet.class).to eq(MQTT::Packet::Subscribe)
1528
+ end
1529
+
1530
+ it "should set the fixed header flags of the packet correctly" do
1531
+ expect(packet.flags).to eq([false, true, false, false])
1532
+ end
1533
+
1534
+ it "should set the Message ID correctly" do
1535
+ expect(packet.id).to eq(6)
1536
+ end
1537
+
1538
+ it "should set the topic name correctly" do
1539
+ expect(packet.topics).to eq([['a/b',0],['c/d',1]])
1540
+ end
1541
+ end
1542
+
1543
+ describe "when parsing packet with invalid fixed header flags" do
1544
+ it "should raise a protocol exception" do
1545
+ expect {
1546
+ MQTT::Packet.parse( "\x80\x08\x00\x01\x00\x03a/b\x00" )
1547
+ }.to raise_error(
1548
+ MQTT::ProtocolException,
1549
+ "Invalid flags in SUBSCRIBE packet header"
1550
+ )
1551
+ end
1552
+ end
1553
+
1554
+ describe "when calling the inspect method" do
1555
+ it "should output correct string for a single topic" do
1556
+ packet = MQTT::Packet::Subscribe.new(:topics => 'test')
1557
+ expect(packet.inspect).to eq("#<MQTT::Packet::Subscribe: 0x00, 'test':0>")
1558
+ end
1559
+
1560
+ it "should output correct string for multiple topics" do
1561
+ packet = MQTT::Packet::Subscribe.new(:topics => {'a' => 1, 'b' => 0, 'c' => 2})
1562
+ expect(packet.inspect).to eq("#<MQTT::Packet::Subscribe: 0x00, 'a':1, 'b':0, 'c':2>")
1563
+ end
1564
+ end
1565
+ end
1566
+
1567
+ describe MQTT::Packet::Suback do
1568
+ describe "when serialising a packet" do
1569
+ it "should output the correct bytes for an acknowledgement to a single topic" do
1570
+ packet = MQTT::Packet::Suback.new( :id => 5, :return_codes => 0 )
1571
+ expect(packet.to_s).to eq("\x90\x03\x00\x05\x00")
1572
+ end
1573
+
1574
+ it "should output the correct bytes for an acknowledgement to a two topics" do
1575
+ packet = MQTT::Packet::Suback.new( :id => 6 , :return_codes => [0,1] )
1576
+ expect(packet.to_s).to eq("\x90\x04\x00\x06\x00\x01")
1577
+ end
1578
+
1579
+ it "should raise an exception when no granted QoSs are given" do
1580
+ expect {
1581
+ MQTT::Packet::Suback.new( :id => 7 ).to_s
1582
+ }.to raise_error(
1583
+ 'no granted QoS given when serialising packet'
1584
+ )
1585
+ end
1586
+
1587
+ it "should raise an exception if the granted QoS is not an integer" do
1588
+ expect {
1589
+ MQTT::Packet::Suback.new( :id => 8, :return_codes => :foo ).to_s
1590
+ }.to raise_error(
1591
+ 'return_codes should be an integer or an array of return codes'
1592
+ )
1593
+ end
1594
+ end
1595
+
1596
+ describe "when parsing a packet with a single QoS value of 0" do
1597
+ let(:packet) { MQTT::Packet.parse( "\x90\x03\x12\x34\x00" ) }
1598
+
1599
+ it "should correctly create the right type of packet object" do
1600
+ expect(packet.class).to eq(MQTT::Packet::Suback)
1601
+ end
1602
+
1603
+ it "should set the message id of the packet correctly" do
1604
+ expect(packet.id).to eq(0x1234)
1605
+ end
1606
+
1607
+ it "should set the Granted QoS of the packet correctly" do
1608
+ expect(packet.return_codes).to eq([0])
1609
+ end
1610
+ end
1611
+
1612
+ describe "when parsing a packet with two QoS values" do
1613
+ let(:packet) { MQTT::Packet.parse( "\x90\x04\x12\x34\x01\x01" ) }
1614
+
1615
+ it "should correctly create the right type of packet object" do
1616
+ expect(packet.class).to eq(MQTT::Packet::Suback)
1617
+ end
1618
+
1619
+ it "should set the message id of the packet correctly" do
1620
+ expect(packet.id).to eq(0x1234)
1621
+ end
1622
+
1623
+ it "should set the Granted QoS of the packet correctly" do
1624
+ expect(packet.return_codes).to eq([1,1])
1625
+ end
1626
+ end
1627
+
1628
+ describe "when parsing packet with invalid fixed header flags" do
1629
+ it "should raise a protocol exception" do
1630
+ expect {
1631
+ MQTT::Packet.parse( "\x92\x03\x12\x34\x00" )
1632
+ }.to raise_error(
1633
+ MQTT::ProtocolException,
1634
+ "Invalid flags in SUBACK packet header"
1635
+ )
1636
+ end
1637
+ end
1638
+
1639
+ describe "when calling the inspect method" do
1640
+ it "should output correct string for a single granted qos" do
1641
+ packet = MQTT::Packet::Suback.new(:id => 0x1234, :return_codes => 0)
1642
+ expect(packet.inspect).to eq("#<MQTT::Packet::Suback: 0x1234, rc=0x00>")
1643
+ end
1644
+
1645
+ it "should output correct string for multiple topics" do
1646
+ packet = MQTT::Packet::Suback.new(:id => 0x1235, :return_codes => [0,1,2])
1647
+ expect(packet.inspect).to eq("#<MQTT::Packet::Suback: 0x1235, rc=0x00,0x01,0x02>")
1648
+ end
1649
+ end
1650
+
1651
+ describe "deprecated attributes" do
1652
+ it "should still have a granted_qos method that is that same as return_codes" do
1653
+ packet = MQTT::Packet::Suback.new
1654
+ packet.granted_qos = [0,1,2]
1655
+ expect(packet.granted_qos).to eq([0,1,2])
1656
+ expect(packet.return_codes).to eq([0,1,2])
1657
+ packet.return_codes = [0,1,0]
1658
+ expect(packet.granted_qos).to eq([0,1,0])
1659
+ expect(packet.return_codes).to eq([0,1,0])
1660
+ end
1661
+ end
1662
+ end
1663
+
1664
+ describe MQTT::Packet::Unsubscribe do
1665
+ describe "when serialising a packet" do
1666
+ it "should output the correct bytes for a packet with single topic" do
1667
+ packet = MQTT::Packet::Unsubscribe.new( :id => 5, :topics => 'a/b' )
1668
+ expect(packet.to_s).to eq("\xa2\x07\x00\x05\x00\x03a/b")
1669
+ end
1670
+
1671
+ it "should output the correct bytes for a packet with multiple topics" do
1672
+ packet = MQTT::Packet::Unsubscribe.new( :id => 6, :topics => ['a/b','c/d'] )
1673
+ expect(packet.to_s).to eq("\xa2\x0c\000\006\000\003a/b\000\003c/d")
1674
+ end
1675
+
1676
+ it "should raise an exception when no topics are given" do
1677
+ expect {
1678
+ MQTT::Packet::Unsubscribe.new.to_s
1679
+ }.to raise_error(
1680
+ 'no topics given when serialising packet'
1681
+ )
1682
+ end
1683
+ end
1684
+
1685
+ describe "when parsing a packet" do
1686
+ let(:packet) { MQTT::Packet.parse( "\xa2\f\000\005\000\003a/b\000\003c/d" ) }
1687
+
1688
+ it "should correctly create the right type of packet object" do
1689
+ expect(packet.class).to eq(MQTT::Packet::Unsubscribe)
1690
+ end
1691
+
1692
+ it "should set the fixed header flags of the packet correctly" do
1693
+ expect(packet.flags).to eq([false, true, false, false])
1694
+ end
1695
+
1696
+ it "should set the topic name correctly" do
1697
+ expect(packet.topics).to eq(['a/b','c/d'])
1698
+ end
1699
+ end
1700
+
1701
+ describe "when parsing packet with invalid fixed header flags" do
1702
+ it "should raise a protocol exception" do
1703
+ expect {
1704
+ MQTT::Packet.parse( "\xa0\x07\x00\x05\x00\x03a/b" )
1705
+ }.to raise_error(
1706
+ MQTT::ProtocolException,
1707
+ "Invalid flags in UNSUBSCRIBE packet header"
1708
+ )
1709
+ end
1710
+ end
1711
+
1712
+ describe "when calling the inspect method" do
1713
+ it "should output correct string for a single topic" do
1714
+ packet = MQTT::Packet::Unsubscribe.new(:topics => 'test')
1715
+ expect(packet.inspect).to eq("#<MQTT::Packet::Unsubscribe: 0x00, 'test'>")
1716
+ end
1717
+
1718
+ it "should output correct string for multiple topics" do
1719
+ packet = MQTT::Packet::Unsubscribe.new( :id => 42, :topics => ['a', 'b', 'c'] )
1720
+ expect(packet.inspect).to eq("#<MQTT::Packet::Unsubscribe: 0x2A, 'a', 'b', 'c'>")
1721
+ end
1722
+ end
1723
+ end
1724
+
1725
+ describe MQTT::Packet::Unsuback do
1726
+ describe "when serialising a packet" do
1727
+ it "should output the correct bytes for a packet with no flags" do
1728
+ packet = MQTT::Packet::Unsuback.new( :id => 0x1234 )
1729
+ expect(packet.to_s).to eq("\xB0\x02\x12\x34")
1730
+ end
1731
+ end
1732
+
1733
+ describe "when parsing a packet" do
1734
+ let(:packet) do
1735
+ MQTT::Packet.parse( "\xB0\x02\x12\x34" )
1736
+ end
1737
+
1738
+ it "should correctly create the right type of packet object" do
1739
+ expect(packet.class).to eq(MQTT::Packet::Unsuback)
1740
+ end
1741
+
1742
+ it "should set the message id of the packet correctly" do
1743
+ expect(packet.id).to eq(0x1234)
1744
+ end
1745
+ end
1746
+
1747
+ describe "when parsing packet with extra bytes on the end" do
1748
+ it "should raise an exception" do
1749
+ expect {
1750
+ packet = MQTT::Packet.parse( "\xB0\x03\x12\x34\x00" )
1751
+ }.to raise_error(
1752
+ MQTT::ProtocolException,
1753
+ "Extra bytes at end of Unsubscribe Acknowledgment packet"
1754
+ )
1755
+ end
1756
+ end
1757
+
1758
+ describe "when parsing packet with invalid fixed header flags" do
1759
+ it "should raise a protocol exception" do
1760
+ expect {
1761
+ MQTT::Packet.parse( "\xB2\x02\x12\x34" )
1762
+ }.to raise_error(
1763
+ MQTT::ProtocolException,
1764
+ "Invalid flags in UNSUBACK packet header"
1765
+ )
1766
+ end
1767
+ end
1768
+
1769
+ it "should output the right string when calling inspect" do
1770
+ packet = MQTT::Packet::Unsuback.new( :id => 0x1234 )
1771
+ expect(packet.inspect).to eq("#<MQTT::Packet::Unsuback: 0x1234>")
1772
+ end
1773
+ end
1774
+
1775
+ describe MQTT::Packet::Pingreq do
1776
+ describe "when serialising a packet" do
1777
+ it "should output the correct bytes for a packet with no flags" do
1778
+ packet = MQTT::Packet::Pingreq.new
1779
+ expect(packet.to_s).to eq("\xC0\x00")
1780
+ end
1781
+ end
1782
+
1783
+ describe "when parsing a packet" do
1784
+ it "should correctly create the right type of packet object" do
1785
+ packet = MQTT::Packet.parse( "\xC0\x00" )
1786
+ expect(packet.class).to eq(MQTT::Packet::Pingreq)
1787
+ end
1788
+
1789
+ it "should raise an exception if the packet has a payload" do
1790
+ expect {
1791
+ MQTT::Packet.parse( "\xC0\x05hello" )
1792
+ }.to raise_error(
1793
+ 'Extra bytes at end of Ping Request packet'
1794
+ )
1795
+ end
1796
+ end
1797
+
1798
+ describe "when parsing packet with invalid fixed header flags" do
1799
+ it "should raise a protocol exception" do
1800
+ expect {
1801
+ MQTT::Packet.parse( "\xC2\x00" )
1802
+ }.to raise_error(
1803
+ MQTT::ProtocolException,
1804
+ "Invalid flags in PINGREQ packet header"
1805
+ )
1806
+ end
1807
+ end
1808
+
1809
+ it "should output the right string when calling inspect" do
1810
+ packet = MQTT::Packet::Pingreq.new
1811
+ expect(packet.inspect).to eq("#<MQTT::Packet::Pingreq>")
1812
+ end
1813
+ end
1814
+
1815
+ describe MQTT::Packet::Pingresp do
1816
+ describe "when serialising a packet" do
1817
+ it "should output the correct bytes for a packet with no flags" do
1818
+ packet = MQTT::Packet::Pingresp.new
1819
+ expect(packet.to_s).to eq("\xD0\x00")
1820
+ end
1821
+ end
1822
+
1823
+ describe "when parsing a packet" do
1824
+ it "should correctly create the right type of packet object" do
1825
+ packet = MQTT::Packet.parse( "\xD0\x00" )
1826
+ expect(packet.class).to eq(MQTT::Packet::Pingresp)
1827
+ end
1828
+
1829
+ it "should raise an exception if the packet has a payload" do
1830
+ expect {
1831
+ MQTT::Packet.parse( "\xD0\x05hello" )
1832
+ }.to raise_error(
1833
+ 'Extra bytes at end of Ping Response packet'
1834
+ )
1835
+ end
1836
+ end
1837
+
1838
+ describe "when parsing packet with invalid fixed header flags" do
1839
+ it "should raise a protocol exception" do
1840
+ expect {
1841
+ MQTT::Packet.parse( "\xD2\x00" )
1842
+ }.to raise_error(
1843
+ MQTT::ProtocolException,
1844
+ "Invalid flags in PINGRESP packet header"
1845
+ )
1846
+ end
1847
+ end
1848
+
1849
+ it "should output the right string when calling inspect" do
1850
+ packet = MQTT::Packet::Pingresp.new
1851
+ expect(packet.inspect).to eq("#<MQTT::Packet::Pingresp>")
1852
+ end
1853
+ end
1854
+
1855
+
1856
+ describe MQTT::Packet::Disconnect do
1857
+ describe "when serialising a packet" do
1858
+ it "should output the correct bytes for a packet with no flags" do
1859
+ packet = MQTT::Packet::Disconnect.new
1860
+ expect(packet.to_s).to eq("\xE0\x00")
1861
+ end
1862
+ end
1863
+
1864
+ describe "when parsing a packet" do
1865
+ it "should correctly create the right type of packet object" do
1866
+ packet = MQTT::Packet.parse( "\xE0\x00" )
1867
+ expect(packet.class).to eq(MQTT::Packet::Disconnect)
1868
+ end
1869
+
1870
+ it "should raise an exception if the packet has a payload" do
1871
+ expect {
1872
+ MQTT::Packet.parse( "\xE0\x05hello" )
1873
+ }.to raise_error(
1874
+ 'Extra bytes at end of Disconnect packet'
1875
+ )
1876
+ end
1877
+ end
1878
+
1879
+ describe "when parsing packet with invalid fixed header flags" do
1880
+ it "should raise a protocol exception" do
1881
+ expect {
1882
+ MQTT::Packet.parse( "\xE2\x00" )
1883
+ }.to raise_error(
1884
+ MQTT::ProtocolException,
1885
+ "Invalid flags in DISCONNECT packet header"
1886
+ )
1887
+ end
1888
+ end
1889
+
1890
+ it "should output the right string when calling inspect" do
1891
+ packet = MQTT::Packet::Disconnect.new
1892
+ expect(packet.inspect).to eq("#<MQTT::Packet::Disconnect>")
1893
+ end
1894
+ end
1895
+
1896
+
1897
+ describe "Serialising an invalid packet" do
1898
+ context "that has a no type" do
1899
+ it "should raise an exception" do
1900
+ expect {
1901
+ MQTT::Packet.new.to_s
1902
+ }.to raise_error(
1903
+ RuntimeError,
1904
+ "Invalid packet type: MQTT::Packet"
1905
+ )
1906
+ end
1907
+ end
1908
+ end
1909
+
1910
+ describe "Reading in an invalid packet from a socket" do
1911
+ context "that has 0 length" do
1912
+ it "should raise an exception" do
1913
+ expect {
1914
+ socket = StringIO.new
1915
+ MQTT::Packet.read(socket)
1916
+ }.to raise_error(
1917
+ MQTT::ProtocolException,
1918
+ "Failed to read byte from socket"
1919
+ )
1920
+ end
1921
+ end
1922
+
1923
+ context "that has an incomplete packet length header" do
1924
+ it "should raise an exception" do
1925
+ expect {
1926
+ socket = StringIO.new("\x30\xFF")
1927
+ MQTT::Packet.read(socket)
1928
+ }.to raise_error(
1929
+ MQTT::ProtocolException,
1930
+ "Failed to read byte from socket"
1931
+ )
1932
+ end
1933
+ end
1934
+
1935
+ context "that has the maximum number of bytes in the length header" do
1936
+ it "should raise an exception" do
1937
+ expect {
1938
+ socket = StringIO.new("\x30\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF")
1939
+ MQTT::Packet.read(socket)
1940
+ }.to raise_error(
1941
+ MQTT::ProtocolException,
1942
+ "Failed to parse packet - input buffer (4) is not the same as the body length header (268435455)"
1943
+ )
1944
+ end
1945
+ end
1946
+ end
1947
+
1948
+ describe "Parsing an invalid packet" do
1949
+ context "that has no length" do
1950
+ it "should raise an exception" do
1951
+ expect {
1952
+ MQTT::Packet.parse( "" )
1953
+ }.to raise_error(
1954
+ MQTT::ProtocolException,
1955
+ "Invalid packet: less than 2 bytes long"
1956
+ )
1957
+ end
1958
+ end
1959
+
1960
+ context "that has an invalid type identifier" do
1961
+ it "should raise an exception" do
1962
+ expect {
1963
+ MQTT::Packet.parse( "\x00\x00" )
1964
+ }.to raise_error(
1965
+ MQTT::ProtocolException,
1966
+ "Invalid packet type identifier: 0"
1967
+ )
1968
+ end
1969
+ end
1970
+
1971
+ context "that has an incomplete packet length header" do
1972
+ it "should raise an exception" do
1973
+ expect {
1974
+ MQTT::Packet.parse( "\x30\xFF" )
1975
+ }.to raise_error(
1976
+ MQTT::ProtocolException,
1977
+ "The packet length header is incomplete"
1978
+ )
1979
+ end
1980
+ end
1981
+
1982
+ context "that has too many bytes in the length field" do
1983
+ it "should raise an exception" do
1984
+ expect {
1985
+ MQTT::Packet.parse( "\x30\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" )
1986
+ }.to raise_error(
1987
+ MQTT::ProtocolException,
1988
+ 'Failed to parse packet - input buffer (4) is not the same as the body length header (268435455)'
1989
+ )
1990
+ end
1991
+ end
1992
+
1993
+ context "that has a bigger buffer than expected" do
1994
+ it "should raise an exception" do
1995
+ expect {
1996
+ MQTT::Packet.parse( "\x30\x11\x00\x04testhello big world" )
1997
+ }.to raise_error(
1998
+ MQTT::ProtocolException,
1999
+ "Failed to parse packet - input buffer (21) is not the same as the body length header (17)"
2000
+ )
2001
+ end
2002
+ end
2003
+
2004
+ context "that has a smaller buffer than expected" do
2005
+ it "should raise an exception" do
2006
+ expect {
2007
+ MQTT::Packet.parse( "\x30\x11\x00\x04testhello" )
2008
+ }.to raise_error(
2009
+ MQTT::ProtocolException,
2010
+ "Failed to parse packet - input buffer (11) is not the same as the body length header (17)"
2011
+ )
2012
+ end
2013
+ end
2014
+ end