mqtt 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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