mqtt-ccutrer 1.0.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.
- checksums.yaml +7 -0
- data/LICENSE.md +21 -0
- data/NEWS.md +173 -0
- data/README.md +218 -0
- data/lib/mqtt-ccutrer.rb +3 -0
- data/lib/mqtt.rb +61 -0
- data/lib/mqtt/client.rb +772 -0
- data/lib/mqtt/packet.rb +1055 -0
- data/lib/mqtt/proxy.rb +117 -0
- data/lib/mqtt/sn/packet.rb +714 -0
- data/lib/mqtt/version.rb +6 -0
- data/spec/zz_client_integration_spec.rb +180 -0
- metadata +182 -0
data/lib/mqtt/version.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'mqtt'
|
5
|
+
require 'fake_server'
|
6
|
+
|
7
|
+
describe 'a client talking to a server' do
|
8
|
+
before do
|
9
|
+
@error_log = StringIO.new
|
10
|
+
@server = MQTT::FakeServer.new
|
11
|
+
@server.just_one_connection = true
|
12
|
+
@server.respond_to_pings = true
|
13
|
+
@server.logger = Logger.new(@error_log)
|
14
|
+
@server.logger.level = Logger::WARN
|
15
|
+
@server.start
|
16
|
+
|
17
|
+
@client = MQTT::Client.new(@server.address, @server.port)
|
18
|
+
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
@client.disconnect
|
22
|
+
@server.stop
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'connecting and publishing a packet' do
|
26
|
+
def connect_and_publish(**kwargs)
|
27
|
+
@client.connect
|
28
|
+
|
29
|
+
@client.publish('test', 'foobar', **kwargs)
|
30
|
+
@client.flush
|
31
|
+
@client.disconnect
|
32
|
+
@server.thread.join(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'the server should have received a packet' do
|
36
|
+
connect_and_publish
|
37
|
+
expect(@server.last_publish).not_to be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'the server should have received the correct topic' do
|
41
|
+
connect_and_publish
|
42
|
+
expect(@server.last_publish.topic).to eq('test')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'the server should have received the correct payload' do
|
46
|
+
connect_and_publish
|
47
|
+
expect(@server.last_publish.payload).to eq('foobar')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'the server should not report any errors' do
|
51
|
+
connect_and_publish
|
52
|
+
expect(@error_log.string).to be_empty
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with qos > 0' do
|
56
|
+
it 'the server should have received a packet without timeout' do
|
57
|
+
connect_and_publish(qos: 1)
|
58
|
+
expect(@server.last_publish).not_to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'connecting, subscribing to a topic and getting a packet' do
|
64
|
+
def connect_and_subscribe
|
65
|
+
@client.connect
|
66
|
+
@client.subscribe('test', 'foobar')
|
67
|
+
@packet = @client.get
|
68
|
+
@client.disconnect
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'the client should have received the correct data' do
|
72
|
+
connect_and_subscribe
|
73
|
+
expect(@packet).not_to be_nil
|
74
|
+
expect(@packet.topic).to eq('test')
|
75
|
+
expect(@packet.payload).to eq('hello test')
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'the server should not report any errors' do
|
79
|
+
connect_and_subscribe
|
80
|
+
expect(@error_log.string).to be_empty
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'sends pings when idle' do
|
85
|
+
def connect_and_ping(keep_alive)
|
86
|
+
@client.keep_alive = keep_alive
|
87
|
+
@client.connect
|
88
|
+
@server.thread.join(2)
|
89
|
+
@client.disconnect
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when keep-alive=1' do
|
93
|
+
it 'the server should have received at least one ping' do
|
94
|
+
connect_and_ping(1)
|
95
|
+
expect(@server.pings_received).to be >= 1
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'the server should not report any errors' do
|
99
|
+
connect_and_ping(1)
|
100
|
+
expect(@error_log.string).to be_empty
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when keep-alive=0' do
|
105
|
+
it 'the server should not receive any pings' do
|
106
|
+
connect_and_ping(0)
|
107
|
+
expect(@server.pings_received).to eq(0)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'the server should not report any errors' do
|
111
|
+
connect_and_ping(0)
|
112
|
+
expect(@error_log.string).to be_empty
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'detects server not sending ping responses' do
|
118
|
+
before do
|
119
|
+
@server.respond_to_pings = false
|
120
|
+
@client.keep_alive = 1
|
121
|
+
@client.ack_timeout = 0.5
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'the server should have received at least one ping' do
|
125
|
+
@client.reconnect_limit = 0
|
126
|
+
@client.connect
|
127
|
+
expect { @client.get }.to raise_error(MQTT::KeepAliveTimeout)
|
128
|
+
expect(@server.pings_received).to eq 1
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'reconnects on idle timeout' do
|
132
|
+
@server.just_one_connection = false
|
133
|
+
|
134
|
+
reconnect_count = 0
|
135
|
+
@client.on_reconnect do
|
136
|
+
reconnect_count += 1
|
137
|
+
end
|
138
|
+
@client.connect
|
139
|
+
# it should reconnect after 1.5s
|
140
|
+
sleep 2
|
141
|
+
@client.disconnect
|
142
|
+
expect(reconnect_count).to eq 1
|
143
|
+
ensure
|
144
|
+
@server.stop
|
145
|
+
end
|
146
|
+
|
147
|
+
it "backs off if can't immediately reconnect" do
|
148
|
+
@client.reconnect_limit = 3
|
149
|
+
|
150
|
+
@client.connect
|
151
|
+
|
152
|
+
expect(TCPSocket).to receive(:new).exactly(3).times.and_raise('fail')
|
153
|
+
|
154
|
+
expect(@client).to receive(:sleep).with(5)
|
155
|
+
expect(@client).to receive(:sleep).with(25)
|
156
|
+
|
157
|
+
# the original error is returned
|
158
|
+
expect { @client.get }.to raise_error(MQTT::KeepAliveTimeout)
|
159
|
+
ensure
|
160
|
+
@server.stop
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'includes the connack packet in on_reconnect callback' do
|
164
|
+
@server.just_one_connection = false
|
165
|
+
|
166
|
+
reconnect_count = 0
|
167
|
+
@client.on_reconnect do |connack|
|
168
|
+
expect(connack).to be_a(MQTT::Packet::Connack)
|
169
|
+
reconnect_count += 1
|
170
|
+
end
|
171
|
+
@client.connect
|
172
|
+
# it should reconnect after 1.5s
|
173
|
+
sleep 2
|
174
|
+
@client.disconnect
|
175
|
+
expect(reconnect_count).to eq 1
|
176
|
+
ensure
|
177
|
+
@server.stop
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
metadata
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mqtt-ccutrer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cody Cutrer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-02-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.11.2
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.11.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '11.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '11.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 10.2.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 10.2.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.5.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.5.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.5'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.2'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.2'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.9.2
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.9.2
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yard
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.9.11
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.9.11
|
139
|
+
description: |2
|
140
|
+
Pure Ruby gem that implements the MQTT protocol, a lightweight protocol for
|
141
|
+
publish/subscribe messaging.
|
142
|
+
email: cody@cutrer.us
|
143
|
+
executables: []
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- LICENSE.md
|
148
|
+
- NEWS.md
|
149
|
+
- README.md
|
150
|
+
- lib/mqtt-ccutrer.rb
|
151
|
+
- lib/mqtt.rb
|
152
|
+
- lib/mqtt/client.rb
|
153
|
+
- lib/mqtt/packet.rb
|
154
|
+
- lib/mqtt/proxy.rb
|
155
|
+
- lib/mqtt/sn/packet.rb
|
156
|
+
- lib/mqtt/version.rb
|
157
|
+
- spec/zz_client_integration_spec.rb
|
158
|
+
homepage: http://github.com/ccutrer/ruby-mqtt
|
159
|
+
licenses:
|
160
|
+
- MIT
|
161
|
+
metadata: {}
|
162
|
+
post_install_message:
|
163
|
+
rdoc_options: []
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '2.5'
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
requirements: []
|
177
|
+
rubygems_version: 3.1.4
|
178
|
+
signing_key:
|
179
|
+
specification_version: 4
|
180
|
+
summary: Implementation of the MQTT protocol
|
181
|
+
test_files:
|
182
|
+
- spec/zz_client_integration_spec.rb
|