ably 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.travis.yml +2 -2
  2. data/Rakefile +2 -0
  3. data/SPEC.md +230 -194
  4. data/ably.gemspec +2 -0
  5. data/lib/ably/auth.rb +7 -5
  6. data/lib/ably/models/idiomatic_ruby_wrapper.rb +5 -7
  7. data/lib/ably/models/paginated_resource.rb +14 -21
  8. data/lib/ably/models/protocol_message.rb +1 -1
  9. data/lib/ably/modules/ably.rb +4 -0
  10. data/lib/ably/modules/async_wrapper.rb +2 -2
  11. data/lib/ably/modules/channels_collection.rb +31 -8
  12. data/lib/ably/modules/conversions.rb +10 -0
  13. data/lib/ably/modules/enum.rb +2 -3
  14. data/lib/ably/modules/state_emitter.rb +8 -8
  15. data/lib/ably/modules/state_machine.rb +7 -3
  16. data/lib/ably/realtime/channel.rb +6 -5
  17. data/lib/ably/realtime/channel/channel_manager.rb +11 -10
  18. data/lib/ably/realtime/channel/channel_state_machine.rb +10 -9
  19. data/lib/ably/realtime/channels.rb +3 -0
  20. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +11 -1
  21. data/lib/ably/realtime/connection.rb +55 -16
  22. data/lib/ably/realtime/connection/connection_manager.rb +25 -8
  23. data/lib/ably/realtime/connection/connection_state_machine.rb +9 -9
  24. data/lib/ably/realtime/connection/websocket_transport.rb +2 -2
  25. data/lib/ably/realtime/presence.rb +16 -17
  26. data/lib/ably/util/crypto.rb +1 -1
  27. data/lib/ably/version.rb +1 -1
  28. data/spec/acceptance/realtime/channel_history_spec.rb +6 -5
  29. data/spec/acceptance/realtime/connection_failures_spec.rb +103 -27
  30. data/spec/acceptance/realtime/connection_spec.rb +81 -17
  31. data/spec/acceptance/realtime/presence_spec.rb +82 -30
  32. data/spec/acceptance/rest/auth_spec.rb +22 -19
  33. data/spec/acceptance/rest/client_spec.rb +4 -4
  34. data/spec/acceptance/rest/presence_spec.rb +12 -6
  35. data/spec/rspec_config.rb +9 -0
  36. data/spec/shared/model_behaviour.rb +1 -1
  37. data/spec/spec_helper.rb +4 -1
  38. data/spec/support/event_machine_helper.rb +26 -37
  39. data/spec/support/markdown_spec_formatter.rb +96 -68
  40. data/spec/support/rest_testapp_before_retry.rb +15 -0
  41. data/spec/support/test_app.rb +4 -0
  42. data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +20 -2
  43. data/spec/unit/models/message_spec.rb +1 -1
  44. data/spec/unit/models/paginated_resource_spec.rb +15 -1
  45. data/spec/unit/modules/enum_spec.rb +10 -0
  46. data/spec/unit/realtime/channels_spec.rb +30 -0
  47. data/spec/unit/rest/channels_spec.rb +30 -0
  48. metadata +101 -35
  49. checksums.yaml +0 -7
@@ -192,7 +192,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
192
192
  it 'is reset to nil when :connected' do
193
193
  connection.once(:disconnected) do |error|
194
194
  # stub the host so that the connection connects
195
- allow(connection).to receive(:host).and_return(TestApp.instance.host)
195
+ allow(connection).to receive(:determine_host).and_yield(TestApp.instance.realtime_host)
196
196
  connection.once(:connected) do
197
197
  expect(connection.error_reason).to be_nil
198
198
  stop_reactor
@@ -393,6 +393,59 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
393
393
  end
394
394
  end
395
395
  end
396
+
397
+ context 'when failing to resume because the connection_key is not or no longer valid' do
398
+ def kill_connection_transport_and_prevent_valid_resume
399
+ connection.transport.close_connection_after_writing
400
+ connection.update_connection_id_and_key '0123456789abcdef', '0123456789abcdef' # force the resume connection key to be invalid
401
+ end
402
+
403
+ it 'updates the connection_id and connection_key' do
404
+ connection.once(:connected) do
405
+ previous_connection_id = connection.id
406
+ previous_connection_key = connection.key
407
+
408
+ connection.once(:connected) do
409
+ expect(connection.key).to_not eql(previous_connection_key)
410
+ expect(connection.id).to_not eql(previous_connection_id)
411
+ stop_reactor
412
+ end
413
+
414
+ kill_connection_transport_and_prevent_valid_resume
415
+ end
416
+ end
417
+
418
+ it 'detaches all channels' do
419
+ channel_count = 10
420
+ channels = channel_count.times.map { |index| client.channel("channel-#{index}") }
421
+ when_all(*channels.map(&:attach)) do
422
+ detached_channels = []
423
+ channels.each do |channel|
424
+ channel.on(:detached) do
425
+ detached_channels << channel
426
+ next unless detached_channels.count == channel_count
427
+ expect(detached_channels.count).to eql(channel_count)
428
+ stop_reactor
429
+ end
430
+ end
431
+
432
+ kill_connection_transport_and_prevent_valid_resume
433
+ end
434
+ end
435
+
436
+ it 'emits an error on the channel and sets the error reason' do
437
+ client.channel(random_str).attach do |channel|
438
+ channel.on(:error) do |error|
439
+ expect(error.message).to match(/Invalid connection key/i)
440
+ expect(error.code).to eql(80008)
441
+ expect(channel.error_reason).to eql(error)
442
+ stop_reactor
443
+ end
444
+
445
+ kill_connection_transport_and_prevent_valid_resume
446
+ end
447
+ end
448
+ end
396
449
  end
397
450
 
398
451
  describe 'fallback host feature' do
@@ -456,41 +509,64 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
456
509
 
457
510
  let(:fallback_hosts_used) { Array.new }
458
511
 
459
- it 'uses a fallback host on every subsequent disconnected attempt until suspended' do
460
- request = 0
461
- expect(EventMachine).to receive(:connect).exactly(retry_count_for_one_state).times do |host|
462
- if request == 0
512
+ context 'when the Internet is down' do
513
+ before do
514
+ allow(connection).to receive(:internet_up?).and_yield(false)
515
+ end
516
+
517
+ it 'never uses a fallback host' do
518
+ expect(EventMachine).to receive(:connect).exactly(retry_count_for_all_states).times do |host|
463
519
  expect(host).to eql(expected_host)
464
- else
465
- expect(custom_hosts).to include(host)
466
- fallback_hosts_used << host
520
+ raise EventMachine::ConnectionError
467
521
  end
468
- request += 1
469
- raise EventMachine::ConnectionError
470
- end
471
522
 
472
- connection.on(:suspended) do
473
- expect(fallback_hosts_used.uniq).to match_array(custom_hosts)
474
- stop_reactor
523
+ connection.on(:failed) do
524
+ stop_reactor
525
+ end
475
526
  end
476
527
  end
477
528
 
478
- it 'uses the primary host when suspended, and a fallback host on every subsequent suspended attempt' do
479
- request = 0
480
- expect(EventMachine).to receive(:connect).exactly(retry_count_for_all_states).times do |host|
481
- if request == 0 || request == expected_retry_attempts + 1
482
- expect(host).to eql(expected_host)
483
- else
484
- expect(custom_hosts).to include(host)
485
- fallback_hosts_used << host
529
+ context 'when the Internet is up' do
530
+ before do
531
+ allow(connection).to receive(:internet_up?).and_yield(true)
532
+ end
533
+
534
+ it 'uses a fallback host on every subsequent disconnected attempt until suspended' do
535
+ request = 0
536
+ expect(EventMachine).to receive(:connect).exactly(retry_count_for_one_state).times do |host|
537
+ if request == 0
538
+ expect(host).to eql(expected_host)
539
+ else
540
+ expect(custom_hosts).to include(host)
541
+ fallback_hosts_used << host
542
+ end
543
+ request += 1
544
+ raise EventMachine::ConnectionError
545
+ end
546
+
547
+ connection.on(:suspended) do
548
+ expect(fallback_hosts_used.uniq).to match_array(custom_hosts)
549
+ stop_reactor
486
550
  end
487
- request += 1
488
- raise EventMachine::ConnectionError
489
551
  end
490
552
 
491
- connection.on(:failed) do
492
- expect(fallback_hosts_used.uniq).to match_array(custom_hosts)
493
- stop_reactor
553
+ it 'uses the primary host when suspended, and a fallback host on every subsequent suspended attempt' do
554
+ request = 0
555
+ expect(EventMachine).to receive(:connect).exactly(retry_count_for_all_states).times do |host|
556
+ if request == 0 || request == expected_retry_attempts + 1
557
+ expect(host).to eql(expected_host)
558
+ else
559
+ expect(custom_hosts).to include(host)
560
+ fallback_hosts_used << host
561
+ end
562
+ request += 1
563
+ raise EventMachine::ConnectionError
564
+ end
565
+
566
+ connection.on(:failed) do
567
+ expect(fallback_hosts_used.uniq).to match_array(custom_hosts)
568
+ stop_reactor
569
+ end
494
570
  end
495
571
  end
496
572
  end
@@ -93,7 +93,7 @@ describe Ably::Realtime::Connection, :event_machine do
93
93
  it 'renews the token on connect' do
94
94
  sleep ttl + 0.1
95
95
  expect(client.auth.current_token).to be_expired
96
- expect(client.auth).to receive(:authorise).once.and_call_original
96
+ expect(client.auth).to receive(:authorise).at_least(:once).and_call_original
97
97
  connection.once(:connected) do
98
98
  expect(client.auth.current_token).to_not be_expired
99
99
  stop_reactor
@@ -105,7 +105,7 @@ describe Ably::Realtime::Connection, :event_machine do
105
105
  let(:ttl) { 0.01 }
106
106
 
107
107
  it 'renews the token on connect, and only makes one subsequent attempt to obtain a new token' do
108
- expect(client.auth).to receive(:authorise).twice.and_call_original
108
+ expect(client.auth).to receive(:authorise).at_least(:twice).and_call_original
109
109
  connection.once(:disconnected) do
110
110
  connection.once(:failed) do |error|
111
111
  expect(error.code).to eql(40140) # token expired
@@ -117,7 +117,10 @@ describe Ably::Realtime::Connection, :event_machine do
117
117
  it 'uses the primary host for subsequent connection and auth requests' do
118
118
  EventMachine.add_timer(1) do # wait for token to expire
119
119
  connection.once(:disconnected) do
120
- expect(client.rest_client.connection).to receive(:post).with(/requestToken$/, anything).and_call_original
120
+ expect(client.rest_client.connection).to receive(:post).
121
+ with(/requestToken$/, anything).
122
+ at_least(:once).
123
+ and_call_original
121
124
 
122
125
  expect(client.rest_client).to_not receive(:fallback_connection)
123
126
  expect(client).to_not receive(:fallback_endpoint)
@@ -139,23 +142,25 @@ describe Ably::Realtime::Connection, :event_machine do
139
142
 
140
143
  context 'the server' do
141
144
  it 'disconnects the client, and the client automatically renews the token and then reconnects', em_timeout: 10 do
142
- expect(client.auth.current_token).to_not be_expired
143
-
144
- channel.attach
145
145
  original_token = client.auth.current_token
146
+ expect(original_token).to_not be_expired
146
147
 
147
148
  connection.once(:connected) do
148
149
  started_at = Time.now
149
150
  connection.once(:disconnected) do |error|
150
- expect(Time.now - started_at >= ttl)
151
- expect(original_token).to be_expired
152
- expect(error.code).to eql(40140) # token expired
153
- connection.once(:connected) do
154
- expect(client.auth.current_token).to_not be_expired
155
- stop_reactor
151
+ EventMachine.add_timer(1) do # allow 1 second
152
+ expect(Time.now - started_at >= ttl)
153
+ expect(original_token).to be_expired
154
+ expect(error.code).to eql(40140) # token expired
155
+ connection.once(:connected) do
156
+ expect(client.auth.current_token).to_not be_expired
157
+ stop_reactor
158
+ end
156
159
  end
157
160
  end
158
161
  end
162
+
163
+ channel.attach
159
164
  end
160
165
  end
161
166
 
@@ -601,13 +606,28 @@ describe Ably::Realtime::Connection, :event_machine do
601
606
  end
602
607
  end
603
608
 
604
- context 'with invalid value' do
605
- let(:client_options) { default_options.merge(recover: 'invalid:key', log_level: :fatal) }
609
+ context 'with invalid formatted value sent to server' do
610
+ let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
606
611
 
607
- skip 'triggers an error on the connection object, sets the #error_reason and connects anyway' do
608
- connection.on(:error) do |error|
612
+ it 'triggers a fatal error on the connection object, sets the #error_reason and disconnects' do
613
+ connection.once(:error) do |error|
614
+ expect(connection.state).to eq(:failed)
615
+ expect(connection.error_reason.message).to match(/Invalid connection key/)
616
+ expect(connection.error_reason.code).to eql(40006)
617
+ expect(connection.error_reason).to eql(error)
618
+ stop_reactor
619
+ end
620
+ end
621
+ end
622
+
623
+ context 'with expired (missing) value sent to server' do
624
+ let(:client_options) { default_options.merge(recover: '0123456789abcdef:0', log_level: :fatal) }
625
+
626
+ it 'triggers an error on the connection object, sets the #error_reason, yet will connect anyway' do
627
+ connection.once(:error) do |error|
609
628
  expect(connection.state).to eq(:connected)
610
- expect(connection.error_reason.message).to match(/Recover/)
629
+ expect(connection.error_reason.message).to match(/Invalid connection key/i)
630
+ expect(connection.error_reason.code).to eql(80008)
611
631
  expect(connection.error_reason).to eql(error)
612
632
  stop_reactor
613
633
  end
@@ -652,5 +672,49 @@ describe Ably::Realtime::Connection, :event_machine do
652
672
  end
653
673
  end
654
674
  end
675
+
676
+
677
+ context 'undocumented method' do
678
+ context '#internet_up?' do
679
+ it 'returns a Deferrable' do
680
+ expect(connection.internet_up?).to be_a(EventMachine::Deferrable)
681
+ stop_reactor
682
+ end
683
+
684
+ context 'when the Internet is up' do
685
+ it 'calls the block with true' do
686
+ connection.internet_up? do |result|
687
+ expect(result).to be_truthy
688
+ stop_reactor
689
+ end
690
+ end
691
+
692
+ it 'calls the success callback of the Deferrable' do
693
+ connection.internet_up?.callback do
694
+ stop_reactor
695
+ end
696
+ end
697
+ end
698
+
699
+ context 'when the Internet is down' do
700
+ before do
701
+ stub_const 'Ably::INTERNET_CHECK', { url: 'http://does.not.exist.com', ok_text: 'no.way.this.will.match' }
702
+ end
703
+
704
+ it 'calls the block with false' do
705
+ connection.internet_up? do |result|
706
+ expect(result).to be_falsey
707
+ stop_reactor
708
+ end
709
+ end
710
+
711
+ it 'calls the failure callback of the Deferrable' do
712
+ connection.internet_up?.errback do
713
+ stop_reactor
714
+ end
715
+ end
716
+ end
717
+ end
718
+ end
655
719
  end
656
720
  end
@@ -256,6 +256,16 @@ describe Ably::Realtime::Presence, :event_machine do
256
256
  end
257
257
  end
258
258
 
259
+ it 'updates the data to nil if :data argument is not provided (assumes nil value)' do
260
+ presence_client_one.enter(data: 'prior') do
261
+ presence_client_one.update
262
+ end
263
+ presence_client_one.subscribe(:update) do |message|
264
+ expect(message.data).to be_nil
265
+ stop_reactor
266
+ end
267
+ end
268
+
259
269
  it 'returns a Deferrable' do
260
270
  presence_client_one.enter do
261
271
  expect(presence_client_one.update).to be_a(EventMachine::Deferrable)
@@ -277,10 +287,11 @@ describe Ably::Realtime::Presence, :event_machine do
277
287
  context '#leave' do
278
288
  context ':data option' do
279
289
  let(:data) { random_str }
290
+ let(:enter_data) { random_str }
280
291
 
281
292
  context 'when set to a string' do
282
293
  it 'emits the new data for the leave event' do
283
- presence_client_one.enter data: random_str do
294
+ presence_client_one.enter data: enter_data do
284
295
  presence_client_one.leave data: data
285
296
  end
286
297
 
@@ -292,26 +303,26 @@ describe Ably::Realtime::Presence, :event_machine do
292
303
  end
293
304
 
294
305
  context 'when set to nil' do
295
- it 'emits nil data for the leave event' do
296
- presence_client_one.enter data: random_str do
306
+ it 'emits the previously defined value as a convenience' do
307
+ presence_client_one.enter data: enter_data do
297
308
  presence_client_one.leave data: nil
298
309
  end
299
310
 
300
311
  presence_client_one.subscribe(:leave) do |presence_message|
301
- expect(presence_message.data).to be_nil
312
+ expect(presence_message.data).to eql(enter_data)
302
313
  stop_reactor
303
314
  end
304
315
  end
305
316
  end
306
317
 
307
318
  context 'when not passed as an argument' do
308
- it 'emits the original data for the leave event' do
309
- presence_client_one.enter data: data do
319
+ it 'emits the previously defined value as a convenience' do
320
+ presence_client_one.enter data: enter_data do
310
321
  presence_client_one.leave
311
322
  end
312
323
 
313
324
  presence_client_one.subscribe(:leave) do |presence_message|
314
- expect(presence_message.data).to eql(data)
325
+ expect(presence_message.data).to eql(enter_data)
315
326
  stop_reactor
316
327
  end
317
328
  end
@@ -380,7 +391,7 @@ describe Ably::Realtime::Presence, :event_machine do
380
391
  presence_client_one.on(:entered) { raise 'Should not have entered' }
381
392
  next unless client_id == client_count - 1
382
393
 
383
- EventMachine.add_timer(0.5) do
394
+ EventMachine.add_timer(1) do
384
395
  expect(presence_client_one.state).to eq(:initialized)
385
396
  stop_reactor
386
397
  end
@@ -435,7 +446,7 @@ describe Ably::Realtime::Presence, :event_machine do
435
446
  clients << presence
436
447
  next unless clients.count == 5
437
448
 
438
- EventMachine.add_timer(0.5) do
449
+ wait_until(proc { updated_callback_count == 5 }) do
439
450
  expect(clients.map(&:client_id).uniq.count).to eql(5)
440
451
  expect(updated_callback_count).to eql(5)
441
452
  stop_reactor
@@ -443,6 +454,18 @@ describe Ably::Realtime::Presence, :event_machine do
443
454
  end
444
455
  end
445
456
 
457
+ it 'updates the data attribute to null for the member when :data option is not provided (assumed null)' do
458
+ presence_client_one.enter_client('client_1') do
459
+ presence_client_one.update_client('client_1')
460
+ end
461
+
462
+ presence_anonymous_client.subscribe(:update) do |presence|
463
+ expect(presence.client_id).to eql('client_1')
464
+ expect(presence.data).to be_nil
465
+ stop_reactor
466
+ end
467
+ end
468
+
446
469
  it 'enters if not already entered' do
447
470
  updated_callback_count = 0
448
471
 
@@ -457,7 +480,7 @@ describe Ably::Realtime::Presence, :event_machine do
457
480
  clients << presence
458
481
  next unless clients.count == 5
459
482
 
460
- EventMachine.add_timer(0.5) do
483
+ wait_until(proc { updated_callback_count == 5 }) do
461
484
  expect(clients.map(&:client_id).uniq.count).to eql(5)
462
485
  expect(updated_callback_count).to eql(5)
463
486
  stop_reactor
@@ -498,7 +521,7 @@ describe Ably::Realtime::Presence, :event_machine do
498
521
  clients << presence
499
522
  next unless clients.count == 5
500
523
 
501
- EventMachine.add_timer(0.5) do
524
+ wait_until(proc { left_callback_count == 5 }) do
502
525
  expect(clients.map(&:client_id).uniq.count).to eql(5)
503
526
  expect(left_callback_count).to eql(5)
504
527
  stop_reactor
@@ -520,7 +543,7 @@ describe Ably::Realtime::Presence, :event_machine do
520
543
  clients << presence
521
544
  next unless clients.count == 5
522
545
 
523
- EventMachine.add_timer(1) do
546
+ wait_until(proc { left_callback_count == 5 }) do
524
547
  expect(clients.map(&:client_id).uniq.count).to eql(5)
525
548
  expect(left_callback_count).to eql(5)
526
549
  stop_reactor
@@ -543,20 +566,20 @@ describe Ably::Realtime::Presence, :event_machine do
543
566
  end
544
567
 
545
568
  context 'with a nil value in :data option' do
546
- it 'emits the leave event with a nil value' do
569
+ it 'emits the leave event with the previous value as a convenience' do
547
570
  presence_client_one.enter_client("client:unique", data: data) do
548
571
  presence_client_one.leave_client("client:unique", data: nil)
549
572
  end
550
573
 
551
574
  presence_client_one.subscribe(:leave) do |presence_message|
552
- expect(presence_message.data).to be_nil
575
+ expect(presence_message.data).to eql(data)
553
576
  stop_reactor
554
577
  end
555
578
  end
556
579
  end
557
580
 
558
581
  context 'with no :data option' do
559
- it 'emits the leave event with the previous data value' do
582
+ it 'emits the leave event with the previous value as a convenience' do
560
583
  presence_client_one.enter_client("client:unique", data: data) do
561
584
  presence_client_one.leave_client("client:unique")
562
585
  end
@@ -612,7 +635,14 @@ describe Ably::Realtime::Presence, :event_machine do
612
635
  end
613
636
 
614
637
  it 'filters by connection_id option if provided' do
615
- when_all(presence_client_one.enter, presence_client_two.enter, and_wait: 0.5) do
638
+ presence_client_one.enter do
639
+ presence_client_two.enter
640
+ end
641
+
642
+ presence_client_one.subscribe(:enter) do |presence_message|
643
+ # wait until the client_two enter event has been sent to client_one
644
+ next unless presence_message.client_id == client_two.client_id
645
+
616
646
  presence_client_one.get(connection_id: client_one.connection.id) do |members|
617
647
  expect(members.count).to eq(1)
618
648
  expect(members.first.connection_id).to eql(client_one.connection.id)
@@ -627,7 +657,14 @@ describe Ably::Realtime::Presence, :event_machine do
627
657
  end
628
658
 
629
659
  it 'filters by client_id option if provided' do
630
- when_all(presence_client_one.enter(client_id: 'one'), presence_client_two.enter(client_id: 'two')) do
660
+ presence_client_one.enter(client_id: 'one') do
661
+ presence_client_two.enter client_id: 'two'
662
+ end
663
+
664
+ presence_client_one.subscribe(:enter) do |presence_message|
665
+ # wait until the client_two enter event has been sent to client_one
666
+ next unless presence_message.client_id == 'two'
667
+
631
668
  presence_client_one.get(client_id: 'one') do |members|
632
669
  expect(members.count).to eq(1)
633
670
  expect(members.first.client_id).to eql('one')
@@ -665,21 +702,36 @@ describe Ably::Realtime::Presence, :event_machine do
665
702
  end
666
703
  end
667
704
 
668
- it 'returns both members on both simultaneously connected clients' do
669
- when_all(presence_client_one.enter(data: data_payload), presence_client_two.enter) do
670
- EventMachine.add_timer(0.5) do
671
- presence_client_one.get do |client_one_members|
672
- presence_client_two.get do |client_two_members|
673
- expect(client_one_members.count).to eq(client_two_members.count)
705
+ context 'with lots of members on different clients' do
706
+ let(:members_per_client) { 10 }
707
+ let(:clients_entered) { Hash.new { |hash, key| hash[key] = 0 } }
708
+ let(:total_members) { members_per_client * 2 }
674
709
 
675
- member_client_one = client_one_members.find { |presence| presence.client_id == client_one.client_id }
676
- member_client_two = client_one_members.find { |presence| presence.client_id == client_two.client_id }
710
+ it 'returns a complete list of members on all clients' do
711
+ members_per_client.times do |index|
712
+ presence_client_one.enter_client("client_1:#{index}")
713
+ presence_client_two.enter_client("client_2:#{index}")
714
+ end
677
715
 
678
- expect(member_client_one).to be_a(Ably::Models::PresenceMessage)
679
- expect(member_client_one.data).to eql(data_payload)
680
- expect(member_client_two).to be_a(Ably::Models::PresenceMessage)
716
+ presence_client_one.subscribe(:enter) do
717
+ clients_entered[:client_one] += 1
718
+ end
681
719
 
682
- stop_reactor
720
+ presence_client_two.subscribe(:enter) do
721
+ clients_entered[:client_two] += 1
722
+ end
723
+
724
+ wait_until(proc { clients_entered[:client_one] + clients_entered[:client_two] == total_members * 2 }) do
725
+ presence_anonymous_client.get do |anonymous_members|
726
+ expect(anonymous_members.count).to eq(total_members)
727
+ expect(anonymous_members.map(&:client_id).uniq.count).to eq(total_members)
728
+
729
+ presence_client_one.get do |client_one_members|
730
+ presence_client_two.get do |client_two_members|
731
+ expect(client_one_members.count).to eq(total_members)
732
+ expect(client_one_members.count).to eq(client_two_members.count)
733
+ stop_reactor
734
+ end
683
735
  end
684
736
  end
685
737
  end
@@ -720,7 +772,7 @@ describe Ably::Realtime::Presence, :event_machine do
720
772
  presence_client_one.enter
721
773
  presence_client_one.update
722
774
  presence_client_one.leave do
723
- EventMachine.add_timer(0.5) do
775
+ EventMachine.add_timer(1) do
724
776
  stop_reactor
725
777
  end
726
778
  end