ably 1.1.4 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/SPEC.md +289 -221
- data/ably.gemspec +2 -2
- data/lib/ably/modules/ably.rb +11 -1
- data/lib/ably/realtime/client.rb +1 -0
- data/lib/ably/rest/client.rb +13 -6
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/connection_failures_spec.rb +26 -11
- data/spec/acceptance/realtime/connection_spec.rb +8 -5
- data/spec/acceptance/rest/base_spec.rb +8 -4
- data/spec/acceptance/rest/client_spec.rb +49 -14
- data/spec/shared/client_initializer_behaviour.rb +131 -0
- metadata +9 -15
data/ably.gemspec
CHANGED
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_runtime_dependency 'eventmachine', '~> 1.2.6'
|
22
22
|
spec.add_runtime_dependency 'em-http-request', '~> 1.1'
|
23
23
|
spec.add_runtime_dependency 'statesman', '~> 7.4'
|
24
|
-
spec.add_runtime_dependency 'faraday', '
|
25
|
-
spec.add_runtime_dependency '
|
24
|
+
spec.add_runtime_dependency 'faraday', '~> 1.0'
|
25
|
+
spec.add_runtime_dependency 'typhoeus', '~> 1.4'
|
26
26
|
|
27
27
|
if RUBY_VERSION.match(/^1\./)
|
28
28
|
spec.add_runtime_dependency 'json', '< 2.0'
|
data/lib/ably/modules/ably.rb
CHANGED
@@ -6,8 +6,18 @@
|
|
6
6
|
module Ably
|
7
7
|
# Fallback hosts to use when a connection to rest/realtime.ably.io is not possible due to
|
8
8
|
# network failures either at the client, between the client and Ably, within an Ably data center, or at the IO domain registrar
|
9
|
+
# see https://docs.ably.io/client-lib-development-guide/features/#RSC15a
|
9
10
|
#
|
10
|
-
|
11
|
+
FALLBACK_DOMAIN = 'ably-realtime.com'.freeze
|
12
|
+
FALLBACK_IDS = %w(a b c d e).freeze
|
13
|
+
|
14
|
+
# Default production fallbacks a.ably-realtime.com ... e.ably-realtime.com
|
15
|
+
FALLBACK_HOSTS = FALLBACK_IDS.map { |host| "#{host}.#{FALLBACK_DOMAIN}".freeze }.freeze
|
16
|
+
|
17
|
+
# Custom environment default fallbacks {ENV}-a-fallback.ably-realtime.com ... {ENV}-a-fallback.ably-realtime.com
|
18
|
+
CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES = FALLBACK_IDS.map do |host|
|
19
|
+
"-#{host}-fallback.#{FALLBACK_DOMAIN}".freeze
|
20
|
+
end.freeze
|
11
21
|
|
12
22
|
INTERNET_CHECK = {
|
13
23
|
url: '//internet-up.ably-realtime.com/is-the-internet-up.txt',
|
data/lib/ably/realtime/client.rb
CHANGED
@@ -74,6 +74,7 @@ module Ably
|
|
74
74
|
def_delegators :@rest_client, :use_tls?, :protocol, :protocol_binary?
|
75
75
|
def_delegators :@rest_client, :environment, :custom_host, :custom_port, :custom_tls_port
|
76
76
|
def_delegators :@rest_client, :log_level
|
77
|
+
def_delegators :@rest_client, :options
|
77
78
|
|
78
79
|
# Creates a {Ably::Realtime::Client Realtime Client} and configures the {Ably::Auth} object for the connection.
|
79
80
|
#
|
data/lib/ably/rest/client.rb
CHANGED
@@ -3,6 +3,9 @@ require 'json'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'uri'
|
5
5
|
|
6
|
+
require 'typhoeus'
|
7
|
+
require 'typhoeus/adapters/faraday'
|
8
|
+
|
6
9
|
require 'ably/rest/middleware/exceptions'
|
7
10
|
|
8
11
|
module Ably
|
@@ -181,16 +184,18 @@ module Ably
|
|
181
184
|
@idempotent_rest_publishing = options.delete(:idempotent_rest_publishing) || Ably.major_minor_version_numeric > 1.1
|
182
185
|
|
183
186
|
|
184
|
-
if options[:fallback_hosts_use_default] && options[:
|
185
|
-
raise ArgumentError, "fallback_hosts_use_default cannot be set to
|
187
|
+
if options[:fallback_hosts_use_default] && options[:fallback_hosts]
|
188
|
+
raise ArgumentError, "fallback_hosts_use_default cannot be set to try when fallback_hosts is also provided"
|
186
189
|
end
|
187
190
|
@fallback_hosts = case
|
188
191
|
when options.delete(:fallback_hosts_use_default)
|
189
192
|
Ably::FALLBACK_HOSTS
|
190
193
|
when options_fallback_hosts = options.delete(:fallback_hosts)
|
191
194
|
options_fallback_hosts
|
192
|
-
when
|
195
|
+
when custom_host || options[:realtime_host] || custom_port || custom_tls_port
|
193
196
|
[]
|
197
|
+
when environment
|
198
|
+
CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES.map { |host| "#{environment}#{host}" }
|
194
199
|
else
|
195
200
|
Ably::FALLBACK_HOSTS
|
196
201
|
end
|
@@ -202,6 +207,8 @@ module Ably
|
|
202
207
|
@http_defaults = HTTP_DEFAULTS.dup
|
203
208
|
options.each do |key, val|
|
204
209
|
if http_key = key[/^http_(.+)/, 1]
|
210
|
+
# Typhoeus converts decimal durations to milliseconds, so 0.0001 timeout is treated as 0 (no timeout)
|
211
|
+
val = 0.001 if val.kind_of?(Numeric) && (val > 0) && (val < 0.001)
|
205
212
|
@http_defaults[http_key.to_sym] = val if val && @http_defaults.has_key?(http_key.to_sym)
|
206
213
|
end
|
207
214
|
end
|
@@ -665,7 +672,7 @@ module Ably
|
|
665
672
|
}
|
666
673
|
end
|
667
674
|
|
668
|
-
# Return a Faraday middleware stack to initiate the Faraday::
|
675
|
+
# Return a Faraday middleware stack to initiate the Faraday::RackBuilder with
|
669
676
|
#
|
670
677
|
# @see http://mislav.uniqpath.com/2011/07/faraday-advanced-http/
|
671
678
|
def middleware
|
@@ -677,8 +684,8 @@ module Ably
|
|
677
684
|
|
678
685
|
setup_incoming_middleware builder, logger, fail_if_unsupported_mime_type: true
|
679
686
|
|
680
|
-
# Set Faraday's HTTP adapter
|
681
|
-
builder.adapter :
|
687
|
+
# Set Faraday's HTTP adapter with support for HTTP/2
|
688
|
+
builder.adapter :typhoeus, http_version: :httpv2_0
|
682
689
|
end
|
683
690
|
end
|
684
691
|
|
@@ -7,7 +7,10 @@ module Ably
|
|
7
7
|
class FailIfUnsupportedMimeType < Faraday::Response::Middleware
|
8
8
|
def on_complete(env)
|
9
9
|
unless env.response_headers['Ably-Middleware-Parsed'] == true
|
10
|
-
|
10
|
+
# Ignore empty body with success status code for no body response
|
11
|
+
return if env.body.to_s.empty? && env.status == 204
|
12
|
+
|
13
|
+
unless (500..599).include?(env.status)
|
11
14
|
raise Ably::Exceptions::InvalidResponseBody,
|
12
15
|
"Content Type #{env.response_headers['Content-Type']} is not supported by this client library"
|
13
16
|
end
|
data/lib/ably/version.rb
CHANGED
@@ -156,10 +156,20 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
156
156
|
|
157
157
|
stub_request(:get, auth_url).
|
158
158
|
to_return do |request|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
sleep Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout)
|
160
|
+
{ status: [500, "Internal Server Error"] }
|
161
|
+
end.then.
|
162
|
+
to_return(:status => 201, :body => token_response.to_json, :headers => { 'Content-Type' => 'application/json' })
|
163
|
+
|
164
|
+
stub_request(:get, 'https://internet-up.ably-realtime.com/is-the-internet-up.txt')
|
165
|
+
.with(
|
166
|
+
headers: {
|
167
|
+
'Accept-Encoding' => 'gzip, compressed',
|
168
|
+
'Connection' => 'close',
|
169
|
+
'Host' => 'internet-up.ably-realtime.com',
|
170
|
+
'User-Agent' => 'EventMachine HttpClient'
|
171
|
+
}
|
172
|
+
).to_return(status: 200, body: 'yes\n', headers: { 'Content-Type' => 'text/plain' })
|
163
173
|
end
|
164
174
|
|
165
175
|
specify 'the connection moves to the disconnected state and tries again, returning again to the disconnected state (#RSA4c, #RSA4c1, #RSA4c2)' do
|
@@ -1423,14 +1433,19 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
1423
1433
|
let(:expected_host) { "#{environment}-#{Ably::Realtime::Client::DOMAIN}" }
|
1424
1434
|
let(:client_options) { timeout_options.merge(environment: environment) }
|
1425
1435
|
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1436
|
+
context ':fallback_hosts_use_default is unset' do
|
1437
|
+
let(:max_time_in_state_for_tests) { 8 }
|
1438
|
+
let(:expected_hosts) { Ably::CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES.map { |suffix| "#{environment}#{suffix}" } + [expected_host] }
|
1439
|
+
let(:fallback_hosts_used) { Array.new }
|
1440
|
+
|
1441
|
+
it 'uses fallback hosts by default' do
|
1442
|
+
allow(connection).to receive(:create_transport) do |host|
|
1443
|
+
fallback_hosts_used << host
|
1444
|
+
raise EventMachine::ConnectionError
|
1445
|
+
end
|
1431
1446
|
|
1432
|
-
connection.once(:suspended) do
|
1433
1447
|
connection.once(:suspended) do
|
1448
|
+
expect(fallback_hosts_used.uniq).to match_array(expected_hosts)
|
1434
1449
|
stop_reactor
|
1435
1450
|
end
|
1436
1451
|
end
|
@@ -1508,7 +1523,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
1508
1523
|
end
|
1509
1524
|
|
1510
1525
|
context 'with production environment' do
|
1511
|
-
let(:custom_hosts) { %w(
|
1526
|
+
let(:custom_hosts) { %w(a.ably-realtime.com b.ably-realtime.com) }
|
1512
1527
|
before do
|
1513
1528
|
stub_const 'Ably::FALLBACK_HOSTS', custom_hosts
|
1514
1529
|
end
|
@@ -122,7 +122,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
context 'with immediately expired token' do
|
125
|
+
context 'with immediately expired token and no fallback hosts' do
|
126
126
|
let(:ttl) { 0.001 }
|
127
127
|
let(:auth_requests) { [] }
|
128
128
|
let(:token_callback) do
|
@@ -131,7 +131,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
131
131
|
Ably::Rest::Client.new(default_options).auth.request_token(ttl: ttl).token
|
132
132
|
end
|
133
133
|
end
|
134
|
-
let(:client_options) { default_options.merge(auth_callback: token_callback) }
|
134
|
+
let(:client_options) { default_options.merge(auth_callback: token_callback, fallback_hosts: []) }
|
135
135
|
|
136
136
|
it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token (#RSA4b)' do
|
137
137
|
started_at = Time.now.to_f
|
@@ -146,7 +146,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
146
146
|
end
|
147
147
|
|
148
148
|
context 'when disconnected_retry_timeout is 0.5 seconds' do
|
149
|
-
let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback) }
|
149
|
+
let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback, fallback_hosts: []) }
|
150
150
|
|
151
151
|
it 'renews the token on connect, and continues to attempt renew based on the retry schedule' do
|
152
152
|
disconnect_count = 0
|
@@ -172,7 +172,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
172
172
|
end
|
173
173
|
|
174
174
|
context 'using implicit token auth' do
|
175
|
-
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }) }
|
175
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }, fallback_hosts: []) }
|
176
176
|
|
177
177
|
before do
|
178
178
|
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', -10 # ensure client lib thinks token is still valid
|
@@ -441,7 +441,9 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
441
441
|
end
|
442
442
|
end
|
443
443
|
|
444
|
-
context '#connect' do
|
444
|
+
context '#connect with no fallbacks' do
|
445
|
+
let(:client_options) { default_options.merge(fallback_hosts: []) }
|
446
|
+
|
445
447
|
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
446
448
|
expect(connection.connect).to be_a(Ably::Util::SafeDeferrable)
|
447
449
|
stop_reactor
|
@@ -1167,6 +1169,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1167
1169
|
host: 'this.host.does.not.exist.com'
|
1168
1170
|
)
|
1169
1171
|
)
|
1172
|
+
allow(client).to receive(:fallback_hosts).and_return([])
|
1170
1173
|
|
1171
1174
|
connection.transition_state_machine! :disconnected
|
1172
1175
|
end
|
@@ -87,8 +87,10 @@ describe Ably::Rest do
|
|
87
87
|
let(:error_response) { '{ "error": { "statusCode": 500, "code": 50000, "message": "Internal error" } }' }
|
88
88
|
|
89
89
|
before do
|
90
|
-
|
91
|
-
|
90
|
+
(client.fallback_hosts.map { |host| "https://#{host}" } + [client.endpoint]).each do |host|
|
91
|
+
stub_request(:get, "#{host}/time")
|
92
|
+
.to_return(:status => 500, :body => error_response, :headers => { 'Content-Type' => 'application/json' })
|
93
|
+
end
|
92
94
|
end
|
93
95
|
|
94
96
|
it 'should raise a ServerError exception' do
|
@@ -98,8 +100,10 @@ describe Ably::Rest do
|
|
98
100
|
|
99
101
|
describe '500 server error without a valid JSON response body', :webmock do
|
100
102
|
before do
|
101
|
-
|
102
|
-
|
103
|
+
(client.fallback_hosts.map { |host| "https://#{host}" } + [client.endpoint]).each do |host|
|
104
|
+
stub_request(:get, "#{host}/time").
|
105
|
+
to_return(:status => 500, :headers => { 'Content-Type' => 'application/json' })
|
106
|
+
end
|
103
107
|
end
|
104
108
|
|
105
109
|
it 'should raise a ServerError exception' do
|
@@ -301,30 +301,44 @@ describe Ably::Rest::Client do
|
|
301
301
|
context 'configured' do
|
302
302
|
let(:client_options) { default_options.merge(key: api_key, environment: 'production') }
|
303
303
|
|
304
|
-
it 'should make connection attempts to
|
304
|
+
it 'should make connection attempts to a.ably-realtime.com, b.ably-realtime.com, c.ably-realtime.com, d.ably-realtime.com, e.ably-realtime.com (#RSC15a)' do
|
305
305
|
hosts = []
|
306
306
|
5.times do
|
307
307
|
hosts << client.fallback_connection.host
|
308
308
|
end
|
309
|
-
expect(hosts).to match_array(%w(
|
309
|
+
expect(hosts).to match_array(%w(a.ably-realtime.com b.ably-realtime.com c.ably-realtime.com d.ably-realtime.com e.ably-realtime.com))
|
310
310
|
end
|
311
311
|
end
|
312
312
|
|
313
313
|
context 'when environment is NOT production (#RSC15b)' do
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
314
|
+
context 'and custom fallback hosts are empty' do
|
315
|
+
let(:client_options) { default_options.merge(environment: 'sandbox', key: api_key, fallback_hosts: []) }
|
316
|
+
let!(:default_host_request_stub) do
|
317
|
+
stub_request(:post, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
318
|
+
raise Faraday::TimeoutError.new('timeout error message')
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'does not retry failed requests with fallback hosts when there is a connection error' do
|
323
|
+
expect { publish_block.call }.to raise_error Ably::Exceptions::ConnectionTimeout
|
318
324
|
end
|
319
325
|
end
|
320
326
|
|
321
|
-
|
322
|
-
|
327
|
+
context 'and no custom fallback hosts are provided' do
|
328
|
+
let(:client_options) { default_options.merge(environment: 'sandbox', key: api_key) }
|
329
|
+
|
330
|
+
it 'should make connection attempts to sandbox-a-fallback.ably-realtime.com, sandbox-b-fallback.ably-realtime.com, sandbox-c-fallback.ably-realtime.com, sandbox-d-fallback.ably-realtime.com, sandbox-e-fallback.ably-realtime.com (#RSC15a)' do
|
331
|
+
hosts = []
|
332
|
+
5.times do
|
333
|
+
hosts << client.fallback_connection.host
|
334
|
+
end
|
335
|
+
expect(hosts).to match_array(%w(a b c d e).map { |id| "sandbox-#{id}-fallback.ably-realtime.com" })
|
336
|
+
end
|
323
337
|
end
|
324
338
|
end
|
325
339
|
|
326
340
|
context 'when environment is production' do
|
327
|
-
let(:custom_hosts) { %w(
|
341
|
+
let(:custom_hosts) { %w(a.ably-realtime.com b.ably-realtime.com) }
|
328
342
|
let(:max_retry_count) { 2 }
|
329
343
|
let(:max_retry_duration) { 0.5 }
|
330
344
|
let(:fallback_block) { proc { raise Faraday::SSLError.new('ssl error message') } }
|
@@ -823,11 +837,12 @@ describe Ably::Rest::Client do
|
|
823
837
|
end
|
824
838
|
|
825
839
|
context 'when environment is not production and server returns a 50x error' do
|
840
|
+
let(:env) { 'custom-env' }
|
841
|
+
let(:default_fallbacks) { %w(a b c d e).map { |id| "#{env}-#{id}-fallback.ably-realtime.com" } }
|
826
842
|
let(:custom_hosts) { %w(A.foo.com B.foo.com) }
|
827
843
|
let(:max_retry_count) { 2 }
|
828
844
|
let(:max_retry_duration) { 0.5 }
|
829
845
|
let(:fallback_block) { proc { raise Faraday::SSLError.new('ssl error message') } }
|
830
|
-
let(:env) { 'custom-env' }
|
831
846
|
let(:production_options) do
|
832
847
|
default_options.merge(
|
833
848
|
environment: env,
|
@@ -851,6 +866,26 @@ describe Ably::Rest::Client do
|
|
851
866
|
stub_request(:post, "https://#{env}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return(&fallback_block)
|
852
867
|
end
|
853
868
|
|
869
|
+
context 'with no fallback hosts provided (#TBC, see https://github.com/ably/wiki/issues/361)' do
|
870
|
+
let(:client_options) {
|
871
|
+
production_options.merge(log_level: :fatal)
|
872
|
+
}
|
873
|
+
|
874
|
+
it 'uses the default fallback hosts for that environment as this is not an authentication failure' do
|
875
|
+
fallbacks_called_count = 0
|
876
|
+
default_fallbacks.each do |host|
|
877
|
+
counting_fallback_proc = proc do
|
878
|
+
fallbacks_called_count += 1
|
879
|
+
fallback_block.call
|
880
|
+
end
|
881
|
+
stub_request(:post, "https://#{host}#{path}").to_return(&counting_fallback_proc)
|
882
|
+
end
|
883
|
+
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
884
|
+
expect(default_host_request_stub).to have_been_requested
|
885
|
+
expect(fallbacks_called_count).to be >= 2
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
854
889
|
context 'with custom fallback hosts provided (#RSC15b, #TO3k6)' do
|
855
890
|
let!(:first_fallback_request_stub) do
|
856
891
|
stub_request(:post, "https://#{custom_hosts[0]}#{path}").to_return(&fallback_block)
|
@@ -1194,9 +1229,9 @@ describe Ably::Rest::Client do
|
|
1194
1229
|
|
1195
1230
|
context 'request_id generation' do
|
1196
1231
|
context 'Timeout error' do
|
1197
|
-
context 'with option add_request_ids: true', :webmock, :prevent_log_stubbing do
|
1232
|
+
context 'with option add_request_ids: true and no fallback hosts', :webmock, :prevent_log_stubbing do
|
1198
1233
|
let(:custom_logger_object) { TestLogger.new }
|
1199
|
-
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, add_request_ids: true) }
|
1234
|
+
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, add_request_ids: true, fallback_hosts: []) }
|
1200
1235
|
|
1201
1236
|
before do
|
1202
1237
|
@request_id = nil
|
@@ -1286,8 +1321,8 @@ describe Ably::Rest::Client do
|
|
1286
1321
|
end
|
1287
1322
|
end
|
1288
1323
|
|
1289
|
-
context 'without request_id' do
|
1290
|
-
let(:client_options) { default_options.merge(key: api_key, http_request_timeout: 0) }
|
1324
|
+
context 'without request_id and no fallback hosts' do
|
1325
|
+
let(:client_options) { default_options.merge(key: api_key, http_request_timeout: 0, fallback_hosts: []) }
|
1291
1326
|
|
1292
1327
|
it 'does not include request_id in ConnectionTimeout error' do
|
1293
1328
|
begin
|
@@ -265,6 +265,137 @@ shared_examples 'a client initializer' do
|
|
265
265
|
end
|
266
266
|
end
|
267
267
|
end
|
268
|
+
|
269
|
+
context 'environment' do
|
270
|
+
context 'when set without custom fallback hosts configured' do
|
271
|
+
let(:environment) { 'foo' }
|
272
|
+
let(:client_options) { default_options.merge(environment: environment) }
|
273
|
+
let(:default_fallbacks) { %w(a b c d e).map { |id| "#{environment}-#{id}-fallback.ably-realtime.com" } }
|
274
|
+
|
275
|
+
it 'sets the environment attribute' do
|
276
|
+
expect(subject.environment).to eql(environment)
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'uses the default fallback hosts (#TBC, see https://github.com/ably/wiki/issues/361)' do
|
280
|
+
expect(subject.fallback_hosts.sort).to eql(default_fallbacks)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context 'when set with custom fallback hosts configured' do
|
285
|
+
let(:environment) { 'foo' }
|
286
|
+
let(:custom_fallbacks) { %w(a b c).map { |id| "#{environment}-#{id}.foo.com" } }
|
287
|
+
let(:client_options) { default_options.merge(environment: environment, fallback_hosts: custom_fallbacks) }
|
288
|
+
|
289
|
+
it 'sets the environment attribute' do
|
290
|
+
expect(subject.environment).to eql(environment)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'uses the custom provided fallback hosts (#RSC15a)' do
|
294
|
+
expect(subject.fallback_hosts.sort).to eql(custom_fallbacks)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'when set with fallback_hosts_use_default' do
|
299
|
+
let(:environment) { 'foo' }
|
300
|
+
let(:custom_fallbacks) { %w(a b c).map { |id| "#{environment}-#{id}.foo.com" } }
|
301
|
+
let(:default_production_fallbacks) { %w(a b c d e).map { |id| "#{id}.ably-realtime.com" } }
|
302
|
+
let(:client_options) { default_options.merge(environment: environment, fallback_hosts_use_default: true) }
|
303
|
+
|
304
|
+
it 'sets the environment attribute' do
|
305
|
+
expect(subject.environment).to eql(environment)
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'uses the production default fallback hosts (#RTN17b)' do
|
309
|
+
expect(subject.fallback_hosts.sort).to eql(default_production_fallbacks)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'rest_host' do
|
315
|
+
context 'when set without custom fallback hosts configured' do
|
316
|
+
let(:custom_rest_host) { 'foo.com' }
|
317
|
+
let(:client_options) { default_options.merge(rest_host: custom_rest_host) }
|
318
|
+
|
319
|
+
it 'sets the custom_host attribute' do
|
320
|
+
expect(subject.custom_host).to eql(custom_rest_host)
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'has no default fallback hosts' do
|
324
|
+
expect(subject.fallback_hosts).to be_empty
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
context 'when set with environment and without custom fallback hosts configured' do
|
329
|
+
let(:environment) { 'foobar' }
|
330
|
+
let(:custom_rest_host) { 'foo.com' }
|
331
|
+
let(:client_options) { default_options.merge(environment: environment, rest_host: custom_rest_host) }
|
332
|
+
|
333
|
+
it 'sets the environment attribute' do
|
334
|
+
expect(subject.environment).to eql(environment)
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'sets the custom_host attribute' do
|
338
|
+
expect(subject.custom_host).to eql(custom_rest_host)
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'has no default fallback hosts' do
|
342
|
+
expect(subject.fallback_hosts).to be_empty
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context 'when set with custom fallback hosts configured' do
|
347
|
+
let(:custom_rest_host) { 'foo.com' }
|
348
|
+
let(:custom_fallbacks) { %w(a b c).map { |id| "#{environment}-#{id}.foo.com" } }
|
349
|
+
let(:client_options) { default_options.merge(rest_host: custom_rest_host, fallback_hosts: custom_fallbacks) }
|
350
|
+
|
351
|
+
it 'sets the custom_host attribute' do
|
352
|
+
expect(subject.custom_host).to eql(custom_rest_host)
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'has no default fallback hosts' do
|
356
|
+
expect(subject.fallback_hosts.sort).to eql(custom_fallbacks)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
context 'realtime_host' do
|
362
|
+
context 'when set without custom fallback hosts configured' do
|
363
|
+
let(:custom_realtime_host) { 'realtime.foo.com' }
|
364
|
+
let(:client_options) { default_options.merge(realtime_host: custom_realtime_host) }
|
365
|
+
|
366
|
+
# These tests are shared between realtime & rest clients
|
367
|
+
# So don't test for the attribute, instead test the options
|
368
|
+
it 'sets the realtime_host option' do
|
369
|
+
expect(subject.options[:realtime_host]).to eql(custom_realtime_host)
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'has no default fallback hosts' do
|
373
|
+
expect(subject.fallback_hosts).to be_empty
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context 'custom port' do
|
379
|
+
context 'when set without custom fallback hosts configured' do
|
380
|
+
let(:custom_port) { 555 }
|
381
|
+
let(:client_options) { default_options.merge(port: custom_port) }
|
382
|
+
|
383
|
+
it 'has no default fallback hosts' do
|
384
|
+
expect(subject.fallback_hosts).to be_empty
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
context 'custom TLS port' do
|
390
|
+
context 'when set without custom fallback hosts configured' do
|
391
|
+
let(:custom_port) { 555 }
|
392
|
+
let(:client_options) { default_options.merge(tls_port: custom_port) }
|
393
|
+
|
394
|
+
it 'has no default fallback hosts' do
|
395
|
+
expect(subject.fallback_hosts).to be_empty
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
268
399
|
end
|
269
400
|
|
270
401
|
context 'delegators' do
|