ably 0.8.5 → 0.8.6

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +42 -48
  4. data/SPEC.md +1099 -640
  5. data/ably.gemspec +10 -4
  6. data/lib/ably/auth.rb +155 -47
  7. data/lib/ably/exceptions.rb +2 -0
  8. data/lib/ably/models/channel_state_change.rb +2 -3
  9. data/lib/ably/models/connection_details.rb +54 -0
  10. data/lib/ably/models/protocol_message.rb +14 -4
  11. data/lib/ably/models/token_details.rb +13 -7
  12. data/lib/ably/models/token_request.rb +1 -2
  13. data/lib/ably/modules/ably.rb +3 -2
  14. data/lib/ably/modules/message_emitter.rb +1 -3
  15. data/lib/ably/modules/state_emitter.rb +2 -2
  16. data/lib/ably/realtime/auth.rb +6 -0
  17. data/lib/ably/realtime/channel/channel_manager.rb +2 -0
  18. data/lib/ably/realtime/channel.rb +15 -4
  19. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +11 -1
  20. data/lib/ably/realtime/client.rb +10 -3
  21. data/lib/ably/realtime/connection/connection_manager.rb +58 -54
  22. data/lib/ably/realtime/connection.rb +62 -6
  23. data/lib/ably/realtime/presence.rb +18 -5
  24. data/lib/ably/rest/channel.rb +9 -1
  25. data/lib/ably/rest/client.rb +32 -14
  26. data/lib/ably/rest/presence.rb +1 -1
  27. data/lib/ably/version.rb +1 -1
  28. data/lib/ably.rb +2 -0
  29. data/spec/acceptance/realtime/auth_spec.rb +251 -11
  30. data/spec/acceptance/realtime/channel_history_spec.rb +12 -2
  31. data/spec/acceptance/realtime/channel_spec.rb +316 -24
  32. data/spec/acceptance/realtime/client_spec.rb +93 -1
  33. data/spec/acceptance/realtime/connection_failures_spec.rb +177 -86
  34. data/spec/acceptance/realtime/connection_spec.rb +284 -60
  35. data/spec/acceptance/realtime/message_spec.rb +45 -6
  36. data/spec/acceptance/realtime/presence_history_spec.rb +4 -0
  37. data/spec/acceptance/realtime/presence_spec.rb +181 -49
  38. data/spec/acceptance/realtime/time_spec.rb +13 -0
  39. data/spec/acceptance/rest/auth_spec.rb +222 -4
  40. data/spec/acceptance/rest/channel_spec.rb +132 -1
  41. data/spec/acceptance/rest/client_spec.rb +129 -28
  42. data/spec/acceptance/rest/presence_spec.rb +7 -7
  43. data/spec/acceptance/rest/time_spec.rb +10 -0
  44. data/spec/shared/client_initializer_behaviour.rb +41 -17
  45. data/spec/spec_helper.rb +1 -0
  46. data/spec/support/debug_failure_helper.rb +16 -0
  47. data/spec/unit/models/connection_details_spec.rb +60 -0
  48. data/spec/unit/models/protocol_message_spec.rb +45 -0
  49. data/spec/unit/modules/event_emitter_spec.rb +3 -1
  50. data/spec/unit/realtime/channel_spec.rb +6 -5
  51. data/spec/unit/realtime/client_spec.rb +5 -1
  52. data/spec/unit/realtime/connection_spec.rb +5 -1
  53. data/spec/unit/realtime/realtime_spec.rb +5 -1
  54. metadata +54 -7
@@ -9,9 +9,12 @@ describe Ably::Realtime::Presence, :event_machine do
9
9
  let(:client_options) { default_options }
10
10
 
11
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)) }
12
+ let(:client_one_id) { random_str }
13
+ let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(client_id: client_one_id)) }
14
+ let(:client_two_id) { random_str }
15
+ let(:client_two) { auto_close Ably::Realtime::Client.new(client_options.merge(client_id: client_two_id)) }
14
16
 
17
+ let(:wildcard_token) { Proc.new { Ably::Rest::Client.new(client_options).auth.request_token(client_id: '*') } }
15
18
  let(:channel_name) { "presence-#{random_str(4)}" }
16
19
  let(:channel_anonymous_client) { anonymous_client.channel(channel_name) }
17
20
  let(:presence_anonymous_client) { channel_anonymous_client.presence }
@@ -29,6 +32,14 @@ describe Ably::Realtime::Presence, :event_machine do
29
32
  end
30
33
 
31
34
  shared_examples_for 'a public presence method' do |method_name, expected_state, args, options = {}|
35
+ let(:client_id) do
36
+ if args.empty?
37
+ random_str
38
+ else
39
+ args
40
+ end
41
+ end
42
+
32
43
  def setup_test(method_name, args, options)
33
44
  if options[:enter_first]
34
45
  presence_client_one.public_send(method_name.to_s.gsub(/leave|update/, 'enter'), args) do
@@ -72,7 +83,7 @@ describe Ably::Realtime::Presence, :event_machine do
72
83
  end
73
84
 
74
85
  context 'when :queue_messages client option is false' do
75
- let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str)) }
86
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: client_id)) }
76
87
 
77
88
  context 'and connection state initialized' do
78
89
  it 'raises an exception' do
@@ -94,7 +105,7 @@ describe Ably::Realtime::Presence, :event_machine do
94
105
  end
95
106
 
96
107
  context 'and connection state disconnected' do
97
- let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str, :log_level => :error)) }
108
+ let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: client_id, :log_level => :error)) }
98
109
 
99
110
  it 'raises an exception' do
100
111
  client_one.connection.once(:connected) do
@@ -122,7 +133,7 @@ describe Ably::Realtime::Presence, :event_machine do
122
133
  context 'with supported data payload content type' do
123
134
  def register_presence_and_check_data(method_name, data)
124
135
  if method_name.to_s.match(/_client/)
125
- presence_client_one.public_send(method_name, 'client_id', data: data)
136
+ presence_client_one.public_send(method_name, client_id, data: data)
126
137
  else
127
138
  presence_client_one.public_send(method_name, data: data)
128
139
  end
@@ -177,7 +188,7 @@ describe Ably::Realtime::Presence, :event_machine do
177
188
  context 'with unsupported data payload content type' do
178
189
  def presence_action(method_name, data)
179
190
  if method_name.to_s.match(/_client/)
180
- presence_client_one.public_send(method_name, 'client_id', data: data)
191
+ presence_client_one.public_send(method_name, client_id, data: data)
181
192
  else
182
193
  presence_client_one.public_send(method_name, data: data)
183
194
  end
@@ -255,15 +266,6 @@ describe Ably::Realtime::Presence, :event_machine do
255
266
  end
256
267
 
257
268
  context 'if connection fails before success' do
258
- before do
259
- # Reconfigure client library so that it makes no retry attempts and fails immediately
260
- stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
261
- Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
262
- disconnected: { retry_every: 0.1, max_time_in_state: 0 },
263
- suspended: { retry_every: 0.1, max_time_in_state: 0 }
264
- )
265
- end
266
-
267
269
  let(:client_options) { default_options.merge(log_level: :none) }
268
270
 
269
271
  it 'calls the Deferrable errback if channel is detached' do
@@ -272,7 +274,8 @@ describe Ably::Realtime::Presence, :event_machine do
272
274
  client_one.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
273
275
  # Don't allow any messages to reach the server
274
276
  client_one.connection.__outgoing_protocol_msgbus__.unsubscribe
275
- force_connection_failure client_one
277
+ error_message = Ably::Models::ProtocolMessage.new(action: 9, error: { message: 'force failure' })
278
+ client_one.connection.__incoming_protocol_msgbus__.publish :protocol_message, error_message
276
279
  end
277
280
 
278
281
  presence_client_one.public_send(method_name, args).tap do |deferrable|
@@ -288,6 +291,123 @@ describe Ably::Realtime::Presence, :event_machine do
288
291
  end
289
292
  end
290
293
 
294
+ shared_examples_for 'a presence on behalf of another client method' do |method_name|
295
+ context ":#{method_name} when authenticated with a wildcard client_id" do
296
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: '*').token }
297
+ let(:client_options) { default_options.merge(key: nil, token: token) }
298
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
299
+ let(:presence_channel) { client.channels.get(channel_name).presence }
300
+
301
+ context 'and a valid client_id' do
302
+ it 'succeeds' do
303
+ presence_channel.public_send(method_name, 'clientId') do
304
+ EM.add_timer(0.5) { stop_reactor }
305
+ end.tap do |deferrable|
306
+ deferrable.errback { raise 'Should have succeeded' }
307
+ end
308
+ end
309
+ end
310
+
311
+ context 'and a wildcard client_id' do
312
+ it 'throws an exception' do
313
+ expect { presence_channel.public_send(method_name, '*') }.to raise_error Ably::Exceptions::IncompatibleClientId
314
+ stop_reactor
315
+ end
316
+ end
317
+
318
+ context 'and an empty client_id' do
319
+ it 'throws an exception' do
320
+ expect { presence_channel.public_send(method_name, nil) }.to raise_error Ably::Exceptions::IncompatibleClientId
321
+ stop_reactor
322
+ end
323
+ end
324
+ end
325
+
326
+ context ":#{method_name} when authenticated with a valid client_id" do
327
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: 'valid').token }
328
+ let(:client_options) { default_options.merge(key: nil, token: token) }
329
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options.merge(log_level: :error)) }
330
+ let(:channel) { client.channels.get(channel_name) }
331
+ let(:presence_channel) { channel.presence }
332
+
333
+ context 'and another invalid client_id' do
334
+ context 'before authentication' do
335
+ it 'allows the operation and then Ably rejects the operation' do
336
+ presence_channel.public_send(method_name, 'invalid').errback do |error|
337
+ expect(error.code).to eql(40012)
338
+ stop_reactor
339
+ end
340
+ end
341
+ end
342
+
343
+ context 'after authentication' do
344
+ it 'throws an exception' do
345
+ channel.attach do
346
+ expect { presence_channel.public_send(method_name, 'invalid') }.to raise_error Ably::Exceptions::IncompatibleClientId
347
+ stop_reactor
348
+ end
349
+ end
350
+ end
351
+ end
352
+
353
+ context 'and a wildcard client_id' do
354
+ it 'throws an exception' do
355
+ expect { presence_channel.public_send(method_name, '*') }.to raise_error Ably::Exceptions::IncompatibleClientId
356
+ stop_reactor
357
+ end
358
+ end
359
+
360
+ context 'and an empty client_id' do
361
+ it 'throws an exception' do
362
+ expect { presence_channel.public_send(method_name, nil) }.to raise_error Ably::Exceptions::IncompatibleClientId
363
+ stop_reactor
364
+ end
365
+ end
366
+ end
367
+
368
+ context ":#{method_name} when anonymous and no client_id" do
369
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: nil).token }
370
+ let(:client_options) { default_options.merge(key: nil, token: token) }
371
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options.merge(log_level: :error)) }
372
+ let(:channel) { client.channels.get(channel_name) }
373
+ let(:presence_channel) { channel.presence }
374
+
375
+ context 'and another invalid client_id' do
376
+ context 'before authentication' do
377
+ it 'allows the operation and then Ably rejects the operation' do
378
+ presence_channel.public_send(method_name, 'invalid').errback do |error|
379
+ expect(error.code).to eql(40012)
380
+ stop_reactor
381
+ end
382
+ end
383
+ end
384
+
385
+ context 'after authentication' do
386
+ it 'throws an exception' do
387
+ channel.attach do
388
+ expect { presence_channel.public_send(method_name, 'invalid') }.to raise_error Ably::Exceptions::IncompatibleClientId
389
+ stop_reactor
390
+ end
391
+ end
392
+ end
393
+ end
394
+
395
+ context 'and a wildcard client_id' do
396
+ it 'throws an exception' do
397
+ expect { presence_channel.public_send(method_name, '*') }.to raise_error Ably::Exceptions::IncompatibleClientId
398
+ stop_reactor
399
+ end
400
+ end
401
+
402
+ context 'and an empty client_id' do
403
+ it 'throws an exception' do
404
+ expect { presence_channel.public_send(method_name, nil) }.to raise_error Ably::Exceptions::IncompatibleClientId
405
+ stop_reactor
406
+ end
407
+ end
408
+ end
409
+ end
410
+
291
411
  context 'when attached (but not present) on a presence channel with an anonymous client (no client ID)' do
292
412
  it 'maintains state as other clients enter and leave the channel' do
293
413
  channel_anonymous_client.attach do
@@ -394,6 +514,7 @@ describe Ably::Realtime::Presence, :event_machine do
394
514
  let(:present) { [] }
395
515
  let(:entered) { [] }
396
516
  let(:sync_pages_received) { [] }
517
+ let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: wildcard_token)) }
397
518
 
398
519
  def setup_members_on(presence)
399
520
  enter_expected_count.times do |index|
@@ -434,7 +555,10 @@ describe Ably::Realtime::Presence, :event_machine do
434
555
  presence_anonymous_client.subscribe(:leave) do |leave_message|
435
556
  expect(leave_message.client_id).to eql(leave_member.client_id)
436
557
  expect(present.count).to be < enter_expected_count
437
- stop_reactor
558
+ EventMachine.add_timer(1) do
559
+ presence_anonymous_client.unsubscribe
560
+ stop_reactor
561
+ end
438
562
  end
439
563
 
440
564
  anonymous_client.connect do
@@ -471,7 +595,10 @@ describe Ably::Realtime::Presence, :event_machine do
471
595
  if present.count == enter_expected_count
472
596
  presence_anonymous_client.get do |members|
473
597
  expect(members.find { |member| member.client_id == leave_member.client_id}.action).to eq(:present)
474
- stop_reactor
598
+ EventMachine.add_timer(1) do
599
+ presence_anonymous_client.unsubscribe
600
+ stop_reactor
601
+ end
475
602
  end
476
603
  end
477
604
  end
@@ -523,7 +650,10 @@ describe Ably::Realtime::Presence, :event_machine do
523
650
  expect(members.count).to eql(enter_expected_count - 1)
524
651
  expect(member_left_emitted).to eql(true)
525
652
  expect(members.map(&:client_id)).to_not include(left_client_id)
526
- stop_reactor
653
+ EventMachine.add_timer(1) do
654
+ presence_anonymous_client.unsubscribe
655
+ stop_reactor
656
+ end
527
657
  end
528
658
 
529
659
  channel_anonymous_client.attach do
@@ -544,7 +674,7 @@ describe Ably::Realtime::Presence, :event_machine do
544
674
 
545
675
  context '#get' do
546
676
  context 'with :wait_for_sync option set to true' do
547
- it 'waits until sync is complete', event_machine: 15 do
677
+ it 'waits until sync is complete', em_timeout: 15 do
548
678
  enter_expected_count.times do |index|
549
679
  presence_client_one.enter_client("client:#{index}") do |message|
550
680
  entered << message
@@ -561,7 +691,7 @@ describe Ably::Realtime::Presence, :event_machine do
561
691
  end
562
692
 
563
693
  context 'by default' do
564
- it 'it does not wait for sync', event_machine: 15 do
694
+ it 'it does not wait for sync', em_timeout: 15 do
565
695
  enter_expected_count.times do |index|
566
696
  presence_client_one.enter_client("client:#{index}") do |message|
567
697
  entered << message
@@ -656,7 +786,7 @@ describe Ably::Realtime::Presence, :event_machine do
656
786
  end
657
787
 
658
788
  it 'raises an exception if client_id is not set' do
659
- expect { channel_anonymous_client.presence.enter }.to raise_error(Ably::Exceptions::Standard, /without a client_id/)
789
+ expect { channel_anonymous_client.presence.enter }.to raise_error(Ably::Exceptions::IncompatibleClientId, /without a client_id/)
660
790
  stop_reactor
661
791
  end
662
792
 
@@ -789,7 +919,7 @@ describe Ably::Realtime::Presence, :event_machine do
789
919
  end
790
920
 
791
921
  it 'raises an exception if not entered' do
792
- expect { channel_anonymous_client.presence.leave }.to raise_error(Ably::Exceptions::Standard, /Unable to leave presence channel that is not entered/)
922
+ expect { channel_client_one.presence.leave }.to raise_error(Ably::Exceptions::Standard, /Unable to leave presence channel that is not entered/)
793
923
  stop_reactor
794
924
  end
795
925
 
@@ -824,8 +954,10 @@ describe Ably::Realtime::Presence, :event_machine do
824
954
 
825
955
  context 'entering/updating/leaving presence state on behalf of another client_id' do
826
956
  let(:client_count) { 5 }
827
- let(:clients) { [] }
828
- let(:data) { random_str }
957
+ let(:clients) { [] }
958
+ let(:data) { random_str }
959
+ let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: wildcard_token)) }
960
+ let(:client_two) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: wildcard_token)) }
829
961
 
830
962
  context '#enter_client' do
831
963
  context 'multiple times on the same channel with different client_ids' do
@@ -875,8 +1007,6 @@ describe Ably::Realtime::Presence, :event_machine do
875
1007
  end
876
1008
  end
877
1009
 
878
- it_should_behave_like 'a public presence method', :enter_client, nil, 'client_id'
879
-
880
1010
  context 'without necessary capabilities to enter on behalf of another client' do
881
1011
  let(:restricted_client) do
882
1012
  auto_close Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
@@ -891,6 +1021,9 @@ describe Ably::Realtime::Presence, :event_machine do
891
1021
  end
892
1022
  end
893
1023
  end
1024
+
1025
+ it_should_behave_like 'a public presence method', :enter_client, nil, 'client_id'
1026
+ it_should_behave_like 'a presence on behalf of another client method', :enter_client
894
1027
  end
895
1028
 
896
1029
  context '#update_client' do
@@ -955,6 +1088,7 @@ describe Ably::Realtime::Presence, :event_machine do
955
1088
  end
956
1089
 
957
1090
  it_should_behave_like 'a public presence method', :update_client, nil, 'client_id'
1091
+ it_should_behave_like 'a presence on behalf of another client method', :update_client
958
1092
  end
959
1093
 
960
1094
  context '#leave_client' do
@@ -1048,6 +1182,7 @@ describe Ably::Realtime::Presence, :event_machine do
1048
1182
  end
1049
1183
 
1050
1184
  it_should_behave_like 'a public presence method', :leave_client, nil, 'client_id'
1185
+ it_should_behave_like 'a presence on behalf of another client method', :leave_client
1051
1186
  end
1052
1187
  end
1053
1188
 
@@ -1091,10 +1226,11 @@ describe Ably::Realtime::Presence, :event_machine do
1091
1226
  end
1092
1227
 
1093
1228
  context 'during a sync' do
1094
- let(:pages) { 2 }
1095
- let(:members_per_page) { 100 }
1229
+ let(:pages) { 2 }
1230
+ let(:members_per_page) { 100 }
1096
1231
  let(:sync_pages_received) { [] }
1097
- let(:client_options) { default_options.merge(log_level: :none) }
1232
+ let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: wildcard_token)) }
1233
+ let(:client_options) { default_options.merge(log_level: :none) }
1098
1234
 
1099
1235
  def connect_members_deferrables
1100
1236
  (members_per_page * pages + 1).times.map do |index|
@@ -1102,15 +1238,6 @@ describe Ably::Realtime::Presence, :event_machine do
1102
1238
  end
1103
1239
  end
1104
1240
 
1105
- before do
1106
- # Reconfigure client library so that it makes no retry attempts and fails immediately
1107
- stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
1108
- Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
1109
- disconnected: { retry_every: 0.1, max_time_in_state: 0 },
1110
- suspended: { retry_every: 0.1, max_time_in_state: 0 }
1111
- )
1112
- end
1113
-
1114
1241
  context 'when :wait_for_sync is true' do
1115
1242
  it 'fails if the connection fails' do
1116
1243
  when_all(*connect_members_deferrables) do
@@ -1118,7 +1245,10 @@ describe Ably::Realtime::Presence, :event_machine do
1118
1245
  client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
1119
1246
  if protocol_message.action == :sync
1120
1247
  sync_pages_received << protocol_message
1121
- force_connection_failure client_two if sync_pages_received.count == 1
1248
+ if sync_pages_received.count == 1
1249
+ error_message = Ably::Models::ProtocolMessage.new(action: 9, error: { message: 'force failure' })
1250
+ client_two.connection.__incoming_protocol_msgbus__.publish :protocol_message, error_message
1251
+ end
1122
1252
  end
1123
1253
  end
1124
1254
  end
@@ -1196,22 +1326,22 @@ describe Ably::Realtime::Presence, :event_machine do
1196
1326
  end
1197
1327
 
1198
1328
  it 'filters by client_id option if provided' do
1199
- presence_client_one.enter(client_id: 'one') do
1200
- presence_client_two.enter client_id: 'two'
1329
+ presence_client_one.enter do
1330
+ presence_client_two.enter
1201
1331
  end
1202
1332
 
1203
1333
  presence_client_one.subscribe(:enter) do |presence_message|
1204
1334
  # wait until the client_two enter event has been sent to client_one
1205
- next unless presence_message.client_id == 'two'
1335
+ next unless presence_message.client_id == client_two_id
1206
1336
 
1207
- presence_client_one.get(client_id: 'one') do |members|
1337
+ presence_client_one.get(client_id: client_one_id) do |members|
1208
1338
  expect(members.count).to eq(1)
1209
- expect(members.first.client_id).to eql('one')
1339
+ expect(members.first.client_id).to eql(client_one_id)
1210
1340
  expect(members.first.connection_id).to eql(client_one.connection.id)
1211
1341
 
1212
- presence_client_one.get(client_id: 'two') do |members|
1342
+ presence_client_one.get(client_id: client_two_id) do |members|
1213
1343
  expect(members.count).to eq(1)
1214
- expect(members.first.client_id).to eql('two')
1344
+ expect(members.first.client_id).to eql(client_two_id)
1215
1345
  expect(members.first.connection_id).to eql(client_two.connection.id)
1216
1346
  stop_reactor
1217
1347
  end
@@ -1220,7 +1350,7 @@ describe Ably::Realtime::Presence, :event_machine do
1220
1350
  end
1221
1351
 
1222
1352
  it 'does not wait for SYNC to complete if :wait_for_sync option is false' do
1223
- presence_client_one.enter(client_id: 'one') do
1353
+ presence_client_one.enter do
1224
1354
  presence_client_two.get(wait_for_sync: false) do |members|
1225
1355
  expect(members.count).to eql(0)
1226
1356
  stop_reactor
@@ -1242,6 +1372,8 @@ describe Ably::Realtime::Presence, :event_machine do
1242
1372
  end
1243
1373
 
1244
1374
  context 'with lots of members on different clients' do
1375
+ let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: wildcard_token)) }
1376
+ let(:client_two) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: wildcard_token)) }
1245
1377
  let(:members_per_client) { 10 }
1246
1378
  let(:clients_entered) { Hash.new { |hash, key| hash[key] = 0 } }
1247
1379
  let(:total_members) { members_per_client * 2 }
@@ -1588,7 +1720,7 @@ describe Ably::Realtime::Presence, :event_machine do
1588
1720
 
1589
1721
  it 'resumes the SYNC operation', em_timeout: 15 do
1590
1722
  when_all(*members_count.times.map do |index|
1591
- presence_client_one.enter_client("client:#{index}")
1723
+ presence_anonymous_client.enter_client("client:#{index}")
1592
1724
  end) do
1593
1725
  channel_client_two.attach do
1594
1726
  client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
@@ -22,6 +22,19 @@ describe Ably::Realtime::Client, '#time', :event_machine do
22
22
  stop_reactor
23
23
  end
24
24
  end
25
+
26
+ context 'with reconfigured HTTP timeout' do
27
+ let(:client) do
28
+ auto_close Ably::Realtime::Client.new(http_request_timeout: 0.0001, key: api_key, environment: environment, protocol: protocol, log_level: :fatal)
29
+ end
30
+
31
+ it 'should raise a timeout exception' do
32
+ client.time.errback do |error|
33
+ expect(error).to be_a Ably::Exceptions::ConnectionTimeout
34
+ stop_reactor
35
+ end
36
+ end
37
+ end
25
38
  end
26
39
  end
27
40
  end