ably-rest 0.7.1 → 0.7.3
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 +13 -5
- data/.gitmodules +1 -1
- data/.rspec +1 -0
- data/.travis.yml +7 -3
- data/SPEC.md +495 -419
- data/ably-rest.gemspec +19 -5
- data/lib/ably-rest.rb +9 -1
- data/lib/submodules/ably-ruby/.gitignore +6 -0
- data/lib/submodules/ably-ruby/.rspec +1 -0
- data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
- data/lib/submodules/ably-ruby/.travis.yml +10 -0
- data/lib/submodules/ably-ruby/Gemfile +4 -0
- data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
- data/lib/submodules/ably-ruby/README.md +122 -0
- data/lib/submodules/ably-ruby/Rakefile +34 -0
- data/lib/submodules/ably-ruby/SPEC.md +1794 -0
- data/lib/submodules/ably-ruby/ably.gemspec +36 -0
- data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
- data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
- data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
- data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
- data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
- data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
- data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
- data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
- metadata +182 -27
|
@@ -0,0 +1,785 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Ably::Realtime::Connection, :event_machine do
|
|
5
|
+
let(:connection) { client.connection }
|
|
6
|
+
|
|
7
|
+
vary_by_protocol do
|
|
8
|
+
let(:default_options) do
|
|
9
|
+
{ api_key: api_key, environment: environment, protocol: protocol }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:client_options) { default_options }
|
|
13
|
+
let(:client) { Ably::Realtime::Client.new(client_options) }
|
|
14
|
+
|
|
15
|
+
before(:example) do
|
|
16
|
+
EventMachine.add_shutdown_hook do
|
|
17
|
+
connection.off # minimise side effects of callbacks from finished test calling stop_reactor
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'intialization' do
|
|
22
|
+
it 'connects automatically' do
|
|
23
|
+
connection.on(:connected) do
|
|
24
|
+
expect(connection.state).to eq(:connected)
|
|
25
|
+
stop_reactor
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'with :connect_automatically option set to false' do
|
|
30
|
+
let(:client) do
|
|
31
|
+
Ably::Realtime::Client.new(default_options.merge(connect_automatically: false))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'does not connect automatically' do
|
|
35
|
+
EventMachine.add_timer(1) do
|
|
36
|
+
expect(connection).to be_initialized
|
|
37
|
+
stop_reactor
|
|
38
|
+
end
|
|
39
|
+
client
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'connects when method #connect is called' do
|
|
43
|
+
connection.connect do
|
|
44
|
+
expect(connection).to be_connected
|
|
45
|
+
stop_reactor
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context 'with token auth' do
|
|
51
|
+
before do
|
|
52
|
+
# Reduce token expiry buffer to zero so that a token expired? predicate is exact
|
|
53
|
+
# Normally there is a buffer so that a token expiring soon is considered expired
|
|
54
|
+
stub_const 'Ably::Models::Token::TOKEN_EXPIRY_BUFFER', 0
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'for renewable tokens' do
|
|
58
|
+
context 'that are valid for the duration of the test' do
|
|
59
|
+
context 'with valid pre authorised token expiring in the future' do
|
|
60
|
+
it 'uses the existing token created by Auth' do
|
|
61
|
+
client.auth.authorise(ttl: 300)
|
|
62
|
+
expect(client.auth).to_not receive(:request_token)
|
|
63
|
+
connection.once(:connected) do
|
|
64
|
+
stop_reactor
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context 'with implicit authorisation' do
|
|
70
|
+
let(:client_options) { default_options.merge(client_id: 'force_token_auth') }
|
|
71
|
+
|
|
72
|
+
it 'uses the token created by the implicit authorisation' do
|
|
73
|
+
expect(client.auth).to receive(:request_token).once.and_call_original
|
|
74
|
+
|
|
75
|
+
connection.once(:connected) do
|
|
76
|
+
stop_reactor
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context 'that expire' do
|
|
83
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
|
84
|
+
|
|
85
|
+
before do
|
|
86
|
+
client.auth.authorise(ttl: ttl)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context 'opening a new connection' do
|
|
90
|
+
context 'with recently expired token' do
|
|
91
|
+
let(:ttl) { 2 }
|
|
92
|
+
|
|
93
|
+
it 'renews the token on connect' do
|
|
94
|
+
sleep ttl + 0.1
|
|
95
|
+
expect(client.auth.current_token).to be_expired
|
|
96
|
+
expect(client.auth).to receive(:authorise).at_least(:once).and_call_original
|
|
97
|
+
connection.once(:connected) do
|
|
98
|
+
expect(client.auth.current_token).to_not be_expired
|
|
99
|
+
stop_reactor
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
context 'with immediately expiring token' do
|
|
105
|
+
let(:ttl) { 0.01 }
|
|
106
|
+
|
|
107
|
+
it 'renews the token on connect, and only makes one subsequent attempt to obtain a new token' do
|
|
108
|
+
expect(client.auth).to receive(:authorise).at_least(:twice).and_call_original
|
|
109
|
+
connection.once(:disconnected) do
|
|
110
|
+
connection.once(:failed) do |error|
|
|
111
|
+
expect(error.code).to eql(40140) # token expired
|
|
112
|
+
stop_reactor
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'uses the primary host for subsequent connection and auth requests' do
|
|
118
|
+
EventMachine.add_timer(1) do # wait for token to expire
|
|
119
|
+
connection.once(:disconnected) do
|
|
120
|
+
expect(client.rest_client.connection).to receive(:post).
|
|
121
|
+
with(/requestToken$/, anything).
|
|
122
|
+
at_least(:once).
|
|
123
|
+
and_call_original
|
|
124
|
+
|
|
125
|
+
expect(client.rest_client).to_not receive(:fallback_connection)
|
|
126
|
+
expect(client).to_not receive(:fallback_endpoint)
|
|
127
|
+
|
|
128
|
+
connection.once(:failed) do
|
|
129
|
+
connection.off
|
|
130
|
+
stop_reactor
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context 'when connected with a valid non-expired token' do
|
|
139
|
+
context 'that then expires following the connection being opened' do
|
|
140
|
+
let(:ttl) { 2 }
|
|
141
|
+
let(:channel) { client.channel('test') }
|
|
142
|
+
|
|
143
|
+
context 'the server' do
|
|
144
|
+
it 'disconnects the client, and the client automatically renews the token and then reconnects', em_timeout: 10 do
|
|
145
|
+
original_token = client.auth.current_token
|
|
146
|
+
expect(original_token).to_not be_expired
|
|
147
|
+
|
|
148
|
+
connection.once(:connected) do
|
|
149
|
+
started_at = Time.now
|
|
150
|
+
connection.once(:disconnected) do |error|
|
|
151
|
+
EventMachine.add_timer(1) do # allow 1 second
|
|
152
|
+
expect(Time.now - started_at >= ttl)
|
|
153
|
+
expect(original_token).to be_expired
|
|
154
|
+
expect(error.code).to eql(40140) # token expired
|
|
155
|
+
connection.once(:connected) do
|
|
156
|
+
expect(client.auth.current_token).to_not be_expired
|
|
157
|
+
stop_reactor
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
channel.attach
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
skip 'retains connection state'
|
|
168
|
+
skip 'changes state to failed if a new token cannot be issued'
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
context 'for non-renewable tokens' do
|
|
175
|
+
context 'that are expired' do
|
|
176
|
+
let!(:expired_token) do
|
|
177
|
+
Ably::Realtime::Client.new(default_options).auth.request_token(ttl: 0.01)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context 'opening a new connection' do
|
|
181
|
+
let(:client_options) { default_options.merge(api_key: nil, token_id: expired_token.id, log_level: :none) }
|
|
182
|
+
|
|
183
|
+
it 'transitions state to failed', em_timeout: 10 do
|
|
184
|
+
EventMachine.add_timer(1) do # wait for token to expire
|
|
185
|
+
expect(expired_token).to be_expired
|
|
186
|
+
connection.once(:connected) { raise 'Connection should never connect as token has expired' }
|
|
187
|
+
connection.once(:failed) do
|
|
188
|
+
expect(client.connection.error_reason.code).to eql(40140)
|
|
189
|
+
stop_reactor
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
context 'when connected' do
|
|
196
|
+
skip 'transitions state to failed'
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
context 'initialization state changes' do
|
|
204
|
+
let(:phases) { [:connecting, :connected] }
|
|
205
|
+
let(:events_triggered) { [] }
|
|
206
|
+
let(:test_expectation) do
|
|
207
|
+
Proc.new do
|
|
208
|
+
expect(events_triggered).to eq(phases)
|
|
209
|
+
stop_reactor
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def expect_ordered_phases
|
|
214
|
+
phases.each do |phase|
|
|
215
|
+
connection.on(phase) do
|
|
216
|
+
events_triggered << phase
|
|
217
|
+
test_expectation.call if events_triggered.length == phases.length
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
context 'with implicit #connect' do
|
|
223
|
+
it 'are triggered in order' do
|
|
224
|
+
expect_ordered_phases
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
context 'with explicit #connect' do
|
|
229
|
+
it 'are triggered in order' do
|
|
230
|
+
expect_ordered_phases
|
|
231
|
+
connection.connect
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
context '#connect' do
|
|
237
|
+
it 'returns a Deferrable' do
|
|
238
|
+
expect(connection.connect).to be_a(EventMachine::Deferrable)
|
|
239
|
+
stop_reactor
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'calls the Deferrable callback on success' do
|
|
243
|
+
connection.connect.callback do |connection|
|
|
244
|
+
expect(connection).to be_a(Ably::Realtime::Connection)
|
|
245
|
+
expect(connection.state).to eq(:connected)
|
|
246
|
+
stop_reactor
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
context 'when already connected' do
|
|
251
|
+
it 'does nothing and no further state changes are emitted' do
|
|
252
|
+
connection.once(:connected) do
|
|
253
|
+
connection.once_state_changed { raise 'State should not have changed' }
|
|
254
|
+
3.times { connection.connect }
|
|
255
|
+
EventMachine.add_timer(1) do
|
|
256
|
+
expect(connection).to be_connected
|
|
257
|
+
connection.off
|
|
258
|
+
stop_reactor
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
describe 'once connected' do
|
|
265
|
+
let(:connection2) { Ably::Realtime::Client.new(client_options).connection }
|
|
266
|
+
|
|
267
|
+
describe 'connection#id' do
|
|
268
|
+
it 'is a string' do
|
|
269
|
+
connection.connect do
|
|
270
|
+
expect(connection.id).to be_a(String)
|
|
271
|
+
stop_reactor
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'is unique from the connection#key' do
|
|
276
|
+
connection.connect do
|
|
277
|
+
expect(connection.id).to_not eql(connection.key)
|
|
278
|
+
stop_reactor
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it 'is unique for every connection' do
|
|
283
|
+
when_all(connection.connect, connection2.connect) do
|
|
284
|
+
expect(connection.id).to_not eql(connection2.id)
|
|
285
|
+
stop_reactor
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
describe 'connection#key' do
|
|
291
|
+
it 'is a string' do
|
|
292
|
+
connection.connect do
|
|
293
|
+
expect(connection.key).to be_a(String)
|
|
294
|
+
stop_reactor
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it 'is unique from the connection#id' do
|
|
299
|
+
connection.connect do
|
|
300
|
+
expect(connection.key).to_not eql(connection.id)
|
|
301
|
+
stop_reactor
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
it 'is unique for every connection' do
|
|
306
|
+
when_all(connection.connect, connection2.connect) do
|
|
307
|
+
expect(connection.key).to_not eql(connection2.key)
|
|
308
|
+
stop_reactor
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
context 'following a previous connection being opened and closed' do
|
|
315
|
+
it 'reconnects and is provided with a new connection ID and connection key from the server' do
|
|
316
|
+
connection.connect do
|
|
317
|
+
connection_id = connection.id
|
|
318
|
+
connection_key = connection.key
|
|
319
|
+
|
|
320
|
+
connection.close do
|
|
321
|
+
connection.connect do
|
|
322
|
+
expect(connection.id).to_not eql(connection_id)
|
|
323
|
+
expect(connection.key).to_not eql(connection_key)
|
|
324
|
+
stop_reactor
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
describe '#serial connection serial' do
|
|
333
|
+
let(:channel) { client.channel(random_str) }
|
|
334
|
+
|
|
335
|
+
it 'is set to -1 when a new connection is opened' do
|
|
336
|
+
connection.connect do
|
|
337
|
+
expect(connection.serial).to eql(-1)
|
|
338
|
+
stop_reactor
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
context 'when a message is sent but the ACK has not yet been received' do
|
|
343
|
+
|
|
344
|
+
it 'the sent message msgSerial is 0 but the connection serial remains at -1' do
|
|
345
|
+
channel.attach do
|
|
346
|
+
connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
347
|
+
connection.__outgoing_protocol_msgbus__.unsubscribe
|
|
348
|
+
expect(protocol_message['msgSerial']).to eql(0)
|
|
349
|
+
expect(connection.serial).to eql(-1)
|
|
350
|
+
stop_reactor
|
|
351
|
+
end
|
|
352
|
+
channel.publish('event', 'data')
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it 'is set to 0 when a message sent ACK is received' do
|
|
358
|
+
channel.publish('event', 'data') do
|
|
359
|
+
expect(connection.serial).to eql(0)
|
|
360
|
+
stop_reactor
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it 'is set to 1 when the second message sent ACK is received' do
|
|
365
|
+
channel.publish('event', 'data') do
|
|
366
|
+
channel.publish('event', 'data') do
|
|
367
|
+
expect(connection.serial).to eql(1)
|
|
368
|
+
stop_reactor
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
context '#close' do
|
|
375
|
+
it 'returns a Deferrable' do
|
|
376
|
+
connection.connect do
|
|
377
|
+
expect(connection.close).to be_a(EventMachine::Deferrable)
|
|
378
|
+
stop_reactor
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
it 'calls the Deferrable callback on success' do
|
|
383
|
+
connection.connect do
|
|
384
|
+
connection.close.callback do |connection|
|
|
385
|
+
expect(connection).to be_a(Ably::Realtime::Connection)
|
|
386
|
+
expect(connection.state).to eq(:closed)
|
|
387
|
+
stop_reactor
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
context 'when already closed' do
|
|
393
|
+
it 'does nothing and no further state changes are emitted' do
|
|
394
|
+
connection.once(:connected) do
|
|
395
|
+
connection.close do
|
|
396
|
+
connection.once_state_changed { raise 'State should not have changed' }
|
|
397
|
+
3.times { connection.close }
|
|
398
|
+
EventMachine.add_timer(1) do
|
|
399
|
+
expect(connection).to be_closed
|
|
400
|
+
connection.off
|
|
401
|
+
stop_reactor
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
context 'when connection state is' do
|
|
409
|
+
let(:events) { Hash.new }
|
|
410
|
+
|
|
411
|
+
def log_connection_changes
|
|
412
|
+
connection.on(:closing) { events[:closing_emitted] = true }
|
|
413
|
+
connection.on(:error) { events[:error_emitted] = true }
|
|
414
|
+
|
|
415
|
+
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
416
|
+
events[:closed_message_from_server_received] = true if protocol_message.action == :closed
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
context ':initialized' do
|
|
421
|
+
it 'changes the connection state to :closing and then immediately :closed without sending a ProtocolMessage CLOSE' do
|
|
422
|
+
connection.on(:closed) do
|
|
423
|
+
expect(connection.state).to eq(:closed)
|
|
424
|
+
|
|
425
|
+
EventMachine.add_timer(1) do # allow for all subscribers on incoming message bes
|
|
426
|
+
expect(events[:error_emitted]).to_not eql(true)
|
|
427
|
+
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
|
428
|
+
expect(events[:closing_emitted]).to eql(true)
|
|
429
|
+
stop_reactor
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
log_connection_changes
|
|
434
|
+
connection.close
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
context ':connected' do
|
|
439
|
+
it 'changes the connection state to :closing and waits for the server to confirm connection is :closed with a ProtocolMessage' do
|
|
440
|
+
connection.on(:connected) do
|
|
441
|
+
connection.on(:closed) do
|
|
442
|
+
EventMachine.add_timer(1) do # allow for all subscribers on incoming message bus
|
|
443
|
+
expect(events[:error_emitted]).to_not eql(true)
|
|
444
|
+
expect(events[:closed_message_from_server_received]).to eql(true)
|
|
445
|
+
expect(events[:closing_emitted]).to eql(true)
|
|
446
|
+
stop_reactor
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
log_connection_changes
|
|
451
|
+
connection.close
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
context 'with an unresponsive connection' do
|
|
456
|
+
let(:stubbed_timeout) { 2 }
|
|
457
|
+
|
|
458
|
+
before do
|
|
459
|
+
stub_const 'Ably::Realtime::Connection::ConnectionManager::TIMEOUTS',
|
|
460
|
+
Ably::Realtime::Connection::ConnectionManager::TIMEOUTS.merge(close: stubbed_timeout)
|
|
461
|
+
|
|
462
|
+
connection.on(:connected) do
|
|
463
|
+
# Prevent all incoming & outgoing ProtocolMessages from being processed by the client library
|
|
464
|
+
connection.__outgoing_protocol_msgbus__.unsubscribe
|
|
465
|
+
connection.__incoming_protocol_msgbus__.unsubscribe
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
it 'force closes the connection when a :closed ProtocolMessage response is not received' do
|
|
470
|
+
connection.on(:connected) do
|
|
471
|
+
close_requested_at = Time.now
|
|
472
|
+
|
|
473
|
+
connection.on(:closed) do
|
|
474
|
+
expect(Time.now - close_requested_at).to be >= stubbed_timeout
|
|
475
|
+
expect(connection.state).to eq(:closed)
|
|
476
|
+
expect(events[:error_emitted]).to_not eql(true)
|
|
477
|
+
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
|
478
|
+
expect(events[:closing_emitted]).to eql(true)
|
|
479
|
+
stop_reactor
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
log_connection_changes
|
|
483
|
+
connection.close
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
context '#ping' do
|
|
492
|
+
it 'echoes a heart beat' do
|
|
493
|
+
connection.on(:connected) do
|
|
494
|
+
connection.ping do |time_elapsed|
|
|
495
|
+
expect(time_elapsed).to be > 0
|
|
496
|
+
stop_reactor
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
context 'when not connected' do
|
|
502
|
+
it 'raises an exception' do
|
|
503
|
+
expect { connection.ping }.to raise_error RuntimeError, /Cannot send a ping when connection/
|
|
504
|
+
stop_reactor
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
context 'recovery' do
|
|
510
|
+
let(:channel_name) { random_str }
|
|
511
|
+
let(:channel) { client.channel(channel_name) }
|
|
512
|
+
let(:publishing_client) do
|
|
513
|
+
Ably::Realtime::Client.new(client_options)
|
|
514
|
+
end
|
|
515
|
+
let(:publishing_client_channel) { publishing_client.channel(channel_name) }
|
|
516
|
+
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
517
|
+
|
|
518
|
+
before do
|
|
519
|
+
# Reconfigure client library retry periods and timeouts so that tests run quickly
|
|
520
|
+
stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
|
|
521
|
+
Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
|
|
522
|
+
disconnected: { retry_every: 0.1, max_time_in_state: 0.2 },
|
|
523
|
+
suspended: { retry_every: 0.1, max_time_in_state: 0.2 },
|
|
524
|
+
)
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
describe '#recovery_key' do
|
|
528
|
+
def self.available_states
|
|
529
|
+
[:connecting, :connected, :disconnected, :suspended, :failed]
|
|
530
|
+
end
|
|
531
|
+
let(:available_states) { self.class.available_states}
|
|
532
|
+
let(:states) { Hash.new }
|
|
533
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
|
534
|
+
|
|
535
|
+
it 'is composed of connection id and serial that is kept up to date with each message ACK received' do
|
|
536
|
+
connection.on(:connected) do
|
|
537
|
+
expected_serial = -1
|
|
538
|
+
expect(connection.id).to_not be_nil
|
|
539
|
+
expect(connection.serial).to eql(expected_serial)
|
|
540
|
+
|
|
541
|
+
client.channel('test').attach do |channel|
|
|
542
|
+
channel.publish('event', 'data') do
|
|
543
|
+
expected_serial += 1 # attach message received
|
|
544
|
+
expect(connection.serial).to eql(expected_serial)
|
|
545
|
+
|
|
546
|
+
channel.publish('event', 'data') do
|
|
547
|
+
expected_serial += 1 # attach message received
|
|
548
|
+
expect(connection.serial).to eql(expected_serial)
|
|
549
|
+
stop_reactor
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
it "is available when connection is in one of the states: #{available_states.join(', ')}" do
|
|
557
|
+
connection.once(:connected) do
|
|
558
|
+
allow(client).to receive(:endpoint).and_return(
|
|
559
|
+
URI::Generic.build(
|
|
560
|
+
scheme: 'wss',
|
|
561
|
+
host: 'this.host.does.not.exist.com'
|
|
562
|
+
)
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
connection.transition_state_machine! :disconnected
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
available_states.each do |state|
|
|
569
|
+
connection.on(state) do
|
|
570
|
+
states[state.to_sym] = true if connection.recovery_key
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
connection.once(:failed) do
|
|
575
|
+
expect(states.keys).to match_array(available_states)
|
|
576
|
+
stop_reactor
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
it 'is nil when connection is explicitly CLOSED' do
|
|
581
|
+
connection.once(:connected) do
|
|
582
|
+
connection.close do
|
|
583
|
+
expect(connection.recovery_key).to be_nil
|
|
584
|
+
stop_reactor
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
context "opening a new connection using a recently disconnected connection's #recovery_key" do
|
|
591
|
+
context 'connection#id and connection#key after recovery' do
|
|
592
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
|
593
|
+
|
|
594
|
+
it 'remain the same' do
|
|
595
|
+
previous_connection_id = nil
|
|
596
|
+
previous_connection_key = nil
|
|
597
|
+
|
|
598
|
+
connection.once(:connected) do
|
|
599
|
+
previous_connection_id = connection.id
|
|
600
|
+
previous_connection_key = connection.key
|
|
601
|
+
connection.transition_state_machine! :failed
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
connection.once(:failed) do
|
|
605
|
+
recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
|
|
606
|
+
recover_client.connection.on(:connected) do
|
|
607
|
+
expect(recover_client.connection.key).to eql(previous_connection_key)
|
|
608
|
+
expect(recover_client.connection.id).to eql(previous_connection_id)
|
|
609
|
+
stop_reactor
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
context 'when messages have been sent whilst the old connection is disconnected' do
|
|
616
|
+
describe 'the new connection' do
|
|
617
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
|
618
|
+
|
|
619
|
+
it 'recovers server-side queued messages' do
|
|
620
|
+
channel.attach do |message|
|
|
621
|
+
connection.transition_state_machine! :failed
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
connection.on(:failed) do
|
|
625
|
+
publishing_client_channel.publish('event', 'message') do
|
|
626
|
+
recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
|
|
627
|
+
recover_client.channel(channel_name).attach do |recover_client_channel|
|
|
628
|
+
recover_client_channel.subscribe('event') do |message|
|
|
629
|
+
expect(message.data).to eql('message')
|
|
630
|
+
stop_reactor
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
context 'with :recover option' do
|
|
641
|
+
context 'with invalid syntax' do
|
|
642
|
+
let(:invaid_client_options) { default_options.merge(recover: 'invalid') }
|
|
643
|
+
|
|
644
|
+
it 'raises an exception' do
|
|
645
|
+
expect { Ably::Realtime::Client.new(invaid_client_options) }.to raise_error ArgumentError, /Recover/
|
|
646
|
+
stop_reactor
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
context 'with invalid formatted value sent to server' do
|
|
651
|
+
let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
|
|
652
|
+
|
|
653
|
+
it 'triggers a fatal error on the connection object, sets the #error_reason and disconnects' do
|
|
654
|
+
connection.once(:error) do |error|
|
|
655
|
+
expect(connection.state).to eq(:failed)
|
|
656
|
+
expect(connection.error_reason.message).to match(/Invalid connection key/)
|
|
657
|
+
expect(connection.error_reason.code).to eql(40006)
|
|
658
|
+
expect(connection.error_reason).to eql(error)
|
|
659
|
+
stop_reactor
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
context 'with expired (missing) value sent to server' do
|
|
665
|
+
let(:client_options) { default_options.merge(recover: '0123456789abcdef:0', log_level: :fatal) }
|
|
666
|
+
|
|
667
|
+
it 'triggers an error on the connection object, sets the #error_reason, yet will connect anyway' do
|
|
668
|
+
connection.once(:error) do |error|
|
|
669
|
+
expect(connection.state).to eq(:connected)
|
|
670
|
+
expect(connection.error_reason.message).to match(/Invalid connection key/i)
|
|
671
|
+
expect(connection.error_reason.code).to eql(80008)
|
|
672
|
+
expect(connection.error_reason).to eql(error)
|
|
673
|
+
stop_reactor
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
context 'with many connections simultaneously', em_timeout: 15 do
|
|
681
|
+
let(:connection_count) { 40 }
|
|
682
|
+
let(:connection_ids) { [] }
|
|
683
|
+
let(:connection_keys) { [] }
|
|
684
|
+
|
|
685
|
+
it 'opens each with a unique connection#id and connection#key' do
|
|
686
|
+
connection_count.times.map do
|
|
687
|
+
Ably::Realtime::Client.new(client_options)
|
|
688
|
+
end.each do |client|
|
|
689
|
+
client.connection.on(:connected) do
|
|
690
|
+
connection_ids << client.connection.id
|
|
691
|
+
connection_keys << client.connection.key
|
|
692
|
+
next unless connection_ids.count == connection_count
|
|
693
|
+
|
|
694
|
+
expect(connection_ids.uniq.count).to eql(connection_count)
|
|
695
|
+
expect(connection_keys.uniq.count).to eql(connection_count)
|
|
696
|
+
stop_reactor
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
context 'when a state transition is unsupported' do
|
|
703
|
+
let(:client_options) { default_options.merge(log_level: :none) } # silence FATAL errors
|
|
704
|
+
|
|
705
|
+
it 'emits a StateChangeError' do
|
|
706
|
+
connection.connect do
|
|
707
|
+
connection.transition_state_machine :initialized
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
connection.on(:error) do |error|
|
|
711
|
+
expect(error).to be_a(Ably::Exceptions::StateChangeError)
|
|
712
|
+
stop_reactor
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
context 'undocumented method' do
|
|
719
|
+
context '#internet_up?' do
|
|
720
|
+
it 'returns a Deferrable' do
|
|
721
|
+
expect(connection.internet_up?).to be_a(EventMachine::Deferrable)
|
|
722
|
+
stop_reactor
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
context 'internet up URL protocol' do
|
|
726
|
+
let(:http_request) { double('EventMachine::HttpRequest', get: EventMachine::DefaultDeferrable.new) }
|
|
727
|
+
|
|
728
|
+
context 'when using TLS for the connection' do
|
|
729
|
+
let(:client_options) { default_options.merge(tls: true) }
|
|
730
|
+
|
|
731
|
+
it 'uses TLS for the Internet check to https://internet-up.ably-realtime.com/is-the-internet-up.txt' do
|
|
732
|
+
expect(EventMachine::HttpRequest).to receive(:new).with('https://internet-up.ably-realtime.com/is-the-internet-up.txt').and_return(http_request)
|
|
733
|
+
connection.internet_up?
|
|
734
|
+
stop_reactor
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
context 'when using a non-secured connection' do
|
|
739
|
+
let(:client_options) { default_options.merge(tls: false, use_token_auth: true) }
|
|
740
|
+
|
|
741
|
+
it 'uses TLS for the Internet check to http://internet-up.ably-realtime.com/is-the-internet-up.txt' do
|
|
742
|
+
expect(EventMachine::HttpRequest).to receive(:new).with('http://internet-up.ably-realtime.com/is-the-internet-up.txt').and_return(http_request)
|
|
743
|
+
connection.internet_up?
|
|
744
|
+
stop_reactor
|
|
745
|
+
end
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
context 'when the Internet is up' do
|
|
750
|
+
it 'calls the block with true' do
|
|
751
|
+
connection.internet_up? do |result|
|
|
752
|
+
expect(result).to be_truthy
|
|
753
|
+
stop_reactor
|
|
754
|
+
end
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
it 'calls the success callback of the Deferrable' do
|
|
758
|
+
connection.internet_up?.callback do
|
|
759
|
+
stop_reactor
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
context 'when the Internet is down' do
|
|
765
|
+
before do
|
|
766
|
+
stub_const 'Ably::INTERNET_CHECK', { url: '//does.not.exist.com', ok_text: 'no.way.this.will.match' }
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
it 'calls the block with false' do
|
|
770
|
+
connection.internet_up? do |result|
|
|
771
|
+
expect(result).to be_falsey
|
|
772
|
+
stop_reactor
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
it 'calls the failure callback of the Deferrable' do
|
|
777
|
+
connection.internet_up?.errback do
|
|
778
|
+
stop_reactor
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
end
|