ably 1.1.1 → 1.1.5

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +27 -0
  3. data/CHANGELOG.md +60 -2
  4. data/COPYRIGHT +1 -0
  5. data/LICENSE +172 -11
  6. data/MAINTAINERS.md +1 -0
  7. data/README.md +2 -14
  8. data/SPEC.md +1020 -922
  9. data/ably.gemspec +5 -5
  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/ably.rb +11 -1
  14. data/lib/ably/modules/state_machine.rb +1 -1
  15. data/lib/ably/realtime/channel.rb +7 -11
  16. data/lib/ably/realtime/channel/channel_manager.rb +2 -2
  17. data/lib/ably/realtime/channel/channel_properties.rb +24 -0
  18. data/lib/ably/realtime/client.rb +9 -0
  19. data/lib/ably/realtime/connection.rb +7 -4
  20. data/lib/ably/realtime/connection/connection_manager.rb +19 -1
  21. data/lib/ably/realtime/connection/websocket_transport.rb +67 -1
  22. data/lib/ably/realtime/presence.rb +0 -14
  23. data/lib/ably/rest/channel.rb +25 -17
  24. data/lib/ably/rest/client.rb +35 -17
  25. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
  26. data/lib/ably/version.rb +1 -1
  27. data/spec/acceptance/realtime/auth_spec.rb +5 -4
  28. data/spec/acceptance/realtime/channel_spec.rb +21 -8
  29. data/spec/acceptance/realtime/client_spec.rb +80 -20
  30. data/spec/acceptance/realtime/connection_failures_spec.rb +90 -9
  31. data/spec/acceptance/realtime/connection_spec.rb +47 -19
  32. data/spec/acceptance/realtime/message_spec.rb +2 -4
  33. data/spec/acceptance/realtime/presence_history_spec.rb +0 -58
  34. data/spec/acceptance/realtime/presence_spec.rb +54 -0
  35. data/spec/acceptance/realtime/push_admin_spec.rb +43 -21
  36. data/spec/acceptance/rest/auth_spec.rb +6 -75
  37. data/spec/acceptance/rest/base_spec.rb +8 -4
  38. data/spec/acceptance/rest/channel_spec.rb +42 -4
  39. data/spec/acceptance/rest/client_spec.rb +121 -26
  40. data/spec/acceptance/rest/message_spec.rb +1 -2
  41. data/spec/acceptance/rest/push_admin_spec.rb +67 -27
  42. data/spec/shared/client_initializer_behaviour.rb +131 -8
  43. data/spec/spec_helper.rb +1 -0
  44. data/spec/support/debug_failure_helper.rb +9 -5
  45. data/spec/support/serialization_helper.rb +21 -0
  46. data/spec/support/test_app.rb +2 -2
  47. data/spec/unit/modules/enum_spec.rb +1 -1
  48. data/spec/unit/realtime/client_spec.rb +20 -7
  49. data/spec/unit/realtime/connection_spec.rb +1 -1
  50. metadata +22 -17
  51. data/.travis.yml +0 -19
@@ -45,7 +45,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
45
45
  connection.on(:failed) do |connection_state_change|
46
46
  error = connection_state_change.reason
47
47
  expect(connection.state).to eq(:failed)
48
- # TODO: Check error type is a TokenNotFOund exception
48
+ # TODO: Check error type is a TokenNotFound exception
49
49
  expect(error.status).to eq(401)
50
50
  expect(error.code).to eq(40400) # not found
51
51
  stop_reactor
@@ -110,6 +110,82 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
110
110
  end
111
111
  end
112
112
  end
113
+
114
+ context 'request fails due to slow response and subsequent timeout', :webmock, em_timeout: (Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout) + 5) * 2 do
115
+ let(:auth_url) { "http://#{random_str}.domain.will.be.stubbed/path" }
116
+ let(:client_options) { default_options.reject { |k, v| k == :key }.merge(auth_url: auth_url, log_level: :fatal) }
117
+
118
+ # Timeout +5 seconds, beyond default allowed timeout
119
+ before do
120
+ stub_request(:get, auth_url).
121
+ to_return do |request|
122
+ sleep Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout) + 5
123
+ { status: [500, "Internal Server Error"] }
124
+ end
125
+ end
126
+
127
+ specify 'the connection moves to the disconnected state and tries again, returning again to the disconnected state (#RSA4c, #RSA4c1, #RSA4c2)' do
128
+ states = Hash.new { |hash, key| hash[key] = [] }
129
+
130
+ connection.once(:connected) { raise "Connection can never move to connected because of auth failures" }
131
+
132
+ connection.on do |connection_state|
133
+ states[connection_state.current.to_sym] << Time.now
134
+ if states[:disconnected].count == 2 && connection_state.current == :disconnected
135
+ expect(connection.error_reason).to be_a(Ably::Exceptions::ConnectionError)
136
+ expect(connection.error_reason.message).to match(/auth_url/)
137
+ EventMachine.add_timer(2) do
138
+ expect(states.keys).to include(:connecting, :disconnected)
139
+ expect(states[:connecting].count).to eql(2)
140
+ expect(states[:connected].count).to eql(0)
141
+ stop_reactor
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'request fails once due to slow response but succeeds the second time' do
149
+ let(:auth_url) { "http://#{random_str}.domain.will.be.stubbed/path" }
150
+ let(:client_options) { default_options.reject { |k, v| k == :key }.merge(auth_url: auth_url, log_level: :fatal) }
151
+
152
+ # Timeout +5 seconds, beyond default allowed timeout
153
+ before do
154
+ token_response = Ably::Rest::Client.new(default_options).auth.request_token
155
+ WebMock.enable!
156
+
157
+ stub_request(:get, auth_url).
158
+ to_return do |request|
159
+ sleep Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout)
160
+ { status: [500, "Internal Server Error"] }
161
+ end.then.
162
+ to_return(:status => 201, :body => token_response.to_json, :headers => { 'Content-Type' => 'application/json' })
163
+
164
+ stub_request(:get, 'https://internet-up.ably-realtime.com/is-the-internet-up.txt')
165
+ .with(
166
+ headers: {
167
+ 'Accept-Encoding' => 'gzip, compressed',
168
+ 'Connection' => 'close',
169
+ 'Host' => 'internet-up.ably-realtime.com',
170
+ 'User-Agent' => 'EventMachine HttpClient'
171
+ }
172
+ ).to_return(status: 200, body: 'yes\n', headers: { 'Content-Type' => 'text/plain' })
173
+ end
174
+
175
+ specify 'the connection moves to the disconnected state and tries again, returning again to the disconnected state (#RSA4c, #RSA4c1, #RSA4c2)' do
176
+ states = Hash.new { |hash, key| hash[key] = [] }
177
+
178
+ connection.once(:connected) do
179
+ expect(states[:disconnected].count).to eql(1)
180
+ expect(states[:connecting].count).to eql(2)
181
+ stop_reactor
182
+ end
183
+
184
+ connection.on do |connection_state|
185
+ states[connection_state.current.to_sym] << Time.now
186
+ end
187
+ end
188
+ end
113
189
  end
114
190
 
115
191
  context 'existing CONNECTED connection' do
@@ -425,7 +501,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
425
501
  let(:client_options) do
426
502
  default_options.merge(
427
503
  log_level: :none,
428
- realtime_request_timeout: timeout
504
+ realtime_request_timeout: timeout,
429
505
  )
430
506
  end
431
507
 
@@ -1357,14 +1433,19 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1357
1433
  let(:expected_host) { "#{environment}-#{Ably::Realtime::Client::DOMAIN}" }
1358
1434
  let(:client_options) { timeout_options.merge(environment: environment) }
1359
1435
 
1360
- it 'does not use a fallback host by default' do
1361
- expect(connection).to receive(:create_transport).exactly(retry_count_for_all_states).times do |host|
1362
- expect(host).to eql(expected_host)
1363
- raise EventMachine::ConnectionError
1364
- end
1436
+ context ':fallback_hosts_use_default is unset' do
1437
+ let(:max_time_in_state_for_tests) { 8 }
1438
+ let(:expected_hosts) { Ably::CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES.map { |suffix| "#{environment}#{suffix}" } + [expected_host] }
1439
+ let(:fallback_hosts_used) { Array.new }
1440
+
1441
+ it 'uses fallback hosts by default' do
1442
+ allow(connection).to receive(:create_transport) do |host|
1443
+ fallback_hosts_used << host
1444
+ raise EventMachine::ConnectionError
1445
+ end
1365
1446
 
1366
- connection.once(:suspended) do
1367
1447
  connection.once(:suspended) do
1448
+ expect(fallback_hosts_used.uniq).to match_array(expected_hosts)
1368
1449
  stop_reactor
1369
1450
  end
1370
1451
  end
@@ -1442,7 +1523,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1442
1523
  end
1443
1524
 
1444
1525
  context 'with production environment' do
1445
- let(:custom_hosts) { %w(A.ably-realtime.com B.ably-realtime.com) }
1526
+ let(:custom_hosts) { %w(a.ably-realtime.com b.ably-realtime.com) }
1446
1527
  before do
1447
1528
  stub_const 'Ably::FALLBACK_HOSTS', custom_hosts
1448
1529
  end
@@ -27,6 +27,13 @@ describe Ably::Realtime::Connection, :event_machine do
27
27
  end
28
28
  end
29
29
 
30
+ context 'current_host' do
31
+ it 'is available immediately after the client is instanced' do
32
+ expect(connection.current_host.to_s).to match(/\.ably\.io$/)
33
+ stop_reactor
34
+ end
35
+ end
36
+
30
37
  context 'with :auto_connect option set to false' do
31
38
  let(:client) do
32
39
  auto_close Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
@@ -70,18 +77,6 @@ describe Ably::Realtime::Connection, :event_machine do
70
77
  end
71
78
  end
72
79
  end
73
-
74
- context 'with implicit authorisation' do
75
- let(:client_options) { default_options.merge(client_id: 'force_token_auth') }
76
-
77
- it 'uses the token created by the implicit authorisation' do
78
- expect(client.rest_client.auth).to receive(:request_token).once.and_call_original
79
-
80
- connection.once(:connected) do
81
- stop_reactor
82
- end
83
- end
84
- end
85
80
  end
86
81
 
87
82
  context 'that expire' do
@@ -127,7 +122,7 @@ describe Ably::Realtime::Connection, :event_machine do
127
122
  end
128
123
  end
129
124
 
130
- context 'with immediately expired token' do
125
+ context 'with immediately expired token and no fallback hosts' do
131
126
  let(:ttl) { 0.001 }
132
127
  let(:auth_requests) { [] }
133
128
  let(:token_callback) do
@@ -136,7 +131,7 @@ describe Ably::Realtime::Connection, :event_machine do
136
131
  Ably::Rest::Client.new(default_options).auth.request_token(ttl: ttl).token
137
132
  end
138
133
  end
139
- let(:client_options) { default_options.merge(auth_callback: token_callback) }
134
+ let(:client_options) { default_options.merge(auth_callback: token_callback, fallback_hosts: []) }
140
135
 
141
136
  it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token (#RSA4b)' do
142
137
  started_at = Time.now.to_f
@@ -151,7 +146,7 @@ describe Ably::Realtime::Connection, :event_machine do
151
146
  end
152
147
 
153
148
  context 'when disconnected_retry_timeout is 0.5 seconds' do
154
- let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback) }
149
+ let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback, fallback_hosts: []) }
155
150
 
156
151
  it 'renews the token on connect, and continues to attempt renew based on the retry schedule' do
157
152
  disconnect_count = 0
@@ -177,7 +172,7 @@ describe Ably::Realtime::Connection, :event_machine do
177
172
  end
178
173
 
179
174
  context 'using implicit token auth' do
180
- let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }) }
175
+ let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }, fallback_hosts: []) }
181
176
 
182
177
  before do
183
178
  stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', -10 # ensure client lib thinks token is still valid
@@ -446,7 +441,9 @@ describe Ably::Realtime::Connection, :event_machine do
446
441
  end
447
442
  end
448
443
 
449
- context '#connect' do
444
+ context '#connect with no fallbacks' do
445
+ let(:client_options) { default_options.merge(fallback_hosts: []) }
446
+
450
447
  it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
451
448
  expect(connection.connect).to be_a(Ably::Util::SafeDeferrable)
452
449
  stop_reactor
@@ -1172,6 +1169,7 @@ describe Ably::Realtime::Connection, :event_machine do
1172
1169
  host: 'this.host.does.not.exist.com'
1173
1170
  )
1174
1171
  )
1172
+ allow(client).to receive(:fallback_hosts).and_return([])
1175
1173
 
1176
1174
  connection.transition_state_machine! :disconnected
1177
1175
  end
@@ -1307,12 +1305,14 @@ describe Ably::Realtime::Connection, :event_machine do
1307
1305
  expect(connection.send(:client_msg_serial)).to eql(-1) # no messages published yet
1308
1306
  connection_id = client.connection.id
1309
1307
  connection.transport.__incoming_protocol_msgbus__
1310
- channel.publish('event', 'message-1') do
1308
+ channel.subscribe('event') do |message|
1309
+ expect(message.data).to eql('message-1')
1311
1310
  msg_serial = connection.send(:client_msg_serial)
1312
1311
  expect(msg_serial).to eql(0)
1313
1312
  recovery_key = client.connection.recovery_key
1314
1313
  connection.transition_state_machine! :failed
1315
1314
  end
1315
+ channel.publish('event', 'message-1')
1316
1316
  end
1317
1317
 
1318
1318
  connection.on(:failed) do
@@ -1329,7 +1329,7 @@ describe Ably::Realtime::Connection, :event_machine do
1329
1329
  expect(recover_client.connection.id).to eql(connection_id)
1330
1330
 
1331
1331
  recover_client_channel.subscribe do |message|
1332
- raise "Unexpected message #{message}" if message.data != 'message-2'
1332
+ expect(message.data).to eql('message-2')
1333
1333
  EventMachine.add_timer(2) do
1334
1334
  stop_reactor
1335
1335
  end
@@ -1870,5 +1870,33 @@ describe Ably::Realtime::Connection, :event_machine do
1870
1870
  end
1871
1871
  end
1872
1872
  end
1873
+
1874
+ context 'transport_params (#RTC1f)' do
1875
+ let(:client_options) { default_options.merge(transport_params: { 'extra_param' => 'extra_param' }) }
1876
+
1877
+ it 'pases transport_params to query' do
1878
+ expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
1879
+ uri = URI.parse(url)
1880
+ expect(CGI::parse(uri.query)['extra_param'][0]).to eq('extra_param')
1881
+ stop_reactor
1882
+ end
1883
+
1884
+ client
1885
+ end
1886
+
1887
+ context 'when changing default param' do
1888
+ let(:client_options) { default_options.merge(transport_params: { v: '1.0' }) }
1889
+
1890
+ it 'overrides default param (#RTC1f1)' do
1891
+ expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
1892
+ uri = URI.parse(url)
1893
+ expect(CGI::parse(uri.query)['v'][0]).to eq('1.0')
1894
+ stop_reactor
1895
+ end
1896
+
1897
+ client
1898
+ end
1899
+ end
1900
+ end
1873
1901
  end
1874
1902
  end
@@ -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
@@ -658,8 +657,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
658
657
  expect(message_state).to be_empty
659
658
  EventMachine.add_timer(2) do
660
659
  expect(message_state).to contain_exactly(:delivered)
661
- # TODO: Uncomment once issue realtime#42 is resolved
662
- # expect(msgs_received.length).to eql(1)
660
+ expect(msgs_received.length).to eql(1)
663
661
  stop_reactor
664
662
  end
665
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
@@ -2449,6 +2449,60 @@ describe Ably::Realtime::Presence, :event_machine do
2449
2449
  end
2450
2450
  end
2451
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
+
2452
2506
  context 'when a channel becomes attached again' do
2453
2507
  let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached.to_i }
2454
2508
  let(:sync_action) { Ably::Models::ProtocolMessage::ACTION.Sync.to_i }
@@ -101,31 +101,15 @@ describe Ably::Realtime::Push::Admin, :event_machine do
101
101
  end
102
102
  end
103
103
 
104
- def request_body(request, protocol)
105
- if protocol == :msgpack
106
- MessagePack.unpack(request.body)
107
- else
108
- JSON.parse(request.body)
109
- end
110
- end
111
-
112
- def serialize(object, protocol)
113
- if protocol == :msgpack
114
- MessagePack.pack(object)
115
- else
116
- JSON.dump(object)
117
- end
118
- end
119
-
120
104
  let!(:publish_stub) do
121
105
  stub_request(:post, "#{client.rest_client.endpoint}/push/publish").
122
106
  with do |request|
123
- expect(request_body(request, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
124
- expect(request_body(request, protocol)['recipient']).to_not have_key('camel_case')
107
+ expect(deserialize_body(request.body, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
108
+ expect(deserialize_body(request.body, protocol)['recipient']).to_not have_key('camel_case')
125
109
  true
126
110
  end.to_return(
127
111
  :status => 201,
128
- :body => serialize({}, protocol),
112
+ :body => serialize_body({}, protocol),
129
113
  :headers => { 'Content-Type' => content_type }
130
114
  )
131
115
  end
@@ -217,6 +201,12 @@ describe Ably::Realtime::Push::Admin, :event_machine do
217
201
  let(:client_id) { random_str }
218
202
  let(:fixture_count) { 6 }
219
203
 
204
+ before(:all) do
205
+ # As push tests often use the global scope (devices),
206
+ # we need to ensure tests cannot conflict
207
+ reload_test_app
208
+ end
209
+
220
210
  before do
221
211
  fixture_count.times.map do |index|
222
212
  Thread.new do # Parallelise the setup
@@ -274,6 +264,12 @@ describe Ably::Realtime::Push::Admin, :event_machine do
274
264
  let(:fixture_count) { 2 }
275
265
  let(:client_id) { random_str }
276
266
 
267
+ before(:all) do
268
+ # As push tests often use the global scope (devices),
269
+ # we need to ensure tests cannot conflict
270
+ reload_test_app
271
+ end
272
+
277
273
  before do
278
274
  fixture_count.times.map do |index|
279
275
  Thread.new do # Parallelise the setup
@@ -353,6 +349,12 @@ describe Ably::Realtime::Push::Admin, :event_machine do
353
349
  }
354
350
  end
355
351
 
352
+ before(:all) do
353
+ # As push tests often use the global scope (devices),
354
+ # we need to ensure tests cannot conflict
355
+ reload_test_app
356
+ end
357
+
356
358
  after do
357
359
  rest_device_registrations.remove_where client_id: client_id
358
360
  end
@@ -388,6 +390,12 @@ describe Ably::Realtime::Push::Admin, :event_machine do
388
390
  let(:device_id) { random_str }
389
391
  let(:client_id) { random_str }
390
392
 
393
+ before(:all) do
394
+ # As push tests often use the global scope (devices),
395
+ # we need to ensure tests cannot conflict
396
+ reload_test_app
397
+ end
398
+
391
399
  before do
392
400
  rest_device_registrations.save({
393
401
  id: "device-#{client_id}-0",
@@ -421,6 +429,12 @@ describe Ably::Realtime::Push::Admin, :event_machine do
421
429
  let(:device_id) { random_str }
422
430
  let(:client_id) { random_str }
423
431
 
432
+ before(:all) do
433
+ # As push tests often use the global scope (devices),
434
+ # we need to ensure tests cannot conflict
435
+ reload_test_app
436
+ end
437
+
424
438
  before do
425
439
  rest_device_registrations.save({
426
440
  id: "device-#{client_id}-0",
@@ -481,6 +495,12 @@ describe Ably::Realtime::Push::Admin, :event_machine do
481
495
  client.push.admin.channel_subscriptions
482
496
  }
483
497
 
498
+ before(:all) do
499
+ # As push tests often use the global scope (devices),
500
+ # we need to ensure tests cannot conflict
501
+ reload_test_app
502
+ end
503
+
484
504
  # Set up 2 devices with the same client_id
485
505
  # and two device with the unique device_id and no client_id
486
506
  before do
@@ -543,8 +563,10 @@ describe Ably::Realtime::Push::Admin, :event_machine do
543
563
  describe '#list_channels' do
544
564
  let(:fixture_count) { 6 }
545
565
 
546
- before(:context) do
547
- reload_test_app # TODO: Review if necessary later, currently other tests may affect list_channels
566
+ before(:all) do
567
+ # As push tests often use the global scope (devices),
568
+ # we need to ensure tests cannot conflict
569
+ reload_test_app
548
570
  end
549
571
 
550
572
  before do