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.
- 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
|