ably 1.2.5 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/check.yml +1 -1
- data/CHANGELOG.md +17 -0
- data/README.md +24 -7
- data/SPEC.md +1722 -853
- data/ably.gemspec +1 -1
- data/lib/ably/auth.rb +19 -11
- data/lib/ably/models/protocol_message.rb +5 -26
- data/lib/ably/modules/safe_deferrable.rb +2 -2
- data/lib/ably/modules/state_emitter.rb +1 -1
- data/lib/ably/realtime/auth.rb +4 -0
- data/lib/ably/realtime/channel/channel_manager.rb +51 -48
- data/lib/ably/realtime/channel/channel_properties.rb +9 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +2 -0
- data/lib/ably/realtime/channel.rb +4 -3
- data/lib/ably/realtime/channels.rb +20 -0
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -13
- data/lib/ably/realtime/client.rb +14 -6
- data/lib/ably/realtime/connection/connection_manager.rb +21 -22
- data/lib/ably/realtime/connection.rb +77 -109
- data/lib/ably/realtime/presence/members_map.rb +41 -92
- data/lib/ably/realtime/presence/presence_manager.rb +12 -17
- data/lib/ably/realtime/presence.rb +15 -6
- data/lib/ably/realtime/push.rb +0 -27
- data/lib/ably/realtime/recovery_key_context.rb +36 -0
- data/lib/ably/rest/client.rb +4 -6
- data/lib/ably/rest/push/admin.rb +1 -1
- data/lib/ably/rest/push.rb +0 -19
- data/lib/ably/util/ably_extensions.rb +29 -0
- data/lib/ably/util/crypto.rb +2 -2
- data/lib/ably/util/safe_deferrable.rb +1 -1
- data/lib/ably/version.rb +5 -7
- data/spec/acceptance/realtime/channel_history_spec.rb +8 -12
- data/spec/acceptance/realtime/channel_spec.rb +474 -300
- data/spec/acceptance/realtime/client_spec.rb +1 -1
- data/spec/acceptance/realtime/connection_failures_spec.rb +8 -25
- data/spec/acceptance/realtime/connection_spec.rb +28 -120
- data/spec/acceptance/realtime/message_spec.rb +23 -52
- data/spec/acceptance/realtime/presence_spec.rb +123 -92
- data/spec/acceptance/rest/channel_spec.rb +2 -2
- data/spec/acceptance/rest/client_spec.rb +9 -2
- data/spec/acceptance/rest/message_spec.rb +8 -11
- data/spec/acceptance/rest/push_admin_spec.rb +20 -15
- data/spec/shared/client_initializer_behaviour.rb +1 -1
- data/spec/support/markdown_spec_formatter.rb +1 -1
- data/spec/unit/models/protocol_message_spec.rb +0 -78
- data/spec/unit/models/token_details_spec.rb +4 -2
- data/spec/unit/realtime/channels_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +0 -30
- data/spec/unit/realtime/recovery_key_context_spec.rb +36 -0
- data/spec/unit/util/crypto_spec.rb +15 -15
- metadata +9 -9
- data/spec/acceptance/realtime/push_spec.rb +0 -27
- data/spec/acceptance/rest/push_spec.rb +0 -25
@@ -60,13 +60,13 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
unless expected_state == :left
|
63
|
-
it
|
63
|
+
it "presence #{method_name} : raise an exception if the channel is detached" do
|
64
64
|
setup_test(method_name, args, options) do
|
65
65
|
channel_client_one.attach do
|
66
66
|
channel_client_one.transition_state_machine :detaching
|
67
67
|
channel_client_one.once(:detached) do
|
68
68
|
presence_client_one.public_send(method_name, args).tap do |deferrable|
|
69
|
-
deferrable.callback { raise
|
69
|
+
deferrable.callback { raise "presence #{method_name} should not succeed" }
|
70
70
|
deferrable.errback do |error|
|
71
71
|
expect(error).to be_a(Ably::Exceptions::InvalidState)
|
72
72
|
expect(error.message).to match(/Operation is not allowed when channel is in STATE.Detached/)
|
@@ -78,12 +78,12 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
it
|
81
|
+
it "presence #{method_name} : raise an exception if the channel becomes detached" do
|
82
82
|
setup_test(method_name, args, options) do
|
83
83
|
channel_client_one.attach do
|
84
84
|
channel_client_one.transition_state_machine :detaching
|
85
85
|
presence_client_one.public_send(method_name, args).tap do |deferrable|
|
86
|
-
deferrable.callback { raise
|
86
|
+
deferrable.callback { raise "presence #{method_name} should not succeed" }
|
87
87
|
deferrable.errback do |error|
|
88
88
|
expect(error).to be_a(Ably::Exceptions::InvalidState)
|
89
89
|
expect(error.message).to match(/Operation failed as channel transitioned to STATE.Detached/)
|
@@ -94,13 +94,13 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
it
|
97
|
+
it "presence #{method_name} : raise an exception if the channel is failed" do
|
98
98
|
setup_test(method_name, args, options) do
|
99
99
|
channel_client_one.attach do
|
100
100
|
channel_client_one.transition_state_machine :failed
|
101
101
|
expect(channel_client_one.state).to eq(:failed)
|
102
102
|
presence_client_one.public_send(method_name, args).tap do |deferrable|
|
103
|
-
deferrable.callback { raise
|
103
|
+
deferrable.callback { raise "presence #{method_name} : Get should not succeed" }
|
104
104
|
deferrable.errback do |error|
|
105
105
|
expect(error).to be_a(Ably::Exceptions::InvalidState)
|
106
106
|
expect(error.message).to match(/Operation is not allowed when channel is in STATE.Failed/)
|
@@ -111,11 +111,11 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
it
|
114
|
+
it "presence #{method_name} : raise an exception if the channel becomes failed" do
|
115
115
|
setup_test(method_name, args, options) do
|
116
116
|
channel_client_one.attach do
|
117
117
|
presence_client_one.public_send(method_name, args).tap do |deferrable|
|
118
|
-
deferrable.callback { raise
|
118
|
+
deferrable.callback { raise "presence #{method_name} : Get should not succeed" }
|
119
119
|
deferrable.errback do |error|
|
120
120
|
expect(error).to be_a(Ably::Exceptions::MessageDeliveryFailed)
|
121
121
|
stop_reactor
|
@@ -516,11 +516,11 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
516
516
|
stop_reactor
|
517
517
|
end
|
518
518
|
|
519
|
-
it 'will emit an :
|
519
|
+
it 'will emit an :sync_complete event when synchronisation is complete' do
|
520
520
|
presence_client_one.enter
|
521
521
|
presence_client_two.enter
|
522
522
|
|
523
|
-
presence_anonymous_client.members.once(:
|
523
|
+
presence_anonymous_client.members.once(:sync_complete) do
|
524
524
|
stop_reactor
|
525
525
|
end
|
526
526
|
|
@@ -545,7 +545,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
545
545
|
entered += 1
|
546
546
|
next unless entered == 2
|
547
547
|
|
548
|
-
presence_anonymous_client.members.once(:
|
548
|
+
presence_anonymous_client.members.once(:sync_complete) do
|
549
549
|
expect(presence_anonymous_client.members.count).to eql(2)
|
550
550
|
member_ids = presence_anonymous_client.members.map(&:member_key)
|
551
551
|
expect(member_ids.count).to eql(2)
|
@@ -580,7 +580,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
580
580
|
action = Ably::Models::ProtocolMessage::ACTION.Presence
|
581
581
|
presence_msg = Ably::Models::ProtocolMessage.new(
|
582
582
|
action: action,
|
583
|
-
connection_serial: 20,
|
584
583
|
channel: channel_name,
|
585
584
|
presence: presence_data,
|
586
585
|
timestamp: Time.now.to_i * 1000
|
@@ -633,7 +632,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
633
632
|
action = Ably::Models::ProtocolMessage::ACTION.Presence
|
634
633
|
presence_msg = Ably::Models::ProtocolMessage.new(
|
635
634
|
action: action,
|
636
|
-
connection_serial: anonymous_client.connection.serial + 1,
|
637
635
|
channel: channel_name,
|
638
636
|
presence: presence_data,
|
639
637
|
timestamp: Time.now.to_i * 1000
|
@@ -644,7 +642,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
644
642
|
action = Ably::Models::ProtocolMessage::ACTION.Sync
|
645
643
|
sync_msg = Ably::Models::ProtocolMessage.new(
|
646
644
|
action: action,
|
647
|
-
connection_serial: anonymous_client.connection.serial + 2,
|
648
645
|
channel: channel_name,
|
649
646
|
channel_serial: 'validserialprefix:', # with no part after the `:` this indicates the end to the SYNC
|
650
647
|
presence: [],
|
@@ -707,21 +704,29 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
707
704
|
|
708
705
|
context '#sync_complete? and SYNC flags (#RTP1)' do
|
709
706
|
context 'when attaching to a channel without any members present' do
|
710
|
-
|
711
|
-
|
707
|
+
it 'sync_complete? is true, no members are received and the presence channel is synced (#RTP1)' do
|
708
|
+
sync_info_received = false
|
712
709
|
|
713
710
|
anonymous_client.connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
714
711
|
if protocol_message.action == :attached
|
715
|
-
|
716
|
-
|
712
|
+
if protocol_message.has_presence_flag?
|
713
|
+
sync_info_received = false
|
714
|
+
else
|
715
|
+
sync_info_received = true
|
716
|
+
end
|
717
|
+
end
|
718
|
+
if protocol_message.action == Ably::Models::ProtocolMessage::ACTION.Sync
|
719
|
+
expect(protocol_message.presence).to be_empty
|
720
|
+
sync_info_received = true
|
717
721
|
end
|
718
722
|
end
|
719
723
|
|
720
724
|
channel_anonymous_client.attach do
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
+
wait_until(lambda { channel_anonymous_client.presence.sync_complete? and sync_info_received}) do
|
726
|
+
channel_anonymous_client.presence.get do |members|
|
727
|
+
expect(members).to be_empty
|
728
|
+
stop_reactor
|
729
|
+
end
|
725
730
|
end
|
726
731
|
end
|
727
732
|
end
|
@@ -851,7 +856,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
851
856
|
# Hacky accessing a private method, but absent members are intentionally not exposed to any public APIs
|
852
857
|
expect(presence_anonymous_client.members.send(:absent_members).length).to eql(1)
|
853
858
|
|
854
|
-
presence_anonymous_client.members.once(:
|
859
|
+
presence_anonymous_client.members.once(:sync_complete) do
|
855
860
|
# Check that members count is exact indicating the members with LEAVE action after sync are removed
|
856
861
|
expect(presence_anonymous_client).to be_sync_complete
|
857
862
|
expect(presence_anonymous_client.members.length).to eql(enter_expected_count - 1)
|
@@ -1007,7 +1012,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1007
1012
|
|
1008
1013
|
channel_anonymous_client.attach do
|
1009
1014
|
presence_anonymous_client.get(wait_for_sync: false) do |members|
|
1010
|
-
expect(presence_anonymous_client.members).to_not
|
1015
|
+
expect(presence_anonymous_client.members).to_not be_sync_complete
|
1011
1016
|
expect(members.count).to eql(0)
|
1012
1017
|
stop_reactor
|
1013
1018
|
end
|
@@ -1214,7 +1219,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1214
1219
|
presence_client_one.subscribe(:enter) do
|
1215
1220
|
presence_client_one.unsubscribe :enter
|
1216
1221
|
EventMachine.add_timer(0.5) do
|
1217
|
-
expect(presence_client_one.members).to
|
1222
|
+
expect(presence_client_one.members).to be_sync_complete
|
1218
1223
|
expect(presence_client_one.members.send(:members).count).to eql(1)
|
1219
1224
|
presence_client_one.leave data
|
1220
1225
|
end
|
@@ -1592,14 +1597,16 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1592
1597
|
end
|
1593
1598
|
|
1594
1599
|
it 'fails if the connection is DETACHED (#RTP11b)' do
|
1595
|
-
|
1596
|
-
channel_client_one.
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1600
|
+
client_one.connection.once :connected do
|
1601
|
+
channel_client_one.attach do
|
1602
|
+
channel_client_one.detach do
|
1603
|
+
presence_client_one.get.tap do |deferrable|
|
1604
|
+
deferrable.callback { raise 'Get should not succeed' }
|
1605
|
+
deferrable.errback do |error|
|
1606
|
+
expect(error).to be_a(Ably::Exceptions::InvalidState)
|
1607
|
+
expect(error.message).to match(/Operation is not allowed when channel is in STATE.Detached/)
|
1608
|
+
stop_reactor
|
1609
|
+
end
|
1603
1610
|
end
|
1604
1611
|
end
|
1605
1612
|
end
|
@@ -1815,29 +1822,31 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1815
1822
|
let(:total_members) { members_per_client * 2 }
|
1816
1823
|
|
1817
1824
|
it 'returns a complete list of members on all clients' do
|
1818
|
-
|
1819
|
-
presence_client_one.
|
1820
|
-
|
1821
|
-
|
1825
|
+
wait_until(lambda { client_one.connection.state == :connected and client_two.connection.state == :connected }) do
|
1826
|
+
presence_client_one.subscribe(:enter) do
|
1827
|
+
clients_entered[:client_one] += 1
|
1828
|
+
end
|
1822
1829
|
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1830
|
+
presence_client_two.subscribe(:enter) do
|
1831
|
+
clients_entered[:client_two] += 1
|
1832
|
+
end
|
1826
1833
|
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1834
|
+
members_per_client.times do |indx|
|
1835
|
+
presence_client_one.enter_client("client_1:#{indx}")
|
1836
|
+
presence_client_two.enter_client("client_2:#{indx}")
|
1837
|
+
end
|
1830
1838
|
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1839
|
+
wait_until(lambda { clients_entered[:client_one] + clients_entered[:client_two] == total_members * 2 }) do
|
1840
|
+
presence_anonymous_client.get(wait_for_sync: true) do |anonymous_members|
|
1841
|
+
expect(anonymous_members.count).to eq(total_members)
|
1842
|
+
expect(anonymous_members.map(&:client_id).uniq.count).to eq(total_members)
|
1835
1843
|
|
1836
|
-
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1844
|
+
presence_client_one.get(wait_for_sync: true) do |client_one_members|
|
1845
|
+
presence_client_two.get(wait_for_sync: true) do |client_two_members|
|
1846
|
+
expect(client_one_members.count).to eq(total_members)
|
1847
|
+
expect(client_one_members.count).to eq(client_two_members.count)
|
1848
|
+
stop_reactor
|
1849
|
+
end
|
1841
1850
|
end
|
1842
1851
|
end
|
1843
1852
|
end
|
@@ -2243,7 +2252,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2243
2252
|
action = Ably::Models::ProtocolMessage::ACTION.Sync
|
2244
2253
|
sync_message = Ably::Models::ProtocolMessage.new(
|
2245
2254
|
action: action,
|
2246
|
-
connection_serial: 10,
|
2247
2255
|
channel_serial: 'sequenceid:cursor',
|
2248
2256
|
channel: channel_name,
|
2249
2257
|
presence: presence_sync_1,
|
@@ -2253,7 +2261,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2253
2261
|
|
2254
2262
|
sync_message = Ably::Models::ProtocolMessage.new(
|
2255
2263
|
action: action,
|
2256
|
-
connection_serial: 11,
|
2257
2264
|
channel_serial: 'sequenceid:', # indicates SYNC is complete
|
2258
2265
|
channel: channel_name,
|
2259
2266
|
presence: presence_sync_2,
|
@@ -2294,7 +2301,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2294
2301
|
action = Ably::Models::ProtocolMessage::ACTION.Sync
|
2295
2302
|
sync_message = Ably::Models::ProtocolMessage.new(
|
2296
2303
|
action: action,
|
2297
|
-
connection_serial: 10,
|
2298
2304
|
channel: channel_name,
|
2299
2305
|
presence: presence_sync,
|
2300
2306
|
timestamp: Time.now.to_i * 1000
|
@@ -2348,7 +2354,6 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2348
2354
|
action = Ably::Models::ProtocolMessage::ACTION.Sync
|
2349
2355
|
sync_message = Ably::Models::ProtocolMessage.new(
|
2350
2356
|
action: action,
|
2351
|
-
connection_serial: 10,
|
2352
2357
|
channel: channel_name,
|
2353
2358
|
presence: presence_sync_protocol_message,
|
2354
2359
|
timestamp: Time.now.to_i * 1000
|
@@ -2467,7 +2472,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2467
2472
|
end
|
2468
2473
|
|
2469
2474
|
leave_message = Ably::Models::PresenceMessage.new(
|
2470
|
-
'id' => "#{client_two.connection.id}:#{
|
2475
|
+
'id' => "#{client_two.connection.id}:#{client_two.connection.send(:client_msg_serial)}:1",
|
2471
2476
|
'clientId' => presence_client_two.client_id,
|
2472
2477
|
'connectionId' => client_two.connection.id,
|
2473
2478
|
'timestamp' => as_since_epoch(Time.now),
|
@@ -2532,37 +2537,59 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2532
2537
|
let(:member_data) { random_str }
|
2533
2538
|
|
2534
2539
|
it 'immediately resends all local presence members (#RTP5c2, #RTP19a)' do
|
2535
|
-
|
2536
|
-
|
2540
|
+
member_leave_event_fired = false
|
2541
|
+
local_members_sent = false
|
2542
|
+
|
2543
|
+
presence_client_one.subscribe(:enter) do |entered_member|
|
2544
|
+
expect(entered_member.action).to eq(Ably::Models::PresenceMessage::ACTION.Enter)
|
2545
|
+
expect(entered_member.data).to eq(member_data)
|
2546
|
+
expect(entered_member.client_id).to eq(client_one.auth.client_id)
|
2547
|
+
expect(entered_member.id).to be_truthy
|
2548
|
+
entered_member_id = entered_member.id
|
2537
2549
|
|
2538
|
-
presence_client_one.enter(member_data)
|
2539
|
-
presence_client_one.subscribe(:enter) do
|
2540
2550
|
presence_client_one.unsubscribe :enter
|
2541
2551
|
|
2542
|
-
presence_client_one.
|
2543
|
-
|
2544
|
-
|
2552
|
+
expect(presence_client_one.members.length).to eql(1)
|
2553
|
+
expect(presence_client_one.members.local_members.length).to eql(1)
|
2554
|
+
|
2555
|
+
# subscribe to outgoing messages to check for entered local members with id
|
2556
|
+
client_one.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
2557
|
+
if protocol_message.action == :presence
|
2558
|
+
protocol_message.presence.each do |local_member|
|
2559
|
+
expect(local_member.id).to eq(entered_member_id)
|
2560
|
+
expect(local_member.action).to eq(Ably::Models::PresenceMessage::ACTION.Enter)
|
2561
|
+
expect(local_member.data).to eq(member_data)
|
2562
|
+
expect(local_member.client_id).to eq(client_one.auth.client_id)
|
2563
|
+
local_members_sent = true
|
2564
|
+
end
|
2565
|
+
end
|
2545
2566
|
end
|
2546
2567
|
|
2547
|
-
|
2548
|
-
|
2549
|
-
presence_client_one.subscribe(:update) do |message|
|
2550
|
-
expect(local_member_leave_event_fired).to be_truthy
|
2568
|
+
presence_client_one.subscribe(:leave) do |message|
|
2569
|
+
# Member will leave the PresenceMap due to the ATTACHED without Presence
|
2551
2570
|
expect(message.data).to eq(member_data)
|
2552
2571
|
expect(message.client_id).to eq(client_one.auth.client_id)
|
2553
|
-
|
2554
|
-
|
2555
|
-
|
2556
|
-
|
2557
|
-
|
2558
|
-
|
2572
|
+
member_leave_event_fired = true
|
2573
|
+
end
|
2574
|
+
|
2575
|
+
# Shouldn't receive enter/update message when local_members are entered
|
2576
|
+
# This is due to the fact that, when we enter local member we also send
|
2577
|
+
# member id, and server automatically checks for duplicate id and doesn't
|
2578
|
+
# send presenceEnter or presenceUpdate if id is found.
|
2579
|
+
presence_client_one.subscribe(:enter, :update) do |message|
|
2580
|
+
raise { "client shouldn't receive update event for entered local members" }
|
2559
2581
|
end
|
2560
2582
|
|
2561
|
-
presence_client_one.members.once(:
|
2562
|
-
# Immediately after SYNC (no sync actually occurred, but this event fires immediately after a channel SYNCs or is not expecting to SYNC)
|
2583
|
+
presence_client_one.members.once(:sync_complete) do
|
2563
2584
|
expect(presence_client_one.members.length).to eql(0)
|
2564
|
-
|
2565
|
-
|
2585
|
+
|
2586
|
+
# Since, this is a client sent event, local_members are not cleared
|
2587
|
+
# local_members acts a source of truth for server and not vice versa
|
2588
|
+
expect(presence_client_one.members.local_members.length).to eql(1)
|
2589
|
+
|
2590
|
+
wait_until(lambda { member_leave_event_fired and local_members_sent}) do
|
2591
|
+
stop_reactor
|
2592
|
+
end
|
2566
2593
|
end
|
2567
2594
|
|
2568
2595
|
# ATTACHED ProtocolMessage with no presence flag will clear the presence set immediately, #RTP19a
|
@@ -2572,6 +2599,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2572
2599
|
flags: 0 # no resume or presence flag
|
2573
2600
|
)
|
2574
2601
|
end
|
2602
|
+
|
2603
|
+
presence_client_one.enter(member_data)
|
2575
2604
|
end
|
2576
2605
|
end
|
2577
2606
|
end
|
@@ -2684,23 +2713,25 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
2684
2713
|
|
2685
2714
|
context 'channel transitions to the DETACHED state' do
|
2686
2715
|
it 'clears the PresenceMap and local member map copy and does not emit any presence events (#RTP5a)' do
|
2687
|
-
|
2688
|
-
|
2689
|
-
presence_client_one.
|
2716
|
+
wait_until(lambda { client_one.connection.state == :connected and anonymous_client.connection.state == :connected }) do
|
2717
|
+
presence_client_one.enter
|
2718
|
+
presence_client_one.subscribe(:enter) do
|
2719
|
+
presence_client_one.unsubscribe :enter
|
2690
2720
|
|
2691
|
-
|
2692
|
-
|
2693
|
-
|
2721
|
+
channel_anonymous_client.attach do
|
2722
|
+
presence_anonymous_client.get do |members|
|
2723
|
+
expect(members.count).to eq(1)
|
2694
2724
|
|
2695
|
-
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2725
|
+
presence_anonymous_client.subscribe { raise 'No presence events should be emitted' }
|
2726
|
+
channel_anonymous_client.detach do
|
2727
|
+
expect(presence_anonymous_client.members.length).to eq(0)
|
2728
|
+
expect(channel_anonymous_client).to be_detached
|
2699
2729
|
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2730
|
+
expect(presence_client_one.members.local_members.count).to eq(1)
|
2731
|
+
channel_client_one.detach do
|
2732
|
+
expect(presence_client_one.members.local_members.count).to eq(0)
|
2733
|
+
stop_reactor
|
2734
|
+
end
|
2704
2735
|
end
|
2705
2736
|
end
|
2706
2737
|
end
|
@@ -191,7 +191,7 @@ describe Ably::Rest::Channel do
|
|
191
191
|
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { capability: capability }) }
|
192
192
|
|
193
193
|
it 'raises a permission error when publishing' do
|
194
|
-
expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::UnauthorizedRequest, /
|
194
|
+
expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::UnauthorizedRequest, /40160/)
|
195
195
|
end
|
196
196
|
end
|
197
197
|
|
@@ -280,7 +280,7 @@ describe Ably::Rest::Channel do
|
|
280
280
|
|
281
281
|
context 'with an invalid client_id in the message' do
|
282
282
|
it 'succeeds in the client library but then fails when published to Ably' do
|
283
|
-
expect { channel.publish([name: 'event', client_id: 'invalid']) }.to raise_error
|
283
|
+
expect { channel.publish([name: 'event', client_id: 'invalid']) }.to raise_error(Ably::Exceptions::InvalidRequest, /40012/)
|
284
284
|
end
|
285
285
|
end
|
286
286
|
|
@@ -1095,9 +1095,16 @@ describe Ably::Rest::Client do
|
|
1095
1095
|
end
|
1096
1096
|
|
1097
1097
|
it 'sends a protocol version and lib version header (#G4, #RSC7a, #RSC7b)' do
|
1098
|
-
client.channels.get('foo').publish("event")
|
1098
|
+
response = client.channels.get('foo').publish("event")
|
1099
|
+
expect(response).to eql true
|
1099
1100
|
expect(publish_message_stub).to have_been_requested
|
1100
|
-
|
1101
|
+
if agent.nil?
|
1102
|
+
expect(publish_message_stub.to_s).to include("'Ably-Agent'=>'#{Ably::AGENT}'")
|
1103
|
+
expect(publish_message_stub.to_s).to include("'X-Ably-Version'=>'2'")
|
1104
|
+
else
|
1105
|
+
expect(publish_message_stub.to_s).to include("'Ably-Agent'=>'ably-ruby/1.1.1 ruby/3.1.1'")
|
1106
|
+
expect(publish_message_stub.to_s).to include("'X-Ably-Version'=>'2'")
|
1107
|
+
end
|
1101
1108
|
end
|
1102
1109
|
end
|
1103
1110
|
end
|
@@ -204,20 +204,17 @@ describe Ably::Rest::Channel, 'messages' do
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
-
specify 'idempotent publishing is
|
208
|
-
|
209
|
-
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
210
|
-
expect(client.idempotent_rest_publishing).to be_falsey
|
211
|
-
stub_const 'Ably::PROTOCOL_VERSION', '1.1'
|
212
|
-
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
207
|
+
specify 'idempotent publishing is set as per clientOptions' do
|
208
|
+
# set idempotent_rest_publishing to false
|
209
|
+
client = Ably::Rest::Client.new(key: api_key, protocol: protocol, idempotent_rest_publishing: false)
|
213
210
|
expect(client.idempotent_rest_publishing).to be_falsey
|
214
|
-
end
|
215
211
|
|
216
|
-
|
217
|
-
|
218
|
-
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
212
|
+
# set idempotent_rest_publishing to true
|
213
|
+
client = Ably::Rest::Client.new(key: api_key, protocol: protocol, idempotent_rest_publishing: true)
|
219
214
|
expect(client.idempotent_rest_publishing).to be_truthy
|
220
|
-
|
215
|
+
end
|
216
|
+
|
217
|
+
specify 'idempotent publishing is enabled by default (#TO3n)' do
|
221
218
|
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
222
219
|
expect(client.idempotent_rest_publishing).to be_truthy
|
223
220
|
end
|
@@ -181,7 +181,7 @@ describe Ably::Rest::Push::Admin do
|
|
181
181
|
client_id: client_id,
|
182
182
|
push: {
|
183
183
|
recipient: {
|
184
|
-
transport_type: '
|
184
|
+
transport_type: 'fcm',
|
185
185
|
registration_token: 'secret_token',
|
186
186
|
}
|
187
187
|
}
|
@@ -250,7 +250,7 @@ describe Ably::Rest::Push::Admin do
|
|
250
250
|
client_id: client_id,
|
251
251
|
push: {
|
252
252
|
recipient: {
|
253
|
-
transport_type: '
|
253
|
+
transport_type: 'fcm',
|
254
254
|
registration_token: 'secret_token',
|
255
255
|
}
|
256
256
|
}
|
@@ -268,7 +268,7 @@ describe Ably::Rest::Push::Admin do
|
|
268
268
|
expect(device).to be_a(Ably::Models::DeviceDetails)
|
269
269
|
expect(device.platform).to eql('ios')
|
270
270
|
expect(device.client_id).to eql(client_id)
|
271
|
-
expect(device.push.recipient.fetch(:transport_type)).to eql('
|
271
|
+
expect(device.push.recipient.fetch(:transport_type)).to eql('fcm')
|
272
272
|
end
|
273
273
|
|
274
274
|
it 'returns a DeviceDetails object if a DeviceDetails object is provided' do
|
@@ -276,7 +276,7 @@ describe Ably::Rest::Push::Admin do
|
|
276
276
|
expect(device).to be_a(Ably::Models::DeviceDetails)
|
277
277
|
expect(device.platform).to eql('ios')
|
278
278
|
expect(device.client_id).to eql(client_id)
|
279
|
-
expect(device.push.recipient.fetch(:transport_type)).to eql('
|
279
|
+
expect(device.push.recipient.fetch(:transport_type)).to eql('fcm')
|
280
280
|
end
|
281
281
|
|
282
282
|
it 'raises a ResourceMissing exception if device ID does not exist' do
|
@@ -350,14 +350,14 @@ describe Ably::Rest::Push::Admin do
|
|
350
350
|
expect(device_retrieved.push.recipient['foo_bar']).to eql('string')
|
351
351
|
end
|
352
352
|
|
353
|
-
context 'with
|
353
|
+
context 'with FCM target' do
|
354
354
|
let(:device_token) { random_str }
|
355
355
|
|
356
356
|
it 'saves the associated DevicePushDetails' do
|
357
357
|
subject.save(device_details.merge(
|
358
358
|
push: {
|
359
359
|
recipient: {
|
360
|
-
transport_type: '
|
360
|
+
transport_type: 'fcm',
|
361
361
|
registrationToken: device_token
|
362
362
|
}
|
363
363
|
}
|
@@ -365,14 +365,15 @@ describe Ably::Rest::Push::Admin do
|
|
365
365
|
|
366
366
|
device_retrieved = subject.get(device_details.fetch(:id))
|
367
367
|
|
368
|
-
expect(device_retrieved.push.recipient.fetch('transportType')).to eql('
|
368
|
+
expect(device_retrieved.push.recipient.fetch('transportType')).to eql('fcm')
|
369
369
|
expect(device_retrieved.push.recipient[:registration_token]).to eql(device_token)
|
370
370
|
end
|
371
371
|
end
|
372
372
|
|
373
373
|
context 'with web target' do
|
374
374
|
let(:target_url) { 'http://foo.com/bar' }
|
375
|
-
let(:
|
375
|
+
let(:p256dh) { random_str }
|
376
|
+
let(:auth) { random_str }
|
376
377
|
|
377
378
|
it 'saves the associated DevicePushDetails' do
|
378
379
|
subject.save(device_details.merge(
|
@@ -380,7 +381,10 @@ describe Ably::Rest::Push::Admin do
|
|
380
381
|
recipient: {
|
381
382
|
transport_type: 'web',
|
382
383
|
targetUrl: target_url,
|
383
|
-
encryptionKey:
|
384
|
+
encryptionKey: {
|
385
|
+
p256dh: p256dh,
|
386
|
+
auth: auth
|
387
|
+
}
|
384
388
|
}
|
385
389
|
}
|
386
390
|
))
|
@@ -389,7 +393,8 @@ describe Ably::Rest::Push::Admin do
|
|
389
393
|
|
390
394
|
expect(device_retrieved.push.recipient[:transport_type]).to eql('web')
|
391
395
|
expect(device_retrieved.push.recipient['targetUrl']).to eql(target_url)
|
392
|
-
expect(device_retrieved.push.recipient['encryptionKey']).to eql(
|
396
|
+
expect(device_retrieved.push.recipient['encryptionKey']['p256dh']).to eql(p256dh)
|
397
|
+
expect(device_retrieved.push.recipient['encryptionKey']['auth']).to eql(auth)
|
393
398
|
end
|
394
399
|
end
|
395
400
|
|
@@ -462,7 +467,7 @@ describe Ably::Rest::Push::Admin do
|
|
462
467
|
client_id: client_id,
|
463
468
|
push: {
|
464
469
|
recipient: {
|
465
|
-
transport_type: '
|
470
|
+
transport_type: 'fcm',
|
466
471
|
registrationToken: 'secret_token',
|
467
472
|
}
|
468
473
|
}
|
@@ -476,7 +481,7 @@ describe Ably::Rest::Push::Admin do
|
|
476
481
|
client_id: client_id,
|
477
482
|
push: {
|
478
483
|
recipient: {
|
479
|
-
transport_type: '
|
484
|
+
transport_type: 'fcm',
|
480
485
|
registration_token: 'secret_token',
|
481
486
|
}
|
482
487
|
}
|
@@ -525,7 +530,7 @@ describe Ably::Rest::Push::Admin do
|
|
525
530
|
client_id: client_id,
|
526
531
|
push: {
|
527
532
|
recipient: {
|
528
|
-
transport_type: '
|
533
|
+
transport_type: 'fcm',
|
529
534
|
registration_token: 'secret_token',
|
530
535
|
}
|
531
536
|
}
|
@@ -539,7 +544,7 @@ describe Ably::Rest::Push::Admin do
|
|
539
544
|
client_id: client_id,
|
540
545
|
push: {
|
541
546
|
recipient: {
|
542
|
-
transport_type: '
|
547
|
+
transport_type: 'fcm',
|
543
548
|
registration_token: 'secret_token',
|
544
549
|
}
|
545
550
|
}
|
@@ -580,7 +585,7 @@ describe Ably::Rest::Push::Admin do
|
|
580
585
|
client_id: client_id,
|
581
586
|
push: {
|
582
587
|
recipient: {
|
583
|
-
transport_type: '
|
588
|
+
transport_type: 'fcm',
|
584
589
|
registration_token: 'secret_token',
|
585
590
|
}
|
586
591
|
}
|
@@ -130,7 +130,7 @@ shared_examples 'a client initializer' do
|
|
130
130
|
end
|
131
131
|
|
132
132
|
context 'with token' do
|
133
|
-
let(:client_options) { { token: 'token',
|
133
|
+
let(:client_options) { { token: 'token', auto_connect: false } }
|
134
134
|
|
135
135
|
it 'sets the token' do
|
136
136
|
expect(subject.auth.current_token_details.token).to eql('token')
|
@@ -83,7 +83,7 @@ module Ably
|
|
83
83
|
attr_reader :output, :indent
|
84
84
|
|
85
85
|
def documenting_rest_only?
|
86
|
-
File.
|
86
|
+
File.exist?(File.expand_path('../../../../../../ably-rest.gemspec', __FILE__))
|
87
87
|
end
|
88
88
|
|
89
89
|
def example_name_and_link(notification)
|