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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -43
  3. data/SPEC.md +707 -580
  4. data/lib/submodules/ably-ruby/.travis.yml +1 -0
  5. data/lib/submodules/ably-ruby/CHANGELOG.md +143 -3
  6. data/lib/submodules/ably-ruby/README.md +1 -1
  7. data/lib/submodules/ably-ruby/SPEC.md +842 -520
  8. data/lib/submodules/ably-ruby/ably.gemspec +1 -1
  9. data/lib/submodules/ably-ruby/lib/ably/auth.rb +114 -87
  10. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +40 -14
  11. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +3 -5
  12. data/lib/submodules/ably-ruby/lib/ably/models/paginated_result.rb +3 -12
  13. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +8 -2
  14. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -3
  15. data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +1 -1
  16. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +1 -1
  17. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +7 -1
  18. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +1 -1
  19. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +6 -3
  20. data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +2 -2
  21. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +1 -1
  22. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
  23. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +191 -0
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +97 -25
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +11 -3
  27. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +22 -6
  28. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +73 -40
  29. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +48 -33
  30. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +17 -3
  31. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +43 -16
  32. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +57 -26
  33. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +3 -1
  34. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -2
  35. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
  36. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +242 -0
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +277 -5
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +64 -0
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +26 -5
  41. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +23 -6
  42. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +167 -16
  43. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +9 -8
  44. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +1 -0
  45. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +121 -10
  46. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +13 -1
  47. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +161 -79
  48. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +3 -3
  49. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +142 -15
  50. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -0
  51. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +180 -18
  52. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +8 -8
  53. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +136 -25
  54. data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +60 -4
  55. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +54 -3
  56. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +7 -6
  57. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +1 -9
  58. data/lib/submodules/ably-ruby/spec/unit/models/paginated_result_spec.rb +1 -18
  59. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
  60. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +21 -1
  61. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +10 -3
  62. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +27 -8
  63. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +0 -8
  64. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +7 -7
  65. 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 'should return a PaginatedResult' do
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.new(token_request_attributes)
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(key: api_key, environment: environment, protocol: protocol)
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(token_response)
54
+ MessagePack.pack(object)
49
55
  else
50
- JSON.dump(token_response)
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 requested token in the expected format with valid issued and expires attributes' do
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 |option|
77
- context "with option :#{option}", :webmock do
78
- def coerce_if_time_value(field_name, value, options = {})
79
- multiply = options[: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(option, random_int_str) }
85
- let(:options) { { option.to_sym => random } }
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, option, coerce_if_time_value(option, random, multiply: 1000))
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 options }
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(:token_options) { { key: "#{key_name}:#{key_secret}", nonce: nonce, timestamp: Time.now } }
112
- let(:token_request) { auth.create_token_request(token_options) }
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) { puts token_options; auth.request_token(token_options) }
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(:name_secret_token_options) { { key_name: key_name, key_secret: key_secret, nonce: nonce, timestamp: Time.now } }
141
- let(:token_request) { auth.create_token_request(name_secret_token_options) }
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(name_secret_token_options); }
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(:options) do
207
+ let(:auth_options) do
190
208
  {
191
- auth_url: auth_url,
192
- auth_params: query_params,
209
+ auth_url: auth_url,
210
+ auth_params: query_params,
193
211
  auth_headers: headers,
194
- auth_method: 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(options) }
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(options) }
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(options) }
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 options }.to raise_error(Ably::Exceptions::ServerError)
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 options }.to raise_error(Ably::Exceptions::InvalidResponseBody)
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(:options) { { client_id: client_id } }
329
- let!(:request_token) do
330
- auth.request_token(options.merge(auth_callback: Proc.new do |block_options|
348
+ let(:ttl) { 8888 }
349
+ let(:auth_callback) do
350
+ Proc.new do |token_params_arg|
331
351
  @block_called = true
332
- @block_options = block_options
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(options.merge(auth_callback: Proc.new do |block_options|
380
+ auth.request_token(auth_callback: Proc.new do |token_params_arg|
358
381
  @block_called = true
359
- @block_options = block_options
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(@block_options).to include(options)
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(:options) { { } }
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(:request_options) do
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 options to #request_token' do
464
- expect(auth).to receive(:request_token).with(request_options)
465
- auth.authorise request_options
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) { 60 * 60 }
544
- let(:capability) { { :foo => ["publish"] } }
545
- let(:token_request_options) { Hash.new }
546
- subject { auth.create_token_request(token_request_options) }
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 option :#{attribute}" do
573
- let(:option_value) { random_int_str(1_000_000_000).to_i }
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
- token_request_options[attribute.to_sym] = option_value
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(option_value.to_s)
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(:token_request_options) { { nonce: 'valid', is_not_used_by_token_request: 'invalid' } }
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::TokenRequestError
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::TokenRequestError
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 'with :query_time option' do
606
- let(:time) { Time.now - 30 }
607
- let(:token_request_options) { { query_time: true } }
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
- it 'queries the server for the timestamp' do
610
- expect(client).to receive(:time).and_return(time)
611
- expect(subject['timestamp']).to be_within(1).of(time.to_f * 1000)
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
- context 'with :timestamp option' do
616
- let(:token_request_time) { Time.now + 5 }
617
- let(:token_request_options) { { timestamp: token_request_time } }
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
- it 'uses the provided timestamp in the token request' do
620
- expect(subject['timestamp']).to be_within(1).of(token_request_time.to_f * 1000)
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(:token_request_options) do
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
- token_request_options.merge(timestamp: token_request_options[:timestamp] * 1000, ttl: token_request_options[:ttl] * 1000)
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)