ably 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +1 -1
  4. data/lib/ably/auth.rb +23 -19
  5. data/lib/ably/models/token_details.rb +8 -6
  6. data/lib/ably/modules/conversions.rb +4 -0
  7. data/lib/ably/modules/state_emitter.rb +1 -1
  8. data/lib/ably/modules/uses_state_machine.rb +8 -1
  9. data/lib/ably/realtime/auth.rb +13 -13
  10. data/lib/ably/realtime/channel.rb +2 -2
  11. data/lib/ably/realtime/channel/channel_manager.rb +3 -3
  12. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -1
  13. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +13 -7
  14. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -0
  15. data/lib/ably/realtime/connection.rb +4 -4
  16. data/lib/ably/realtime/connection/connection_manager.rb +9 -3
  17. data/lib/ably/realtime/connection/connection_state_machine.rb +1 -1
  18. data/lib/ably/realtime/presence.rb +4 -4
  19. data/lib/ably/rest/client.rb +2 -2
  20. data/lib/ably/version.rb +1 -1
  21. data/spec/acceptance/realtime/auth_spec.rb +9 -9
  22. data/spec/acceptance/realtime/channel_history_spec.rb +2 -2
  23. data/spec/acceptance/realtime/channel_spec.rb +13 -12
  24. data/spec/acceptance/realtime/channels_spec.rb +6 -2
  25. data/spec/acceptance/realtime/client_spec.rb +4 -3
  26. data/spec/acceptance/realtime/connection_failures_spec.rb +21 -15
  27. data/spec/acceptance/realtime/connection_spec.rb +31 -27
  28. data/spec/acceptance/realtime/message_spec.rb +31 -24
  29. data/spec/acceptance/realtime/presence_history_spec.rb +2 -2
  30. data/spec/acceptance/realtime/presence_spec.rb +10 -11
  31. data/spec/acceptance/realtime/stats_spec.rb +1 -1
  32. data/spec/acceptance/realtime/time_spec.rb +1 -1
  33. data/spec/acceptance/rest/auth_spec.rb +77 -46
  34. data/spec/acceptance/rest/channel_spec.rb +22 -3
  35. data/spec/acceptance/rest/client_spec.rb +6 -6
  36. data/spec/acceptance/rest/presence_spec.rb +9 -7
  37. data/spec/support/event_machine_helper.rb +30 -4
  38. data/spec/support/protocol_helper.rb +9 -6
  39. data/spec/unit/auth_spec.rb +1 -1
  40. data/spec/unit/models/token_details_spec.rb +8 -0
  41. data/spec/unit/modules/async_wrapper_spec.rb +1 -1
  42. metadata +2 -2
@@ -11,7 +11,7 @@ describe Ably::Realtime::Connection, :event_machine do
11
11
  end
12
12
 
13
13
  let(:client_options) { default_options }
14
- let(:client) { Ably::Realtime::Client.new(client_options) }
14
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
15
15
 
16
16
  before(:example) do
17
17
  EventMachine.add_shutdown_hook do
@@ -29,7 +29,7 @@ describe Ably::Realtime::Connection, :event_machine do
29
29
 
30
30
  context 'with :auto_connect option set to false' do
31
31
  let(:client) do
32
- Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
32
+ auto_close Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
33
33
  end
34
34
 
35
35
  it 'does not connect automatically' do
@@ -96,7 +96,7 @@ describe Ably::Realtime::Connection, :event_machine do
96
96
  stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0)
97
97
 
98
98
  # Authorise synchronously to ensure token has been issued
99
- client.auth.authorise_sync(token_params: { ttl: ttl })
99
+ client.auth.authorise_sync(ttl: ttl)
100
100
  end
101
101
 
102
102
  let(:original_renew_token_buffer) { @original_renew_token_buffer }
@@ -158,7 +158,7 @@ describe Ably::Realtime::Connection, :event_machine do
158
158
  context 'when connected with a valid non-expired token' do
159
159
  context 'that then expires following the connection being opened' do
160
160
  let(:ttl) { 5 }
161
- let(:channel) { client.channel('test') }
161
+ let(:channel) { client.channel(random_str) }
162
162
 
163
163
  context 'the server' do
164
164
  it 'disconnects the client, and the client automatically renews the token and then reconnects', em_timeout: 15 do
@@ -204,7 +204,8 @@ describe Ably::Realtime::Connection, :event_machine do
204
204
 
205
205
  let!(:expired_token_details) do
206
206
  # Request a token synchronously
207
- Ably::Realtime::Client.new(default_options).auth.request_token_sync(token_params: { ttl: 0.01 })
207
+ token_client = auto_close Ably::Realtime::Client.new(default_options)
208
+ token_client.auth.request_token_sync(ttl: 0.01)
208
209
  end
209
210
 
210
211
  context 'opening a new connection' do
@@ -270,8 +271,7 @@ describe Ably::Realtime::Connection, :event_machine do
270
271
  end
271
272
 
272
273
  it 'calls the Deferrable callback on success' do
273
- connection.connect.callback do |connection|
274
- expect(connection).to be_a(Ably::Realtime::Connection)
274
+ connection.connect.callback do
275
275
  expect(connection.state).to eq(:connected)
276
276
  stop_reactor
277
277
  end
@@ -306,7 +306,8 @@ describe Ably::Realtime::Connection, :event_machine do
306
306
  end
307
307
 
308
308
  describe 'once connected' do
309
- let(:connection2) { Ably::Realtime::Client.new(client_options).connection }
309
+ let(:client2) { auto_close Ably::Realtime::Client.new(client_options) }
310
+ let(:connection2) { client2.connection }
310
311
 
311
312
  describe 'connection#id' do
312
313
  it 'is a string' do
@@ -436,7 +437,7 @@ describe Ably::Realtime::Connection, :event_machine do
436
437
 
437
438
  it 'calls the Deferrable callback on success' do
438
439
  connection.connect do
439
- connection.close.callback do |connection|
440
+ connection.close.callback do
440
441
  expect(connection).to be_a(Ably::Realtime::Connection)
441
442
  expect(connection.state).to eq(:closed)
442
443
  stop_reactor
@@ -576,7 +577,7 @@ describe Ably::Realtime::Connection, :event_machine do
576
577
  let(:channel_name) { random_str }
577
578
  let(:channel) { client.channel(channel_name) }
578
579
  let(:publishing_client) do
579
- Ably::Realtime::Client.new(client_options)
580
+ auto_close Ably::Realtime::Client.new(client_options)
580
581
  end
581
582
  let(:publishing_client_channel) { publishing_client.channel(channel_name) }
582
583
  let(:client_options) { default_options.merge(log_level: :fatal) }
@@ -594,9 +595,10 @@ describe Ably::Realtime::Connection, :event_machine do
594
595
  def self.available_states
595
596
  [:connecting, :connected, :disconnected, :suspended, :failed]
596
597
  end
597
- let(:available_states) { self.class.available_states}
598
+ let(:available_states) { self.class.available_states }
598
599
  let(:states) { Hash.new }
599
600
  let(:client_options) { default_options.merge(log_level: :none) }
601
+ let(:channel) { client.channel(random_str) }
600
602
 
601
603
  it 'is composed of connection key and serial that is kept up to date with each message ACK received' do
602
604
  connection.on(:connected) do
@@ -604,7 +606,7 @@ describe Ably::Realtime::Connection, :event_machine do
604
606
  expect(connection.key).to_not be_nil
605
607
  expect(connection.serial).to eql(expected_serial)
606
608
 
607
- client.channel('test').attach do |channel|
609
+ channel.attach do
608
610
  channel.publish('event', 'data') do
609
611
  expected_serial += 1 # attach message received
610
612
  expect(connection.serial).to eql(expected_serial)
@@ -670,9 +672,10 @@ describe Ably::Realtime::Connection, :event_machine do
670
672
  end
671
673
 
672
674
  connection.once(:failed) do
673
- recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
675
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
674
676
  recover_client.connection.on(:connected) do
675
- expect(recover_client.connection.key).to eql(previous_connection_key)
677
+ expect(recover_client.connection.key[/^\w{5,}-/, 0]).to_not be_nil
678
+ expect(recover_client.connection.key[/^\w{5,}-/, 0]).to eql(previous_connection_key[/^\w{5,}-/, 0])
676
679
  expect(recover_client.connection.id).to eql(previous_connection_id)
677
680
  stop_reactor
678
681
  end
@@ -685,7 +688,7 @@ describe Ably::Realtime::Connection, :event_machine do
685
688
  end
686
689
 
687
690
  connection.once(:failed) do
688
- recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
691
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
689
692
  recover_client.connection.on_resume do
690
693
  raise 'Should not call the resume callback'
691
694
  end
@@ -701,14 +704,15 @@ describe Ably::Realtime::Connection, :event_machine do
701
704
  let(:client_options) { default_options.merge(log_level: :none) }
702
705
 
703
706
  it 'recovers server-side queued messages' do
704
- channel.attach do |message|
707
+ channel.attach do
705
708
  connection.transition_state_machine! :failed
706
709
  end
707
710
 
708
711
  connection.on(:failed) do
709
712
  publishing_client_channel.publish('event', 'message') do
710
- recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
711
- recover_client.channel(channel_name).attach do |recover_client_channel|
713
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
714
+ recover_client_channel = recover_client.channel(channel_name)
715
+ recover_client_channel.attach do
712
716
  recover_client_channel.subscribe('event') do |message|
713
717
  expect(message.data).to eql('message')
714
718
  stop_reactor
@@ -737,9 +741,9 @@ describe Ably::Realtime::Connection, :event_machine do
737
741
  it 'emits a fatal error on the connection object, sets the #error_reason and disconnects' do
738
742
  connection.once(:error) do |error|
739
743
  expect(connection.state).to eq(:failed)
740
- expect(error.message).to match(/Invalid connection key/)
741
- expect(connection.error_reason.message).to match(/Invalid connection key/)
742
- expect(connection.error_reason.code).to eql(40006)
744
+ expect(error.message).to match(/Invalid connectionKey/i)
745
+ expect(connection.error_reason.message).to match(/Invalid connectionKey/i)
746
+ expect(connection.error_reason.code).to eql(80018)
743
747
  expect(connection.error_reason).to eql(error)
744
748
  stop_reactor
745
749
  end
@@ -747,13 +751,13 @@ describe Ably::Realtime::Connection, :event_machine do
747
751
  end
748
752
 
749
753
  context 'with expired (missing) value sent to server' do
750
- let(:client_options) { default_options.merge(recover: '0123456789abcdef:0', log_level: :fatal) }
754
+ let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0', log_level: :fatal) }
751
755
 
752
756
  it 'emits an error on the connection object, sets the #error_reason, yet will connect anyway' do
753
757
  connection.once(:error) do |error|
754
758
  expect(connection.state).to eq(:connected)
755
- expect(error.message).to match(/Invalid connection key/i)
756
- expect(connection.error_reason.message).to match(/Invalid connection key/i)
759
+ expect(error.message).to match(/Unable to recover connection/i)
760
+ expect(connection.error_reason.message).to match(/Unable to recover connection/i)
757
761
  expect(connection.error_reason.code).to eql(80008)
758
762
  expect(connection.error_reason).to eql(error)
759
763
  stop_reactor
@@ -1046,7 +1050,7 @@ describe Ably::Realtime::Connection, :event_machine do
1046
1050
  end
1047
1051
 
1048
1052
  context 'retry_in' do
1049
- let(:client_options) { default_options.merge(log_level: :debug) }
1053
+ let(:client_options) { default_options.merge(log_level: :error) }
1050
1054
 
1051
1055
  it 'is nil when a retry is not required' do
1052
1056
  connection.on(:connected) do |connection_state_change|
@@ -1061,7 +1065,7 @@ describe Ably::Realtime::Connection, :event_machine do
1061
1065
  expect(connection_state_change.retry_in).to eql(0)
1062
1066
  stop_reactor
1063
1067
  end
1064
- EventMachine.add_timer(0.001) { connection.transport.unbind }
1068
+ EventMachine.add_timer(0.005) { connection.transport.unbind }
1065
1069
  end
1066
1070
  end
1067
1071
 
@@ -1082,7 +1086,7 @@ describe Ably::Realtime::Connection, :event_machine do
1082
1086
  expect(connection_state_change.retry_in).to be > 0
1083
1087
  stop_reactor
1084
1088
  end
1085
- EventMachine.add_timer(0.001) { connection.transport.unbind }
1089
+ EventMachine.add_timer(0.005) { connection.transport.unbind }
1086
1090
  end
1087
1091
  connection.transport.unbind
1088
1092
  end
@@ -9,12 +9,12 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
9
9
  let(:default_options) { options.merge(key: api_key, environment: environment, protocol: protocol) }
10
10
  let(:client_options) { default_options }
11
11
  let(:client) do
12
- Ably::Realtime::Client.new(client_options)
12
+ auto_close Ably::Realtime::Client.new(client_options)
13
13
  end
14
14
  let(:channel) { client.channel(channel_name) }
15
15
 
16
16
  let(:other_client) do
17
- Ably::Realtime::Client.new(client_options)
17
+ auto_close Ably::Realtime::Client.new(client_options)
18
18
  end
19
19
  let(:other_client_channel) { other_client.channel(channel_name) }
20
20
 
@@ -181,12 +181,12 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
181
181
 
182
182
  context 'with :echo_messages option set to false' do
183
183
  let(:no_echo_client) do
184
- Ably::Realtime::Client.new(default_options.merge(echo_messages: false, log_level: :debug))
184
+ auto_close Ably::Realtime::Client.new(default_options.merge(echo_messages: false))
185
185
  end
186
186
  let(:no_echo_channel) { no_echo_client.channel(channel_name) }
187
187
 
188
188
  let(:rest_client) do
189
- Ably::Rest::Client.new(default_options.merge(log_level: :debug))
189
+ Ably::Rest::Client.new(default_options)
190
190
  end
191
191
 
192
192
  it 'will not echo messages to the client but will still broadcast messages to other connected clients', em_timeout: 10 do
@@ -275,7 +275,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
275
275
 
276
276
  context 'without suitable publishing permissions' do
277
277
  let(:restricted_client) do
278
- Ably::Realtime::Client.new(options.merge(key: restricted_api_key, environment: environment, protocol: protocol, :log_level => :error))
278
+ auto_close Ably::Realtime::Client.new(options.merge(key: restricted_api_key, environment: environment, protocol: protocol, :log_level => :error))
279
279
  end
280
280
  let(:restricted_channel) { restricted_client.channel("cansubscribe:example") }
281
281
  let(:payload) { 'Test message without permission to publish' }
@@ -283,8 +283,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
283
283
  it 'calls the error callback' do
284
284
  restricted_channel.attach do
285
285
  deferrable = restricted_channel.publish('test_event', payload)
286
- deferrable.errback do |message, error|
287
- expect(message.data).to eql(payload)
286
+ deferrable.errback do |error|
288
287
  expect(error.status).to eql(401)
289
288
  stop_reactor
290
289
  end
@@ -418,31 +417,39 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
418
417
  let(:encrypted_channel_client1) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
419
418
  let(:encrypted_channel_client2) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
420
419
 
421
- let(:data) { MessagePack.pack({ 'key' => random_str }) }
420
+ let(:data) { { 'key' => random_str } }
422
421
  let(:message_count) { 50 }
423
422
 
424
423
  it 'encrypts and decrypts all messages' do
425
- messages_received = {
426
- decrypted: 0,
427
- encrypted: 0
428
- }
424
+ messages_received = []
429
425
 
430
- encrypted_channel_client2.attach do
431
- encrypted_channel_client2.subscribe do |message|
432
- expect(message.data).to eql("#{message.name}-#{data}")
426
+ encrypted_channel_client1.attach do
427
+ encrypted_channel_client1.subscribe do |message|
428
+ expect(message.data).to eql(MessagePack.pack(data.merge(index: message.name.to_i)))
433
429
  expect(message.encoding).to be_nil
434
- messages_received[:decrypted] += 1
435
- stop_reactor if messages_received[:decrypted] == message_count
430
+ messages_received << message
431
+ stop_reactor if messages_received.count == message_count
436
432
  end
437
433
 
438
- encrypted_channel_client1.__incoming_msgbus__.subscribe(:message) do |message|
439
- expect(message['encoding']).to match(/cipher\+/)
440
- messages_received[:encrypted] += 1
434
+ message_count.times do |index|
435
+ encrypted_channel_client2.publish index.to_s, MessagePack.pack(data.merge(index: index))
441
436
  end
442
437
  end
438
+ end
439
+
440
+ it 'receives raw messages with the correct encoding' do
441
+ encrypted_channel_client1.attach do
442
+ client.connection.__incoming_protocol_msgbus__.unsubscribe # remove all listeners
443
+ client.connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
444
+ if protocol_message.action == Ably::Models::ProtocolMessage::ACTION.Message
445
+ protocol_message.messages.each do |message|
446
+ expect(message['encoding']).to match(/cipher\+/)
447
+ end
448
+ stop_reactor
449
+ end
450
+ end
443
451
 
444
- message_count.times do |index|
445
- encrypted_channel_client2.publish index.to_s, "#{index}-#{data}"
452
+ encrypted_channel_client2.publish 'name', MessagePack.pack('data')
446
453
  end
447
454
  end
448
455
  end
@@ -450,7 +457,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
450
457
  context 'subscribing with a different transport protocol' do
451
458
  let(:other_protocol) { protocol == :msgpack ? :json : :msgpack }
452
459
  let(:other_client) do
453
- Ably::Realtime::Client.new(default_options.merge(protocol: other_protocol))
460
+ auto_close Ably::Realtime::Client.new(default_options.merge(protocol: other_protocol))
454
461
  end
455
462
 
456
463
  let(:cipher_options) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
@@ -592,7 +599,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
592
599
  let(:event_name) { random_str }
593
600
  let(:message_state) { [] }
594
601
  let(:connection) { client.connection }
595
- let(:client_options) { default_options.merge(:log_level => :debug) }
602
+ let(:client_options) { default_options.merge(:log_level => :none) }
596
603
  let(:msgs_received) { [] }
597
604
 
598
605
  it 'publishes the message again, later receives the ACK and only one message is ever received from Ably' do
@@ -7,11 +7,11 @@ describe Ably::Realtime::Presence, 'history', :event_machine do
7
7
 
8
8
  let(:channel_name) { "persisted:#{random_str(2)}" }
9
9
 
10
- let(:client_one) { Ably::Realtime::Client.new(default_options.merge(client_id: random_str)) }
10
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(client_id: random_str)) }
11
11
  let(:channel_client_one) { client_one.channel(channel_name) }
12
12
  let(:presence_client_one) { channel_client_one.presence }
13
13
 
14
- let(:client_two) { Ably::Realtime::Client.new(default_options.merge(client_id: random_str)) }
14
+ let(:client_two) { auto_close Ably::Realtime::Client.new(default_options.merge(client_id: random_str)) }
15
15
  let(:channel_client_two) { client_two.channel(channel_name) }
16
16
  let(:presence_client_two) { channel_client_two.presence }
17
17
 
@@ -8,9 +8,9 @@ describe Ably::Realtime::Presence, :event_machine do
8
8
  let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
9
9
  let(:client_options) { default_options }
10
10
 
11
- let(:anonymous_client) { Ably::Realtime::Client.new(client_options) }
12
- let(:client_one) { Ably::Realtime::Client.new(client_options.merge(client_id: random_str)) }
13
- let(:client_two) { Ably::Realtime::Client.new(client_options.merge(client_id: random_str)) }
11
+ let(:anonymous_client) { auto_close Ably::Realtime::Client.new(client_options) }
12
+ let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(client_id: random_str)) }
13
+ let(:client_two) { auto_close Ably::Realtime::Client.new(client_options.merge(client_id: random_str)) }
14
14
 
15
15
  let(:channel_name) { "presence-#{random_str(4)}" }
16
16
  let(:channel_anonymous_client) { anonymous_client.channel(channel_name) }
@@ -72,7 +72,7 @@ describe Ably::Realtime::Presence, :event_machine do
72
72
  end
73
73
 
74
74
  context 'when :queue_messages client option is false' do
75
- let(:client_one) { Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str)) }
75
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str)) }
76
76
 
77
77
  context 'and connection state initialized' do
78
78
  it 'raises an exception' do
@@ -94,7 +94,7 @@ describe Ably::Realtime::Presence, :event_machine do
94
94
  end
95
95
 
96
96
  context 'and connection state disconnected' do
97
- let(:client_one) { Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str, :log_level => :error)) }
97
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str, :log_level => :error)) }
98
98
 
99
99
  it 'raises an exception' do
100
100
  client_one.connection.once(:connected) do
@@ -277,8 +277,7 @@ describe Ably::Realtime::Presence, :event_machine do
277
277
 
278
278
  presence_client_one.public_send(method_name, args).tap do |deferrable|
279
279
  deferrable.callback { raise 'Should not succeed' }
280
- deferrable.errback do |presence, error|
281
- expect(presence).to be_a(Ably::Realtime::Presence)
280
+ deferrable.errback do |error|
282
281
  expect(error).to be_kind_of(Ably::Exceptions::BaseAblyException)
283
282
  stop_reactor
284
283
  end
@@ -663,7 +662,7 @@ describe Ably::Realtime::Presence, :event_machine do
663
662
 
664
663
  context 'without necessary capabilities to join presence' do
665
664
  let(:restricted_client) do
666
- Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
665
+ auto_close Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
667
666
  end
668
667
  let(:restricted_channel) { restricted_client.channel("cansubscribe:channel") }
669
668
  let(:restricted_presence) { restricted_channel.presence }
@@ -880,7 +879,7 @@ describe Ably::Realtime::Presence, :event_machine do
880
879
 
881
880
  context 'without necessary capabilities to enter on behalf of another client' do
882
881
  let(:restricted_client) do
883
- Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
882
+ auto_close Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
884
883
  end
885
884
  let(:restricted_channel) { restricted_client.channel("cansubscribe:channel") }
886
885
  let(:restricted_presence) { restricted_channel.presence }
@@ -1400,7 +1399,7 @@ describe Ably::Realtime::Presence, :event_machine do
1400
1399
  let(:client_id) { random_str.encode(Encoding::ASCII_8BIT) }
1401
1400
 
1402
1401
  context 'in connection set up' do
1403
- let(:client_one) { Ably::Realtime::Client.new(default_options.merge(client_id: client_id)) }
1402
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(client_id: client_id)) }
1404
1403
 
1405
1404
  it 'is converted into UTF_8' do
1406
1405
  presence_client_one.enter
@@ -1413,7 +1412,7 @@ describe Ably::Realtime::Presence, :event_machine do
1413
1412
  end
1414
1413
 
1415
1414
  context 'in channel options' do
1416
- let(:client_one) { Ably::Realtime::Client.new(default_options) }
1415
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options) }
1417
1416
 
1418
1417
  it 'is converted into UTF_8' do
1419
1418
  presence_client_one.enter(client_id: client_id)
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Ably::Realtime::Client, '#stats', :event_machine do
4
4
  vary_by_protocol do
5
5
  let(:client) do
6
- Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
6
+ auto_close Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
7
7
  end
8
8
 
9
9
  describe 'fetching stats' do
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Ably::Realtime::Client, '#time', :event_machine do
4
4
  vary_by_protocol do
5
5
  let(:client) do
6
- Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
6
+ auto_close Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
7
7
  end
8
8
 
9
9
  describe 'fetching the service time' do
@@ -27,7 +27,7 @@ describe Ably::Auth do
27
27
 
28
28
  vary_by_protocol do
29
29
  let(:default_options) { { environment: environment, protocol: protocol } }
30
- let(:client_options) { default_options.merge(key: api_key) }
30
+ let(:client_options) { default_options.merge(key: api_key) }
31
31
  let(:client) do
32
32
  Ably::Rest::Client.new(client_options)
33
33
  end
@@ -66,10 +66,10 @@ describe Ably::Auth do
66
66
  let(:capability) { { :foo => ['publish'] } }
67
67
 
68
68
  let(:token_details) do
69
- auth.request_token(token_params: {
69
+ auth.request_token(
70
70
  ttl: ttl,
71
71
  capability: capability
72
- })
72
+ )
73
73
  end
74
74
 
75
75
  it 'creates a TokenRequest automatically and sends it to Ably to obtain a token', webmock: true do
@@ -112,7 +112,7 @@ describe Ably::Auth do
112
112
  )
113
113
  end
114
114
 
115
- before { auth.request_token token_params: token_params }
115
+ before { auth.request_token token_params }
116
116
 
117
117
  it "overrides default and uses camelCase notation for attributes" do
118
118
  expect(request_token_stub).to have_been_requested
@@ -126,7 +126,7 @@ describe Ably::Auth do
126
126
  let(:nonce) { random_str }
127
127
  let(:auth_options) { { key: "#{key_name}:#{key_secret}" } }
128
128
  let(:token_params) { { nonce: nonce, timestamp: Time.now } }
129
- let(:token_request) { auth.create_token_request(auth_options, token_params) }
129
+ let(:token_request) { auth.create_token_request(token_params, auth_options) }
130
130
  let(:mac) do
131
131
  hmac_for(token_request, key_secret)
132
132
  end
@@ -142,7 +142,7 @@ describe Ably::Auth do
142
142
  :headers => { 'Content-Type' => content_type })
143
143
  end
144
144
 
145
- let!(:token) { auth.request_token(auth_options, token_params) }
145
+ let!(:token) { auth.request_token(token_params, auth_options) }
146
146
 
147
147
  specify 'key_name is used in request and signing uses key_secret' do
148
148
  expect(request_token_stub).to have_been_requested
@@ -156,7 +156,7 @@ describe Ably::Auth do
156
156
 
157
157
  let(:auth_options) { { key_name: key_name, key_secret: key_secret } }
158
158
  let(:token_params) { { nonce: nonce, timestamp: Time.now } }
159
- let(:token_request) { auth.create_token_request(auth_options, token_params) }
159
+ let(:token_request) { auth.create_token_request(token_params, auth_options) }
160
160
  let(:mac) do
161
161
  hmac_for(token_request, key_secret)
162
162
  end
@@ -172,7 +172,7 @@ describe Ably::Auth do
172
172
  :headers => { 'Content-Type' => content_type })
173
173
  end
174
174
 
175
- let!(:token) { auth.request_token(auth_options, token_params) }
175
+ let!(:token) { auth.request_token(token_params, auth_options) }
176
176
 
177
177
  specify 'key_name is used in request and signing uses key_secret' do
178
178
  expect(request_token_stub).to have_been_requested
@@ -184,7 +184,7 @@ describe Ably::Auth do
184
184
 
185
185
  it 'queries the server for the time' do
186
186
  expect(client).to receive(:time).and_call_original
187
- auth.request_token(options)
187
+ auth.request_token({}, options)
188
188
  end
189
189
  end
190
190
 
@@ -193,7 +193,7 @@ describe Ably::Auth do
193
193
 
194
194
  it 'does not query the server for the time' do
195
195
  expect(client).to_not receive(:time)
196
- auth.request_token(options)
196
+ auth.request_token({}, options)
197
197
  end
198
198
  end
199
199
 
@@ -237,7 +237,7 @@ describe Ably::Auth do
237
237
  end
238
238
 
239
239
  context 'when response from :auth_url is a valid token request' do
240
- let!(:token) { auth.request_token(auth_options) }
240
+ let!(:token) { auth.request_token({}, auth_options) }
241
241
 
242
242
  it 'requests a token from :auth_url using an HTTP GET request' do
243
243
  expect(request_token_stub).to have_been_requested
@@ -290,7 +290,7 @@ describe Ably::Auth do
290
290
  }.to_json
291
291
  end
292
292
 
293
- let!(:token_details) { auth.request_token(auth_options) }
293
+ let!(:token_details) { auth.request_token({}, auth_options) }
294
294
 
295
295
  it 'returns TokenDetails created from the token JSON' do
296
296
  expect(auth_url_request_stub).to have_been_requested
@@ -308,7 +308,7 @@ describe Ably::Auth do
308
308
  let(:auth_url_content_type) { 'text/plain' }
309
309
  let(:auth_url_response) { token }
310
310
 
311
- let!(:token_details) { auth.request_token(auth_options) }
311
+ let!(:token_details) { auth.request_token({}, auth_options) }
312
312
 
313
313
  it 'returns TokenDetails created from the token JSON' do
314
314
  expect(auth_url_request_stub).to have_been_requested
@@ -325,7 +325,7 @@ describe Ably::Auth do
325
325
  end
326
326
 
327
327
  it 'raises ServerError' do
328
- expect { auth.request_token auth_options }.to raise_error(Ably::Exceptions::ServerError)
328
+ expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::ServerError)
329
329
  end
330
330
  end
331
331
 
@@ -336,7 +336,7 @@ describe Ably::Auth do
336
336
  end
337
337
 
338
338
  it 'raises InvalidResponseBody' do
339
- expect { auth.request_token auth_options }.to raise_error(Ably::Exceptions::InvalidResponseBody)
339
+ expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::InvalidResponseBody)
340
340
  end
341
341
  end
342
342
  end
@@ -350,12 +350,12 @@ describe Ably::Auth do
350
350
  Proc.new do |token_params_arg|
351
351
  @block_called = true
352
352
  expect(token_params_arg).to eq(token_params)
353
- auth.create_token_request(token_params: { client_id: client_id })
353
+ auth.create_token_request(client_id: client_id)
354
354
  end
355
355
  end
356
356
  let(:token_params) { { ttl: ttl } }
357
357
  let!(:request_token) do
358
- auth.request_token(auth_callback: auth_callback, token_params: token_params)
358
+ auth.request_token(token_params, auth_callback: auth_callback)
359
359
  end
360
360
 
361
361
  it 'calls the Proc with token_params when authenticating to obtain the request token' do
@@ -369,7 +369,7 @@ describe Ably::Auth do
369
369
 
370
370
  context 'that returns a TokenDetails JSON object' do
371
371
  let(:client_id) { random_str }
372
- let(:options) { { client_id: client_id } }
372
+ let(:token_params){ { client_id: client_id } }
373
373
  let(:token) { 'J_0Tlg.D7AVZkdOZW-PqNNGvCSp38' }
374
374
  let(:issued) { Time.now }
375
375
  let(:expires) { Time.now + 60}
@@ -377,7 +377,7 @@ describe Ably::Auth do
377
377
  let(:capability_str) { JSON.dump(capability) }
378
378
 
379
379
  let!(:token_details) do
380
- auth.request_token(auth_callback: Proc.new do |token_params_arg|
380
+ auth.request_token(token_params, auth_callback: Proc.new do |token_params_arg|
381
381
  @block_called = true
382
382
  @block_params = token_params_arg
383
383
  {
@@ -388,12 +388,12 @@ describe Ably::Auth do
388
388
  'expires' => expires.to_i * 1000,
389
389
  'capability'=> capability_str
390
390
  }
391
- end, token_params: options)
391
+ end)
392
392
  end
393
393
 
394
394
  it 'calls the Proc when authenticating to obtain the request token' do
395
395
  expect(@block_called).to eql(true)
396
- expect(@block_params).to include(options)
396
+ expect(@block_params).to include(token_params)
397
397
  end
398
398
 
399
399
  it 'uses the token request returned from the callback when requesting a new token' do
@@ -410,10 +410,8 @@ describe Ably::Auth do
410
410
  let(:client_id) { random_str }
411
411
 
412
412
  let!(:token_details) do
413
- auth.request_token(auth_callback: Proc.new do |block_options|
414
- auth.create_token_request(token_params: {
415
- client_id: client_id
416
- })
413
+ auth.request_token({}, auth_callback: Proc.new do |block_options|
414
+ auth.create_token_request(client_id: client_id)
417
415
  end)
418
416
  end
419
417
 
@@ -428,7 +426,7 @@ describe Ably::Auth do
428
426
  let(:token) { second_client.auth.request_token.token }
429
427
 
430
428
  let!(:token_details) do
431
- auth.request_token(auth_callback: Proc.new do |block_options|
429
+ auth.request_token({}, auth_callback: Proc.new do |block_options|
432
430
  token
433
431
  end)
434
432
  end
@@ -440,10 +438,9 @@ describe Ably::Auth do
440
438
  end
441
439
  end
442
440
 
443
- context 'persisted option', api_private: true do
441
+ context 'persisted option of token params', api_private: true do
444
442
  context 'when set to true', api_private: true do
445
- let(:options) { { persisted: true } }
446
- let(:token_details) { auth.request_token(token_params: options) }
443
+ let(:token_details) { auth.request_token(persisted: true) }
447
444
 
448
445
  it 'returns a token with a short token ID that is used to look up the token details' do
449
446
  expect(token_details.token.length).to be < 64
@@ -462,7 +459,7 @@ describe Ably::Auth do
462
459
 
463
460
  context 'with auth_option :client_id' do
464
461
  let(:client_id) { random_str }
465
- let(:token_details) { auth.request_token(client_id: client_id) }
462
+ let(:token_details) { auth.request_token({}, client_id: client_id) }
466
463
 
467
464
  it 'returns a token with the client_id' do
468
465
  expect(token_details.client_id).to eql(client_id)
@@ -471,7 +468,7 @@ describe Ably::Auth do
471
468
 
472
469
  context 'with token_param :client_id' do
473
470
  let(:client_id) { random_str }
474
- let(:token_details) { auth.request_token(token_params: { client_id: client_id }) }
471
+ let(:token_details) { auth.request_token(client_id: client_id) }
475
472
 
476
473
  it 'returns a token with the client_id' do
477
474
  expect(token_details.client_id).to eql(client_id)
@@ -495,8 +492,8 @@ describe Ably::Auth do
495
492
  end
496
493
 
497
494
  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
495
+ expect(auth).to receive(:request_token).with(token_params, auth_options)
496
+ auth.authorise token_params, auth_options
500
497
  end
501
498
 
502
499
  it 'returns a valid token' do
@@ -526,20 +523,26 @@ describe Ably::Auth do
526
523
  end
527
524
 
528
525
  it 'issues a new token if option :force => true' do
529
- expect { auth.authorise(force: true) }.to change { auth.current_token_details }
526
+ expect { auth.authorise({}, force: true) }.to change { auth.current_token_details }
530
527
  end
531
528
  end
532
529
 
533
- it 'updates the persisted auth options that are then used for subsequent authorise requests' do
534
- expect(auth.options[:ttl]).to_not eql(26)
530
+ it 'updates the persisted token params that are then used for subsequent authorise requests' do
531
+ expect(auth.token_params[:ttl]).to_not eql(26)
535
532
  auth.authorise(ttl: 26)
536
- expect(auth.options[:ttl]).to eql(26)
533
+ expect(auth.token_params[:ttl]).to eql(26)
534
+ end
535
+
536
+ it 'updates the persisted token params that are then used for subsequent authorise requests' do
537
+ expect(auth.options[:query_time]).to_not eql(true)
538
+ auth.authorise({}, query_time: true)
539
+ expect(auth.options[:query_time]).to eql(true)
537
540
  end
538
541
 
539
542
  context 'with a Proc for the :auth_callback option' do
540
543
  let(:client_id) { random_str }
541
544
  let!(:token) do
542
- auth.authorise(auth_callback: Proc.new do
545
+ auth.authorise({}, auth_callback: Proc.new do
543
546
  @block_called ||= 0
544
547
  @block_called += 1
545
548
  auth.create_token_request(client_id: client_id)
@@ -564,13 +567,41 @@ describe Ably::Auth do
564
567
 
565
568
  context 'with a provided block' do
566
569
  it 'does not call the originally provided Proc and calls the new #request_token :auth_callback Proc' do
567
- auth.request_token(auth_callback: Proc.new { @request_block_called = true; auth.create_token_request })
570
+ auth.request_token({}, auth_callback: Proc.new { @request_block_called = true; auth.create_token_request })
568
571
  expect(@block_called).to eql(1)
569
572
  expect(@request_block_called).to eql(true)
570
573
  end
571
574
  end
572
575
  end
573
576
  end
577
+
578
+ context 'with an explicit token string that expires' do
579
+ context 'and a Proc for the :auth_callback option to provide a means to renew the token' do
580
+ before do
581
+ # Ensure a soon to expire token is not treated as expired
582
+ stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0
583
+ old_token_defaults = Ably::Auth::TOKEN_DEFAULTS
584
+ stub_const 'Ably::Auth::TOKEN_DEFAULTS', old_token_defaults.merge(renew_token_buffer: 0)
585
+ end
586
+
587
+ let(:token_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, token_params: { ttl: 3 })) }
588
+ let(:client_options) {
589
+ default_options.merge(token: token_client.auth.request_token.token, auth_callback: Proc.new do
590
+ @block_called ||= 0
591
+ @block_called += 1
592
+ token_client.auth.create_token_request
593
+ end)
594
+ }
595
+
596
+ it 'calls the Proc once the token has expired and the new token is used' do
597
+ client.stats
598
+ expect(@block_called).to be_nil
599
+ sleep 3.5
600
+ expect { client.stats }.to change { client.auth.current_token_details }
601
+ expect(@block_called).to eql(1)
602
+ end
603
+ end
604
+ end
574
605
  end
575
606
 
576
607
  describe '#create_token_request' do
@@ -578,7 +609,7 @@ describe Ably::Auth do
578
609
  let(:capability) { { "foo" => ["publish"] } }
579
610
  let(:token_params) { Hash.new }
580
611
 
581
- subject { auth.create_token_request(token_params: token_params) }
612
+ subject { auth.create_token_request(token_params) }
582
613
 
583
614
  it 'returns a TokenRequest object' do
584
615
  expect(subject).to be_a(Ably::Models::TokenRequest)
@@ -666,11 +697,11 @@ describe Ably::Auth do
666
697
  let(:client) { Ably::Rest::Client.new(auth_url: 'http://example.com', protocol: protocol) }
667
698
 
668
699
  it 'should raise an exception if key secret is missing' do
669
- expect { auth.create_token_request(key_name: 'name') }.to raise_error Ably::Exceptions::TokenRequestFailed
700
+ expect { auth.create_token_request({}, key_name: 'name') }.to raise_error Ably::Exceptions::TokenRequestFailed
670
701
  end
671
702
 
672
703
  it 'should raise an exception if key name is missing' do
673
- expect { auth.create_token_request(key_secret: 'secret') }.to raise_error Ably::Exceptions::TokenRequestFailed
704
+ expect { auth.create_token_request({}, key_secret: 'secret') }.to raise_error Ably::Exceptions::TokenRequestFailed
674
705
  end
675
706
  end
676
707
 
@@ -679,7 +710,7 @@ describe Ably::Auth do
679
710
  let(:time) { Time.now - 30 }
680
711
  let(:auth_options) { { query_time: true } }
681
712
 
682
- subject { auth.create_token_request(auth_options) }
713
+ subject { auth.create_token_request({}, auth_options) }
683
714
 
684
715
  it 'queries the server for the timestamp' do
685
716
  expect(client).to receive(:time).and_return(time)
@@ -733,10 +764,10 @@ describe Ably::Auth do
733
764
  describe 'with :token option' do
734
765
  let(:ttl) { 60 * 60 }
735
766
  let(:token_details) do
736
- auth.request_token(token_params: {
767
+ auth.request_token(
737
768
  ttl: ttl,
738
769
  capability: capability
739
- })
770
+ )
740
771
  end
741
772
  let(:token) { token_details.token }
742
773
  let(:token_auth_client) do
@@ -756,7 +787,7 @@ describe Ably::Auth do
756
787
  end
757
788
 
758
789
  it 'fails if timestamp is invalid' do
759
- expect { auth.request_token(token_params: { timestamp: Time.now - 180 }) }.to raise_error do |error|
790
+ expect { auth.request_token(timestamp: Time.now - 180) }.to raise_error do |error|
760
791
  expect(error).to be_a(Ably::Exceptions::InvalidRequest)
761
792
  expect(error.status).to eql(401)
762
793
  expect(error.code).to eql(40101)