ably 1.1.1 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/check.yml +27 -0
- data/CHANGELOG.md +60 -2
- data/COPYRIGHT +1 -0
- data/LICENSE +172 -11
- data/MAINTAINERS.md +1 -0
- data/README.md +2 -14
- data/SPEC.md +1020 -922
- data/ably.gemspec +5 -5
- data/lib/ably/auth.rb +12 -2
- data/lib/ably/exceptions.rb +2 -2
- data/lib/ably/logger.rb +7 -1
- data/lib/ably/modules/ably.rb +11 -1
- data/lib/ably/modules/state_machine.rb +1 -1
- data/lib/ably/realtime/channel.rb +7 -11
- data/lib/ably/realtime/channel/channel_manager.rb +2 -2
- data/lib/ably/realtime/channel/channel_properties.rb +24 -0
- data/lib/ably/realtime/client.rb +9 -0
- data/lib/ably/realtime/connection.rb +7 -4
- data/lib/ably/realtime/connection/connection_manager.rb +19 -1
- data/lib/ably/realtime/connection/websocket_transport.rb +67 -1
- data/lib/ably/realtime/presence.rb +0 -14
- data/lib/ably/rest/channel.rb +25 -17
- data/lib/ably/rest/client.rb +35 -17
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/auth_spec.rb +5 -4
- data/spec/acceptance/realtime/channel_spec.rb +21 -8
- data/spec/acceptance/realtime/client_spec.rb +80 -20
- data/spec/acceptance/realtime/connection_failures_spec.rb +90 -9
- data/spec/acceptance/realtime/connection_spec.rb +47 -19
- data/spec/acceptance/realtime/message_spec.rb +2 -4
- data/spec/acceptance/realtime/presence_history_spec.rb +0 -58
- data/spec/acceptance/realtime/presence_spec.rb +54 -0
- data/spec/acceptance/realtime/push_admin_spec.rb +43 -21
- data/spec/acceptance/rest/auth_spec.rb +6 -75
- data/spec/acceptance/rest/base_spec.rb +8 -4
- data/spec/acceptance/rest/channel_spec.rb +42 -4
- data/spec/acceptance/rest/client_spec.rb +121 -26
- data/spec/acceptance/rest/message_spec.rb +1 -2
- data/spec/acceptance/rest/push_admin_spec.rb +67 -27
- data/spec/shared/client_initializer_behaviour.rb +131 -8
- data/spec/spec_helper.rb +1 -0
- data/spec/support/debug_failure_helper.rb +9 -5
- data/spec/support/serialization_helper.rb +21 -0
- data/spec/support/test_app.rb +2 -2
- data/spec/unit/modules/enum_spec.rb +1 -1
- data/spec/unit/realtime/client_spec.rb +20 -7
- data/spec/unit/realtime/connection_spec.rb +1 -1
- metadata +22 -17
- 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
|
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
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
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(
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
124
|
-
expect(
|
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 =>
|
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(:
|
547
|
-
|
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
|