spec/mqtt_client_spec.rb in mqtt-0.4.0 vs spec/mqtt_client_spec.rb in mqtt-0.5.0

- old
+ new

@@ -26,11 +26,11 @@ describe "initializing a client" do it "with no arguments, it should use the defaults" do client = MQTT::Client.new expect(client.host).to eq(nil) expect(client.port).to eq(1883) - expect(client.version).to eq('3.1.0') + expect(client.version).to eq('3.1.1') expect(client.keep_alive).to eq(15) end it "with a single string argument, it should use it has the host" do client = MQTT::Client.new('otherhost.mqtt.org') @@ -115,10 +115,26 @@ expect(client.port).to eq(1883) expect(client.username).to eq('auser') expect(client.password).to eq('bpass') end + it "with a URI containing an escaped username and password" do + client = MQTT::Client.new(URI.parse('mqtt://foo%20bar:%40123%2B%25@mqtt.example.com')) + expect(client.host).to eq('mqtt.example.com') + expect(client.port).to eq(1883) + expect(client.username).to eq('foo bar') + expect(client.password).to eq('@123+%') + end + + it "with a URI containing a double escaped username and password" do + client = MQTT::Client.new(URI.parse('mqtt://foo%2520bar:123%2525@mqtt.example.com')) + expect(client.host).to eq('mqtt.example.com') + expect(client.port).to eq(1883) + expect(client.username).to eq('foo%20bar') + expect(client.password).to eq('123%25') + end + it "with a URI as a string" do client = MQTT::Client.new('mqtt://mqtt.example.com') expect(client.host).to eq('mqtt.example.com') expect(client.port).to eq(1883) end @@ -173,11 +189,11 @@ expect(client.ssl_context.cert).to be_nil client.cert = File.read(fixture_path('client.pem')) expect(client.ssl_context.cert).to be_a(OpenSSL::X509::Certificate) end end - + describe "setting a client private key file path" do it "should add a certificate to the SSL context" do expect(client.ssl_context.key).to be_nil client.key_file = fixture_path('client.key') expect(client.ssl_context.key).to be_a(OpenSSL::PKey::RSA) @@ -321,13 +337,13 @@ it "should include the username and password for an authenticated connection" do client.username = 'username' client.password = 'password' client.connect('myclient') expect(socket.string).to eq( - "\x10\x2A"+ - "\x00\x06MQIsdp"+ - "\x03\xC2\x00\x0f"+ + "\x10\x28"+ + "\x00\x04MQTT"+ + "\x04\xC2\x00\x0f"+ "\x00\x08myclient"+ "\x00\x08username"+ "\x00\x08password" ) end @@ -401,10 +417,19 @@ client = MQTT::Client.new('mqtt.example.com', :ssl => :TLSv1) expect(client.ssl_context).to receive('ssl_version=').with(:TLSv1) allow(client).to receive(:receive_connack) client.connect end + + it "should use set hostname on the SSL socket for SNI" do + expect(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl_socket) + expect(ssl_socket).to receive(:hostname=).with('mqtt.example.com') + + client = MQTT::Client.new('mqtts://mqtt.example.com') + allow(client).to receive(:receive_connack) + client.connect + end end context "with a last will and testament set" do before(:each) do client.set_will('topic', 'hello', retain=false, qos=1) @@ -427,13 +452,13 @@ end it "should include the will in the CONNECT message" do client.connect('myclient') expect(socket.string).to eq( - "\x10\x24"+ - "\x00\x06MQIsdp"+ - "\x03\x0e\x00\x0f"+ + "\x10\x22"+ + "\x00\x04MQTT"+ + "\x04\x0e\x00\x0f"+ "\x00\x08myclient"+ "\x00\x05topic\x00\x05hello" ) end end @@ -471,10 +496,11 @@ it "should not raise an exception for a successful CONNACK packet" do socket.write("\x20\x02\x00\x00") socket.rewind expect { client.send(:receive_connack) }.not_to raise_error + expect(socket).not_to be_closed end it "should raise an exception if the packet type isn't CONNACK" do socket.write("\xD0\x00") socket.rewind @@ -502,10 +528,17 @@ it "should raise an exception if the CONNACK packet return code is an unknown" do socket.write("\x20\x02\x00\xAA") socket.rewind expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /connection refused/i) end + + it "should close the socket for an unsuccessful CONNACK packet" do + socket.write("\x20\x02\x00\x05") + socket.rewind + expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /not authorised/i) + expect(socket).to be_closed + end end describe "when calling the 'disconnect' method" do before(:each) do thread = double('Read Thread', :alive? => true, :kill => true) @@ -593,11 +626,11 @@ end it "correctly assigns consecutive ids to packets with QoS 1" do inject_puback(1) inject_puback(2) - + expect(client).to receive(:send_packet) { |packet| expect(packet.id).to eq(1) } client.publish "topic", "message", false, 1 expect(client).to receive(:send_packet) { |packet| expect(packet.id).to eq(2) } client.publish "topic", "message", false, 1 end @@ -675,10 +708,19 @@ expect(topic).to eq('topic1') expect(payload).to eq('payload1') expect(client.queue_empty?).to be_truthy end + it "should successfully receive a valid PUBLISH packet, but not return it, if omit_retained is set" do + inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1, :retain => 1) + inject_packet(:topic => 'topic1', :payload => 'payload2', :qos => 1) + topic,payload = client.get(nil, :omit_retained => true) + expect(topic).to eq('topic1') + expect(payload).to eq('payload2') + expect(client.queue_empty?).to be_truthy + end + it "acks calling #get_packet and qos=1" do inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1) expect(client).to receive(:send_packet).with(an_instance_of(MQTT::Packet::Puback)) client.get_packet end @@ -710,10 +752,22 @@ client.get do |topic,payload| payloads << payload break if payloads.size > 1 end end + + it "should ignore a PUBLISH message when it is marked as retained and omit_retained is set" do + inject_packet(:topic => 'topic0', :payload => 'payload0', :retain => 1) + inject_packet(:topic => 'topic1', :payload => 'payload1') + payloads = [] + client.get(nil, :omit_retained => true) do |topic,payload| + payloads << payload + break if payloads.size > 0 + end + expect(payloads.size).to eq(1) + expect(payloads).to eq(['payload1']) + end end end describe "when calling the 'get_packet' method" do before(:each) do @@ -842,9 +896,16 @@ client.send('keep_alive!') }.to raise_error( MQTT::ProtocolException, /No Ping Response received for \d+ seconds/ ) + end + + it "should not raise an exception if no ping response received and client is disconnected" do + client.instance_variable_set('@last_ping_request', Time.now) + client.instance_variable_set('@last_ping_response', Time.at(0)) + client.disconnect(false) + client.send('keep_alive!') end end describe "generating a client identifier" do context "with default parameters" do