ably 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +185 -0
  4. data/LICENSE +15 -0
  5. data/README.md +8 -4
  6. data/SPEC.md +999 -531
  7. data/ably.gemspec +1 -1
  8. data/lib/ably.rb +1 -1
  9. data/lib/ably/auth.rb +114 -87
  10. data/lib/ably/exceptions.rb +40 -14
  11. data/lib/ably/models/message.rb +3 -5
  12. data/lib/ably/models/paginated_result.rb +3 -12
  13. data/lib/ably/models/presence_message.rb +8 -2
  14. data/lib/ably/models/protocol_message.rb +15 -3
  15. data/lib/ably/models/stat.rb +1 -1
  16. data/lib/ably/models/token_details.rb +1 -1
  17. data/lib/ably/modules/channels_collection.rb +7 -1
  18. data/lib/ably/modules/conversions.rb +1 -1
  19. data/lib/ably/modules/encodeable.rb +6 -3
  20. data/lib/ably/modules/message_pack.rb +2 -2
  21. data/lib/ably/modules/model_common.rb +1 -1
  22. data/lib/ably/modules/state_machine.rb +2 -2
  23. data/lib/ably/realtime.rb +1 -0
  24. data/lib/ably/realtime/auth.rb +191 -0
  25. data/lib/ably/realtime/channel.rb +97 -25
  26. data/lib/ably/realtime/channel/channel_manager.rb +11 -3
  27. data/lib/ably/realtime/client.rb +22 -6
  28. data/lib/ably/realtime/connection.rb +74 -41
  29. data/lib/ably/realtime/connection/connection_manager.rb +48 -33
  30. data/lib/ably/realtime/presence.rb +17 -3
  31. data/lib/ably/rest/channel.rb +43 -16
  32. data/lib/ably/rest/client.rb +57 -26
  33. data/lib/ably/rest/middleware/exceptions.rb +3 -1
  34. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -2
  35. data/lib/ably/rest/presence.rb +1 -0
  36. data/lib/ably/version.rb +1 -1
  37. data/spec/acceptance/realtime/auth_spec.rb +242 -0
  38. data/spec/acceptance/realtime/channel_spec.rb +277 -5
  39. data/spec/acceptance/realtime/channels_spec.rb +64 -0
  40. data/spec/acceptance/realtime/client_spec.rb +26 -5
  41. data/spec/acceptance/realtime/connection_failures_spec.rb +23 -6
  42. data/spec/acceptance/realtime/connection_spec.rb +167 -16
  43. data/spec/acceptance/realtime/message_spec.rb +9 -8
  44. data/spec/acceptance/realtime/presence_history_spec.rb +1 -0
  45. data/spec/acceptance/realtime/presence_spec.rb +121 -10
  46. data/spec/acceptance/realtime/stats_spec.rb +13 -1
  47. data/spec/acceptance/rest/auth_spec.rb +161 -79
  48. data/spec/acceptance/rest/base_spec.rb +3 -3
  49. data/spec/acceptance/rest/channel_spec.rb +142 -15
  50. data/spec/acceptance/rest/channels_spec.rb +23 -0
  51. data/spec/acceptance/rest/client_spec.rb +180 -18
  52. data/spec/acceptance/rest/message_spec.rb +8 -8
  53. data/spec/acceptance/rest/presence_spec.rb +136 -25
  54. data/spec/acceptance/rest/stats_spec.rb +60 -4
  55. data/spec/shared/client_initializer_behaviour.rb +54 -3
  56. data/spec/unit/auth_spec.rb +7 -6
  57. data/spec/unit/models/message_spec.rb +1 -9
  58. data/spec/unit/models/paginated_result_spec.rb +1 -18
  59. data/spec/unit/models/presence_message_spec.rb +1 -1
  60. data/spec/unit/models/protocol_message_spec.rb +21 -1
  61. data/spec/unit/realtime/channel_spec.rb +10 -3
  62. data/spec/unit/realtime/channels_spec.rb +27 -8
  63. data/spec/unit/rest/channel_spec.rb +0 -8
  64. data/spec/unit/rest/client_spec.rb +7 -7
  65. metadata +13 -7
  66. data/LICENSE.txt +0 -22
@@ -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)