ably 1.1.0 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +27 -0
  3. data/CHANGELOG.md +68 -2
  4. data/COPYRIGHT +1 -0
  5. data/LICENSE +172 -11
  6. data/MAINTAINERS.md +1 -0
  7. data/README.md +3 -7
  8. data/SPEC.md +944 -914
  9. data/ably.gemspec +7 -7
  10. data/lib/ably/auth.rb +12 -2
  11. data/lib/ably/exceptions.rb +2 -2
  12. data/lib/ably/logger.rb +7 -1
  13. data/lib/ably/modules/state_machine.rb +1 -1
  14. data/lib/ably/realtime/channel.rb +7 -11
  15. data/lib/ably/realtime/channel/channel_manager.rb +2 -2
  16. data/lib/ably/realtime/channel/channel_properties.rb +24 -0
  17. data/lib/ably/realtime/client.rb +12 -3
  18. data/lib/ably/realtime/connection.rb +31 -19
  19. data/lib/ably/realtime/connection/connection_manager.rb +19 -3
  20. data/lib/ably/realtime/connection/websocket_transport.rb +67 -1
  21. data/lib/ably/realtime/presence.rb +0 -14
  22. data/lib/ably/rest/channel.rb +25 -17
  23. data/lib/ably/rest/client.rb +22 -11
  24. data/lib/ably/version.rb +1 -1
  25. data/spec/acceptance/realtime/auth_spec.rb +16 -13
  26. data/spec/acceptance/realtime/channel_history_spec.rb +26 -20
  27. data/spec/acceptance/realtime/channel_spec.rb +21 -8
  28. data/spec/acceptance/realtime/client_spec.rb +80 -20
  29. data/spec/acceptance/realtime/connection_failures_spec.rb +71 -5
  30. data/spec/acceptance/realtime/connection_spec.rb +153 -26
  31. data/spec/acceptance/realtime/message_spec.rb +17 -17
  32. data/spec/acceptance/realtime/presence_history_spec.rb +0 -58
  33. data/spec/acceptance/realtime/presence_spec.rb +250 -162
  34. data/spec/acceptance/realtime/push_admin_spec.rb +49 -25
  35. data/spec/acceptance/rest/auth_spec.rb +6 -75
  36. data/spec/acceptance/rest/channel_spec.rb +79 -4
  37. data/spec/acceptance/rest/channels_spec.rb +6 -0
  38. data/spec/acceptance/rest/client_spec.rb +72 -12
  39. data/spec/acceptance/rest/message_spec.rb +8 -27
  40. data/spec/acceptance/rest/push_admin_spec.rb +67 -27
  41. data/spec/shared/client_initializer_behaviour.rb +0 -8
  42. data/spec/spec_helper.rb +2 -1
  43. data/spec/support/debug_failure_helper.rb +9 -5
  44. data/spec/support/serialization_helper.rb +21 -0
  45. data/spec/support/test_app.rb +2 -2
  46. data/spec/unit/modules/enum_spec.rb +1 -1
  47. data/spec/unit/realtime/client_spec.rb +20 -7
  48. data/spec/unit/realtime/connection_spec.rb +1 -1
  49. metadata +40 -29
  50. data/.travis.yml +0 -16
@@ -96,8 +96,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
96
96
  end
97
97
 
98
98
  context 'JSON Array' do
99
- # TODO: Add nil type back in
100
- let(:data) { { 'push' => { 'data' => { 'key' => [ true, false, 55, 'string', { 'Hash' => true }, ['array'] ] } } } }
99
+ let(:data) { { 'push' => { 'data' => { 'key' => [ true, false, 55, nil, 'string', { 'Hash' => true }, ['array'] ] } } } }
101
100
 
102
101
  it 'is encoded and decoded to the same Array' do
103
102
  publish_and_check_extras data
@@ -353,23 +352,25 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
353
352
  first_message_protocol_message ||= protocol_message unless protocol_message.messages.empty?
354
353
  end
355
354
 
356
- channel.subscribe do |message|
357
- messages_received << message
358
- if messages_received.count == 2
359
- # simulate a duplicate protocol message being received
360
- EventMachine.next_tick do
361
- connection.__incoming_protocol_msgbus__.publish :protocol_message, first_message_protocol_message
355
+ channel.attach do
356
+ channel.subscribe do |message|
357
+ messages_received << message
358
+ if messages_received.count == 2
359
+ # simulate a duplicate protocol message being received
360
+ EventMachine.next_tick do
361
+ connection.__incoming_protocol_msgbus__.publish :protocol_message, first_message_protocol_message
362
+ end
362
363
  end
363
364
  end
364
- end
365
- 2.times { |i| EventMachine.add_timer(i.to_f / 5) { channel.publish('event', 'data') } }
365
+ 2.times { |i| EventMachine.add_timer(i.to_f / 5) { channel.publish('event', 'data') } }
366
366
 
367
- expect(client.logger).to receive(:error) do |*args, &block|
368
- expect(args.concat([block ? block.call : nil]).join(',')).to match(/duplicate/)
367
+ expect(client.logger).to receive(:error) do |*args, &block|
368
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/duplicate/)
369
369
 
370
- EventMachine.add_timer(0.5) do
371
- expect(messages_received.count).to eql(2)
372
- stop_reactor
370
+ EventMachine.add_timer(0.5) do
371
+ expect(messages_received.count).to eql(2)
372
+ stop_reactor
373
+ end
373
374
  end
374
375
  end
375
376
  end
@@ -656,8 +657,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
656
657
  expect(message_state).to be_empty
657
658
  EventMachine.add_timer(2) do
658
659
  expect(message_state).to contain_exactly(:delivered)
659
- # TODO: Uncomment once issue realtime#42 is resolved
660
- # expect(msgs_received.length).to eql(1)
660
+ expect(msgs_received.length).to eql(1)
661
661
  stop_reactor
662
662
  end
663
663
  end
@@ -52,63 +52,5 @@ describe Ably::Realtime::Presence, 'history', :event_machine do
52
52
 
53
53
  presence_client_one.enter(data)
54
54
  end
55
-
56
- context 'with option until_attach: true' do
57
- let(:event) { random_str }
58
- let(:presence_data_before_attach) { random_str }
59
- let(:presence_data_after_attach) { random_str }
60
-
61
- it 'retrieves all presence messages before channel was attached' do
62
- presence_client_two.enter(presence_data_before_attach) do
63
- presence_client_one.enter(presence_data_after_attach) do
64
- presence_client_one.history(until_attach: true) do |presence_page|
65
- expect(presence_page.items.count).to eql(1)
66
- expect(presence_page.items.first.data).to eql(presence_data_before_attach)
67
- stop_reactor
68
- end
69
- end
70
- end
71
- end
72
-
73
- context 'and two pages of messages' do
74
- let(:wildcard_token) { lambda { |token_params| Ably::Rest::Client.new(default_options).auth.request_token(client_id: '*') } }
75
- let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(auth_callback: wildcard_token)) }
76
- let(:client_two) { auto_close Ably::Realtime::Client.new(default_options.merge(auth_callback: wildcard_token)) }
77
-
78
- # TODO: Remove retry logic when presence history regression fixed
79
- # https://github.com/ably/realtime/issues/1707
80
- #
81
- it 'retrieves two pages of messages before channel was attached', retry: 10, :retry_wait => 5 do
82
- when_all(*10.times.map { |i| presence_client_two.enter_client("client:#{i}", presence_data_before_attach) }) do
83
- when_all(*10.times.map { |i| presence_client_one.enter_client("client:#{i}", presence_data_after_attach) }) do
84
- presence_client_one.history(until_attach: true, limit: 5) do |presence_page|
85
- expect(presence_page.items.count).to eql(5)
86
- expect(presence_page.items.map(&:data).uniq.first).to eql(presence_data_before_attach)
87
-
88
- presence_page.next do |presence_next_page|
89
- expect(presence_next_page.items.count).to eql(5)
90
- expect(presence_next_page.items.map(&:data).uniq.first).to eql(presence_data_before_attach)
91
- if presence_next_page.has_next?
92
- presence_next_page.next do |last|
93
- expect(last.items.count).to eql(0)
94
- end
95
- else
96
- expect(presence_next_page).to be_last
97
- end
98
- stop_reactor
99
- end
100
- end
101
- end
102
- end
103
- end
104
- end
105
-
106
- it 'fails with an exception unless state is attached' do
107
- presence_client_one.history(until_attach: true).errback do |error|
108
- expect(error.message).to match(/not attached/)
109
- stop_reactor
110
- end
111
- end
112
- end
113
55
  end
114
56
  end
@@ -1073,12 +1073,12 @@ describe Ably::Realtime::Presence, :event_machine do
1073
1073
  context 'message #connection_id' do
1074
1074
  it 'matches the current client connection_id' do
1075
1075
  channel_client_two.attach do
1076
- presence_client_one.enter
1077
- end
1076
+ presence_client_two.subscribe do |presence|
1077
+ expect(presence.connection_id).to eq(client_one.connection.id)
1078
+ stop_reactor
1079
+ end
1078
1080
 
1079
- presence_client_two.subscribe do |presence|
1080
- expect(presence.connection_id).to eq(client_one.connection.id)
1081
- stop_reactor
1081
+ presence_client_one.enter
1082
1082
  end
1083
1083
  end
1084
1084
  end
@@ -1128,22 +1128,26 @@ describe Ably::Realtime::Presence, :event_machine do
1128
1128
  end
1129
1129
 
1130
1130
  it 'updates the data if :data argument provided' do
1131
- presence_client_one.enter('prior') do
1132
- presence_client_one.update(data_payload)
1133
- end
1134
- presence_client_one.subscribe(:update) do |message|
1135
- expect(message.data).to eql(data_payload)
1136
- stop_reactor
1131
+ channel_client_one.attach do
1132
+ presence_client_one.enter('prior') do
1133
+ presence_client_one.update(data_payload)
1134
+ end
1135
+ presence_client_one.subscribe(:update) do |message|
1136
+ expect(message.data).to eql(data_payload)
1137
+ stop_reactor
1138
+ end
1137
1139
  end
1138
1140
  end
1139
1141
 
1140
1142
  it 'updates the data to nil if :data argument is not provided (assumes nil value)' do
1141
- presence_client_one.enter('prior') do
1142
- presence_client_one.update
1143
- end
1144
- presence_client_one.subscribe(:update) do |message|
1145
- expect(message.data).to be_nil
1146
- stop_reactor
1143
+ channel_client_one.attach do
1144
+ presence_client_one.enter('prior') do
1145
+ presence_client_one.update
1146
+ end
1147
+ presence_client_one.subscribe(:update) do |message|
1148
+ expect(message.data).to be_nil
1149
+ stop_reactor
1150
+ end
1147
1151
  end
1148
1152
  end
1149
1153
 
@@ -1157,39 +1161,45 @@ describe Ably::Realtime::Presence, :event_machine do
1157
1161
 
1158
1162
  context 'when set to a string' do
1159
1163
  it 'emits the new data for the leave event' do
1160
- presence_client_one.enter enter_data do
1161
- presence_client_one.leave data
1162
- end
1164
+ channel_client_one.attach do
1165
+ presence_client_one.enter enter_data do
1166
+ presence_client_one.leave data
1167
+ end
1163
1168
 
1164
- presence_client_one.subscribe(:leave) do |presence_message|
1165
- expect(presence_message.data).to eql(data)
1166
- stop_reactor
1169
+ presence_client_one.subscribe(:leave) do |presence_message|
1170
+ expect(presence_message.data).to eql(data)
1171
+ stop_reactor
1172
+ end
1167
1173
  end
1168
1174
  end
1169
1175
  end
1170
1176
 
1171
1177
  context 'when set to nil' do
1172
1178
  it 'emits the last value for the data attribute when leaving' do
1173
- presence_client_one.enter enter_data do
1174
- presence_client_one.leave nil
1175
- end
1179
+ channel_client_one.attach do
1180
+ presence_client_one.enter enter_data do
1181
+ presence_client_one.leave nil
1182
+ end
1176
1183
 
1177
- presence_client_one.subscribe(:leave) do |presence_message|
1178
- expect(presence_message.data).to eql(enter_data)
1179
- stop_reactor
1184
+ presence_client_one.subscribe(:leave) do |presence_message|
1185
+ expect(presence_message.data).to eql(enter_data)
1186
+ stop_reactor
1187
+ end
1180
1188
  end
1181
1189
  end
1182
1190
  end
1183
1191
 
1184
1192
  context 'when not passed as an argument (i.e. nil)' do
1185
1193
  it 'emits the previous value for the data attribute when leaving' do
1186
- presence_client_one.enter enter_data do
1187
- presence_client_one.leave
1188
- end
1194
+ channel_client_one.attach do
1195
+ presence_client_one.enter enter_data do
1196
+ presence_client_one.leave
1197
+ end
1189
1198
 
1190
- presence_client_one.subscribe(:leave) do |presence_message|
1191
- expect(presence_message.data).to eql(enter_data)
1192
- stop_reactor
1199
+ presence_client_one.subscribe(:leave) do |presence_message|
1200
+ expect(presence_message.data).to eql(enter_data)
1201
+ stop_reactor
1202
+ end
1193
1203
  end
1194
1204
  end
1195
1205
  end
@@ -1198,38 +1208,42 @@ describe Ably::Realtime::Presence, :event_machine do
1198
1208
  it 'does not cache members that have left' do
1199
1209
  enter_ack = false
1200
1210
 
1201
- presence_client_one.subscribe(:enter) do
1202
- presence_client_one.unsubscribe :enter
1211
+ channel_client_one.attach do
1212
+ presence_client_one.subscribe(:enter) do
1213
+ presence_client_one.unsubscribe :enter
1203
1214
 
1204
- expect(presence_client_one.members).to be_in_sync
1205
- expect(presence_client_one.members.send(:members).count).to eql(1)
1206
- presence_client_one.leave data
1207
- end
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
1218
+ end
1208
1219
 
1209
- presence_client_one.enter(enter_data) do
1210
- enter_ack = true
1211
- end
1220
+ presence_client_one.enter(enter_data) do
1221
+ enter_ack = true
1222
+ end
1212
1223
 
1213
- presence_client_one.subscribe(:leave) do |presence_message|
1214
- presence_client_one.unsubscribe :leave
1215
- expect(presence_message.data).to eql(data)
1216
- expect(presence_client_one.members.send(:members).count).to eql(0)
1217
- expect(enter_ack).to eql(true)
1218
- stop_reactor
1224
+ presence_client_one.subscribe(:leave) do |presence_message|
1225
+ presence_client_one.unsubscribe :leave
1226
+ expect(presence_message.data).to eql(data)
1227
+ expect(presence_client_one.members.send(:members).count).to eql(0)
1228
+ expect(enter_ack).to eql(true)
1229
+ stop_reactor
1230
+ end
1219
1231
  end
1220
1232
  end
1221
1233
  end
1222
1234
  end
1223
1235
 
1224
1236
  it 'succeeds and does not emit an event (#RTP10d)' do
1225
- channel_client_one.presence.leave do
1226
- # allow enough time for leave event to (not) fire
1227
- EventMachine.add_timer(2) do
1228
- stop_reactor
1237
+ channel_client_one.attach do
1238
+ channel_client_one.presence.leave do
1239
+ # allow enough time for leave event to (not) fire
1240
+ EventMachine.add_timer(2) do
1241
+ stop_reactor
1242
+ end
1243
+ end
1244
+ channel_client_one.subscribe(:leave) do
1245
+ raise "No leave event should fire"
1229
1246
  end
1230
- end
1231
- channel_client_one.subscribe(:leave) do
1232
- raise "No leave event should fire"
1233
1247
  end
1234
1248
  end
1235
1249
 
@@ -1238,26 +1252,30 @@ describe Ably::Realtime::Presence, :event_machine do
1238
1252
 
1239
1253
  context ':left event' do
1240
1254
  it 'emits the data defined in enter' do
1241
- channel_client_one.presence.enter('data') do
1242
- channel_client_one.presence.leave
1243
- end
1255
+ channel_client_two.attach do
1256
+ channel_client_one.presence.enter('data') do
1257
+ channel_client_one.presence.leave
1258
+ end
1244
1259
 
1245
- channel_client_two.presence.subscribe(:leave) do |message|
1246
- expect(message.data).to eql('data')
1247
- stop_reactor
1260
+ channel_client_two.presence.subscribe(:leave) do |message|
1261
+ expect(message.data).to eql('data')
1262
+ stop_reactor
1263
+ end
1248
1264
  end
1249
1265
  end
1250
1266
 
1251
1267
  it 'emits the data defined in update' do
1252
- channel_client_one.presence.enter('something else') do
1253
- channel_client_one.presence.update('data') do
1254
- channel_client_one.presence.leave
1268
+ channel_client_two.attach do
1269
+ channel_client_one.presence.enter('something else') do
1270
+ channel_client_one.presence.update('data') do
1271
+ channel_client_one.presence.leave
1272
+ end
1255
1273
  end
1256
- end
1257
1274
 
1258
- channel_client_two.presence.subscribe(:leave) do |message|
1259
- expect(message.data).to eql('data')
1260
- stop_reactor
1275
+ channel_client_two.presence.subscribe(:leave) do |message|
1276
+ expect(message.data).to eql('data')
1277
+ stop_reactor
1278
+ end
1261
1279
  end
1262
1280
  end
1263
1281
  end
@@ -1286,17 +1304,19 @@ describe Ably::Realtime::Presence, :event_machine do
1286
1304
  end
1287
1305
 
1288
1306
  it 'enters a channel and sets the data based on the provided :data option' do
1289
- client_count.times do |client_id|
1290
- presence_client_one.enter_client("client:#{client_id}", data)
1291
- end
1307
+ channel_anonymous_client.attach do
1308
+ client_count.times do |client_id|
1309
+ presence_client_one.enter_client("client:#{client_id}", data)
1310
+ end
1292
1311
 
1293
- presence_anonymous_client.subscribe(:enter) do |presence|
1294
- expect(presence.data).to eql(data)
1295
- clients << presence
1296
- next unless clients.count == 5
1312
+ presence_anonymous_client.subscribe(:enter) do |presence|
1313
+ expect(presence.data).to eql(data)
1314
+ clients << presence
1315
+ next unless clients.count == 5
1297
1316
 
1298
- expect(clients.map(&:client_id).uniq.count).to eql(5)
1299
- stop_reactor
1317
+ expect(clients.map(&:client_id).uniq.count).to eql(5)
1318
+ stop_reactor
1319
+ end
1300
1320
  end
1301
1321
  end
1302
1322
  end
@@ -1307,12 +1327,12 @@ describe Ably::Realtime::Presence, :event_machine do
1307
1327
  it 'matches the current client connection_id' do
1308
1328
  channel_client_two.attach do
1309
1329
  presence_client_one.enter_client(client_id)
1310
- end
1311
1330
 
1312
- presence_client_two.subscribe do |presence|
1313
- expect(presence.client_id).to eq(client_id)
1314
- expect(presence.connection_id).to eq(client_one.connection.id)
1315
- stop_reactor
1331
+ presence_client_two.subscribe do |presence|
1332
+ expect(presence.client_id).to eq(client_id)
1333
+ expect(presence.connection_id).to eq(client_one.connection.id)
1334
+ stop_reactor
1335
+ end
1316
1336
  end
1317
1337
  end
1318
1338
  end
@@ -1341,57 +1361,63 @@ describe Ably::Realtime::Presence, :event_machine do
1341
1361
  it 'updates the data attribute for the member when :data option provided' do
1342
1362
  updated_callback_count = 0
1343
1363
 
1344
- client_count.times do |client_id|
1345
- presence_client_one.enter_client("client:#{client_id}") do
1346
- presence_client_one.update_client("client:#{client_id}", data) do
1347
- updated_callback_count += 1
1364
+ channel_anonymous_client.attach do
1365
+ client_count.times do |client_id|
1366
+ presence_client_one.enter_client("client:#{client_id}") do
1367
+ presence_client_one.update_client("client:#{client_id}", data) do
1368
+ updated_callback_count += 1
1369
+ end
1348
1370
  end
1349
1371
  end
1350
- end
1351
1372
 
1352
- presence_anonymous_client.subscribe(:update) do |presence|
1353
- expect(presence.data).to eql(data)
1354
- clients << presence
1355
- next unless clients.count == 5
1373
+ presence_anonymous_client.subscribe(:update) do |presence|
1374
+ expect(presence.data).to eql(data)
1375
+ clients << presence
1376
+ next unless clients.count == 5
1356
1377
 
1357
- wait_until(lambda { updated_callback_count == 5 }) do
1358
- expect(clients.map(&:client_id).uniq.count).to eql(5)
1359
- expect(updated_callback_count).to eql(5)
1360
- stop_reactor
1378
+ wait_until(lambda { updated_callback_count == 5 }) do
1379
+ expect(clients.map(&:client_id).uniq.count).to eql(5)
1380
+ expect(updated_callback_count).to eql(5)
1381
+ stop_reactor
1382
+ end
1361
1383
  end
1362
1384
  end
1363
1385
  end
1364
1386
 
1365
1387
  it 'updates the data attribute to null for the member when :data option is not provided (assumed null)' do
1366
- presence_client_one.enter_client('client_1') do
1367
- presence_client_one.update_client('client_1')
1368
- end
1388
+ channel_anonymous_client.attach do
1389
+ presence_client_one.enter_client('client_1') do
1390
+ presence_client_one.update_client('client_1')
1391
+ end
1369
1392
 
1370
- presence_anonymous_client.subscribe(:update) do |presence|
1371
- expect(presence.client_id).to eql('client_1')
1372
- expect(presence.data).to be_nil
1373
- stop_reactor
1393
+ presence_anonymous_client.subscribe(:update) do |presence|
1394
+ expect(presence.client_id).to eql('client_1')
1395
+ expect(presence.data).to be_nil
1396
+ stop_reactor
1397
+ end
1374
1398
  end
1375
1399
  end
1376
1400
 
1377
1401
  it 'enters if not already entered' do
1378
1402
  updated_callback_count = 0
1379
1403
 
1380
- client_count.times do |client_id|
1381
- presence_client_one.update_client("client:#{client_id}", data) do
1382
- updated_callback_count += 1
1404
+ channel_anonymous_client.attach do
1405
+ client_count.times do |client_id|
1406
+ presence_client_one.update_client("client:#{client_id}", data) do
1407
+ updated_callback_count += 1
1408
+ end
1383
1409
  end
1384
- end
1385
1410
 
1386
- presence_anonymous_client.subscribe(:enter) do |presence|
1387
- expect(presence.data).to eql(data)
1388
- clients << presence
1389
- next unless clients.count == 5
1411
+ presence_anonymous_client.subscribe(:enter) do |presence|
1412
+ expect(presence.data).to eql(data)
1413
+ clients << presence
1414
+ next unless clients.count == 5
1390
1415
 
1391
- wait_until(lambda { updated_callback_count == 5 }) do
1392
- expect(clients.map(&:client_id).uniq.count).to eql(5)
1393
- expect(updated_callback_count).to eql(5)
1394
- stop_reactor
1416
+ wait_until(lambda { updated_callback_count == 5 }) do
1417
+ expect(clients.map(&:client_id).uniq.count).to eql(5)
1418
+ expect(updated_callback_count).to eql(5)
1419
+ stop_reactor
1420
+ end
1395
1421
  end
1396
1422
  end
1397
1423
  end
@@ -1407,23 +1433,25 @@ describe Ably::Realtime::Presence, :event_machine do
1407
1433
  it 'emits the :leave event for each client_id' do
1408
1434
  left_callback_count = 0
1409
1435
 
1410
- client_count.times do |client_id|
1411
- presence_client_one.enter_client("client:#{client_id}", random_str) do
1412
- presence_client_one.leave_client("client:#{client_id}", data) do
1413
- left_callback_count += 1
1436
+ channel_anonymous_client.attach do
1437
+ client_count.times do |client_id|
1438
+ presence_client_one.enter_client("client:#{client_id}", random_str) do
1439
+ presence_client_one.leave_client("client:#{client_id}", data) do
1440
+ left_callback_count += 1
1441
+ end
1414
1442
  end
1415
1443
  end
1416
- end
1417
1444
 
1418
- presence_anonymous_client.subscribe(:leave) do |presence|
1419
- expect(presence.data).to eql(data)
1420
- clients << presence
1421
- next unless clients.count == 5
1445
+ presence_anonymous_client.subscribe(:leave) do |presence|
1446
+ expect(presence.data).to eql(data)
1447
+ clients << presence
1448
+ next unless clients.count == 5
1422
1449
 
1423
- wait_until(lambda { left_callback_count == 5 }) do
1424
- expect(clients.map(&:client_id).uniq.count).to eql(5)
1425
- expect(left_callback_count).to eql(5)
1426
- stop_reactor
1450
+ wait_until(lambda { left_callback_count == 5 }) do
1451
+ expect(clients.map(&:client_id).uniq.count).to eql(5)
1452
+ expect(left_callback_count).to eql(5)
1453
+ stop_reactor
1454
+ end
1427
1455
  end
1428
1456
  end
1429
1457
  end
@@ -1431,21 +1459,23 @@ describe Ably::Realtime::Presence, :event_machine do
1431
1459
  it 'succeeds if that client_id has not previously entered the channel' do
1432
1460
  left_callback_count = 0
1433
1461
 
1434
- client_count.times do |client_id|
1435
- presence_client_one.leave_client("client:#{client_id}") do
1436
- left_callback_count += 1
1462
+ channel_anonymous_client.attach do
1463
+ client_count.times do |client_id|
1464
+ presence_client_one.leave_client("client:#{client_id}") do
1465
+ left_callback_count += 1
1466
+ end
1437
1467
  end
1438
- end
1439
1468
 
1440
- presence_anonymous_client.subscribe(:leave) do |presence|
1441
- expect(presence.data).to be_nil
1442
- clients << presence
1443
- next unless clients.count == 5
1469
+ presence_anonymous_client.subscribe(:leave) do |presence|
1470
+ expect(presence.data).to be_nil
1471
+ clients << presence
1472
+ next unless clients.count == 5
1444
1473
 
1445
- wait_until(lambda { left_callback_count == 5 }) do
1446
- expect(clients.map(&:client_id).uniq.count).to eql(5)
1447
- expect(left_callback_count).to eql(5)
1448
- stop_reactor
1474
+ wait_until(lambda { left_callback_count == 5 }) do
1475
+ expect(clients.map(&:client_id).uniq.count).to eql(5)
1476
+ expect(left_callback_count).to eql(5)
1477
+ stop_reactor
1478
+ end
1449
1479
  end
1450
1480
  end
1451
1481
  end
@@ -1453,39 +1483,45 @@ describe Ably::Realtime::Presence, :event_machine do
1453
1483
 
1454
1484
  context 'with a new value in :data option' do
1455
1485
  it 'emits the leave event with the new data value' do
1456
- presence_client_one.enter_client("client:unique", random_str) do
1457
- presence_client_one.leave_client("client:unique", data)
1458
- end
1486
+ channel_client_one.attach do
1487
+ presence_client_one.enter_client("client:unique", random_str) do
1488
+ presence_client_one.leave_client("client:unique", data)
1489
+ end
1459
1490
 
1460
- presence_client_one.subscribe(:leave) do |presence_message|
1461
- expect(presence_message.data).to eql(data)
1462
- stop_reactor
1491
+ presence_client_one.subscribe(:leave) do |presence_message|
1492
+ expect(presence_message.data).to eql(data)
1493
+ stop_reactor
1494
+ end
1463
1495
  end
1464
1496
  end
1465
1497
  end
1466
1498
 
1467
1499
  context 'with a nil value in :data option' do
1468
1500
  it 'emits the leave event with the previous value as a convenience' do
1469
- presence_client_one.enter_client("client:unique", data) do
1470
- presence_client_one.leave_client("client:unique", nil)
1471
- end
1501
+ channel_client_one.attach do
1502
+ presence_client_one.enter_client("client:unique", data) do
1503
+ presence_client_one.leave_client("client:unique", nil)
1504
+ end
1472
1505
 
1473
- presence_client_one.subscribe(:leave) do |presence_message|
1474
- expect(presence_message.data).to eql(data)
1475
- stop_reactor
1506
+ presence_client_one.subscribe(:leave) do |presence_message|
1507
+ expect(presence_message.data).to eql(data)
1508
+ stop_reactor
1509
+ end
1476
1510
  end
1477
1511
  end
1478
1512
  end
1479
1513
 
1480
1514
  context 'with no :data option' do
1481
1515
  it 'emits the leave event with the previous value as a convenience' do
1482
- presence_client_one.enter_client("client:unique", data) do
1483
- presence_client_one.leave_client("client:unique")
1484
- end
1516
+ channel_client_one.attach do
1517
+ presence_client_one.enter_client("client:unique", data) do
1518
+ presence_client_one.leave_client("client:unique")
1519
+ end
1485
1520
 
1486
- presence_client_one.subscribe(:leave) do |presence_message|
1487
- expect(presence_message.data).to eql(data)
1488
- stop_reactor
1521
+ presence_client_one.subscribe(:leave) do |presence_message|
1522
+ expect(presence_message.data).to eql(data)
1523
+ stop_reactor
1524
+ end
1489
1525
  end
1490
1526
  end
1491
1527
  end
@@ -2341,15 +2377,13 @@ describe Ably::Realtime::Presence, :event_machine do
2341
2377
  let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: present_only_callback)) }
2342
2378
 
2343
2379
  it 'receives presence updates for all presence events generated by the current connection and the presence map is kept up to date (#RTP17a)' do
2344
- skip 'This functionality is not yet in sandbox, see https://github.com/ably/realtime/issues/656'
2345
-
2346
2380
  enter_client_ids = []
2347
2381
  presence_client_one.subscribe(:enter) do |presence_message|
2348
2382
  enter_client_ids << presence_message.client_id
2349
2383
  end
2350
2384
 
2351
2385
  leave_client_ids = []
2352
- presence_client_one.subscribe(:leave) do
2386
+ presence_client_one.subscribe(:leave) do |presence_message|
2353
2387
  leave_client_ids << presence_message.client_id
2354
2388
  end
2355
2389
 
@@ -2415,6 +2449,60 @@ describe Ably::Realtime::Presence, :event_machine do
2415
2449
  end
2416
2450
  end
2417
2451
 
2452
+ describe '#RTP17b' do
2453
+ let(:leave_action) { Ably::Models::PresenceMessage::ACTION.Leave }
2454
+
2455
+ it 'updates presence members on leave' do
2456
+ presence_client_two.subscribe(:enter) do
2457
+ channel_anonymous_client.attach do
2458
+ channel_anonymous_client.presence.get do |members|
2459
+ presence_client_two.subscribe(:leave) do
2460
+ expect(presence_client_two.members.local_members).to be_empty
2461
+ stop_reactor
2462
+ end
2463
+
2464
+ leave_message = Ably::Models::PresenceMessage.new(
2465
+ 'id' => "#{client_two.connection.id}:#{presence_client_two.client_id}:1",
2466
+ 'clientId' => presence_client_two.client_id,
2467
+ 'connectionId' => client_two.connection.id,
2468
+ 'timestamp' => as_since_epoch(Time.now),
2469
+ 'action' => leave_action
2470
+ )
2471
+
2472
+ presence_client_two.__incoming_msgbus__.publish :presence, leave_message
2473
+ end
2474
+ end
2475
+ end
2476
+
2477
+ presence_client_two.enter
2478
+ end
2479
+
2480
+ it 'does no update presence members on fabricated leave' do
2481
+ presence_client_two.subscribe(:enter) do
2482
+ channel_anonymous_client.attach do
2483
+ channel_anonymous_client.presence.get do |members|
2484
+ presence_client_two.subscribe(:leave) do
2485
+ expect(presence_client_two.members.local_members).to_not be_empty
2486
+ stop_reactor
2487
+ end
2488
+
2489
+ fabricated_leave_message = Ably::Models::PresenceMessage.new(
2490
+ 'id' => "#{client_two.connection.id}:#{presence_client_two.client_id}:1",
2491
+ 'clientId' => presence_client_two.client_id,
2492
+ 'connectionId' => "fabricated:#{presence_client_two.client_id}:0",
2493
+ 'timestamp' => as_since_epoch(Time.now),
2494
+ 'action' => leave_action
2495
+ )
2496
+
2497
+ presence_client_two.__incoming_msgbus__.publish :presence, fabricated_leave_message
2498
+ end
2499
+ end
2500
+ end
2501
+
2502
+ presence_client_two.enter
2503
+ end
2504
+ end
2505
+
2418
2506
  context 'when a channel becomes attached again' do
2419
2507
  let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached.to_i }
2420
2508
  let(:sync_action) { Ably::Models::ProtocolMessage::ACTION.Sync.to_i }