ably-rest 0.8.2 → 0.8.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 +4 -4
- data/CHANGELOG.md +1 -43
- data/SPEC.md +707 -580
- data/lib/submodules/ably-ruby/.travis.yml +1 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +143 -3
- data/lib/submodules/ably-ruby/README.md +1 -1
- data/lib/submodules/ably-ruby/SPEC.md +842 -520
- data/lib/submodules/ably-ruby/ably.gemspec +1 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +114 -87
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +40 -14
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +3 -5
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_result.rb +3 -12
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -3
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +7 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +6 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +191 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +97 -25
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +11 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +22 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +73 -40
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +48 -33
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +17 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +43 -16
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +57 -26
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +3 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +242 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +277 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +64 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +26 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +23 -6
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +167 -16
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +9 -8
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +1 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +121 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +13 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +161 -79
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +142 -15
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +180 -18
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +8 -8
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +136 -25
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +60 -4
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +54 -3
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +7 -6
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +1 -9
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_result_spec.rb +1 -18
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +21 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +10 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +27 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +0 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +7 -7
- metadata +5 -2
@@ -7,13 +7,25 @@ describe Ably::Realtime::Client, '#stats', :event_machine do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'fetching stats' do
|
10
|
-
it '
|
10
|
+
it 'returns a PaginatedResult' do
|
11
11
|
client.stats do |stats|
|
12
12
|
expect(stats).to be_a(Ably::Models::PaginatedResult)
|
13
13
|
stop_reactor
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
context 'with options' do
|
18
|
+
let(:options) { { arbitrary: random_str } }
|
19
|
+
|
20
|
+
it 'passes the option arguments to the REST stat method' do
|
21
|
+
expect(client.rest_client).to receive(:stats).with(options)
|
22
|
+
|
23
|
+
client.stats(options) do |stats|
|
24
|
+
stop_reactor
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
17
29
|
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
18
30
|
expect(client.stats).to be_a(Ably::Util::SafeDeferrable)
|
19
31
|
stop_reactor
|
@@ -5,7 +5,11 @@ describe Ably::Auth do
|
|
5
5
|
include Ably::Modules::Conversions
|
6
6
|
|
7
7
|
def hmac_for(token_request_attributes, secret)
|
8
|
-
token_request= Ably::Models::IdiomaticRubyWrapper
|
8
|
+
token_request = if token_request_attributes.kind_of?(Ably::Models::IdiomaticRubyWrapper)
|
9
|
+
token_request_attributes
|
10
|
+
else
|
11
|
+
Ably::Models::IdiomaticRubyWrapper.new(token_request_attributes)
|
12
|
+
end
|
9
13
|
|
10
14
|
text = [
|
11
15
|
:key_name,
|
@@ -22,8 +26,10 @@ describe Ably::Auth do
|
|
22
26
|
end
|
23
27
|
|
24
28
|
vary_by_protocol do
|
29
|
+
let(:default_options) { { environment: environment, protocol: protocol } }
|
30
|
+
let(:client_options) { default_options.merge(key: api_key) }
|
25
31
|
let(:client) do
|
26
|
-
Ably::Rest::Client.new(
|
32
|
+
Ably::Rest::Client.new(client_options)
|
27
33
|
end
|
28
34
|
let(:auth) { client.auth }
|
29
35
|
let(:content_type) do
|
@@ -45,9 +51,9 @@ describe Ably::Auth do
|
|
45
51
|
|
46
52
|
def serialize(object, protocol)
|
47
53
|
if protocol == :msgpack
|
48
|
-
MessagePack.pack(
|
54
|
+
MessagePack.pack(object)
|
49
55
|
else
|
50
|
-
JSON.dump(
|
56
|
+
JSON.dump(object)
|
51
57
|
end
|
52
58
|
end
|
53
59
|
|
@@ -60,35 +66,45 @@ describe Ably::Auth do
|
|
60
66
|
let(:capability) { { :foo => ['publish'] } }
|
61
67
|
|
62
68
|
let(:token_details) do
|
63
|
-
auth.request_token(
|
69
|
+
auth.request_token(token_params: {
|
64
70
|
ttl: ttl,
|
65
71
|
capability: capability
|
66
|
-
)
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'creates a TokenRequest automatically and sends it to Ably to obtain a token', webmock: true do
|
76
|
+
token_request_stub = stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").
|
77
|
+
to_return(status: 201, body: serialize({}, protocol), headers: { 'Content-Type' => content_type })
|
78
|
+
expect(auth).to receive(:create_token_request).and_call_original
|
79
|
+
auth.request_token
|
80
|
+
|
81
|
+
expect(token_request_stub).to have_been_requested
|
67
82
|
end
|
68
83
|
|
69
|
-
it 'returns a valid
|
84
|
+
it 'returns a valid TokenDetails object in the expected format with valid issued and expires attributes' do
|
85
|
+
expect(token_details).to be_a(Ably::Models::TokenDetails)
|
70
86
|
expect(token_details.token).to match(/^#{app_id}\.[\w-]+$/)
|
71
87
|
expect(token_details.key_name).to match(/^#{key_name}$/)
|
72
88
|
expect(token_details.issued).to be_within(2).of(Time.now)
|
73
89
|
expect(token_details.expires).to be_within(2).of(Time.now + ttl)
|
74
90
|
end
|
75
91
|
|
76
|
-
%w(client_id capability nonce timestamp ttl).each do |
|
77
|
-
context "with
|
78
|
-
def coerce_if_time_value(field_name, value,
|
79
|
-
multiply =
|
92
|
+
%w(client_id capability nonce timestamp ttl).each do |token_param|
|
93
|
+
context "with token_param :#{token_param}", :webmock do
|
94
|
+
def coerce_if_time_value(field_name, value, params = {})
|
95
|
+
multiply = params[:multiply]
|
80
96
|
return value unless %w(timestamp ttl).include?(field_name)
|
81
97
|
value.to_i * (multiply ? multiply : 1)
|
82
98
|
end
|
83
99
|
|
84
|
-
let(:random) { coerce_if_time_value(
|
85
|
-
let(:
|
100
|
+
let(:random) { coerce_if_time_value(token_param, random_int_str) }
|
101
|
+
let(:token_params) { { token_param.to_sym => random } }
|
86
102
|
|
87
103
|
let(:token_response) { {} }
|
88
104
|
let!(:request_token_stub) do
|
89
105
|
stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").
|
90
106
|
with do |request|
|
91
|
-
request_body_includes(request, protocol,
|
107
|
+
request_body_includes(request, protocol, token_param, coerce_if_time_value(token_param, random, multiply: 1000))
|
92
108
|
end.to_return(
|
93
109
|
:status => 201,
|
94
110
|
:body => serialize(token_response, protocol),
|
@@ -96,7 +112,7 @@ describe Ably::Auth do
|
|
96
112
|
)
|
97
113
|
end
|
98
114
|
|
99
|
-
before { auth.request_token
|
115
|
+
before { auth.request_token token_params: token_params }
|
100
116
|
|
101
117
|
it "overrides default and uses camelCase notation for attributes" do
|
102
118
|
expect(request_token_stub).to have_been_requested
|
@@ -108,8 +124,9 @@ describe Ably::Auth do
|
|
108
124
|
let(:key_name) { "app.#{random_str}" }
|
109
125
|
let(:key_secret) { random_str }
|
110
126
|
let(:nonce) { random_str }
|
111
|
-
let(:
|
112
|
-
let(:
|
127
|
+
let(:auth_options) { { key: "#{key_name}:#{key_secret}" } }
|
128
|
+
let(:token_params) { { nonce: nonce, timestamp: Time.now } }
|
129
|
+
let(:token_request) { auth.create_token_request(auth_options, token_params) }
|
113
130
|
let(:mac) do
|
114
131
|
hmac_for(token_request, key_secret)
|
115
132
|
end
|
@@ -125,7 +142,7 @@ describe Ably::Auth do
|
|
125
142
|
:headers => { 'Content-Type' => content_type })
|
126
143
|
end
|
127
144
|
|
128
|
-
let!(:token) {
|
145
|
+
let!(:token) { auth.request_token(auth_options, token_params) }
|
129
146
|
|
130
147
|
specify 'key_name is used in request and signing uses key_secret' do
|
131
148
|
expect(request_token_stub).to have_been_requested
|
@@ -137,8 +154,9 @@ describe Ably::Auth do
|
|
137
154
|
let(:key_secret) { random_str }
|
138
155
|
let(:nonce) { random_str }
|
139
156
|
|
140
|
-
let(:
|
141
|
-
let(:
|
157
|
+
let(:auth_options) { { key_name: key_name, key_secret: key_secret } }
|
158
|
+
let(:token_params) { { nonce: nonce, timestamp: Time.now } }
|
159
|
+
let(:token_request) { auth.create_token_request(auth_options, token_params) }
|
142
160
|
let(:mac) do
|
143
161
|
hmac_for(token_request, key_secret)
|
144
162
|
end
|
@@ -154,7 +172,7 @@ describe Ably::Auth do
|
|
154
172
|
:headers => { 'Content-Type' => content_type })
|
155
173
|
end
|
156
174
|
|
157
|
-
let!(:token) { auth.request_token(
|
175
|
+
let!(:token) { auth.request_token(auth_options, token_params) }
|
158
176
|
|
159
177
|
specify 'key_name is used in request and signing uses key_secret' do
|
160
178
|
expect(request_token_stub).to have_been_requested
|
@@ -186,12 +204,12 @@ describe Ably::Auth do
|
|
186
204
|
let(:query_params) { nil }
|
187
205
|
let(:headers) { nil }
|
188
206
|
let(:auth_method) { :get }
|
189
|
-
let(:
|
207
|
+
let(:auth_options) do
|
190
208
|
{
|
191
|
-
auth_url:
|
192
|
-
auth_params:
|
209
|
+
auth_url: auth_url,
|
210
|
+
auth_params: query_params,
|
193
211
|
auth_headers: headers,
|
194
|
-
auth_method:
|
212
|
+
auth_method: auth_method
|
195
213
|
}
|
196
214
|
end
|
197
215
|
|
@@ -219,7 +237,7 @@ describe Ably::Auth do
|
|
219
237
|
end
|
220
238
|
|
221
239
|
context 'when response from :auth_url is a valid token request' do
|
222
|
-
let!(:token) { auth.request_token(
|
240
|
+
let!(:token) { auth.request_token(auth_options) }
|
223
241
|
|
224
242
|
it 'requests a token from :auth_url using an HTTP GET request' do
|
225
243
|
expect(request_token_stub).to have_been_requested
|
@@ -272,9 +290,10 @@ describe Ably::Auth do
|
|
272
290
|
}.to_json
|
273
291
|
end
|
274
292
|
|
275
|
-
let!(:token_details) { auth.request_token(
|
293
|
+
let!(:token_details) { auth.request_token(auth_options) }
|
276
294
|
|
277
295
|
it 'returns TokenDetails created from the token JSON' do
|
296
|
+
expect(auth_url_request_stub).to have_been_requested
|
278
297
|
expect(request_token_stub).to_not have_been_requested
|
279
298
|
expect(token_details).to be_a(Ably::Models::TokenDetails)
|
280
299
|
expect(token_details.token).to eql(token)
|
@@ -289,9 +308,10 @@ describe Ably::Auth do
|
|
289
308
|
let(:auth_url_content_type) { 'text/plain' }
|
290
309
|
let(:auth_url_response) { token }
|
291
310
|
|
292
|
-
let!(:token_details) { auth.request_token(
|
311
|
+
let!(:token_details) { auth.request_token(auth_options) }
|
293
312
|
|
294
313
|
it 'returns TokenDetails created from the token JSON' do
|
314
|
+
expect(auth_url_request_stub).to have_been_requested
|
295
315
|
expect(request_token_stub).to_not have_been_requested
|
296
316
|
expect(token_details).to be_a(Ably::Models::TokenDetails)
|
297
317
|
expect(token_details.token).to eql(token)
|
@@ -305,7 +325,7 @@ describe Ably::Auth do
|
|
305
325
|
end
|
306
326
|
|
307
327
|
it 'raises ServerError' do
|
308
|
-
expect { auth.request_token
|
328
|
+
expect { auth.request_token auth_options }.to raise_error(Ably::Exceptions::ServerError)
|
309
329
|
end
|
310
330
|
end
|
311
331
|
|
@@ -316,7 +336,7 @@ describe Ably::Auth do
|
|
316
336
|
end
|
317
337
|
|
318
338
|
it 'raises InvalidResponseBody' do
|
319
|
-
expect { auth.request_token
|
339
|
+
expect { auth.request_token auth_options }.to raise_error(Ably::Exceptions::InvalidResponseBody)
|
320
340
|
end
|
321
341
|
end
|
322
342
|
end
|
@@ -325,18 +345,21 @@ describe Ably::Auth do
|
|
325
345
|
context 'with a Proc for the :auth_callback option' do
|
326
346
|
context 'that returns a TokenRequest' do
|
327
347
|
let(:client_id) { random_str }
|
328
|
-
let(:
|
329
|
-
let
|
330
|
-
|
348
|
+
let(:ttl) { 8888 }
|
349
|
+
let(:auth_callback) do
|
350
|
+
Proc.new do |token_params_arg|
|
331
351
|
@block_called = true
|
332
|
-
|
333
|
-
auth.create_token_request(client_id: client_id)
|
334
|
-
end
|
352
|
+
expect(token_params_arg).to eq(token_params)
|
353
|
+
auth.create_token_request(token_params: { client_id: client_id })
|
354
|
+
end
|
355
|
+
end
|
356
|
+
let(:token_params) { { ttl: ttl } }
|
357
|
+
let!(:request_token) do
|
358
|
+
auth.request_token(auth_callback: auth_callback, token_params: token_params)
|
335
359
|
end
|
336
360
|
|
337
|
-
it 'calls the Proc when authenticating to obtain the request token' do
|
361
|
+
it 'calls the Proc with token_params when authenticating to obtain the request token' do
|
338
362
|
expect(@block_called).to eql(true)
|
339
|
-
expect(@block_options).to include(options)
|
340
363
|
end
|
341
364
|
|
342
365
|
it 'uses the token request returned from the callback when requesting a new token' do
|
@@ -354,9 +377,9 @@ describe Ably::Auth do
|
|
354
377
|
let(:capability_str) { JSON.dump(capability) }
|
355
378
|
|
356
379
|
let!(:token_details) do
|
357
|
-
auth.request_token(
|
380
|
+
auth.request_token(auth_callback: Proc.new do |token_params_arg|
|
358
381
|
@block_called = true
|
359
|
-
@
|
382
|
+
@block_params = token_params_arg
|
360
383
|
{
|
361
384
|
'token' => token,
|
362
385
|
'keyName' => 'J_0Tlg.NxCRig',
|
@@ -365,12 +388,12 @@ describe Ably::Auth do
|
|
365
388
|
'expires' => expires.to_i * 1000,
|
366
389
|
'capability'=> capability_str
|
367
390
|
}
|
368
|
-
end)
|
391
|
+
end, token_params: options)
|
369
392
|
end
|
370
393
|
|
371
394
|
it 'calls the Proc when authenticating to obtain the request token' do
|
372
395
|
expect(@block_called).to eql(true)
|
373
|
-
expect(@
|
396
|
+
expect(@block_params).to include(options)
|
374
397
|
end
|
375
398
|
|
376
399
|
it 'uses the token request returned from the callback when requesting a new token' do
|
@@ -388,7 +411,7 @@ describe Ably::Auth do
|
|
388
411
|
|
389
412
|
let!(:token_details) do
|
390
413
|
auth.request_token(auth_callback: Proc.new do |block_options|
|
391
|
-
auth.create_token_request({
|
414
|
+
auth.create_token_request(token_params: {
|
392
415
|
client_id: client_id
|
393
416
|
})
|
394
417
|
end)
|
@@ -420,7 +443,7 @@ describe Ably::Auth do
|
|
420
443
|
context 'persisted option', api_private: true do
|
421
444
|
context 'when set to true', api_private: true do
|
422
445
|
let(:options) { { persisted: true } }
|
423
|
-
let(:token_details) { auth.request_token(options) }
|
446
|
+
let(:token_details) { auth.request_token(token_params: options) }
|
424
447
|
|
425
448
|
it 'returns a token with a short token ID that is used to look up the token details' do
|
426
449
|
expect(token_details.token.length).to be < 64
|
@@ -429,8 +452,7 @@ describe Ably::Auth do
|
|
429
452
|
end
|
430
453
|
|
431
454
|
context 'when omitted', api_private: true do
|
432
|
-
let(:
|
433
|
-
let(:token_details) { auth.request_token(options) }
|
455
|
+
let(:token_details) { auth.request_token }
|
434
456
|
|
435
457
|
it 'returns a literal token' do
|
436
458
|
expect(token_details.token.length).to be > 64
|
@@ -438,7 +460,7 @@ describe Ably::Auth do
|
|
438
460
|
end
|
439
461
|
end
|
440
462
|
|
441
|
-
context 'with client_id' do
|
463
|
+
context 'with auth_option :client_id' do
|
442
464
|
let(:client_id) { random_str }
|
443
465
|
let(:token_details) { auth.request_token(client_id: client_id) }
|
444
466
|
|
@@ -446,6 +468,15 @@ describe Ably::Auth do
|
|
446
468
|
expect(token_details.client_id).to eql(client_id)
|
447
469
|
end
|
448
470
|
end
|
471
|
+
|
472
|
+
context 'with token_param :client_id' do
|
473
|
+
let(:client_id) { random_str }
|
474
|
+
let(:token_details) { auth.request_token(token_params: { client_id: client_id }) }
|
475
|
+
|
476
|
+
it 'returns a token with the client_id' do
|
477
|
+
expect(token_details.client_id).to eql(client_id)
|
478
|
+
end
|
479
|
+
end
|
449
480
|
end
|
450
481
|
|
451
482
|
context 'before #authorise has been called' do
|
@@ -456,13 +487,16 @@ describe Ably::Auth do
|
|
456
487
|
|
457
488
|
describe '#authorise' do
|
458
489
|
context 'when called for the first time since the client has been instantiated' do
|
459
|
-
let(:
|
490
|
+
let(:auth_options) do
|
460
491
|
{ auth_url: 'http://somewhere.com/' }
|
461
492
|
end
|
493
|
+
let(:token_params) do
|
494
|
+
{ ttl: 55 }
|
495
|
+
end
|
462
496
|
|
463
|
-
it 'passes all
|
464
|
-
expect(auth).to receive(:request_token).with(
|
465
|
-
auth.authorise
|
497
|
+
it 'passes all auth_options and token_params to #request_token' do
|
498
|
+
expect(auth).to receive(:request_token).with(auth_options, token_params)
|
499
|
+
auth.authorise auth_options, token_params
|
466
500
|
end
|
467
501
|
|
468
502
|
it 'returns a valid token' do
|
@@ -540,10 +574,22 @@ describe Ably::Auth do
|
|
540
574
|
end
|
541
575
|
|
542
576
|
describe '#create_token_request' do
|
543
|
-
let(:ttl)
|
544
|
-
let(:capability)
|
545
|
-
let(:
|
546
|
-
|
577
|
+
let(:ttl) { 60 * 60 }
|
578
|
+
let(:capability) { { "foo" => ["publish"] } }
|
579
|
+
let(:token_params) { Hash.new }
|
580
|
+
|
581
|
+
subject { auth.create_token_request(token_params: token_params) }
|
582
|
+
|
583
|
+
it 'returns a TokenRequest object' do
|
584
|
+
expect(subject).to be_a(Ably::Models::TokenRequest)
|
585
|
+
end
|
586
|
+
|
587
|
+
it 'returns a TokenRequest that can be passed to a client that can use it for authentication without an API key' do
|
588
|
+
auth_callback = Proc.new { subject }
|
589
|
+
client_without_api_key = Ably::Rest::Client.new(default_options.merge(auth_callback: auth_callback))
|
590
|
+
expect(client_without_api_key.auth).to be_using_token_auth
|
591
|
+
expect { client_without_api_key.auth.authorise }.to_not raise_error
|
592
|
+
end
|
547
593
|
|
548
594
|
it 'uses the key name from the client' do
|
549
595
|
expect(subject['keyName']).to eql(key_name)
|
@@ -553,6 +599,15 @@ describe Ably::Auth do
|
|
553
599
|
expect(subject['ttl']).to eql(Ably::Auth::TOKEN_DEFAULTS.fetch(:ttl) * 1000)
|
554
600
|
end
|
555
601
|
|
602
|
+
context 'with a :ttl option below the Token expiry buffer that ensures tokens are renewed 15s before they expire as they are considered expired' do
|
603
|
+
let(:ttl) { 1 }
|
604
|
+
|
605
|
+
it 'uses the Token expiry buffer default + 10s to allow for a token request in flight' do
|
606
|
+
expect(subject.ttl).to be > 1
|
607
|
+
expect(subject.ttl).to be > Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
556
611
|
it 'uses the default capability' do
|
557
612
|
expect(subject['capability']).to eql(Ably::Auth::TOKEN_DEFAULTS.fetch(:capability).to_json)
|
558
613
|
end
|
@@ -569,19 +624,36 @@ describe Ably::Auth do
|
|
569
624
|
end
|
570
625
|
|
571
626
|
%w(ttl nonce client_id).each do |attribute|
|
572
|
-
context "with
|
573
|
-
let(:
|
627
|
+
context "with token param :#{attribute}" do
|
628
|
+
let(:token_param) { random_int_str(1_000_000_000).to_i }
|
574
629
|
before do
|
575
|
-
|
630
|
+
token_params[attribute.to_sym] = token_param
|
576
631
|
end
|
577
632
|
it "overrides default" do
|
578
|
-
expect(subject.public_send(attribute).to_s).to eql(
|
633
|
+
expect(subject.public_send(attribute).to_s).to eql(token_param.to_s)
|
579
634
|
end
|
580
635
|
end
|
581
636
|
end
|
582
637
|
|
638
|
+
context 'when specifying capability' do
|
639
|
+
before do
|
640
|
+
token_params[:capability] = capability
|
641
|
+
end
|
642
|
+
|
643
|
+
it 'overrides the default' do
|
644
|
+
expect(subject.capability).to eql(capability)
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'uses these capabilities when Ably issues an actual token' do
|
648
|
+
auth_callback = Proc.new { subject }
|
649
|
+
client_without_api_key = Ably::Rest::Client.new(default_options.merge(auth_callback: auth_callback))
|
650
|
+
client_without_api_key.auth.authorise
|
651
|
+
expect(client_without_api_key.auth.current_token_details.capability).to eql(capability)
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
583
655
|
context 'with additional invalid attributes' do
|
584
|
-
let(:
|
656
|
+
let(:token_params) { { nonce: 'valid', is_not_used_by_token_request: 'invalid' } }
|
585
657
|
specify 'are ignored' do
|
586
658
|
expect(subject.hash.keys).to_not include(:is_not_used_by_token_request)
|
587
659
|
expect(subject.hash.keys).to_not include(convert_to_mixed_case(:is_not_used_by_token_request))
|
@@ -594,35 +666,43 @@ describe Ably::Auth do
|
|
594
666
|
let(:client) { Ably::Rest::Client.new(auth_url: 'http://example.com', protocol: protocol) }
|
595
667
|
|
596
668
|
it 'should raise an exception if key secret is missing' do
|
597
|
-
expect { auth.create_token_request(key_name: 'name') }.to raise_error Ably::Exceptions::
|
669
|
+
expect { auth.create_token_request(key_name: 'name') }.to raise_error Ably::Exceptions::TokenRequestFailed
|
598
670
|
end
|
599
671
|
|
600
672
|
it 'should raise an exception if key name is missing' do
|
601
|
-
expect { auth.create_token_request(key_secret: 'secret') }.to raise_error Ably::Exceptions::
|
673
|
+
expect { auth.create_token_request(key_secret: 'secret') }.to raise_error Ably::Exceptions::TokenRequestFailed
|
602
674
|
end
|
603
675
|
end
|
604
676
|
|
605
|
-
context '
|
606
|
-
|
607
|
-
|
677
|
+
context 'timestamp attribute' do
|
678
|
+
context 'with :query_time auth_option' do
|
679
|
+
let(:time) { Time.now - 30 }
|
680
|
+
let(:auth_options) { { query_time: true } }
|
681
|
+
|
682
|
+
subject { auth.create_token_request(auth_options) }
|
608
683
|
|
609
|
-
|
610
|
-
|
611
|
-
|
684
|
+
it 'queries the server for the timestamp' do
|
685
|
+
expect(client).to receive(:time).and_return(time)
|
686
|
+
expect(subject['timestamp']).to be_within(1).of(time.to_f * 1000)
|
687
|
+
end
|
612
688
|
end
|
613
|
-
end
|
614
689
|
|
615
|
-
|
616
|
-
|
617
|
-
|
690
|
+
context 'with :timestamp option' do
|
691
|
+
let(:token_request_time) { Time.now + 5 }
|
692
|
+
let(:token_params) { { timestamp: token_request_time } }
|
618
693
|
|
619
|
-
|
620
|
-
|
694
|
+
it 'uses the provided timestamp in the token request' do
|
695
|
+
expect(subject['timestamp']).to be_within(1).of(token_request_time.to_f * 1000)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
it 'is a Time object in Ruby and is set to the local time' do
|
700
|
+
expect(subject.timestamp.to_f).to be_within(1).of(Time.now.to_f)
|
621
701
|
end
|
622
702
|
end
|
623
703
|
|
624
704
|
context 'signing' do
|
625
|
-
let(:
|
705
|
+
let(:token_attributes) do
|
626
706
|
{
|
627
707
|
key_name: random_str,
|
628
708
|
ttl: random_int_str.to_i,
|
@@ -632,10 +712,12 @@ describe Ably::Auth do
|
|
632
712
|
nonce: random_str
|
633
713
|
}
|
634
714
|
end
|
715
|
+
let(:client_options) { default_options.merge(key_name: token_attributes.fetch(:key_name), key_secret: key_secret) }
|
716
|
+
let(:token_params) { token_attributes }
|
635
717
|
|
636
718
|
# TokenRequest expects times in milliseconds, whereas create_token_request assumes Ruby default of seconds
|
637
719
|
let(:token_request_attributes) do
|
638
|
-
|
720
|
+
token_attributes.merge(timestamp: token_attributes[:timestamp] * 1000, ttl: token_attributes[:ttl] * 1000)
|
639
721
|
end
|
640
722
|
|
641
723
|
it 'generates a valid HMAC' do
|
@@ -651,10 +733,10 @@ describe Ably::Auth do
|
|
651
733
|
describe 'with :token option' do
|
652
734
|
let(:ttl) { 60 * 60 }
|
653
735
|
let(:token_details) do
|
654
|
-
auth.request_token(
|
736
|
+
auth.request_token(token_params: {
|
655
737
|
ttl: ttl,
|
656
738
|
capability: capability
|
657
|
-
)
|
739
|
+
})
|
658
740
|
end
|
659
741
|
let(:token) { token_details.token }
|
660
742
|
let(:token_auth_client) do
|
@@ -674,7 +756,7 @@ describe Ably::Auth do
|
|
674
756
|
end
|
675
757
|
|
676
758
|
it 'fails if timestamp is invalid' do
|
677
|
-
expect { auth.request_token(timestamp: Time.now - 180) }.to raise_error do |error|
|
759
|
+
expect { auth.request_token(token_params: { timestamp: Time.now - 180 }) }.to raise_error do |error|
|
678
760
|
expect(error).to be_a(Ably::Exceptions::InvalidRequest)
|
679
761
|
expect(error.status).to eql(401)
|
680
762
|
expect(error.code).to eql(40101)
|