ably-rest 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/lib/submodules/ably-ruby/CHANGELOG.md +10 -0
  4. data/lib/submodules/ably-ruby/README.md +1 -1
  5. data/lib/submodules/ably-ruby/Rakefile +1 -1
  6. data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -20
  7. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +3 -0
  8. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +41 -0
  9. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +43 -0
  10. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +1 -1
  11. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +1 -1
  12. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +2 -1
  13. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +8 -6
  14. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +4 -0
  15. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +4 -1
  16. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +35 -4
  17. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +13 -13
  18. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +13 -5
  19. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +27 -7
  20. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +22 -12
  21. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +16 -10
  22. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -0
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +5 -4
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +42 -24
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +25 -17
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +4 -4
  27. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -2
  28. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +2 -2
  29. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +15 -0
  30. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  31. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +9 -9
  32. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
  33. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +168 -21
  34. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +6 -2
  35. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +6 -5
  36. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +29 -19
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +150 -35
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +146 -23
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +2 -2
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +44 -24
  41. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +1 -1
  42. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +1 -1
  43. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +77 -46
  44. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +31 -3
  45. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +15 -5
  46. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +9 -7
  47. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +30 -4
  48. data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +9 -6
  49. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +1 -1
  50. data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +44 -0
  51. data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +54 -0
  52. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +8 -0
  53. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +1 -1
  54. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +18 -0
  55. metadata +6 -2
@@ -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,10 +181,14 @@ 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))
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
+ let(:rest_client) do
189
+ Ably::Rest::Client.new(default_options)
190
+ end
191
+
188
192
  it 'will not echo messages to the client but will still broadcast messages to other connected clients', em_timeout: 10 do
189
193
  channel.attach do |echo_channel|
190
194
  no_echo_channel.attach do
@@ -196,13 +200,27 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
196
200
 
197
201
  echo_channel.subscribe('test_event') do |message|
198
202
  expect(message.data).to eql(payload)
199
- EventMachine.add_timer(1) do
203
+ EventMachine.add_timer(1.5) do
200
204
  stop_reactor
201
205
  end
202
206
  end
203
207
  end
204
208
  end
205
209
  end
210
+
211
+ it 'will not echo messages to the client from other REST clients publishing using that connection_ID', em_timeout: 10 do
212
+ skip 'Waiting on realtime#285 to be resolved'
213
+ no_echo_channel.attach do
214
+ no_echo_channel.subscribe('test_event') do |message|
215
+ fail "Message should not have been echoed back"
216
+ end
217
+
218
+ rest_client.channel(channel_name).publish('test_event', nil, connection_id: no_echo_client.connection.id)
219
+ EventMachine.add_timer(1.5) do
220
+ stop_reactor
221
+ end
222
+ end
223
+ end
206
224
  end
207
225
  end
208
226
 
@@ -257,7 +275,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
257
275
 
258
276
  context 'without suitable publishing permissions' do
259
277
  let(:restricted_client) do
260
- Ably::Realtime::Client.new(options.merge(key: restricted_api_key, environment: environment, protocol: protocol))
278
+ auto_close Ably::Realtime::Client.new(options.merge(key: restricted_api_key, environment: environment, protocol: protocol, :log_level => :error))
261
279
  end
262
280
  let(:restricted_channel) { restricted_client.channel("cansubscribe:example") }
263
281
  let(:payload) { 'Test message without permission to publish' }
@@ -265,8 +283,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
265
283
  it 'calls the error callback' do
266
284
  restricted_channel.attach do
267
285
  deferrable = restricted_channel.publish('test_event', payload)
268
- deferrable.errback do |message, error|
269
- expect(message.data).to eql(payload)
286
+ deferrable.errback do |error|
270
287
  expect(error.status).to eql(401)
271
288
  stop_reactor
272
289
  end
@@ -400,31 +417,39 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
400
417
  let(:encrypted_channel_client1) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
401
418
  let(:encrypted_channel_client2) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
402
419
 
403
- let(:data) { MessagePack.pack({ 'key' => random_str }) }
420
+ let(:data) { { 'key' => random_str } }
404
421
  let(:message_count) { 50 }
405
422
 
406
423
  it 'encrypts and decrypts all messages' do
407
- messages_received = {
408
- decrypted: 0,
409
- encrypted: 0
410
- }
424
+ messages_received = []
411
425
 
412
- encrypted_channel_client2.attach do
413
- encrypted_channel_client2.subscribe do |message|
414
- 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)))
415
429
  expect(message.encoding).to be_nil
416
- messages_received[:decrypted] += 1
417
- stop_reactor if messages_received[:decrypted] == message_count
430
+ messages_received << message
431
+ stop_reactor if messages_received.count == message_count
418
432
  end
419
433
 
420
- encrypted_channel_client1.__incoming_msgbus__.subscribe(:message) do |message|
421
- expect(message['encoding']).to match(/cipher\+/)
422
- messages_received[:encrypted] += 1
434
+ message_count.times do |index|
435
+ encrypted_channel_client2.publish index.to_s, MessagePack.pack(data.merge(index: index))
423
436
  end
424
437
  end
438
+ end
425
439
 
426
- message_count.times do |index|
427
- encrypted_channel_client2.publish index.to_s, "#{index}-#{data}"
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
451
+
452
+ encrypted_channel_client2.publish 'name', MessagePack.pack('data')
428
453
  end
429
454
  end
430
455
  end
@@ -432,7 +457,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
432
457
  context 'subscribing with a different transport protocol' do
433
458
  let(:other_protocol) { protocol == :msgpack ? :json : :msgpack }
434
459
  let(:other_client) do
435
- Ably::Realtime::Client.new(default_options.merge(protocol: other_protocol))
460
+ auto_close Ably::Realtime::Client.new(default_options.merge(protocol: other_protocol))
436
461
  end
437
462
 
438
463
  let(:cipher_options) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
@@ -569,5 +594,103 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
569
594
  end
570
595
  end
571
596
  end
597
+
598
+ describe 'when message is published, the connection disconnects before the ACK is received, and the connection is resumed' do
599
+ let(:event_name) { random_str }
600
+ let(:message_state) { [] }
601
+ let(:connection) { client.connection }
602
+ let(:client_options) { default_options.merge(:log_level => :none) }
603
+ let(:msgs_received) { [] }
604
+
605
+ it 'publishes the message again, later receives the ACK and only one message is ever received from Ably' do
606
+ on_reconnected = Proc.new do
607
+ expect(message_state).to be_empty
608
+ EventMachine.add_timer(2) do
609
+ expect(message_state).to contain_exactly(:delivered)
610
+ # TODO: Uncomment once issue realtime#42 is resolved
611
+ # expect(msgs_received.length).to eql(1)
612
+ stop_reactor
613
+ end
614
+ end
615
+
616
+ connection.once(:connected) do
617
+ connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
618
+ if protocol_message.messages.find { |message| message.name == event_name }
619
+ EventMachine.add_timer(0.001) do
620
+ connection.transport.unbind # trigger failure
621
+ expect(message_state).to be_empty
622
+ connection.once :connected, &on_reconnected
623
+ end
624
+ end
625
+ end
626
+ end
627
+
628
+ channel.publish(event_name).tap do |deferrable|
629
+ deferrable.callback { message_state << :delivered }
630
+ deferrable.errback do
631
+ raise 'Message delivery should not fail'
632
+ end
633
+ end
634
+
635
+ channel.subscribe do |message|
636
+ msgs_received << message
637
+ end
638
+ end
639
+ end
640
+
641
+ describe 'when message is published, the connection disconnects before the ACK is received' do
642
+ let(:connection) { client.connection }
643
+ let(:event_name) { random_str }
644
+
645
+ describe 'the connection becomes suspended' do
646
+ let(:client_options) { default_options.merge(:log_level => :fatal) }
647
+
648
+ it 'calls the errback for all messages' do
649
+ connection.once(:connected) do
650
+ connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
651
+ if protocol_message.messages.find { |message| message.name == event_name }
652
+ EventMachine.add_timer(0.001) do
653
+ connection.transition_state_machine :suspended
654
+ end
655
+ end
656
+ end
657
+ end
658
+
659
+ channel.publish(event_name).tap do |deferrable|
660
+ deferrable.callback do
661
+ raise 'Message delivery should not happen'
662
+ end
663
+ deferrable.errback do
664
+ stop_reactor
665
+ end
666
+ end
667
+ end
668
+ end
669
+
670
+ describe 'the connection becomes failed' do
671
+ let(:client_options) { default_options.merge(:log_level => :none) }
672
+
673
+ it 'calls the errback for all messages' do
674
+ connection.once(:connected) do
675
+ connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
676
+ if protocol_message.messages.find { |message| message.name == event_name }
677
+ EventMachine.add_timer(0.001) do
678
+ connection.transition_state_machine :failed, reason: RuntimeError.new
679
+ end
680
+ end
681
+ end
682
+ end
683
+
684
+ channel.publish(event_name).tap do |deferrable|
685
+ deferrable.callback do
686
+ raise 'Message delivery should not happen'
687
+ end
688
+ deferrable.errback do
689
+ stop_reactor
690
+ end
691
+ end
692
+ end
693
+ end
694
+ end
572
695
  end
573
696
  end
@@ -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) }
@@ -40,18 +40,29 @@ describe Ably::Realtime::Presence, :event_machine do
40
40
  end
41
41
 
42
42
  unless expected_state == :left
43
- %w(detached failed).each do |state|
44
- it "raise an exception if the channel is #{state}" do
45
- setup_test(method_name, args, options) do
46
- channel_client_one.attach do
47
- channel_client_one.change_state state.to_sym
48
- expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.#{state}/i
43
+ it 'raise an exception if the channel is detached' do
44
+ setup_test(method_name, args, options) do
45
+ channel_client_one.attach do
46
+ channel_client_one.transition_state_machine :detaching
47
+ channel_client_one.once(:detached) do
48
+ expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.detached/i
49
49
  stop_reactor
50
50
  end
51
51
  end
52
52
  end
53
53
  end
54
54
 
55
+ it 'raise an exception if the channel is failed' do
56
+ setup_test(method_name, args, options) do
57
+ channel_client_one.attach do
58
+ channel_client_one.transition_state_machine :failed
59
+ expect(channel_client_one.state).to eq(:failed)
60
+ expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.failed/i
61
+ stop_reactor
62
+ end
63
+ end
64
+ end
65
+
55
66
  it 'implicitly attaches the channel' do
56
67
  expect(channel_client_one).to_not be_attached
57
68
  presence_client_one.public_send(method_name, args) do
@@ -61,7 +72,7 @@ describe Ably::Realtime::Presence, :event_machine do
61
72
  end
62
73
 
63
74
  context 'when :queue_messages client option is false' do
64
- 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)) }
65
76
 
66
77
  context 'and connection state initialized' do
67
78
  it 'raises an exception' do
@@ -83,7 +94,7 @@ describe Ably::Realtime::Presence, :event_machine do
83
94
  end
84
95
 
85
96
  context 'and connection state disconnected' do
86
- 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)) }
87
98
 
88
99
  it 'raises an exception' do
89
100
  client_one.connection.once(:connected) do
@@ -266,8 +277,7 @@ describe Ably::Realtime::Presence, :event_machine do
266
277
 
267
278
  presence_client_one.public_send(method_name, args).tap do |deferrable|
268
279
  deferrable.callback { raise 'Should not succeed' }
269
- deferrable.errback do |presence, error|
270
- expect(presence).to be_a(Ably::Realtime::Presence)
280
+ deferrable.errback do |error|
271
281
  expect(error).to be_kind_of(Ably::Exceptions::BaseAblyException)
272
282
  stop_reactor
273
283
  end
@@ -652,7 +662,7 @@ describe Ably::Realtime::Presence, :event_machine do
652
662
 
653
663
  context 'without necessary capabilities to join presence' do
654
664
  let(:restricted_client) do
655
- 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))
656
666
  end
657
667
  let(:restricted_channel) { restricted_client.channel("cansubscribe:channel") }
658
668
  let(:restricted_presence) { restricted_channel.presence }
@@ -869,7 +879,7 @@ describe Ably::Realtime::Presence, :event_machine do
869
879
 
870
880
  context 'without necessary capabilities to enter on behalf of another client' do
871
881
  let(:restricted_client) do
872
- 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))
873
883
  end
874
884
  let(:restricted_channel) { restricted_client.channel("cansubscribe:channel") }
875
885
  let(:restricted_presence) { restricted_channel.presence }
@@ -1061,16 +1071,25 @@ describe Ably::Realtime::Presence, :event_machine do
1061
1071
  presence_client_one.get { raise 'Intentional exception' }
1062
1072
  end
1063
1073
 
1064
- %w(detached failed).each do |state|
1065
- it "raise an exception if the channel is #{state}" do
1066
- channel_client_one.attach do
1067
- channel_client_one.change_state state.to_sym
1068
- expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.#{state}/i
1074
+ it 'raise an exception if the channel is detached' do
1075
+ channel_client_one.attach do
1076
+ channel_client_one.transition_state_machine :detaching
1077
+ channel_client_one.once(:detached) do
1078
+ expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.detached/i
1069
1079
  stop_reactor
1070
1080
  end
1071
1081
  end
1072
1082
  end
1073
1083
 
1084
+ it 'raise an exception if the channel is failed' do
1085
+ channel_client_one.attach do
1086
+ channel_client_one.transition_state_machine :failed
1087
+ expect(channel_client_one.state).to eq(:failed)
1088
+ expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.failed/i
1089
+ stop_reactor
1090
+ end
1091
+ end
1092
+
1074
1093
  context 'during a sync' do
1075
1094
  let(:pages) { 2 }
1076
1095
  let(:members_per_page) { 100 }
@@ -1120,8 +1139,8 @@ describe Ably::Realtime::Presence, :event_machine do
1120
1139
  if protocol_message.action == :sync
1121
1140
  # prevent any more SYNC messages coming through
1122
1141
  client_two.connection.transport.__incoming_protocol_msgbus__.unsubscribe
1123
- channel_client_two.change_state :detaching
1124
- channel_client_two.change_state :detached
1142
+ channel_client_two.transition_state_machine :detaching
1143
+ channel_client_two.transition_state_machine :detached
1125
1144
  end
1126
1145
  end
1127
1146
  end
@@ -1380,7 +1399,7 @@ describe Ably::Realtime::Presence, :event_machine do
1380
1399
  let(:client_id) { random_str.encode(Encoding::ASCII_8BIT) }
1381
1400
 
1382
1401
  context 'in connection set up' do
1383
- 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)) }
1384
1403
 
1385
1404
  it 'is converted into UTF_8' do
1386
1405
  presence_client_one.enter
@@ -1393,7 +1412,7 @@ describe Ably::Realtime::Presence, :event_machine do
1393
1412
  end
1394
1413
 
1395
1414
  context 'in channel options' do
1396
- let(:client_one) { Ably::Realtime::Client.new(default_options) }
1415
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options) }
1397
1416
 
1398
1417
  it 'is converted into UTF_8' do
1399
1418
  presence_client_one.enter(client_id: client_id)
@@ -1565,6 +1584,7 @@ describe Ably::Realtime::Presence, :event_machine do
1565
1584
  context 'connection failure mid-way through a large member sync' do
1566
1585
  let(:members_count) { 400 }
1567
1586
  let(:sync_pages_received) { [] }
1587
+ let(:client_options) { default_options.merge(log_level: :error) }
1568
1588
 
1569
1589
  it 'resumes the SYNC operation', em_timeout: 15 do
1570
1590
  when_all(*members_count.times.map do |index|
@@ -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)