mqtt 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,16 +5,16 @@ class MQTT::Proxy
5
5
 
6
6
  # Port to bind listening socket to
7
7
  attr_reader :local_port
8
-
9
- # Address of upstream broker to send packets upstream to
10
- attr_reader :broker_host
11
-
12
- # Port of upstream broker to send packets upstream to.
13
- attr_reader :broker_port
8
+
9
+ # Address of upstream server to send packets upstream to
10
+ attr_reader :server_host
11
+
12
+ # Port of upstream server to send packets upstream to.
13
+ attr_reader :server_port
14
14
 
15
15
  # Time in seconds before disconnecting an idle connection
16
16
  attr_reader :select_timeout
17
-
17
+
18
18
  # Ruby Logger object to send informational messages to
19
19
  attr_reader :logger
20
20
 
@@ -24,8 +24,8 @@ class MQTT::Proxy
24
24
  #
25
25
  # :local_host Address to bind listening socket to.
26
26
  # :local_port Port to bind listening socket to.
27
- # :broker_host Address of upstream broker to send packets upstream to.
28
- # :broker_port Port of upstream broker to send packets upstream to.
27
+ # :server_host Address of upstream server to send packets upstream to.
28
+ # :server_port Port of upstream server to send packets upstream to.
29
29
  # :select_timeout Time in seconds before disconnecting a connection.
30
30
  # :logger Ruby Logger object to send informational messages to.
31
31
  #
@@ -33,8 +33,8 @@ class MQTT::Proxy
33
33
  def initialize(args={})
34
34
  @local_host = args[:local_host] || '0.0.0.0'
35
35
  @local_port = args[:local_port] || MQTT::DEFAULT_PORT
36
- @broker_host = args[:broker_host]
37
- @broker_port = args[:broker_port] || 18830
36
+ @server_host = args[:server_host]
37
+ @server_port = args[:server_port] || 18830
38
38
  @select_timeout = args[:select_timeout] || 60
39
39
 
40
40
  # Setup a logger
@@ -46,21 +46,21 @@ class MQTT::Proxy
46
46
 
47
47
  # Default is not to have any filters
48
48
  @client_filter = nil
49
- @broker_filter = nil
49
+ @server_filter = nil
50
50
 
51
51
  # Create TCP server socket
52
52
  @server = TCPServer.open(@local_host,@local_port)
53
53
  @logger.info "MQTT::Proxy listening on #{@local_host}:#{@local_port}"
54
54
  end
55
55
 
56
- # Set a filter Proc for packets coming from the client (to the broker).
56
+ # Set a filter Proc for packets coming from the client (to the server).
57
57
  def client_filter=(proc)
58
58
  @client_filter = proc
59
59
  end
60
60
 
61
- # Set a filter Proc for packets coming from the broker (to the client).
62
- def broker_filter=(proc)
63
- @broker_filter = proc
61
+ # Set a filter Proc for packets coming from the server (to the client).
62
+ def server_filter=(proc)
63
+ @server_filter = proc
64
64
  end
65
65
 
66
66
  # Start accepting connections and processing packets.
@@ -69,14 +69,14 @@ class MQTT::Proxy
69
69
  # Wait for a client to connect and then create a thread for it
70
70
  Thread.new(@server.accept) do |client_socket|
71
71
  logger.info "Accepted client: #{client_socket.peeraddr.join(':')}"
72
- broker_socket = TCPSocket.new(@broker_host,@broker_port)
72
+ server_socket = TCPSocket.new(@server_host,@server_port)
73
73
  begin
74
- process_packets(client_socket,broker_socket)
74
+ process_packets(client_socket,server_socket)
75
75
  rescue Exception => exp
76
76
  logger.error exp.to_s
77
77
  end
78
78
  logger.info "Disconnected: #{client_socket.peeraddr.join(':')}"
79
- broker_socket.close
79
+ server_socket.close
80
80
  client_socket.close
81
81
  end
82
82
  end
@@ -84,10 +84,10 @@ class MQTT::Proxy
84
84
 
85
85
  private
86
86
 
87
- def process_packets(client_socket,broker_socket)
87
+ def process_packets(client_socket,server_socket)
88
88
  loop do
89
89
  # Wait for some data on either socket
90
- selected = IO.select([client_socket,broker_socket], nil, nil, @select_timeout)
90
+ selected = IO.select([client_socket,server_socket], nil, nil, @select_timeout)
91
91
  if selected.nil?
92
92
  # Timeout
93
93
  raise "Timeout in select"
@@ -98,19 +98,19 @@ class MQTT::Proxy
98
98
  logger.debug "client -> <#{packet.type}>"
99
99
  packet = @client_filter.call(packet) unless @client_filter.nil?
100
100
  unless packet.nil?
101
- broker_socket.write(packet)
102
- logger.debug "<#{packet.type}> -> broker"
101
+ server_socket.write(packet)
102
+ logger.debug "<#{packet.type}> -> server"
103
103
  end
104
- elsif selected[0].include?(broker_socket)
105
- packet = MQTT::Packet.read(broker_socket)
106
- logger.debug "broker -> <#{packet.type}>"
107
- packet = @broker_filter.call(packet) unless @broker_filter.nil?
104
+ elsif selected[0].include?(server_socket)
105
+ packet = MQTT::Packet.read(server_socket)
106
+ logger.debug "server -> <#{packet.type}>"
107
+ packet = @server_filter.call(packet) unless @server_filter.nil?
108
108
  unless packet.nil?
109
109
  client_socket.write(packet)
110
110
  logger.debug "<#{packet.type}> -> client"
111
111
  end
112
112
  else
113
- logger.error "Problem with select: socket is neither broker or client"
113
+ logger.error "Problem with select: socket is neither server or client"
114
114
  end
115
115
  end
116
116
  end
@@ -1,3 +1,4 @@
1
1
  module MQTT
2
- VERSION = "0.2.0"
2
+ # The version number of the MQTT gem
3
+ VERSION = "0.3.0"
3
4
  end
@@ -10,10 +10,10 @@ describe MQTT::Client do
10
10
 
11
11
  before(:each) do
12
12
  # Reset environment variable
13
- ENV.delete('MQTT_BROKER')
13
+ ENV.delete('MQTT_SERVER')
14
14
  end
15
15
 
16
- let(:client) { MQTT::Client.new(:remote_host => 'localhost') }
16
+ let(:client) { MQTT::Client.new(:host => 'localhost') }
17
17
  let(:socket) do
18
18
  socket = StringIO.new
19
19
  if socket.respond_to?(:set_encoding)
@@ -26,128 +26,135 @@ describe MQTT::Client do
26
26
  describe "initializing a client" do
27
27
  it "with no arguments, it should use the defaults" do
28
28
  client = MQTT::Client.new
29
- client.remote_host.should == nil
30
- client.remote_port.should == 1883
31
- client.keep_alive.should == 15
29
+ expect(client.host).to eq(nil)
30
+ expect(client.port).to eq(1883)
31
+ expect(client.version).to eq('3.1.0')
32
+ expect(client.keep_alive).to eq(15)
32
33
  end
33
34
 
34
35
  it "with a single string argument, it should use it has the host" do
35
36
  client = MQTT::Client.new('otherhost.mqtt.org')
36
- client.remote_host.should == 'otherhost.mqtt.org'
37
- client.remote_port.should == 1883
38
- client.keep_alive.should == 15
37
+ expect(client.host).to eq('otherhost.mqtt.org')
38
+ expect(client.port).to eq(1883)
39
+ expect(client.keep_alive).to eq(15)
39
40
  end
40
41
 
41
42
  it "with two arguments, it should use it as the host and port" do
42
43
  client = MQTT::Client.new('otherhost.mqtt.org', 1000)
43
- client.remote_host.should == 'otherhost.mqtt.org'
44
- client.remote_port.should == 1000
45
- client.keep_alive.should == 15
44
+ expect(client.host).to eq('otherhost.mqtt.org')
45
+ expect(client.port).to eq(1000)
46
+ expect(client.keep_alive).to eq(15)
46
47
  end
47
48
 
48
49
  it "with names arguments, it should use those as arguments" do
49
- client = MQTT::Client.new(:remote_host => 'otherhost.mqtt.org', :remote_port => 1000)
50
- client.remote_host.should == 'otherhost.mqtt.org'
51
- client.remote_port.should == 1000
52
- client.keep_alive.should == 15
50
+ client = MQTT::Client.new(:host => 'otherhost.mqtt.org', :port => 1000)
51
+ expect(client.host).to eq('otherhost.mqtt.org')
52
+ expect(client.port).to eq(1000)
53
+ expect(client.keep_alive).to eq(15)
53
54
  end
54
55
 
55
56
  it "with a hash, it should use those as arguments" do
56
- client = MQTT::Client.new({:remote_host => 'otherhost.mqtt.org', :remote_port => 1000})
57
- client.remote_host.should == 'otherhost.mqtt.org'
58
- client.remote_port.should == 1000
59
- client.keep_alive.should == 15
57
+ client = MQTT::Client.new({:host => 'otherhost.mqtt.org', :port => 1000})
58
+ expect(client.host).to eq('otherhost.mqtt.org')
59
+ expect(client.port).to eq(1000)
60
+ expect(client.keep_alive).to eq(15)
60
61
  end
61
62
 
62
63
  it "with a hash containing just a keep alive setting" do
63
- client = MQTT::Client.new(:remote_host => 'localhost', :keep_alive => 60)
64
- client.remote_host.should == 'localhost'
65
- client.remote_port.should == 1883
66
- client.keep_alive.should == 60
64
+ client = MQTT::Client.new(:host => 'localhost', :keep_alive => 60)
65
+ expect(client.host).to eq('localhost')
66
+ expect(client.port).to eq(1883)
67
+ expect(client.keep_alive).to eq(60)
67
68
  end
68
69
 
69
70
  it "with a combination of a host name and a hash of settings" do
70
71
  client = MQTT::Client.new('localhost', :keep_alive => 65)
71
- client.remote_host.should == 'localhost'
72
- client.remote_port.should == 1883
73
- client.keep_alive.should == 65
72
+ expect(client.host).to eq('localhost')
73
+ expect(client.port).to eq(1883)
74
+ expect(client.keep_alive).to eq(65)
74
75
  end
75
76
 
76
77
  it "with a combination of a host name, port and a hash of settings" do
77
78
  client = MQTT::Client.new('localhost', 1888, :keep_alive => 65)
78
- client.remote_host.should == 'localhost'
79
- client.remote_port.should == 1888
80
- client.keep_alive.should == 65
79
+ expect(client.host).to eq('localhost')
80
+ expect(client.port).to eq(1888)
81
+ expect(client.keep_alive).to eq(65)
81
82
  end
82
83
 
83
84
  it "with a mqtt:// URI containing just a hostname" do
84
85
  client = MQTT::Client.new(URI.parse('mqtt://mqtt.example.com'))
85
- client.remote_host.should == 'mqtt.example.com'
86
- client.remote_port.should == 1883
87
- client.ssl.should be_false
86
+ expect(client.host).to eq('mqtt.example.com')
87
+ expect(client.port).to eq(1883)
88
+ expect(client.ssl).to be_falsey
88
89
  end
89
90
 
90
91
  it "with a mqtts:// URI containing just a hostname" do
91
92
  client = MQTT::Client.new(URI.parse('mqtts://mqtt.example.com'))
92
- client.remote_host.should == 'mqtt.example.com'
93
- client.remote_port.should == 8883
94
- client.ssl.should be_true
93
+ expect(client.host).to eq('mqtt.example.com')
94
+ expect(client.port).to eq(8883)
95
+ expect(client.ssl).to be_truthy
95
96
  end
96
97
 
97
98
  it "with a mqtt:// URI containing a custom port number" do
98
99
  client = MQTT::Client.new(URI.parse('mqtt://mqtt.example.com:1234/'))
99
- client.remote_host.should == 'mqtt.example.com'
100
- client.remote_port.should == 1234
101
- client.ssl.should be_false
100
+ expect(client.host).to eq('mqtt.example.com')
101
+ expect(client.port).to eq(1234)
102
+ expect(client.ssl).to be_falsey
102
103
  end
103
104
 
104
105
  it "with a mqtts:// URI containing a custom port number" do
105
106
  client = MQTT::Client.new(URI.parse('mqtts://mqtt.example.com:1234/'))
106
- client.remote_host.should == 'mqtt.example.com'
107
- client.remote_port.should == 1234
108
- client.ssl.should be_true
107
+ expect(client.host).to eq('mqtt.example.com')
108
+ expect(client.port).to eq(1234)
109
+ expect(client.ssl).to be_truthy
109
110
  end
110
111
 
111
112
  it "with a URI containing a username and password" do
112
113
  client = MQTT::Client.new(URI.parse('mqtt://auser:bpass@mqtt.example.com'))
113
- client.remote_host.should == 'mqtt.example.com'
114
- client.remote_port.should == 1883
115
- client.username.should == 'auser'
116
- client.password.should == 'bpass'
114
+ expect(client.host).to eq('mqtt.example.com')
115
+ expect(client.port).to eq(1883)
116
+ expect(client.username).to eq('auser')
117
+ expect(client.password).to eq('bpass')
117
118
  end
118
119
 
119
120
  it "with a URI as a string" do
120
121
  client = MQTT::Client.new('mqtt://mqtt.example.com')
121
- client.remote_host.should == 'mqtt.example.com'
122
- client.remote_port.should == 1883
122
+ expect(client.host).to eq('mqtt.example.com')
123
+ expect(client.port).to eq(1883)
124
+ end
125
+
126
+ it "with a URI as a string including port" do
127
+ client = MQTT::Client.new('mqtt://user:pass@m10.cloudmqtt.com:13858', nil)
128
+ expect(client.host).to eq('m10.cloudmqtt.com')
129
+ expect(client.port).to eq(13858)
123
130
  end
124
131
 
125
132
  it "with a URI and a hash of settings" do
126
133
  client = MQTT::Client.new('mqtt://mqtt.example.com', :keep_alive => 65)
127
- client.remote_host.should == 'mqtt.example.com'
128
- client.remote_port.should == 1883
129
- client.keep_alive.should == 65
134
+ expect(client.host).to eq('mqtt.example.com')
135
+ expect(client.port).to eq(1883)
136
+ expect(client.keep_alive).to eq(65)
130
137
  end
131
138
 
132
- it "with no arguments uses the MQTT_BROKER environment variable as connect URI" do
133
- ENV['MQTT_BROKER'] = 'mqtt://mqtt.example.com:1234'
139
+ it "with no arguments uses the MQTT_SERVER environment variable as connect URI" do
140
+ ENV['MQTT_SERVER'] = 'mqtt://mqtt.example.com:1234'
134
141
  client = MQTT::Client.new
135
- client.remote_host.should == 'mqtt.example.com'
136
- client.remote_port.should == 1234
142
+ expect(client.host).to eq('mqtt.example.com')
143
+ expect(client.port).to eq(1234)
137
144
  end
138
145
 
139
146
  it "with an unsupported URI scheme" do
140
- lambda {
147
+ expect {
141
148
  client = MQTT::Client.new(URI.parse('http://mqtt.example.com/'))
142
- }.should raise_error(
149
+ }.to raise_error(
143
150
  'Only the mqtt:// and mqtts:// schemes are supported'
144
151
  )
145
152
  end
146
153
 
147
154
  it "with three arguments" do
148
- lambda {
155
+ expect {
149
156
  client = MQTT::Client.new(1, 2, 3)
150
- }.should raise_error(
157
+ }.to raise_error(
151
158
  'Unsupported number of arguments'
152
159
  )
153
160
  end
@@ -155,82 +162,113 @@ describe MQTT::Client do
155
162
 
156
163
  describe "setting a client certificate file path" do
157
164
  it "should add a certificate to the SSL context" do
158
- client.ssl_context.cert.should be_nil
165
+ expect(client.ssl_context.cert).to be_nil
159
166
  client.cert_file = fixture_path('client.pem')
160
- client.ssl_context.cert.should be_a(OpenSSL::X509::Certificate)
167
+ expect(client.ssl_context.cert).to be_a(OpenSSL::X509::Certificate)
161
168
  end
162
169
  end
163
170
 
164
171
  describe "setting a client private key file path" do
165
172
  it "should add a certificate to the SSL context" do
166
- client.ssl_context.key.should be_nil
173
+ expect(client.ssl_context.key).to be_nil
167
174
  client.key_file = fixture_path('client.key')
168
- client.ssl_context.key.should be_a(OpenSSL::PKey::RSA)
175
+ expect(client.ssl_context.key).to be_a(OpenSSL::PKey::RSA)
169
176
  end
170
177
  end
171
178
 
172
179
  describe "setting a Certificate Authority file path" do
173
180
  it "should add a CA file path to the SSL context" do
174
- client.ssl_context.ca_file.should be_nil
181
+ expect(client.ssl_context.ca_file).to be_nil
175
182
  client.ca_file = fixture_path('root-ca.pem')
176
- client.ssl_context.ca_file.should == fixture_path('root-ca.pem')
183
+ expect(client.ssl_context.ca_file).to eq(fixture_path('root-ca.pem'))
177
184
  end
178
185
 
179
186
  it "should enable peer verification" do
180
187
  client.ca_file = fixture_path('root-ca.pem')
181
- client.ssl_context.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
188
+ expect(client.ssl_context.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
189
+ end
190
+ end
191
+
192
+ describe "deprecated attributes" do
193
+ it "should allow getting and setting the host name using the remote_host method" do
194
+ client.remote_host = 'remote-host.example.com'
195
+ expect(client.host).to eq('remote-host.example.com')
196
+ expect(client.remote_host).to eq('remote-host.example.com')
197
+ client.host = 'foo.example.org'
198
+ expect(client.host).to eq('foo.example.org')
199
+ expect(client.remote_host).to eq('foo.example.org')
200
+ end
201
+
202
+ it "should allow getting and setting the port using the remote_port method" do
203
+ client.remote_port = 9999
204
+ expect(client.port).to eq(9999)
205
+ expect(client.remote_port).to eq(9999)
206
+ client.port = 1234
207
+ expect(client.port).to eq(1234)
208
+ expect(client.remote_port).to eq(1234)
182
209
  end
183
210
  end
184
211
 
185
212
  describe "when calling the 'connect' method on a client" do
186
213
  before(:each) do
187
- TCPSocket.stub(:new).and_return(socket)
188
- Thread.stub(:new)
189
- client.stub(:receive_connack)
214
+ allow(TCPSocket).to receive(:new).and_return(socket)
215
+ allow(Thread).to receive(:new)
216
+ allow(client).to receive(:receive_connack)
190
217
  end
191
218
 
192
219
  it "should create a TCP Socket if not connected" do
193
- TCPSocket.should_receive(:new).once.and_return(socket)
220
+ expect(TCPSocket).to receive(:new).once.and_return(socket)
194
221
  client.connect('myclient')
195
222
  end
196
223
 
197
224
  it "should not create a new TCP Socket if connected" do
198
- client.stub(:connected?).and_return(true)
199
- TCPSocket.should_receive(:new).never
225
+ allow(client).to receive(:connected?).and_return(true)
226
+ expect(TCPSocket).to receive(:new).never
200
227
  client.connect('myclient')
201
228
  end
202
229
 
203
230
  it "should start the reader thread if not connected" do
204
- Thread.should_receive(:new).once
231
+ expect(Thread).to receive(:new).once
205
232
  client.connect('myclient')
206
233
  end
207
234
 
208
- it "should write a valid CONNECT packet to the socket if not connected" do
209
- client.connect('myclient')
210
- socket.string.should == "\020\026\x00\x06MQIsdp\x03\x02\x00\x0f\x00\x08myclient"
235
+ context "protocol version 3.1.0" do
236
+ it "should write a valid CONNECT packet to the socket if not connected" do
237
+ client.version = '3.1.0'
238
+ client.connect('myclient')
239
+ expect(socket.string).to eq("\020\026\x00\x06MQIsdp\x03\x02\x00\x0f\x00\x08myclient")
240
+ end
241
+ end
242
+
243
+ context "protocol version 3.1.1" do
244
+ it "should write a valid CONNECT packet to the socket if not connected" do
245
+ client.version = '3.1.1'
246
+ client.connect('myclient')
247
+ expect(socket.string).to eq("\020\024\x00\x04MQTT\x04\x02\x00\x0f\x00\x08myclient")
248
+ end
211
249
  end
212
250
 
213
251
  it "should try and read an acknowledgement packet to the socket if not connected" do
214
- client.should_receive(:receive_connack).once
252
+ expect(client).to receive(:receive_connack).once
215
253
  client.connect('myclient')
216
254
  end
217
255
 
218
256
  it "should throw an exception if no host is configured" do
219
- lambda {
257
+ expect {
220
258
  client = MQTT::Client.new
221
259
  client.connect
222
- }.should raise_error(
223
- 'No MQTT broker host set when attempting to connect'
260
+ }.to raise_error(
261
+ 'No MQTT server host set when attempting to connect'
224
262
  )
225
263
  end
226
264
 
227
265
  it "should disconnect after connecting, if a block is given" do
228
- client.should_receive(:disconnect).once
266
+ expect(client).to receive(:disconnect).once
229
267
  client.connect('myclient') { nil }
230
268
  end
231
269
 
232
270
  it "should not disconnect after connecting, if no block is given" do
233
- client.should_receive(:disconnect).never
271
+ expect(client).to receive(:disconnect).never
234
272
  client.connect('myclient')
235
273
  end
236
274
 
@@ -238,31 +276,46 @@ describe MQTT::Client do
238
276
  client.username = 'username'
239
277
  client.password = 'password'
240
278
  client.connect('myclient')
241
- socket.string.should ==
279
+ expect(socket.string).to eq(
242
280
  "\x10\x2A"+
243
281
  "\x00\x06MQIsdp"+
244
282
  "\x03\xC2\x00\x0f"+
245
283
  "\x00\x08myclient"+
246
284
  "\x00\x08username"+
247
285
  "\x00\x08password"
286
+ )
248
287
  end
249
288
 
250
289
  context "no client id is given" do
251
290
  it "should throw an exception if the clean session flag is false" do
252
- lambda {
291
+ expect {
253
292
  client.client_id = nil
254
293
  client.clean_session = false
255
294
  client.connect
256
- }.should raise_error(
295
+ }.to raise_error(
257
296
  'Must provide a client_id if clean_session is set to false'
258
297
  )
259
298
  end
260
299
 
261
- it "should generate a client if the clean session flag is true" do
262
- client.client_id = nil
263
- client.clean_session = true
264
- client.connect
265
- client.client_id.should match(/^\w+$/)
300
+ context "protocol version 3.1.0" do
301
+ it "should generate a client if the clean session flag is true" do
302
+ client.version = '3.1.0'
303
+ client.client_id = nil
304
+ client.clean_session = true
305
+ client.connect
306
+ expect(client.client_id).to match(/^\w+$/)
307
+ end
308
+ end
309
+
310
+ context "protocol version 3.1.1" do
311
+ it "should send empty client if the clean session flag is true" do
312
+ client.version = '3.1.1'
313
+ client.client_id = nil
314
+ client.clean_session = true
315
+ client.connect
316
+ expect(client.client_id).to be_nil
317
+ expect(socket.string).to eq("\020\014\x00\x04MQTT\x04\x02\x00\x0f\x00\x00")
318
+ end
266
319
  end
267
320
  end
268
321
 
@@ -278,30 +331,30 @@ describe MQTT::Client do
278
331
  }
279
332
 
280
333
  it "should use ssl if it enabled using the :ssl => true parameter" do
281
- OpenSSL::SSL::SSLSocket.should_receive(:new).and_return(ssl_socket)
282
- ssl_socket.should_receive(:connect)
334
+ expect(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl_socket)
335
+ expect(ssl_socket).to receive(:connect)
283
336
 
284
337
  client = MQTT::Client.new('mqtt.example.com', :ssl => true)
285
- client.stub(:receive_connack)
338
+ allow(client).to receive(:receive_connack)
286
339
  client.connect
287
340
  end
288
341
 
289
342
  it "should use ssl if it enabled using the mqtts:// scheme" do
290
- OpenSSL::SSL::SSLSocket.should_receive(:new).and_return(ssl_socket)
291
- ssl_socket.should_receive(:connect)
343
+ expect(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl_socket)
344
+ expect(ssl_socket).to receive(:connect)
292
345
 
293
346
  client = MQTT::Client.new('mqtts://mqtt.example.com')
294
- client.stub(:receive_connack)
347
+ allow(client).to receive(:receive_connack)
295
348
  client.connect
296
349
  end
297
350
 
298
351
  it "should use set the SSL version, if the :ssl parameter is a symbol" do
299
- OpenSSL::SSL::SSLSocket.should_receive(:new).and_return(ssl_socket)
300
- ssl_socket.should_receive(:connect)
352
+ expect(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl_socket)
353
+ expect(ssl_socket).to receive(:connect)
301
354
 
302
355
  client = MQTT::Client.new('mqtt.example.com', :ssl => :TLSv1)
303
- client.ssl_context.should_receive('ssl_version=').with(:TLSv1)
304
- client.stub(:receive_connack)
356
+ expect(client.ssl_context).to receive('ssl_version=').with(:TLSv1)
357
+ allow(client).to receive(:receive_connack)
305
358
  client.connect
306
359
  end
307
360
  end
@@ -312,29 +365,30 @@ describe MQTT::Client do
312
365
  end
313
366
 
314
367
  it "should have set the Will's topic" do
315
- client.will_topic.should == 'topic'
368
+ expect(client.will_topic).to eq('topic')
316
369
  end
317
370
 
318
371
  it "should have set the Will's payload" do
319
- client.will_payload.should == 'hello'
372
+ expect(client.will_payload).to eq('hello')
320
373
  end
321
374
 
322
375
  it "should have set the Will's retain flag to true" do
323
- client.will_retain.should be_false
376
+ expect(client.will_retain).to be_falsey
324
377
  end
325
378
 
326
379
  it "should have set the Will's retain QOS value to 1" do
327
- client.will_qos.should == 1
380
+ expect(client.will_qos).to eq(1)
328
381
  end
329
382
 
330
383
  it "should include the will in the CONNECT message" do
331
384
  client.connect('myclient')
332
- socket.string.should ==
385
+ expect(socket.string).to eq(
333
386
  "\x10\x24"+
334
387
  "\x00\x06MQIsdp"+
335
388
  "\x03\x0e\x00\x0f"+
336
389
  "\x00\x08myclient"+
337
390
  "\x00\x05topic\x00\x05hello"
391
+ )
338
392
  end
339
393
  end
340
394
 
@@ -359,50 +413,50 @@ describe MQTT::Client do
359
413
  client = double("MQTT::Client")
360
414
  allow(client).to receive(:connect)
361
415
  allow(MQTT::Client).to receive(:new).once.and_return(client)
362
- MQTT::Client.connect.should == client
416
+ expect(MQTT::Client.connect).to eq(client)
363
417
  end
364
418
  end
365
419
 
366
420
  describe "when calling the 'receive_connack' method" do
367
421
  before(:each) do
368
422
  client.instance_variable_set('@socket', socket)
369
- IO.stub(:select).and_return([[socket], [], []])
423
+ allow(IO).to receive(:select).and_return([[socket], [], []])
370
424
  end
371
425
 
372
426
  it "should not throw an exception for a successful CONNACK packet" do
373
427
  socket.write("\x20\x02\x00\x00")
374
428
  socket.rewind
375
- lambda { client.send(:receive_connack) }.should_not raise_error
429
+ expect { client.send(:receive_connack) }.not_to raise_error
376
430
  end
377
431
 
378
432
  it "should throw an exception if the packet type isn't CONNACK" do
379
433
  socket.write("\xD0\x00")
380
434
  socket.rewind
381
- lambda { client.send(:receive_connack) }.should raise_error(MQTT::ProtocolException)
435
+ expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException)
382
436
  end
383
437
 
384
438
  it "should throw an exception if the CONNACK packet return code is 'unacceptable protocol version'" do
385
439
  socket.write("\x20\x02\x00\x01")
386
440
  socket.rewind
387
- lambda { client.send(:receive_connack) }.should raise_error(MQTT::ProtocolException, /unacceptable protocol version/i)
441
+ expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /unacceptable protocol version/i)
388
442
  end
389
443
 
390
444
  it "should throw an exception if the CONNACK packet return code is 'client identifier rejected'" do
391
445
  socket.write("\x20\x02\x00\x02")
392
446
  socket.rewind
393
- lambda { client.send(:receive_connack) }.should raise_error(MQTT::ProtocolException, /client identifier rejected/i)
447
+ expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /client identifier rejected/i)
394
448
  end
395
449
 
396
- it "should throw an exception if the CONNACK packet return code is 'broker unavailable'" do
450
+ it "should throw an exception if the CONNACK packet return code is 'server unavailable'" do
397
451
  socket.write("\x20\x02\x00\x03")
398
452
  socket.rewind
399
- lambda { client.send(:receive_connack) }.should raise_error(MQTT::ProtocolException, /broker unavailable/i)
453
+ expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /server unavailable/i)
400
454
  end
401
455
 
402
456
  it "should throw an exception if the CONNACK packet return code is an unknown" do
403
457
  socket.write("\x20\x02\x00\xAA")
404
458
  socket.rewind
405
- lambda { client.send(:receive_connack) }.should raise_error(MQTT::ProtocolException, /connection refused/i)
459
+ expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /connection refused/i)
406
460
  end
407
461
  end
408
462
 
@@ -414,25 +468,25 @@ describe MQTT::Client do
414
468
  end
415
469
 
416
470
  it "should not do anything if the socket is already disconnected" do
417
- client.stub(:connected?).and_return(false)
471
+ allow(client).to receive(:connected?).and_return(false)
418
472
  client.disconnect(true)
419
- socket.string.should == ""
473
+ expect(socket.string).to eq("")
420
474
  end
421
475
 
422
476
  it "should write a valid DISCONNECT packet to the socket if connected and the send_msg=true an" do
423
- client.stub(:connected?).and_return(true)
477
+ allow(client).to receive(:connected?).and_return(true)
424
478
  client.disconnect(true)
425
- socket.string.should == "\xE0\x00"
479
+ expect(socket.string).to eq("\xE0\x00")
426
480
  end
427
481
 
428
482
  it "should not write anything to the socket if the send_msg=false" do
429
- client.stub(:connected?).and_return(true)
483
+ allow(client).to receive(:connected?).and_return(true)
430
484
  client.disconnect(false)
431
- socket.string.should be_empty
485
+ expect(socket.string).to be_empty
432
486
  end
433
487
 
434
488
  it "should call the close method on the socket" do
435
- socket.should_receive(:close)
489
+ expect(socket).to receive(:close)
436
490
  client.disconnect
437
491
  end
438
492
  end
@@ -444,13 +498,13 @@ describe MQTT::Client do
444
498
 
445
499
  it "should write a valid PINGREQ packet to the socket" do
446
500
  client.ping
447
- socket.string.should == "\xC0\x00"
501
+ expect(socket.string).to eq("\xC0\x00")
448
502
  end
449
503
 
450
504
  it "should update the time a ping was last sent" do
451
505
  client.instance_variable_set('@last_pingreq', 0)
452
506
  client.ping
453
- client.instance_variable_get('@last_pingreq').should_not == 0
507
+ expect(client.instance_variable_get('@last_pingreq')).not_to eq(0)
454
508
  end
455
509
  end
456
510
 
@@ -461,22 +515,45 @@ describe MQTT::Client do
461
515
 
462
516
  it "should write a valid PUBLISH packet to the socket without the retain flag" do
463
517
  client.publish('topic','payload', false, 0)
464
- socket.string.should == "\x30\x0e\x00\x05topicpayload"
518
+ expect(socket.string).to eq("\x30\x0e\x00\x05topicpayload")
465
519
  end
466
520
 
467
521
  it "should write a valid PUBLISH packet to the socket with the retain flag set" do
468
522
  client.publish('topic','payload', true, 0)
469
- socket.string.should == "\x31\x0e\x00\x05topicpayload"
523
+ expect(socket.string).to eq("\x31\x0e\x00\x05topicpayload")
470
524
  end
471
525
 
472
526
  it "should write a valid PUBLISH packet to the socket with the QOS set to 1" do
473
527
  client.publish('topic','payload', false, 1)
474
- socket.string.should == "\x32\x10\x00\x05topic\x00\x01payload"
528
+ expect(socket.string).to eq("\x32\x10\x00\x05topic\x00\x01payload")
475
529
  end
476
530
 
477
531
  it "should write a valid PUBLISH packet to the socket with the QOS set to 2" do
478
532
  client.publish('topic','payload', false, 2)
479
- socket.string.should == "\x34\x10\x00\x05topic\x00\x01payload"
533
+ expect(socket.string).to eq("\x34\x10\x00\x05topic\x00\x01payload")
534
+ end
535
+
536
+ it "should write a valid PUBLISH packet with no payload" do
537
+ client.publish('test')
538
+ expect(socket.string).to eq("\x30\x06\x00\x04test")
539
+ end
540
+
541
+ it "should throw an ArgumentError exception, if the topic is nil" do
542
+ expect {
543
+ client.publish(nil)
544
+ }.to raise_error(
545
+ ArgumentError,
546
+ 'Topic name cannot be nil'
547
+ )
548
+ end
549
+
550
+ it "should throw an ArgumentError exception, if the topic is empty" do
551
+ expect {
552
+ client.publish("")
553
+ }.to raise_error(
554
+ ArgumentError,
555
+ 'Topic name cannot be empty'
556
+ )
480
557
  end
481
558
  end
482
559
 
@@ -487,50 +564,50 @@ describe MQTT::Client do
487
564
 
488
565
  it "should write a valid SUBSCRIBE packet to the socket if given a single topic String" do
489
566
  client.subscribe('a/b')
490
- socket.string.should == "\x82\x08\x00\x01\x00\x03a/b\x00"
567
+ expect(socket.string).to eq("\x82\x08\x00\x01\x00\x03a/b\x00")
491
568
  end
492
569
 
493
570
  it "should write a valid SUBSCRIBE packet to the socket if given a two topic Strings in an Array" do
494
571
  client.subscribe('a/b','c/d')
495
- socket.string.should == "\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x00"
572
+ expect(socket.string).to eq("\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x00")
496
573
  end
497
574
 
498
575
  it "should write a valid SUBSCRIBE packet to the socket if given a two topic Strings with QoS in an Array" do
499
576
  client.subscribe(['a/b',0],['c/d',1])
500
- socket.string.should == "\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x01"
577
+ expect(socket.string).to eq("\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x01")
501
578
  end
502
579
 
503
580
  it "should write a valid SUBSCRIBE packet to the socket if given a two topic Strings with QoS in a Hash" do
504
581
  client.subscribe('a/b' => 0,'c/d' => 1)
505
- socket.string.should == "\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x01"
582
+ expect(socket.string).to eq("\x82\x0e\x00\x01\x00\x03a/b\x00\x00\x03c/d\x01")
506
583
  end
507
584
  end
508
585
 
509
586
  describe "when calling the 'queue_length' method" do
510
587
  it "should return 0 if there are no incoming messages waiting" do
511
- client.queue_length.should == 0
588
+ expect(client.queue_length).to eq(0)
512
589
  end
513
590
 
514
591
  it "should return 1 if there is one incoming message waiting" do
515
592
  inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
516
- client.queue_length.should == 1
593
+ expect(client.queue_length).to eq(1)
517
594
  end
518
595
 
519
596
  it "should return 2 if there are two incoming message waiting" do
520
597
  inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
521
598
  inject_packet(:topic => 'topic0', :payload => 'payload1', :qos => 0)
522
- client.queue_length.should == 2
599
+ expect(client.queue_length).to eq(2)
523
600
  end
524
601
  end
525
602
 
526
603
  describe "when calling the 'queue_emtpy?' method" do
527
604
  it "should return return true if there no incoming messages waiting" do
528
- client.queue_empty?.should be_true
605
+ expect(client.queue_empty?).to be_truthy
529
606
  end
530
607
 
531
608
  it "should return return false if there is an incoming messages waiting" do
532
609
  inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
533
- client.queue_empty?.should be_false
610
+ expect(client.queue_empty?).to be_falsey
534
611
  end
535
612
  end
536
613
 
@@ -542,16 +619,16 @@ describe MQTT::Client do
542
619
  it "should successfull receive a valid PUBLISH packet with a QoS 0" do
543
620
  inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
544
621
  topic,payload = client.get
545
- topic.should == 'topic0'
546
- payload.should == 'payload0'
622
+ expect(topic).to eq('topic0')
623
+ expect(payload).to eq('payload0')
547
624
  end
548
625
 
549
626
  it "should successfull receive a valid PUBLISH packet with a QoS 1" do
550
627
  inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1)
551
628
  topic,payload = client.get
552
- topic.should == 'topic1'
553
- payload.should == 'payload1'
554
- client.queue_empty?.should be_true
629
+ expect(topic).to eq('topic1')
630
+ expect(payload).to eq('payload1')
631
+ expect(client.queue_empty?).to be_truthy
555
632
  end
556
633
 
557
634
  context "with a block" do
@@ -563,8 +640,8 @@ describe MQTT::Client do
563
640
  payloads << payload
564
641
  break if payloads.size > 1
565
642
  end
566
- payloads.size.should == 2
567
- payloads.should == ['payload0', 'payload1']
643
+ expect(payloads.size).to eq(2)
644
+ expect(payloads).to eq(['payload0', 'payload1'])
568
645
  end
569
646
  end
570
647
  end
@@ -577,20 +654,20 @@ describe MQTT::Client do
577
654
  it "should successfull receive a valid PUBLISH packet with a QoS 0" do
578
655
  inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
579
656
  packet = client.get_packet
580
- packet.class.should == MQTT::Packet::Publish
581
- packet.qos.should == 0
582
- packet.topic.should == 'topic0'
583
- packet.payload.should == 'payload0'
657
+ expect(packet.class).to eq(MQTT::Packet::Publish)
658
+ expect(packet.qos).to eq(0)
659
+ expect(packet.topic).to eq('topic0')
660
+ expect(packet.payload).to eq('payload0')
584
661
  end
585
662
 
586
663
  it "should successfull receive a valid PUBLISH packet with a QoS 1" do
587
664
  inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1)
588
665
  packet = client.get_packet
589
- packet.class.should == MQTT::Packet::Publish
590
- packet.qos.should == 1
591
- packet.topic.should == 'topic1'
592
- packet.payload.should == 'payload1'
593
- client.queue_empty?.should be_true
666
+ expect(packet.class).to eq(MQTT::Packet::Publish)
667
+ expect(packet.qos).to eq(1)
668
+ expect(packet.topic).to eq('topic1')
669
+ expect(packet.payload).to eq('payload1')
670
+ expect(client.queue_empty?).to be_truthy
594
671
  end
595
672
 
596
673
  context "with a block" do
@@ -602,8 +679,8 @@ describe MQTT::Client do
602
679
  packets << packet
603
680
  break if packets.size > 1
604
681
  end
605
- packets.size.should == 2
606
- packets.map{|p| p.payload}.should == ['payload0', 'payload1']
682
+ expect(packets.size).to eq(2)
683
+ expect(packets.map{|p| p.payload}).to eq(['payload0', 'payload1'])
607
684
  end
608
685
  end
609
686
  end
@@ -615,59 +692,59 @@ describe MQTT::Client do
615
692
 
616
693
  it "should write a valid UNSUBSCRIBE packet to the socket if given a single topic String" do
617
694
  client.unsubscribe('a/b')
618
- socket.string.should == "\xa2\x07\x00\x01\x00\x03a/b"
695
+ expect(socket.string).to eq("\xa2\x07\x00\x01\x00\x03a/b")
619
696
  end
620
697
 
621
698
  it "should write a valid UNSUBSCRIBE packet to the socket if given a two topic Strings" do
622
699
  client.unsubscribe('a/b','c/d')
623
- socket.string.should == "\xa2\x0c\x00\x01\x00\x03a/b\x00\x03c/d"
700
+ expect(socket.string).to eq("\xa2\x0c\x00\x01\x00\x03a/b\x00\x03c/d")
624
701
  end
625
702
 
626
703
  it "should write a valid UNSUBSCRIBE packet to the socket if given an array of Strings" do
627
704
  client.unsubscribe(['a/b','c/d'])
628
- socket.string.should == "\xa2\x0c\x00\x01\x00\x03a/b\x00\x03c/d"
705
+ expect(socket.string).to eq("\xa2\x0c\x00\x01\x00\x03a/b\x00\x03c/d")
629
706
  end
630
707
  end
631
708
 
632
709
  describe "when calling the 'receive_packet' method" do
633
710
  before(:each) do
634
711
  client.instance_variable_set('@socket', socket)
635
- IO.stub(:select).and_return([[socket], [], []])
712
+ allow(IO).to receive(:select).and_return([[socket], [], []])
636
713
  @read_queue = client.instance_variable_get('@read_queue')
637
714
  @parent_thread = Thread.current[:parent] = double('Parent Thread')
638
- @parent_thread.stub(:raise)
715
+ allow(@parent_thread).to receive(:raise)
639
716
  end
640
717
 
641
718
  it "should put PUBLISH messages on to the read queue" do
642
719
  socket.write("\x30\x0e\x00\x05topicpayload")
643
720
  socket.rewind
644
721
  client.send(:receive_packet)
645
- @read_queue.size.should == 1
722
+ expect(@read_queue.size).to eq(1)
646
723
  end
647
724
 
648
725
  it "should not put other messages on to the read queue" do
649
726
  socket.write("\x20\x02\x00\x00")
650
727
  socket.rewind
651
728
  client.send(:receive_packet)
652
- @read_queue.size.should == 0
729
+ expect(@read_queue.size).to eq(0)
653
730
  end
654
731
 
655
732
  it "should send a ping packet if one is due" do
656
- IO.should_receive(:select).and_return(nil)
733
+ expect(IO).to receive(:select).and_return(nil)
657
734
  client.instance_variable_set('@last_pingreq', Time.at(0))
658
- client.should_receive(:ping).once
735
+ expect(client).to receive(:ping).once
659
736
  client.send(:receive_packet)
660
737
  end
661
738
 
662
739
  it "should close the socket if there is an exception" do
663
- socket.should_receive(:close).once
664
- MQTT::Packet.stub(:read).and_raise(MQTT::Exception)
740
+ expect(socket).to receive(:close).once
741
+ allow(MQTT::Packet).to receive(:read).and_raise(MQTT::Exception)
665
742
  client.send(:receive_packet)
666
743
  end
667
744
 
668
745
  it "should pass exceptions up to parent thread" do
669
- @parent_thread.should_receive(:raise).once
670
- MQTT::Packet.stub(:read).and_raise(MQTT::Exception)
746
+ expect(@parent_thread).to receive(:raise).once
747
+ allow(MQTT::Packet).to receive(:read).and_raise(MQTT::Exception)
671
748
  client.send(:receive_packet)
672
749
  end
673
750
  end
@@ -677,31 +754,31 @@ describe MQTT::Client do
677
754
  let(:client_id) { MQTT::Client.generate_client_id }
678
755
 
679
756
  it "should be less or equal to 23 characters long" do
680
- client_id.length.should <= 23
757
+ expect(client_id.length).to be <= 23
681
758
  end
682
759
 
683
- it "should have a prefix of ruby_" do
684
- client_id.should match(/^ruby_/)
760
+ it "should have a prefix of ruby" do
761
+ expect(client_id).to match(/^ruby/)
685
762
  end
686
763
 
687
764
  it "should end in 16 characters of lowercase letters and numbers" do
688
- client_id.should match(/_[a-z0-9]{16}$/)
765
+ expect(client_id).to match(/^ruby[a-z0-9]{16}$/)
689
766
  end
690
767
  end
691
768
 
692
769
  context "with an alternative prefix" do
693
- let(:client_id) { MQTT::Client.generate_client_id('test_') }
770
+ let(:client_id) { MQTT::Client.generate_client_id('test') }
694
771
 
695
772
  it "should be less or equal to 23 characters long" do
696
- client_id.length.should <= 23
773
+ expect(client_id.length).to be <= 23
697
774
  end
698
775
 
699
- it "should have a prefix of test_" do
700
- client_id.should match(/^test_/)
776
+ it "should have a prefix of test" do
777
+ expect(client_id).to match(/^test/)
701
778
  end
702
779
 
703
780
  it "should end in 16 characters of lowercase letters and numbers" do
704
- client_id.should match(/_[a-z0-9]{16}$/)
781
+ expect(client_id).to match(/^test[a-z0-9]{16}$/)
705
782
  end
706
783
  end
707
784
  end