ably 1.1.1 → 1.1.5
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 +27 -0
- data/CHANGELOG.md +60 -2
- data/COPYRIGHT +1 -0
- data/LICENSE +172 -11
- data/MAINTAINERS.md +1 -0
- data/README.md +2 -14
- data/SPEC.md +1020 -922
- data/ably.gemspec +5 -5
- data/lib/ably/auth.rb +12 -2
- data/lib/ably/exceptions.rb +2 -2
- data/lib/ably/logger.rb +7 -1
- data/lib/ably/modules/ably.rb +11 -1
- data/lib/ably/modules/state_machine.rb +1 -1
- data/lib/ably/realtime/channel.rb +7 -11
- data/lib/ably/realtime/channel/channel_manager.rb +2 -2
- data/lib/ably/realtime/channel/channel_properties.rb +24 -0
- data/lib/ably/realtime/client.rb +9 -0
- data/lib/ably/realtime/connection.rb +7 -4
- data/lib/ably/realtime/connection/connection_manager.rb +19 -1
- data/lib/ably/realtime/connection/websocket_transport.rb +67 -1
- data/lib/ably/realtime/presence.rb +0 -14
- data/lib/ably/rest/channel.rb +25 -17
- data/lib/ably/rest/client.rb +35 -17
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/auth_spec.rb +5 -4
- data/spec/acceptance/realtime/channel_spec.rb +21 -8
- data/spec/acceptance/realtime/client_spec.rb +80 -20
- data/spec/acceptance/realtime/connection_failures_spec.rb +90 -9
- data/spec/acceptance/realtime/connection_spec.rb +47 -19
- data/spec/acceptance/realtime/message_spec.rb +2 -4
- data/spec/acceptance/realtime/presence_history_spec.rb +0 -58
- data/spec/acceptance/realtime/presence_spec.rb +54 -0
- data/spec/acceptance/realtime/push_admin_spec.rb +43 -21
- data/spec/acceptance/rest/auth_spec.rb +6 -75
- data/spec/acceptance/rest/base_spec.rb +8 -4
- data/spec/acceptance/rest/channel_spec.rb +42 -4
- data/spec/acceptance/rest/client_spec.rb +121 -26
- data/spec/acceptance/rest/message_spec.rb +1 -2
- data/spec/acceptance/rest/push_admin_spec.rb +67 -27
- data/spec/shared/client_initializer_behaviour.rb +131 -8
- data/spec/spec_helper.rb +1 -0
- data/spec/support/debug_failure_helper.rb +9 -5
- data/spec/support/serialization_helper.rb +21 -0
- data/spec/support/test_app.rb +2 -2
- data/spec/unit/modules/enum_spec.rb +1 -1
- data/spec/unit/realtime/client_spec.rb +20 -7
- data/spec/unit/realtime/connection_spec.rb +1 -1
- metadata +22 -17
- data/.travis.yml +0 -19
@@ -41,22 +41,10 @@ describe Ably::Auth do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def request_body_includes(request, protocol, key, val)
|
44
|
-
body =
|
45
|
-
MessagePack.unpack(request.body)
|
46
|
-
else
|
47
|
-
JSON.parse(request.body)
|
48
|
-
end
|
44
|
+
body = deserialize_body(request.body, protocol)
|
49
45
|
body[convert_to_mixed_case(key)].to_s == val.to_s
|
50
46
|
end
|
51
47
|
|
52
|
-
def serialize(object, protocol)
|
53
|
-
if protocol == :msgpack
|
54
|
-
MessagePack.pack(object)
|
55
|
-
else
|
56
|
-
JSON.dump(object)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
48
|
it 'has immutable options' do
|
61
49
|
expect { auth.options['key_name'] = 'new_name' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
|
62
50
|
end
|
@@ -74,7 +62,7 @@ describe Ably::Auth do
|
|
74
62
|
|
75
63
|
it 'creates a TokenRequest automatically and sends it to Ably to obtain a token', webmock: true do
|
76
64
|
token_request_stub = stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").
|
77
|
-
to_return(status: 201, body:
|
65
|
+
to_return(status: 201, body: serialize_body({}, protocol), headers: { 'Content-Type' => content_type })
|
78
66
|
expect(auth).to receive(:create_token_request).and_call_original
|
79
67
|
auth.request_token
|
80
68
|
|
@@ -107,7 +95,7 @@ describe Ably::Auth do
|
|
107
95
|
request_body_includes(request, protocol, token_param, coerce_if_time_value(token_param, random, multiply: 1000))
|
108
96
|
end.to_return(
|
109
97
|
:status => 201,
|
110
|
-
:body =>
|
98
|
+
:body => serialize_body(token_response, protocol),
|
111
99
|
:headers => { 'Content-Type' => content_type }
|
112
100
|
)
|
113
101
|
end
|
@@ -138,7 +126,7 @@ describe Ably::Auth do
|
|
138
126
|
request_body_includes(request, protocol, 'mac', mac)
|
139
127
|
end.to_return(
|
140
128
|
:status => 201,
|
141
|
-
:body =>
|
129
|
+
:body => serialize_body(token_response, protocol),
|
142
130
|
:headers => { 'Content-Type' => content_type })
|
143
131
|
end
|
144
132
|
|
@@ -168,7 +156,7 @@ describe Ably::Auth do
|
|
168
156
|
request_body_includes(request, protocol, 'mac', mac)
|
169
157
|
end.to_return(
|
170
158
|
:status => 201,
|
171
|
-
:body =>
|
159
|
+
:body => serialize_body(token_response, protocol),
|
172
160
|
:headers => { 'Content-Type' => content_type })
|
173
161
|
end
|
174
162
|
|
@@ -310,7 +298,7 @@ describe Ably::Auth do
|
|
310
298
|
request_body_includes(request, protocol, 'key_name', key_name)
|
311
299
|
end.to_return(
|
312
300
|
:status => 201,
|
313
|
-
:body =>
|
301
|
+
:body => serialize_body(token_response, protocol),
|
314
302
|
:headers => { 'Content-Type' => content_type }
|
315
303
|
)
|
316
304
|
end
|
@@ -1129,63 +1117,6 @@ describe Ably::Auth do
|
|
1129
1117
|
end
|
1130
1118
|
end
|
1131
1119
|
|
1132
|
-
context 'when implicit as a result of using :client_id' do
|
1133
|
-
let(:client_id) { '999' }
|
1134
|
-
let(:client) do
|
1135
|
-
Ably::Rest::Client.new(key: api_key, client_id: client_id, environment: environment, protocol: protocol)
|
1136
|
-
end
|
1137
|
-
let(:token) { 'unique-token' }
|
1138
|
-
let(:token_response) do
|
1139
|
-
{
|
1140
|
-
token: token
|
1141
|
-
}.to_json
|
1142
|
-
end
|
1143
|
-
|
1144
|
-
context 'and requests to the Ably server are mocked', :webmock do
|
1145
|
-
let!(:request_token_stub) do
|
1146
|
-
stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").
|
1147
|
-
to_return(:status => 201, :body => token_response, :headers => { 'Content-Type' => 'application/json' })
|
1148
|
-
end
|
1149
|
-
let!(:publish_message_stub) do
|
1150
|
-
stub_request(:post, "#{client.endpoint}/channels/foo/publish").
|
1151
|
-
with(headers: { 'Authorization' => "Bearer #{encode64(token)}" }).
|
1152
|
-
to_return(status: 201, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
1153
|
-
end
|
1154
|
-
|
1155
|
-
it 'will send a token request to the server' do
|
1156
|
-
client.channel('foo').publish('event', 'data')
|
1157
|
-
expect(request_token_stub).to have_been_requested
|
1158
|
-
end
|
1159
|
-
end
|
1160
|
-
|
1161
|
-
describe 'a token is created' do
|
1162
|
-
let(:token) { client.auth.current_token_details }
|
1163
|
-
|
1164
|
-
it 'before a request is made' do
|
1165
|
-
expect(token).to be_nil
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
it 'when a message is published' do
|
1169
|
-
expect(client.channel('foo').publish('event', 'data')).to be_truthy
|
1170
|
-
end
|
1171
|
-
|
1172
|
-
it 'with capability and TTL defaults (#TK2a, #TK2b)' do
|
1173
|
-
client.channel('foo').publish('event', 'data')
|
1174
|
-
|
1175
|
-
expect(token).to be_a(Ably::Models::TokenDetails)
|
1176
|
-
capability_with_str_key = { "*" => ["*"] } # Ably default is all capabilities
|
1177
|
-
capability = Hash[capability_with_str_key.keys.map(&:to_s).zip(capability_with_str_key.values)]
|
1178
|
-
expect(token.capability).to eq(capability)
|
1179
|
-
expect(token.expires.to_i).to be_within(2).of(Time.now.to_i + 60 * 60) # Ably default is 1hr
|
1180
|
-
expect(token.client_id).to eq(client_id)
|
1181
|
-
end
|
1182
|
-
|
1183
|
-
specify '#client_id contains the client_id' do
|
1184
|
-
expect(client.auth.client_id).to eql(client_id)
|
1185
|
-
end
|
1186
|
-
end
|
1187
|
-
end
|
1188
|
-
|
1189
1120
|
context 'when token expires' do
|
1190
1121
|
before do
|
1191
1122
|
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0 # allow token to be used even if about to expire
|
@@ -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
|
@@ -40,7 +40,7 @@ describe Ably::Rest::Channel do
|
|
40
40
|
|
41
41
|
it 'publishes the message without a client_id' do
|
42
42
|
expect(client).to receive(:post).
|
43
|
-
with("/channels/#{channel_name}/publish", hash_excluding(client_id: client_id)).
|
43
|
+
with("/channels/#{channel_name}/publish", hash_excluding(client_id: client_id), {}).
|
44
44
|
and_return(double('response', status: 201))
|
45
45
|
|
46
46
|
expect(channel.publish(name, data)).to eql(true)
|
@@ -82,6 +82,44 @@ describe Ably::Rest::Channel do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
context 'with a Message object' do
|
86
|
+
let(:name) { random_str }
|
87
|
+
|
88
|
+
let(:message) do
|
89
|
+
Ably::Models::Message(name: name, data: data)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'publishes the message' do
|
93
|
+
expect(client).to receive(:post).once.and_call_original
|
94
|
+
expect(channel.publish(message)).to eql(true)
|
95
|
+
expect(channel.history.items.first.name).to eql(name)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'with a Message object and query params' do
|
100
|
+
let(:message) do
|
101
|
+
Ably::Models::Message(name: name, data: data)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should fail to publish the message (RSL1l1)' do
|
105
|
+
expect(client).to receive(:post).once.and_call_original
|
106
|
+
expect { channel.publish(message, { _forceNack: 'true' }) }.to raise_error(Ably::Exceptions::InvalidRequest, /40099/)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with Messages and query params' do
|
111
|
+
let(:messages) do
|
112
|
+
10.times.map do |index|
|
113
|
+
{ name: index.to_s, data: { "index" => index + 10 } }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should fail to publish the message (RSL1l1)' do
|
118
|
+
expect(client).to receive(:post).once.and_call_original
|
119
|
+
expect { channel.publish(messages, { _forceNack: 'true' }) }.to raise_error(Ably::Exceptions::InvalidRequest, /40099/)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
85
123
|
context 'without adequate permissions on the channel' do
|
86
124
|
let(:capability) { { onlyChannel: ['subscribe'] } }
|
87
125
|
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { capability: capability }) }
|
@@ -96,7 +134,7 @@ describe Ably::Rest::Channel do
|
|
96
134
|
let(:data) { random_str }
|
97
135
|
|
98
136
|
it 'publishes the message without a name attribute in the payload' do
|
99
|
-
expect(client).to receive(:post).with(anything, { "data" => data }).once.and_call_original
|
137
|
+
expect(client).to receive(:post).with(anything, { "data" => data }, {}).once.and_call_original
|
100
138
|
expect(channel.publish(nil, data)).to eql(true)
|
101
139
|
expect(channel.history.items.first.name).to be_nil
|
102
140
|
expect(channel.history.items.first.data).to eql(data)
|
@@ -107,7 +145,7 @@ describe Ably::Rest::Channel do
|
|
107
145
|
let(:name) { random_str }
|
108
146
|
|
109
147
|
it 'publishes the message without a data attribute in the payload' do
|
110
|
-
expect(client).to receive(:post).with(anything, { "name" => name }).once.and_call_original
|
148
|
+
expect(client).to receive(:post).with(anything, { "name" => name }, {}).once.and_call_original
|
111
149
|
expect(channel.publish(name)).to eql(true)
|
112
150
|
expect(channel.history.items.first.name).to eql(name)
|
113
151
|
expect(channel.history.items.first.data).to be_nil
|
@@ -118,7 +156,7 @@ describe Ably::Rest::Channel do
|
|
118
156
|
let(:name) { random_str }
|
119
157
|
|
120
158
|
it 'publishes the message without any attributes in the payload' do
|
121
|
-
expect(client).to receive(:post).with(anything, {}).once.and_call_original
|
159
|
+
expect(client).to receive(:post).with(anything, {}, {}).once.and_call_original
|
122
160
|
expect(channel.publish(nil)).to eql(true)
|
123
161
|
expect(channel.history.items.first.name).to be_nil
|
124
162
|
expect(channel.history.items.first.data).to be_nil
|
@@ -12,7 +12,7 @@ describe Ably::Rest::Client do
|
|
12
12
|
http_defaults = Ably::Rest::Client::HTTP_DEFAULTS
|
13
13
|
|
14
14
|
def encode64(text)
|
15
|
-
Base64.
|
15
|
+
Base64.urlsafe_encode64(text)
|
16
16
|
end
|
17
17
|
|
18
18
|
context '#initialize' do
|
@@ -56,14 +56,6 @@ describe Ably::Rest::Client do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
context 'with a :client_id configured' do
|
60
|
-
let(:client) { Ably::Rest::Client.new(client_options.merge(key: api_key, client_id: random_str)) }
|
61
|
-
|
62
|
-
it 'uses token authentication' do
|
63
|
-
expect(client.auth).to be_using_token_auth
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
59
|
context 'with a non string :client_id' do
|
68
60
|
let(:client) { Ably::Rest::Client.new(client_options.merge(key: api_key, client_id: 1)) }
|
69
61
|
|
@@ -144,11 +136,12 @@ describe Ably::Rest::Client do
|
|
144
136
|
let(:history_querystring) { history_params.map { |k, v| "#{k}=#{v}" }.join("&") }
|
145
137
|
|
146
138
|
context 'with basic auth', webmock: true do
|
147
|
-
let(:client_options) { default_options.merge(key: api_key) }
|
139
|
+
let(:client_options) { default_options.merge(key: api_key, client_id: client_id) }
|
148
140
|
|
149
141
|
let!(:get_message_history_stub) do
|
150
|
-
stub_request(:get, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}/channels/#{channel_name}/messages?#{history_querystring}")
|
151
|
-
|
142
|
+
stub_request(:get, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}/channels/#{channel_name}/messages?#{history_querystring}")
|
143
|
+
.with(headers: { 'X-Ably-ClientId' => encode64(client_id) })
|
144
|
+
.to_return(body: [], headers: { 'Content-Type' => 'application/json' })
|
152
145
|
end
|
153
146
|
|
154
147
|
it 'sends the API key in authentication part of the secure URL (the Authorization: Basic header is not used with the Faraday HTTP library by default)' do
|
@@ -308,30 +301,44 @@ describe Ably::Rest::Client do
|
|
308
301
|
context 'configured' do
|
309
302
|
let(:client_options) { default_options.merge(key: api_key, environment: 'production') }
|
310
303
|
|
311
|
-
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
|
312
305
|
hosts = []
|
313
306
|
5.times do
|
314
307
|
hosts << client.fallback_connection.host
|
315
308
|
end
|
316
|
-
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))
|
317
310
|
end
|
318
311
|
end
|
319
312
|
|
320
313
|
context 'when environment is NOT production (#RSC15b)' do
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
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
|
325
324
|
end
|
326
325
|
end
|
327
326
|
|
328
|
-
|
329
|
-
|
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
|
330
337
|
end
|
331
338
|
end
|
332
339
|
|
333
340
|
context 'when environment is production' do
|
334
|
-
let(:custom_hosts) { %w(
|
341
|
+
let(:custom_hosts) { %w(a.ably-realtime.com b.ably-realtime.com) }
|
335
342
|
let(:max_retry_count) { 2 }
|
336
343
|
let(:max_retry_duration) { 0.5 }
|
337
344
|
let(:fallback_block) { proc { raise Faraday::SSLError.new('ssl error message') } }
|
@@ -830,11 +837,12 @@ describe Ably::Rest::Client do
|
|
830
837
|
end
|
831
838
|
|
832
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" } }
|
833
842
|
let(:custom_hosts) { %w(A.foo.com B.foo.com) }
|
834
843
|
let(:max_retry_count) { 2 }
|
835
844
|
let(:max_retry_duration) { 0.5 }
|
836
845
|
let(:fallback_block) { proc { raise Faraday::SSLError.new('ssl error message') } }
|
837
|
-
let(:env) { 'custom-env' }
|
838
846
|
let(:production_options) do
|
839
847
|
default_options.merge(
|
840
848
|
environment: env,
|
@@ -858,6 +866,26 @@ describe Ably::Rest::Client do
|
|
858
866
|
stub_request(:post, "https://#{env}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return(&fallback_block)
|
859
867
|
end
|
860
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
|
+
|
861
889
|
context 'with custom fallback hosts provided (#RSC15b, #TO3k6)' do
|
862
890
|
let!(:first_fallback_request_stub) do
|
863
891
|
stub_request(:post, "https://#{custom_hosts[0]}#{path}").to_return(&fallback_block)
|
@@ -1091,6 +1119,8 @@ describe Ably::Rest::Client do
|
|
1091
1119
|
|
1092
1120
|
context '#request (#RSC19*)' do
|
1093
1121
|
let(:client_options) { default_options.merge(key: api_key) }
|
1122
|
+
let(:device_id) { random_str }
|
1123
|
+
let(:endpoint) { client.endpoint }
|
1094
1124
|
|
1095
1125
|
context 'get' do
|
1096
1126
|
it 'returns an HttpPaginatedResponse object' do
|
@@ -1130,13 +1160,78 @@ describe Ably::Rest::Client do
|
|
1130
1160
|
end
|
1131
1161
|
end
|
1132
1162
|
end
|
1163
|
+
|
1164
|
+
context 'post', :webmock do
|
1165
|
+
before do
|
1166
|
+
stub_request(:delete, "#{endpoint}/push/deviceRegistrations/#{device_id}/resetUpdateToken").
|
1167
|
+
to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
it 'supports post' do
|
1171
|
+
response = client.request(:delete, "push/deviceRegistrations/#{device_id}/resetUpdateToken")
|
1172
|
+
|
1173
|
+
expect(response).to be_success
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
context 'delete', :webmock do
|
1178
|
+
before do
|
1179
|
+
stub_request(:delete, "#{endpoint}/push/channelSubscriptions?deviceId=#{device_id}").
|
1180
|
+
to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
it 'supports delete' do
|
1184
|
+
response = client.request(:delete, "/push/channelSubscriptions", { deviceId: device_id})
|
1185
|
+
|
1186
|
+
expect(response).to be_success
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
context 'patch', :webmock do
|
1191
|
+
let(:body_params) { { 'metadata' => { 'key' => 'value' } } }
|
1192
|
+
|
1193
|
+
before do
|
1194
|
+
stub_request(:patch, "#{endpoint}/push/deviceRegistrations/#{device_id}")
|
1195
|
+
.with(body: serialize_body(body_params, protocol))
|
1196
|
+
.to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
it 'supports patch' do
|
1200
|
+
response = client.request(:patch, "/push/deviceRegistrations/#{device_id}", {}, body_params)
|
1201
|
+
|
1202
|
+
expect(response).to be_success
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
context 'put', :webmock do
|
1207
|
+
let(:body_params) do
|
1208
|
+
{
|
1209
|
+
'id' => random_str,
|
1210
|
+
'platform' => 'ios',
|
1211
|
+
'formFactor' => 'phone',
|
1212
|
+
'metadata' => { 'key' => 'value' }
|
1213
|
+
}
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
before do
|
1217
|
+
stub_request(:put, "#{endpoint}/push/deviceRegistrations/#{device_id}")
|
1218
|
+
.with(body: serialize_body(body_params, protocol))
|
1219
|
+
.to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
it 'supports put' do
|
1223
|
+
response = client.request(:put, "/push/deviceRegistrations/#{device_id}", {}, body_params)
|
1224
|
+
|
1225
|
+
expect(response).to be_success
|
1226
|
+
end
|
1227
|
+
end
|
1133
1228
|
end
|
1134
1229
|
|
1135
1230
|
context 'request_id generation' do
|
1136
1231
|
context 'Timeout error' do
|
1137
|
-
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
|
1138
1233
|
let(:custom_logger_object) { TestLogger.new }
|
1139
|
-
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: []) }
|
1140
1235
|
|
1141
1236
|
before do
|
1142
1237
|
@request_id = nil
|
@@ -1226,8 +1321,8 @@ describe Ably::Rest::Client do
|
|
1226
1321
|
end
|
1227
1322
|
end
|
1228
1323
|
|
1229
|
-
context 'without request_id' do
|
1230
|
-
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: []) }
|
1231
1326
|
|
1232
1327
|
it 'does not include request_id in ConnectionTimeout error' do
|
1233
1328
|
begin
|