ably 1.1.4 → 1.1.8
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 +4 -4
- data/.github/workflows/check.yml +15 -1
- data/CHANGELOG.md +109 -0
- data/COPYRIGHT +1 -1
- data/README.md +23 -9
- data/SPEC.md +289 -228
- data/ably.gemspec +14 -9
- data/lib/ably/agent.rb +3 -0
- data/lib/ably/exceptions.rb +6 -0
- data/lib/ably/models/connection_details.rb +8 -0
- data/lib/ably/models/delta_extras.rb +29 -0
- data/lib/ably/models/error_info.rb +6 -2
- data/lib/ably/models/message.rb +25 -0
- data/lib/ably/models/presence_message.rb +14 -0
- data/lib/ably/models/protocol_message.rb +13 -8
- data/lib/ably/modules/ably.rb +11 -1
- data/lib/ably/realtime/channel/channel_manager.rb +2 -2
- data/lib/ably/realtime/channel/channel_state_machine.rb +5 -1
- data/lib/ably/realtime/channel/publisher.rb +6 -0
- data/lib/ably/realtime/channel.rb +2 -0
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
- data/lib/ably/realtime/client.rb +1 -0
- data/lib/ably/realtime/connection/connection_manager.rb +13 -4
- data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
- data/lib/ably/realtime/connection.rb +2 -2
- data/lib/ably/rest/channel.rb +11 -3
- data/lib/ably/rest/client.rb +37 -18
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
- data/lib/ably/version.rb +1 -13
- data/lib/ably.rb +1 -0
- data/spec/acceptance/realtime/auth_spec.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +25 -0
- data/spec/acceptance/realtime/channel_spec.rb +220 -1
- data/spec/acceptance/realtime/connection_failures_spec.rb +85 -13
- data/spec/acceptance/realtime/connection_spec.rb +263 -32
- data/spec/acceptance/realtime/presence_history_spec.rb +3 -1
- data/spec/acceptance/realtime/presence_spec.rb +31 -159
- data/spec/acceptance/rest/base_spec.rb +8 -4
- data/spec/acceptance/rest/channel_spec.rb +84 -9
- data/spec/acceptance/rest/channels_spec.rb +1 -1
- data/spec/acceptance/rest/client_spec.rb +72 -33
- data/spec/shared/client_initializer_behaviour.rb +131 -0
- data/spec/shared/model_behaviour.rb +1 -1
- data/spec/spec_helper.rb +11 -2
- data/spec/support/test_app.rb +1 -1
- data/spec/unit/models/delta_extras_spec.rb +14 -0
- data/spec/unit/models/error_info_spec.rb +17 -1
- data/spec/unit/models/message_spec.rb +83 -0
- data/spec/unit/models/presence_message_spec.rb +49 -0
- data/spec/unit/models/protocol_message_spec.rb +72 -20
- data/spec/unit/realtime/channel_spec.rb +3 -2
- data/spec/unit/realtime/channels_spec.rb +3 -3
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
- data/spec/unit/rest/channel_spec.rb +44 -1
- data/spec/unit/rest/client_spec.rb +47 -0
- metadata +48 -36
@@ -5,11 +5,13 @@ describe Ably::Rest::Channel do
|
|
5
5
|
include Ably::Modules::Conversions
|
6
6
|
|
7
7
|
vary_by_protocol do
|
8
|
-
let(:default_options) { { key: api_key, environment: environment, protocol: protocol} }
|
8
|
+
let(:default_options) { { key: api_key, environment: environment, protocol: protocol, max_frame_size: max_frame_size, max_message_size: max_message_size } }
|
9
9
|
let(:client_options) { default_options }
|
10
10
|
let(:client) do
|
11
11
|
Ably::Rest::Client.new(client_options)
|
12
12
|
end
|
13
|
+
let(:max_message_size) { nil }
|
14
|
+
let(:max_frame_size) { nil }
|
13
15
|
|
14
16
|
describe '#publish' do
|
15
17
|
let(:channel_name) { random_str }
|
@@ -60,6 +62,9 @@ describe Ably::Rest::Channel do
|
|
60
62
|
end
|
61
63
|
|
62
64
|
it 'publishes an array of messages in one HTTP request' do
|
65
|
+
expect(client.max_message_size).to eq(Ably::Rest::Client::MAX_MESSAGE_SIZE)
|
66
|
+
expect(messages.sum(&:size) < Ably::Rest::Client::MAX_MESSAGE_SIZE).to eq(true)
|
67
|
+
|
63
68
|
expect(client).to receive(:post).once.and_call_original
|
64
69
|
expect(channel.publish(messages)).to eql(true)
|
65
70
|
expect(channel.history.items.map(&:name)).to match_array(messages.map { |message| message[:name] })
|
@@ -68,17 +73,78 @@ describe Ably::Rest::Channel do
|
|
68
73
|
end
|
69
74
|
|
70
75
|
context 'with an array of Message objects' do
|
71
|
-
|
72
|
-
|
73
|
-
Ably::
|
76
|
+
context 'when max_message_size and max_frame_size is not set' do
|
77
|
+
before do
|
78
|
+
expect(client.max_message_size).to eq(Ably::Rest::Client::MAX_MESSAGE_SIZE)
|
79
|
+
expect(client.max_frame_size).to eq(Ably::Rest::Client::MAX_FRAME_SIZE)
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'and messages size (130 bytes) is smaller than the max_message_size' do
|
83
|
+
let(:messages) do
|
84
|
+
10.times.map do |index|
|
85
|
+
Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 })
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'publishes an array of messages in one HTTP request' do
|
90
|
+
expect(messages.sum &:size).to eq(130)
|
91
|
+
expect(client).to receive(:post).once.and_call_original
|
92
|
+
expect(channel.publish(messages)).to eql(true)
|
93
|
+
expect(channel.history.items.map(&:name)).to match_array(messages.map(&:name))
|
94
|
+
expect(channel.history.items.map(&:data)).to match_array(messages.map(&:data))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'and messages size (177784 bytes) is bigger than the max_message_size' do
|
99
|
+
let(:messages) do
|
100
|
+
10000.times.map do |index|
|
101
|
+
Ably::Models::Message(name: index.to_s, data: { "index" => index + 1 })
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should not publish and raise Ably::Exceptions::MaxMessageSizeExceeded' do
|
106
|
+
expect(messages.sum &:size).to eq(177784)
|
107
|
+
expect { channel.publish(messages) }.to raise_error(Ably::Exceptions::MaxMessageSizeExceeded)
|
108
|
+
end
|
74
109
|
end
|
75
110
|
end
|
76
111
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
112
|
+
context 'when max_message_size is 655 bytes' do
|
113
|
+
let(:max_message_size) { 655 }
|
114
|
+
|
115
|
+
before do
|
116
|
+
expect(client.max_message_size).to eq(max_message_size)
|
117
|
+
expect(client.max_frame_size).to eq(Ably::Rest::Client::MAX_FRAME_SIZE)
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'and messages size (130 bytes) is smaller than the max_message_size' do
|
121
|
+
let(:messages) do
|
122
|
+
10.times.map do |index|
|
123
|
+
Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 })
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'publishes an array of messages in one HTTP request' do
|
128
|
+
expect(messages.sum &:size).to eq(130)
|
129
|
+
expect(client).to receive(:post).once.and_call_original
|
130
|
+
expect(channel.publish(messages)).to eql(true)
|
131
|
+
expect(channel.history.items.map(&:name)).to match_array(messages.map(&:name))
|
132
|
+
expect(channel.history.items.map(&:data)).to match_array(messages.map(&:data))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'and messages size (177784 bytes) is bigger than the max_message_size' do
|
137
|
+
let(:messages) do
|
138
|
+
10000.times.map do |index|
|
139
|
+
Ably::Models::Message(name: index.to_s, data: { "index" => index + 1 })
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should not publish and raise Ably::Exceptions::MaxMessageSizeExceeded' do
|
144
|
+
expect(messages.sum &:size).to eq(177784)
|
145
|
+
expect { channel.publish(messages) }.to raise_error(Ably::Exceptions::MaxMessageSizeExceeded)
|
146
|
+
end
|
147
|
+
end
|
82
148
|
end
|
83
149
|
end
|
84
150
|
|
@@ -350,6 +416,15 @@ describe Ably::Rest::Channel do
|
|
350
416
|
end
|
351
417
|
end
|
352
418
|
end
|
419
|
+
|
420
|
+
context 'message size is exceeded (#TO3l8)' do
|
421
|
+
let(:data) { 101.times.map { { data: 'x' * 655 } } }
|
422
|
+
|
423
|
+
it 'should raise Ably::Exceptions::MaxMessageSizeExceeded exception' do
|
424
|
+
expect { channel.publish([ data: data ]) }.to \
|
425
|
+
raise_error(Ably::Exceptions::MaxMessageSizeExceeded)
|
426
|
+
end
|
427
|
+
end
|
353
428
|
end
|
354
429
|
|
355
430
|
describe '#history' do
|
@@ -36,7 +36,7 @@ describe Ably::Rest::Channels do
|
|
36
36
|
let(:new_channel_options) { { encrypted: true } }
|
37
37
|
let(:original_channel) { client.channels.get(channel_name, options) }
|
38
38
|
|
39
|
-
it 'overrides the existing channel options and returns the channel object' do
|
39
|
+
it 'overrides the existing channel options and returns the channel object (RSN3c)' do
|
40
40
|
expect(original_channel.options).to_not include(:encrypted)
|
41
41
|
new_channel = client.channels.get(channel_name, new_channel_options)
|
42
42
|
expect(new_channel).to be_a(Ably::Rest::Channel)
|
@@ -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)
|
@@ -1046,29 +1081,15 @@ describe Ably::Rest::Client do
|
|
1046
1081
|
end
|
1047
1082
|
|
1048
1083
|
context 'version headers', :webmock do
|
1049
|
-
[nil, '
|
1050
|
-
context "with
|
1051
|
-
|
1052
|
-
before do
|
1053
|
-
Ably.lib_variant = variant
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
after do
|
1057
|
-
Ably.lib_variant = nil
|
1058
|
-
end
|
1059
|
-
end
|
1084
|
+
[nil, 'ably-ruby/1.1.1 ruby/1.9.3'].each do |agent|
|
1085
|
+
context "with #{agent ? "custom #{agent}" : 'default'} agent" do
|
1086
|
+
let(:client_options) { default_options.merge(key: api_key, agent: agent) }
|
1060
1087
|
|
1061
|
-
let(:client_options) { default_options.merge(key: api_key) }
|
1062
1088
|
let!(:publish_message_stub) do
|
1063
|
-
lib = ['ruby']
|
1064
|
-
lib << variant if variant
|
1065
|
-
lib << Ably::VERSION
|
1066
|
-
|
1067
|
-
|
1068
1089
|
stub_request(:post, "#{client.endpoint}/channels/foo/publish").
|
1069
1090
|
with(headers: {
|
1070
1091
|
'X-Ably-Version' => Ably::PROTOCOL_VERSION,
|
1071
|
-
'
|
1092
|
+
'Ably-Agent' => agent || Ably::AGENT
|
1072
1093
|
}).
|
1073
1094
|
to_return(status: 201, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
1074
1095
|
end
|
@@ -1082,7 +1103,7 @@ describe Ably::Rest::Client do
|
|
1082
1103
|
end
|
1083
1104
|
end
|
1084
1105
|
|
1085
|
-
context '#request (#RSC19
|
1106
|
+
context '#request (#RSC19*, #TO3l9)' do
|
1086
1107
|
let(:client_options) { default_options.merge(key: api_key) }
|
1087
1108
|
let(:device_id) { random_str }
|
1088
1109
|
let(:endpoint) { client.endpoint }
|
@@ -1137,6 +1158,12 @@ describe Ably::Rest::Client do
|
|
1137
1158
|
|
1138
1159
|
expect(response).to be_success
|
1139
1160
|
end
|
1161
|
+
|
1162
|
+
it 'raises an exception once body size in bytes exceeded' do
|
1163
|
+
expect {
|
1164
|
+
client.request(:post, endpoint, {}, { content: 'x' * Ably::Rest::Client::MAX_FRAME_SIZE })
|
1165
|
+
}.to raise_error(Ably::Exceptions::MaxFrameSizeExceeded)
|
1166
|
+
end
|
1140
1167
|
end
|
1141
1168
|
|
1142
1169
|
context 'delete', :webmock do
|
@@ -1166,6 +1193,12 @@ describe Ably::Rest::Client do
|
|
1166
1193
|
|
1167
1194
|
expect(response).to be_success
|
1168
1195
|
end
|
1196
|
+
|
1197
|
+
it 'raises an exception once body size in bytes exceeded' do
|
1198
|
+
expect {
|
1199
|
+
client.request(:patch, endpoint, {}, { content: 'x' * Ably::Rest::Client::MAX_FRAME_SIZE })
|
1200
|
+
}.to raise_error(Ably::Exceptions::MaxFrameSizeExceeded)
|
1201
|
+
end
|
1169
1202
|
end
|
1170
1203
|
|
1171
1204
|
context 'put', :webmock do
|
@@ -1189,14 +1222,20 @@ describe Ably::Rest::Client do
|
|
1189
1222
|
|
1190
1223
|
expect(response).to be_success
|
1191
1224
|
end
|
1225
|
+
|
1226
|
+
it 'raises an exception once body size in bytes exceeded' do
|
1227
|
+
expect {
|
1228
|
+
client.request(:put, endpoint, {}, { content: 'x' * Ably::Rest::Client::MAX_FRAME_SIZE })
|
1229
|
+
}.to raise_error(Ably::Exceptions::MaxFrameSizeExceeded)
|
1230
|
+
end
|
1192
1231
|
end
|
1193
1232
|
end
|
1194
1233
|
|
1195
1234
|
context 'request_id generation' do
|
1196
1235
|
context 'Timeout error' do
|
1197
|
-
context 'with option add_request_ids: true', :webmock, :prevent_log_stubbing do
|
1236
|
+
context 'with option add_request_ids: true and no fallback hosts', :webmock, :prevent_log_stubbing do
|
1198
1237
|
let(:custom_logger_object) { TestLogger.new }
|
1199
|
-
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, add_request_ids: true) }
|
1238
|
+
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, add_request_ids: true, fallback_hosts: []) }
|
1200
1239
|
|
1201
1240
|
before do
|
1202
1241
|
@request_id = nil
|
@@ -1286,8 +1325,8 @@ describe Ably::Rest::Client do
|
|
1286
1325
|
end
|
1287
1326
|
end
|
1288
1327
|
|
1289
|
-
context 'without request_id' do
|
1290
|
-
let(:client_options) { default_options.merge(key: api_key, http_request_timeout: 0) }
|
1328
|
+
context 'without request_id and no fallback hosts' do
|
1329
|
+
let(:client_options) { default_options.merge(key: api_key, http_request_timeout: 0, fallback_hosts: []) }
|
1291
1330
|
|
1292
1331
|
it 'does not include request_id in ConnectionTimeout error' do
|
1293
1332
|
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
|
@@ -19,7 +19,7 @@ shared_examples 'a model' do |shared_options = {}|
|
|
19
19
|
end
|
20
20
|
|
21
21
|
context '#attributes', :api_private do
|
22
|
-
let(:model_options) { { action: 5 } }
|
22
|
+
let(:model_options) { { action: 5, max_message_size: 65536, max_frame_size: 524288 } }
|
23
23
|
|
24
24
|
it 'provides access to #attributes' do
|
25
25
|
expect(model.attributes).to eq(model_options)
|
data/spec/spec_helper.rb
CHANGED
@@ -5,8 +5,17 @@ def console(message)
|
|
5
5
|
end
|
6
6
|
|
7
7
|
unless RUBY_VERSION.match(/^1\./)
|
8
|
-
require '
|
9
|
-
|
8
|
+
require 'simplecov'
|
9
|
+
|
10
|
+
SimpleCov.start do
|
11
|
+
require 'simplecov-lcov'
|
12
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
13
|
+
c.report_with_single_file = true
|
14
|
+
c.single_report_path = 'coverage/lcov.info'
|
15
|
+
end
|
16
|
+
formatter SimpleCov::Formatter::LcovFormatter
|
17
|
+
add_filter %w[vendor spec]
|
18
|
+
end
|
10
19
|
end
|
11
20
|
|
12
21
|
require 'webmock/rspec'
|
data/spec/support/test_app.rb
CHANGED
@@ -59,7 +59,7 @@ class TestApp
|
|
59
59
|
|
60
60
|
url = "#{sandbox_client.endpoint}/apps/#{app_id}"
|
61
61
|
|
62
|
-
basic_auth = Base64.
|
62
|
+
basic_auth = Base64.urlsafe_encode64(api_key).chomp
|
63
63
|
headers = { "Authorization" => "Basic #{basic_auth}" }
|
64
64
|
|
65
65
|
Faraday.delete(url, nil, headers)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Ably::Models::DeltaExtras do
|
5
|
+
subject { described_class.new({ format: 'vcdiff', from: '1234-4567-8910-1001-1111'}) }
|
6
|
+
|
7
|
+
it 'should have `from` attribute' do
|
8
|
+
expect(subject.from).to eq('1234-4567-8910-1001-1111')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have `format` attribute' do
|
12
|
+
expect(subject.format).to eq('vcdiff')
|
13
|
+
end
|
14
|
+
end
|
@@ -5,7 +5,7 @@ describe Ably::Models::ErrorInfo do
|
|
5
5
|
subject { Ably::Models::ErrorInfo }
|
6
6
|
|
7
7
|
context '#TI1, #TI4' do
|
8
|
-
it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message) do
|
8
|
+
it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message request_id cause) do
|
9
9
|
let(:model_args) { [] }
|
10
10
|
end
|
11
11
|
end
|
@@ -18,6 +18,22 @@ describe Ably::Models::ErrorInfo do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
context '#request_id #RSC7c' do
|
22
|
+
subject { Ably::Models::ErrorInfo.new('request_id' => '123-456-789-001') }
|
23
|
+
|
24
|
+
it 'should return request ID' do
|
25
|
+
expect(subject.request_id).to eql('123-456-789-001')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#cause #TI1' do
|
30
|
+
subject { Ably::Models::ErrorInfo.new('cause' => Ably::Models::ErrorInfo.new({})) }
|
31
|
+
|
32
|
+
it 'should return cause attribute' do
|
33
|
+
expect(subject.cause).to be_kind_of(Ably::Models::ErrorInfo)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
21
37
|
context 'log entries container help link #TI5' do
|
22
38
|
context 'without an error code' do
|
23
39
|
subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
|
@@ -211,6 +211,65 @@ describe Ably::Models::Message do
|
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
214
|
+
describe '#size' do
|
215
|
+
let(:model) { subject.new({ name: name, data: data, client_id: client_id, extras: extras }, protocol_message: protocol_message) }
|
216
|
+
|
217
|
+
context 'String (#TO3l8a)' do
|
218
|
+
let(:data) { 'example string data' }
|
219
|
+
let(:client_id) { '1' }
|
220
|
+
let(:name) { 'My Name' }
|
221
|
+
let(:extras) { 'extras' }
|
222
|
+
|
223
|
+
it 'should return 33 bytes' do
|
224
|
+
expect(model.size).to eq(33)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
context 'Object (#TO3l8b)' do
|
229
|
+
let(:data) { Object.new }
|
230
|
+
let(:client_id) { String('10') }
|
231
|
+
let(:name) { 'John' }
|
232
|
+
let(:extras) { Hash.new }
|
233
|
+
|
234
|
+
it 'should return 38 bytes' do
|
235
|
+
expect(model.size).to eq(38)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'Array (#TO3l8b)' do
|
240
|
+
let(:data) { [1, 'two', :three] }
|
241
|
+
let(:client_id) { '2' }
|
242
|
+
let(:name) { 'Kate' }
|
243
|
+
let(:extras) { [] }
|
244
|
+
|
245
|
+
it 'should return 24 bytes' do
|
246
|
+
expect(model.size).to eq(24)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'extras (#TO3l8d)' do
|
251
|
+
let(:data) { { example: 'value', score: 1, hash: { test: true } } }
|
252
|
+
let(:client_id) { '3' }
|
253
|
+
let(:name) { 'John' }
|
254
|
+
let(:extras) { {} }
|
255
|
+
|
256
|
+
it 'should return 57 bytes' do
|
257
|
+
expect(model.size).to eq(57)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'nil (#TO3l8e)' do
|
262
|
+
let(:data) { nil }
|
263
|
+
let(:client_id) { '' }
|
264
|
+
let(:name) { '' }
|
265
|
+
let(:extras) { nil}
|
266
|
+
|
267
|
+
it 'should return 19 bytes' do
|
268
|
+
expect(model.size).to eq(0)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
214
273
|
context 'from REST request with embedded fields', :api_private do
|
215
274
|
let(:id) { random_str }
|
216
275
|
let(:protocol_message_id) { random_str }
|
@@ -547,4 +606,28 @@ describe Ably::Models::Message do
|
|
547
606
|
end
|
548
607
|
end
|
549
608
|
end
|
609
|
+
|
610
|
+
context '#delta_extras (TM2i)' do
|
611
|
+
let(:delta_extras) { message.delta_extras }
|
612
|
+
|
613
|
+
context 'when delta' do
|
614
|
+
let(:message) { subject.new({ extras: { delta: { from: '1234-1234-5678-9009', format: 'vcdiff' } } }) }
|
615
|
+
|
616
|
+
it 'should return vcdiff format' do
|
617
|
+
expect(delta_extras.format).to eq('vcdiff')
|
618
|
+
end
|
619
|
+
|
620
|
+
it 'should return 1234-1234-5678-9009 message id' do
|
621
|
+
expect(delta_extras.from).to eq('1234-1234-5678-9009')
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
context 'when no delta' do
|
626
|
+
let(:message) { subject.new({ extras: {} }) }
|
627
|
+
|
628
|
+
it 'should return nil' do
|
629
|
+
expect(delta_extras).to eq(nil)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
550
633
|
end
|