ably-rest 1.1.2 → 1.2.2

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/CHANGELOG.md +1 -1
  4. data/MAINTAINERS.md +1 -0
  5. data/README.md +4 -2
  6. data/ably-rest.gemspec +15 -18
  7. data/lib/ably-rest.rb +2 -0
  8. data/lib/submodules/ably-ruby/.github/workflows/check.yml +50 -0
  9. data/lib/submodules/ably-ruby/CHANGELOG.md +200 -0
  10. data/lib/submodules/ably-ruby/COPYRIGHT +1 -0
  11. data/lib/submodules/ably-ruby/LICENSE +172 -11
  12. data/lib/submodules/ably-ruby/MAINTAINERS.md +1 -0
  13. data/lib/submodules/ably-ruby/README.md +24 -22
  14. data/lib/submodules/ably-ruby/SPEC.md +1020 -929
  15. data/lib/submodules/ably-ruby/UPDATING.md +30 -0
  16. data/lib/submodules/ably-ruby/ably.gemspec +16 -23
  17. data/lib/submodules/ably-ruby/lib/ably/agent.rb +3 -0
  18. data/lib/submodules/ably-ruby/lib/ably/auth.rb +20 -10
  19. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +8 -2
  20. data/lib/submodules/ably-ruby/lib/ably/logger.rb +4 -4
  21. data/lib/submodules/ably-ruby/lib/ably/models/channel_details.rb +59 -0
  22. data/lib/submodules/ably-ruby/lib/ably/models/channel_metrics.rb +84 -0
  23. data/lib/submodules/ably-ruby/lib/ably/models/channel_occupancy.rb +43 -0
  24. data/lib/submodules/ably-ruby/lib/ably/models/channel_options.rb +97 -0
  25. data/lib/submodules/ably-ruby/lib/ably/models/channel_status.rb +53 -0
  26. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +8 -0
  27. data/lib/submodules/ably-ruby/lib/ably/models/delta_extras.rb +29 -0
  28. data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +1 -1
  29. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +6 -2
  30. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
  31. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +28 -3
  32. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +14 -0
  33. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +31 -14
  34. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +7 -2
  35. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +1 -1
  36. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +11 -1
  37. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +22 -2
  38. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +34 -0
  39. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +2 -2
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +19 -7
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_properties.rb +24 -0
  42. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
  43. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +6 -0
  44. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +56 -28
  45. data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +1 -1
  46. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
  47. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +9 -0
  48. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +13 -4
  49. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
  50. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +67 -1
  51. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +6 -5
  52. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +0 -14
  53. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +44 -29
  54. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +60 -29
  55. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +1 -1
  56. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -1
  57. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +1 -1
  58. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +5 -2
  59. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +1 -1
  60. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +1 -1
  61. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +1 -1
  62. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +1 -1
  63. data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -14
  64. data/lib/submodules/ably-ruby/lib/ably.rb +1 -0
  65. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +4 -4
  66. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +25 -0
  67. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +476 -21
  68. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +59 -7
  69. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +72 -16
  70. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +85 -13
  71. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +301 -34
  72. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +77 -0
  73. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +3 -59
  74. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +84 -158
  75. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +3 -19
  76. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +24 -75
  77. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +8 -4
  78. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +141 -10
  79. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -6
  80. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +146 -47
  81. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +61 -3
  82. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +3 -19
  83. data/lib/submodules/ably-ruby/spec/lib/unit/models/channel_options_spec.rb +52 -0
  84. data/lib/submodules/ably-ruby/spec/run_parallel_tests +2 -7
  85. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +131 -8
  86. data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +1 -1
  87. data/lib/submodules/ably-ruby/spec/spec_helper.rb +12 -2
  88. data/lib/submodules/ably-ruby/spec/support/serialization_helper.rb +21 -0
  89. data/lib/submodules/ably-ruby/spec/support/test_app.rb +3 -3
  90. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +6 -14
  91. data/lib/submodules/ably-ruby/spec/unit/models/channel_details_spec.rb +30 -0
  92. data/lib/submodules/ably-ruby/spec/unit/models/channel_metrics_spec.rb +42 -0
  93. data/lib/submodules/ably-ruby/spec/unit/models/channel_occupancy_spec.rb +17 -0
  94. data/lib/submodules/ably-ruby/spec/unit/models/channel_status_spec.rb +36 -0
  95. data/lib/submodules/ably-ruby/spec/unit/models/delta_extras_spec.rb +14 -0
  96. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +17 -1
  97. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +97 -0
  98. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +49 -0
  99. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +125 -27
  100. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +14 -0
  101. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +3 -2
  102. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +53 -15
  103. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +19 -6
  104. data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
  105. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +44 -1
  106. data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +81 -14
  107. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +47 -0
  108. data/spec/spec_helper.rb +5 -0
  109. data/spec/unit/client_spec.rb +30 -0
  110. metadata +88 -25
  111. data/lib/submodules/ably-ruby/.travis.yml +0 -19
@@ -498,7 +498,9 @@ describe Ably::Realtime::Presence, :event_machine do
498
498
  end
499
499
 
500
500
  presence_client_one.enter do
501
- presence_client_one.leave
501
+ EventMachine.add_timer(0.5) do
502
+ presence_client_one.leave
503
+ end
502
504
  end
503
505
  end
504
506
  end
@@ -705,7 +707,7 @@ describe Ably::Realtime::Presence, :event_machine do
705
707
 
706
708
  context '#sync_complete? and SYNC flags (#RTP1)' do
707
709
  context 'when attaching to a channel without any members present' do
708
- it 'sync_complete? is true, there is no presence flag, and the presence channel is considered synced immediately (#RTP1)' do
710
+ xit 'sync_complete? is true, there is no presence flag, and the presence channel is considered synced immediately (#RTP1)' do
709
711
  flag_checked = false
710
712
 
711
713
  anonymous_client.connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
@@ -1211,10 +1213,11 @@ describe Ably::Realtime::Presence, :event_machine do
1211
1213
  channel_client_one.attach do
1212
1214
  presence_client_one.subscribe(:enter) do
1213
1215
  presence_client_one.unsubscribe :enter
1214
-
1215
- expect(presence_client_one.members).to be_in_sync
1216
- expect(presence_client_one.members.send(:members).count).to eql(1)
1217
- presence_client_one.leave data
1216
+ EventMachine.add_timer(0.5) do
1217
+ expect(presence_client_one.members).to be_in_sync
1218
+ expect(presence_client_one.members.send(:members).count).to eql(1)
1219
+ presence_client_one.leave data
1220
+ end
1218
1221
  end
1219
1222
 
1220
1223
  presence_client_one.enter(enter_data) do
@@ -2137,16 +2140,18 @@ describe Ably::Realtime::Presence, :event_machine do
2137
2140
  end
2138
2141
 
2139
2142
  it 'emits an error when cipher does not match and presence data cannot be decoded' do
2140
- incompatible_encrypted_channel.attach do
2143
+ incompatible_encrypted_channel.once(:attached) do
2141
2144
  expect(client_two.logger).to receive(:error) do |*args, &block|
2142
2145
  expect(args.concat([block ? block.call : nil]).join(',')).to match(/Cipher algorithm AES-128-CBC does not match/)
2143
2146
  stop_reactor
2144
- end
2147
+ end.at_least(:once)
2145
2148
 
2146
2149
  encrypted_channel.attach do
2147
2150
  encrypted_channel.presence.enter data
2148
2151
  end
2149
2152
  end
2153
+
2154
+ incompatible_encrypted_channel.attach
2150
2155
  end
2151
2156
  end
2152
2157
  end
@@ -2449,173 +2454,77 @@ describe Ably::Realtime::Presence, :event_machine do
2449
2454
  end
2450
2455
  end
2451
2456
 
2452
- context 'when a channel becomes attached again' do
2453
- let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached.to_i }
2454
- let(:sync_action) { Ably::Models::ProtocolMessage::ACTION.Sync.to_i }
2455
- let(:presence_action) { Ably::Models::ProtocolMessage::ACTION.Presence.to_i }
2456
- let(:present_action) { Ably::Models::PresenceMessage::ACTION.Present.to_i }
2457
- let(:resume_flag) { 4 }
2458
- let(:presence_flag) { 1 }
2459
-
2460
- def fabricate_incoming_protocol_message(protocol_message)
2461
- client_one.connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
2462
- end
2463
-
2464
- # Prevents any messages from the WebSocket transport being sent / received
2465
- # Connection protocol message subscriptions are still active, but nothing reaches or comes from the WebSocket transport
2466
- def cripple_websocket_transport
2467
- client_one.connection.transport.__incoming_protocol_msgbus__.unsubscribe
2468
- client_one.connection.transport.__outgoing_protocol_msgbus__.unsubscribe
2469
- end
2457
+ describe '#RTP17b' do
2458
+ let(:leave_action) { Ably::Models::PresenceMessage::ACTION.Leave }
2470
2459
 
2471
- context 'and the resume flag is true' do
2472
- context 'and the presence flag is false' do
2473
- it 'does not send any presence events as the PresenceMap is in sync (#RTP5c1)' do
2474
- presence_client_one.enter
2475
- presence_client_one.subscribe(:enter) do
2476
- presence_client_one.unsubscribe :enter
2477
-
2478
- client_one.connection.transport.__outgoing_protocol_msgbus__.subscribe do |message|
2479
- raise "No presence state updates to Ably are expected. Message sent: #{message.to_json}" if client_one.connection.connected?
2460
+ it 'updates presence members on leave' do
2461
+ presence_client_two.subscribe(:enter) do
2462
+ channel_anonymous_client.attach do
2463
+ channel_anonymous_client.presence.get do |members|
2464
+ presence_client_two.subscribe(:leave) do
2465
+ expect(presence_client_two.members.local_members).to be_empty
2466
+ stop_reactor
2480
2467
  end
2481
2468
 
2482
- cripple_websocket_transport
2483
-
2484
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2485
- action: attached_action,
2486
- channel: channel_name,
2487
- flags: resume_flag
2469
+ leave_message = Ably::Models::PresenceMessage.new(
2470
+ 'id' => "#{client_two.connection.id}:#{presence_client_two.client_id}:1",
2471
+ 'clientId' => presence_client_two.client_id,
2472
+ 'connectionId' => client_two.connection.id,
2473
+ 'timestamp' => as_since_epoch(Time.now),
2474
+ 'action' => leave_action
2488
2475
  )
2489
2476
 
2490
- EventMachine.add_timer(1) do
2491
- presence_client_one.get do |members|
2492
- expect(members.length).to eql(1)
2493
- expect(presence_client_one.members.local_members.length).to eql(1)
2494
- stop_reactor
2495
- end
2496
- end
2477
+ presence_client_two.__incoming_msgbus__.publish :presence, leave_message
2497
2478
  end
2498
2479
  end
2499
2480
  end
2500
2481
 
2501
- context 'and the presence flag is true' do
2502
- context 'and following the SYNC all local MemberMap members are present in the PresenceMap' do
2503
- it 'does nothing as MemberMap is in sync (#RTP5c2)' do
2504
- presence_client_one.enter
2505
- presence_client_one.subscribe(:enter) do
2506
- presence_client_one.unsubscribe :enter
2507
-
2508
- expect(presence_client_one.members.length).to eql(1)
2509
- expect(presence_client_one.members.local_members.length).to eql(1)
2510
-
2511
- presence_client_one.members.once(:in_sync) do
2512
- presence_client_one.get do |members|
2513
- expect(members.length).to eql(1)
2514
- expect(presence_client_one.members.local_members.length).to eql(1)
2515
- stop_reactor
2516
- end
2517
- end
2518
-
2519
- client_one.connection.transport.__outgoing_protocol_msgbus__.subscribe do |message|
2520
- raise "No presence state updates to Ably are expected. Message sent: #{message.to_json}" if client_one.connection.connected?
2521
- end
2482
+ presence_client_two.enter
2483
+ end
2522
2484
 
2523
- cripple_websocket_transport
2485
+ it 'does no update presence members on fabricated leave' do
2486
+ presence_client_two.subscribe(:enter) do
2487
+ channel_anonymous_client.attach do
2488
+ channel_anonymous_client.presence.get do |members|
2489
+ presence_client_two.subscribe(:leave) do
2490
+ expect(presence_client_two.members.local_members).to_not be_empty
2491
+ stop_reactor
2492
+ end
2524
2493
 
2525
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2526
- action: attached_action,
2527
- channel: channel_name,
2528
- flags: resume_flag + presence_flag
2529
- )
2494
+ fabricated_leave_message = Ably::Models::PresenceMessage.new(
2495
+ 'id' => "#{client_two.connection.id}:#{presence_client_two.client_id}:1",
2496
+ 'clientId' => presence_client_two.client_id,
2497
+ 'connectionId' => "fabricated:#{presence_client_two.client_id}:0",
2498
+ 'timestamp' => as_since_epoch(Time.now),
2499
+ 'action' => leave_action
2500
+ )
2530
2501
 
2531
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2532
- action: sync_action,
2533
- channel: channel_name,
2534
- presence: presence_client_one.members.map(&:shallow_clone).map(&:as_json),
2535
- channelSerial: nil # no further SYNC messages expected
2536
- )
2537
- end
2502
+ presence_client_two.__incoming_msgbus__.publish :presence, fabricated_leave_message
2538
2503
  end
2539
2504
  end
2505
+ end
2540
2506
 
2541
- context 'and following the SYNC a local MemberMap member is not present in the PresenceMap' do
2542
- it 're-enters the missing members automatically (#RTP5c2)' do
2543
- sync_check_completed = false
2544
-
2545
- presence_client_one.enter
2546
- presence_client_one.subscribe(:enter) do
2547
- presence_client_one.unsubscribe :enter
2548
-
2549
- expect(presence_client_one.members.length).to eql(1)
2550
- expect(presence_client_one.members.local_members.length).to eql(1)
2551
-
2552
- client_one.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |message|
2553
- next if message.action == :close # ignore finalization of connection
2554
-
2555
- expect(message.action).to eq(:presence)
2556
- presence_message = message.presence.first
2557
- expect(presence_message.action).to eq(:enter)
2558
- expect(presence_message.client_id).to eq(client_one.auth.client_id)
2559
-
2560
- presence_client_one.subscribe(:enter) do |message|
2561
- expect(message.connection_id).to eql(client_one.connection.id)
2562
- expect(message.client_id).to eq(client_one.auth.client_id)
2563
-
2564
- EventMachine.next_tick do
2565
- expect(presence_client_one.members.length).to eql(2)
2566
- expect(presence_client_one.members.local_members.length).to eql(1)
2567
- expect(sync_check_completed).to be_truthy
2568
- stop_reactor
2569
- end
2570
- end
2571
-
2572
- # Fabricate Ably sending back the Enter PresenceMessage to the client a short while after
2573
- # ensuring the PresenceMap for a short period does not have this member as to be expected in reality
2574
- EventMachine.add_timer(0.2) do
2575
- connection_id = random_str
2576
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2577
- action: presence_action,
2578
- channel: channel_name,
2579
- connectionId: client_one.connection.id,
2580
- connectionSerial: 50,
2581
- timestamp: as_since_epoch(Time.now),
2582
- presence: [presence_message.shallow_clone(id: "#{client_one.connection.id}:0:0", timestamp: as_since_epoch(Time.now)).as_json]
2583
- )
2584
- end
2585
- end
2586
-
2587
- presence_client_one.members.once(:in_sync) do
2588
- # For a brief period, the client will have re-entered the missing members from the local_members
2589
- # but the enter from Ably will have not been received, so at this point the local_members will be empty
2590
- presence_client_one.get do |members|
2591
- expect(members.length).to eql(1)
2592
- expect(members.first.connection_id).to_not eql(client_one.connection.id)
2593
- expect(presence_client_one.members.local_members.length).to eql(0)
2594
- sync_check_completed = true
2595
- end
2596
- end
2507
+ presence_client_two.enter
2508
+ end
2509
+ end
2597
2510
 
2598
- cripple_websocket_transport
2511
+ context 'when a channel becomes attached again' do
2512
+ let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached.to_i }
2513
+ let(:sync_action) { Ably::Models::ProtocolMessage::ACTION.Sync.to_i }
2514
+ let(:presence_action) { Ably::Models::ProtocolMessage::ACTION.Presence.to_i }
2515
+ let(:present_action) { Ably::Models::PresenceMessage::ACTION.Present.to_i }
2516
+ let(:resume_flag) { 4 }
2517
+ let(:presence_flag) { 1 }
2599
2518
 
2600
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2601
- action: attached_action,
2602
- channel: channel_name,
2603
- flags: resume_flag + presence_flag
2604
- )
2519
+ def fabricate_incoming_protocol_message(protocol_message)
2520
+ client_one.connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
2521
+ end
2605
2522
 
2606
- # Complete the SYNC but without the member who was entered by this client
2607
- connection_id = random_str
2608
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2609
- action: sync_action,
2610
- channel: channel_name,
2611
- timestamp: as_since_epoch(Time.now),
2612
- presence: [{ id: "#{connection_id}:0:0", action: present_action, connection_id: connection_id, client_id: random_str }],
2613
- chanenlSerial: nil # no further SYNC messages expected
2614
- )
2615
- end
2616
- end
2617
- end
2618
- end
2523
+ # Prevents any messages from the WebSocket transport being sent / received
2524
+ # Connection protocol message subscriptions are still active, but nothing reaches or comes from the WebSocket transport
2525
+ def cripple_websocket_transport
2526
+ client_one.connection.transport.__incoming_protocol_msgbus__.unsubscribe
2527
+ client_one.connection.transport.__outgoing_protocol_msgbus__.unsubscribe
2619
2528
  end
2620
2529
 
2621
2530
  context 'and the resume flag is false' do
@@ -2725,7 +2634,24 @@ describe Ably::Realtime::Presence, :event_machine do
2725
2634
  end
2726
2635
  end
2727
2636
 
2728
- context 'channel state side effects' do
2637
+ context 'channel state side effects (RTP5)' do
2638
+ context 'channel transitions to the ATTACHED state (RTP5b)' do
2639
+ it 'all queued presence messages are sent' do
2640
+ channel_client_one.on(:attached) do
2641
+ client_one.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2642
+ if protocol_message.action == :presence
2643
+ expect(protocol_message.action).to eq(:presence)
2644
+ stop_reactor
2645
+ end
2646
+ end
2647
+ end
2648
+
2649
+ presence_client_one.enter do
2650
+ channel_client_one.attach
2651
+ end
2652
+ end
2653
+ end
2654
+
2729
2655
  context 'channel transitions to the FAILED state' do
2730
2656
  let(:anonymous_client) { auto_close Ably::Realtime::Client.new(client_options.merge(log_level: :fatal)) }
2731
2657
  let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(client_id: client_one_id, log_level: :fatal)) }
@@ -101,31 +101,15 @@ describe Ably::Realtime::Push::Admin, :event_machine do
101
101
  end
102
102
  end
103
103
 
104
- def request_body(request, protocol)
105
- if protocol == :msgpack
106
- MessagePack.unpack(request.body)
107
- else
108
- JSON.parse(request.body)
109
- end
110
- end
111
-
112
- def serialize(object, protocol)
113
- if protocol == :msgpack
114
- MessagePack.pack(object)
115
- else
116
- JSON.dump(object)
117
- end
118
- end
119
-
120
104
  let!(:publish_stub) do
121
105
  stub_request(:post, "#{client.rest_client.endpoint}/push/publish").
122
106
  with do |request|
123
- expect(request_body(request, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
124
- expect(request_body(request, protocol)['recipient']).to_not have_key('camel_case')
107
+ expect(deserialize_body(request.body, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
108
+ expect(deserialize_body(request.body, protocol)['recipient']).to_not have_key('camel_case')
125
109
  true
126
110
  end.to_return(
127
111
  :status => 201,
128
- :body => serialize({}, protocol),
112
+ :body => serialize_body({}, protocol),
129
113
  :headers => { 'Content-Type' => content_type }
130
114
  )
131
115
  end
@@ -41,22 +41,10 @@ describe Ably::Auth do
41
41
  end
42
42
 
43
43
  def request_body_includes(request, protocol, key, val)
44
- body = if protocol == :msgpack
45
- MessagePack.unpack(request.body)
46
- else
47
- JSON.parse(request.body)
48
- end
44
+ body = deserialize_body(request.body, protocol)
49
45
  body[convert_to_mixed_case(key)].to_s == val.to_s
50
46
  end
51
47
 
52
- def serialize(object, protocol)
53
- if protocol == :msgpack
54
- MessagePack.pack(object)
55
- else
56
- JSON.dump(object)
57
- end
58
- end
59
-
60
48
  it 'has immutable options' do
61
49
  expect { auth.options['key_name'] = 'new_name' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
62
50
  end
@@ -74,7 +62,7 @@ describe Ably::Auth do
74
62
 
75
63
  it 'creates a TokenRequest automatically and sends it to Ably to obtain a token', webmock: true do
76
64
  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 })
65
+ to_return(status: 201, body: serialize_body({}, protocol), headers: { 'Content-Type' => content_type })
78
66
  expect(auth).to receive(:create_token_request).and_call_original
79
67
  auth.request_token
80
68
 
@@ -107,7 +95,7 @@ describe Ably::Auth do
107
95
  request_body_includes(request, protocol, token_param, coerce_if_time_value(token_param, random, multiply: 1000))
108
96
  end.to_return(
109
97
  :status => 201,
110
- :body => serialize(token_response, protocol),
98
+ :body => serialize_body(token_response, protocol),
111
99
  :headers => { 'Content-Type' => content_type }
112
100
  )
113
101
  end
@@ -138,7 +126,7 @@ describe Ably::Auth do
138
126
  request_body_includes(request, protocol, 'mac', mac)
139
127
  end.to_return(
140
128
  :status => 201,
141
- :body => serialize(token_response, protocol),
129
+ :body => serialize_body(token_response, protocol),
142
130
  :headers => { 'Content-Type' => content_type })
143
131
  end
144
132
 
@@ -168,7 +156,7 @@ describe Ably::Auth do
168
156
  request_body_includes(request, protocol, 'mac', mac)
169
157
  end.to_return(
170
158
  :status => 201,
171
- :body => serialize(token_response, protocol),
159
+ :body => serialize_body(token_response, protocol),
172
160
  :headers => { 'Content-Type' => content_type })
173
161
  end
174
162
 
@@ -310,7 +298,7 @@ describe Ably::Auth do
310
298
  request_body_includes(request, protocol, 'key_name', key_name)
311
299
  end.to_return(
312
300
  :status => 201,
313
- :body => serialize(token_response, protocol),
301
+ :body => serialize_body(token_response, protocol),
314
302
  :headers => { 'Content-Type' => content_type }
315
303
  )
316
304
  end
@@ -1129,63 +1117,6 @@ describe Ably::Auth do
1129
1117
  end
1130
1118
  end
1131
1119
 
1132
- context 'when implicit as a result of using :client_id' do
1133
- let(:client_id) { '999' }
1134
- let(:client) do
1135
- Ably::Rest::Client.new(key: api_key, client_id: client_id, environment: environment, protocol: protocol)
1136
- end
1137
- let(:token) { 'unique-token' }
1138
- let(:token_response) do
1139
- {
1140
- token: token
1141
- }.to_json
1142
- end
1143
-
1144
- context 'and requests to the Ably server are mocked', :webmock do
1145
- let!(:request_token_stub) do
1146
- stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").
1147
- to_return(:status => 201, :body => token_response, :headers => { 'Content-Type' => 'application/json' })
1148
- end
1149
- let!(:publish_message_stub) do
1150
- stub_request(:post, "#{client.endpoint}/channels/foo/publish").
1151
- with(headers: { 'Authorization' => "Bearer #{encode64(token)}" }).
1152
- to_return(status: 201, body: '{}', headers: { 'Content-Type' => 'application/json' })
1153
- end
1154
-
1155
- it 'will send a token request to the server' do
1156
- client.channel('foo').publish('event', 'data')
1157
- expect(request_token_stub).to have_been_requested
1158
- end
1159
- end
1160
-
1161
- describe 'a token is created' do
1162
- let(:token) { client.auth.current_token_details }
1163
-
1164
- it 'before a request is made' do
1165
- expect(token).to be_nil
1166
- end
1167
-
1168
- it 'when a message is published' do
1169
- expect(client.channel('foo').publish('event', 'data')).to be_truthy
1170
- end
1171
-
1172
- it 'with capability and TTL defaults (#TK2a, #TK2b)' do
1173
- client.channel('foo').publish('event', 'data')
1174
-
1175
- expect(token).to be_a(Ably::Models::TokenDetails)
1176
- capability_with_str_key = { "*" => ["*"] } # Ably default is all capabilities
1177
- capability = Hash[capability_with_str_key.keys.map(&:to_s).zip(capability_with_str_key.values)]
1178
- expect(token.capability).to eq(capability)
1179
- expect(token.expires.to_i).to be_within(2).of(Time.now.to_i + 60 * 60) # Ably default is 1hr
1180
- expect(token.client_id).to eq(client_id)
1181
- end
1182
-
1183
- specify '#client_id contains the client_id' do
1184
- expect(client.auth.client_id).to eql(client_id)
1185
- end
1186
- end
1187
- end
1188
-
1189
1120
  context 'when token expires' do
1190
1121
  before do
1191
1122
  stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0 # allow token to be used even if about to expire
@@ -1234,6 +1165,24 @@ describe Ably::Auth do
1234
1165
  end
1235
1166
  end
1236
1167
 
1168
+ context 'when token does not expire' do
1169
+ let(:client_options) { default_options.merge(use_token_auth: true, key: api_key, query_time: true) }
1170
+ let(:channel) { client.channels.get(random_str) }
1171
+
1172
+ context 'for the next 2 hours' do
1173
+ let(:local_time) { Time.now - 2 * 60 * 60 }
1174
+
1175
+ before { allow(Time).to receive(:now).and_return(local_time) }
1176
+
1177
+ it 'should not request for the new token (#RSA4b1)' do
1178
+ expect { channel.publish 'event' }.to change { auth.current_token_details }
1179
+ expect do
1180
+ expect { channel.publish 'event' }.not_to change { auth.current_token_details }
1181
+ end.not_to change { auth.current_token_details.expires }
1182
+ end
1183
+ end
1184
+ end
1185
+
1237
1186
  context 'when :client_id is provided in a token' do
1238
1187
  let(:client_id) { '123' }
1239
1188
  let(:token) do
@@ -87,8 +87,10 @@ describe Ably::Rest do
87
87
  let(:error_response) { '{ "error": { "statusCode": 500, "code": 50000, "message": "Internal error" } }' }
88
88
 
89
89
  before do
90
- stub_request(:get, "#{client.endpoint}/time").
91
- to_return(:status => 500, :body => error_response, :headers => { 'Content-Type' => 'application/json' })
90
+ (client.fallback_hosts.map { |host| "https://#{host}" } + [client.endpoint]).each do |host|
91
+ stub_request(:get, "#{host}/time")
92
+ .to_return(:status => 500, :body => error_response, :headers => { 'Content-Type' => 'application/json' })
93
+ end
92
94
  end
93
95
 
94
96
  it 'should raise a ServerError exception' do
@@ -98,8 +100,10 @@ describe Ably::Rest do
98
100
 
99
101
  describe '500 server error without a valid JSON response body', :webmock do
100
102
  before do
101
- stub_request(:get, "#{client.endpoint}/time").
102
- to_return(:status => 500, :headers => { 'Content-Type' => 'application/json' })
103
+ (client.fallback_hosts.map { |host| "https://#{host}" } + [client.endpoint]).each do |host|
104
+ stub_request(:get, "#{host}/time").
105
+ to_return(:status => 500, :headers => { 'Content-Type' => 'application/json' })
106
+ end
103
107
  end
104
108
 
105
109
  it 'should raise a ServerError exception' do