ably 1.1.6 → 1.2.0
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 +15 -1
- data/CHANGELOG.md +131 -0
- data/COPYRIGHT +1 -1
- data/README.md +14 -2
- data/SPEC.md +0 -7
- data/UPDATING.md +30 -0
- data/ably.gemspec +12 -7
- data/lib/ably/agent.rb +3 -0
- data/lib/ably/auth.rb +3 -3
- data/lib/ably/exceptions.rb +6 -0
- data/lib/ably/models/channel_options.rb +97 -0
- data/lib/ably/models/connection_details.rb +8 -0
- data/lib/ably/models/delta_extras.rb +29 -0
- data/lib/ably/models/error_info.rb +6 -2
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/ably/models/message.rb +28 -3
- data/lib/ably/models/presence_message.rb +14 -0
- data/lib/ably/models/protocol_message.rb +29 -12
- data/lib/ably/models/token_details.rb +7 -2
- data/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/ably/modules/conversions.rb +34 -0
- data/lib/ably/realtime/channel/channel_manager.rb +18 -6
- data/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
- data/lib/ably/realtime/channel/publisher.rb +6 -0
- data/lib/ably/realtime/channel.rb +54 -22
- data/lib/ably/realtime/channels.rb +1 -1
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
- data/lib/ably/realtime/connection/connection_manager.rb +13 -4
- data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
- data/lib/ably/realtime/connection.rb +2 -2
- data/lib/ably/rest/channel.rb +31 -31
- data/lib/ably/rest/client.rb +27 -12
- data/lib/ably/util/crypto.rb +1 -1
- data/lib/ably/version.rb +2 -14
- data/lib/ably.rb +1 -0
- data/spec/acceptance/realtime/auth_spec.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +25 -0
- data/spec/acceptance/realtime/channel_spec.rb +466 -21
- data/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/spec/acceptance/realtime/connection_failures_spec.rb +59 -2
- data/spec/acceptance/realtime/connection_spec.rb +256 -28
- data/spec/acceptance/realtime/message_spec.rb +77 -0
- data/spec/acceptance/realtime/presence_history_spec.rb +3 -1
- data/spec/acceptance/realtime/presence_spec.rb +31 -159
- data/spec/acceptance/rest/auth_spec.rb +18 -0
- data/spec/acceptance/rest/channel_spec.rb +84 -9
- data/spec/acceptance/rest/channels_spec.rb +23 -6
- data/spec/acceptance/rest/client_spec.rb +25 -21
- data/spec/acceptance/rest/message_spec.rb +61 -3
- data/spec/lib/unit/models/channel_options_spec.rb +52 -0
- data/spec/shared/model_behaviour.rb +1 -1
- data/spec/spec_helper.rb +11 -2
- data/spec/support/test_app.rb +1 -1
- data/spec/unit/models/delta_extras_spec.rb +14 -0
- data/spec/unit/models/error_info_spec.rb +17 -1
- data/spec/unit/models/message_spec.rb +97 -0
- data/spec/unit/models/presence_message_spec.rb +49 -0
- data/spec/unit/models/protocol_message_spec.rb +125 -27
- data/spec/unit/models/token_details_spec.rb +14 -0
- data/spec/unit/realtime/channel_spec.rb +3 -2
- data/spec/unit/realtime/channels_spec.rb +53 -15
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
- data/spec/unit/rest/channel_spec.rb +44 -1
- data/spec/unit/rest/channels_spec.rb +81 -14
- data/spec/unit/rest/client_spec.rb +47 -0
- metadata +60 -24
@@ -19,7 +19,7 @@ shared_examples 'a model' do |shared_options = {}|
|
|
19
19
|
end
|
20
20
|
|
21
21
|
context '#attributes', :api_private do
|
22
|
-
let(:model_options) { { action: 5 } }
|
22
|
+
let(:model_options) { { action: 5, max_message_size: 65536, max_frame_size: 524288 } }
|
23
23
|
|
24
24
|
it 'provides access to #attributes' do
|
25
25
|
expect(model.attributes).to eq(model_options)
|
data/spec/spec_helper.rb
CHANGED
@@ -5,8 +5,17 @@ def console(message)
|
|
5
5
|
end
|
6
6
|
|
7
7
|
unless RUBY_VERSION.match(/^1\./)
|
8
|
-
require '
|
9
|
-
|
8
|
+
require 'simplecov'
|
9
|
+
|
10
|
+
SimpleCov.start do
|
11
|
+
require 'simplecov-lcov'
|
12
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
13
|
+
c.report_with_single_file = true
|
14
|
+
c.single_report_path = 'coverage/lcov.info'
|
15
|
+
end
|
16
|
+
formatter SimpleCov::Formatter::LcovFormatter
|
17
|
+
add_filter %w[vendor spec]
|
18
|
+
end
|
10
19
|
end
|
11
20
|
|
12
21
|
require 'webmock/rspec'
|
data/spec/support/test_app.rb
CHANGED
@@ -59,7 +59,7 @@ class TestApp
|
|
59
59
|
|
60
60
|
url = "#{sandbox_client.endpoint}/apps/#{app_id}"
|
61
61
|
|
62
|
-
basic_auth = Base64.
|
62
|
+
basic_auth = Base64.urlsafe_encode64(api_key).chomp
|
63
63
|
headers = { "Authorization" => "Basic #{basic_auth}" }
|
64
64
|
|
65
65
|
Faraday.delete(url, nil, headers)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Ably::Models::DeltaExtras do
|
5
|
+
subject { described_class.new({ format: 'vcdiff', from: '1234-4567-8910-1001-1111'}) }
|
6
|
+
|
7
|
+
it 'should have `from` attribute' do
|
8
|
+
expect(subject.from).to eq('1234-4567-8910-1001-1111')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have `format` attribute' do
|
12
|
+
expect(subject.format).to eq('vcdiff')
|
13
|
+
end
|
14
|
+
end
|
@@ -5,7 +5,7 @@ describe Ably::Models::ErrorInfo do
|
|
5
5
|
subject { Ably::Models::ErrorInfo }
|
6
6
|
|
7
7
|
context '#TI1, #TI4' do
|
8
|
-
it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message) do
|
8
|
+
it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message request_id cause) do
|
9
9
|
let(:model_args) { [] }
|
10
10
|
end
|
11
11
|
end
|
@@ -18,6 +18,22 @@ describe Ably::Models::ErrorInfo do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
context '#request_id #RSC7c' do
|
22
|
+
subject { Ably::Models::ErrorInfo.new('request_id' => '123-456-789-001') }
|
23
|
+
|
24
|
+
it 'should return request ID' do
|
25
|
+
expect(subject.request_id).to eql('123-456-789-001')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#cause #TI1' do
|
30
|
+
subject { Ably::Models::ErrorInfo.new('cause' => Ably::Models::ErrorInfo.new({})) }
|
31
|
+
|
32
|
+
it 'should return cause attribute' do
|
33
|
+
expect(subject.cause).to be_kind_of(Ably::Models::ErrorInfo)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
21
37
|
context 'log entries container help link #TI5' do
|
22
38
|
context 'without an error code' do
|
23
39
|
subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
|
@@ -211,6 +211,79 @@ describe Ably::Models::Message do
|
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
214
|
+
describe '#size' do
|
215
|
+
let(:model) { subject.new({ name: name, data: data, client_id: client_id, extras: extras }, protocol_message: protocol_message) }
|
216
|
+
|
217
|
+
context 'String (#TO3l8a)' do
|
218
|
+
let(:data) { 'example string data' }
|
219
|
+
let(:client_id) { '1' }
|
220
|
+
let(:name) { 'My Name' }
|
221
|
+
let(:extras) { 'extras' }
|
222
|
+
|
223
|
+
it 'should return 33 bytes' do
|
224
|
+
expect(model.size).to eq(33)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
context 'Object (#TO3l8b)' do
|
229
|
+
let(:data) { Object.new }
|
230
|
+
let(:client_id) { String('10') }
|
231
|
+
let(:name) { 'John' }
|
232
|
+
let(:extras) { Hash.new }
|
233
|
+
|
234
|
+
it 'should return 38 bytes' do
|
235
|
+
expect(model.size).to eq(38)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'Array (#TO3l8b)' do
|
240
|
+
let(:data) { [1, 'two', :three] }
|
241
|
+
let(:client_id) { '2' }
|
242
|
+
let(:name) { 'Kate' }
|
243
|
+
let(:extras) { [] }
|
244
|
+
|
245
|
+
it 'should return 24 bytes' do
|
246
|
+
expect(model.size).to eq(24)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'extras (#TO3l8d)' do
|
251
|
+
let(:data) { { example: 'value', score: 1, hash: { test: true } } }
|
252
|
+
let(:client_id) { '3' }
|
253
|
+
let(:name) { 'John' }
|
254
|
+
let(:extras) { {} }
|
255
|
+
|
256
|
+
it 'should return 57 bytes' do
|
257
|
+
expect(model.size).to eq(57)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'nil (#TO3l8e)' do
|
262
|
+
let(:data) { nil }
|
263
|
+
let(:client_id) { '' }
|
264
|
+
let(:name) { '' }
|
265
|
+
let(:extras) { nil}
|
266
|
+
|
267
|
+
it 'should return 19 bytes' do
|
268
|
+
expect(model.size).to eq(0)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe '#protocol_message_index (#RTL21)' do
|
274
|
+
let(:messages) { [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }] }
|
275
|
+
|
276
|
+
let(:protocol_message) do
|
277
|
+
Ably::Models::ProtocolMessage.new({ action: 1 }.merge(messages: messages))
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should return correct protocol_message_index' do
|
281
|
+
expect(protocol_message.messages[0].protocol_message_index).to eq(0)
|
282
|
+
expect(protocol_message.messages[1].protocol_message_index).to eq(1)
|
283
|
+
expect(protocol_message.messages[2].protocol_message_index).to eq(2)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
214
287
|
context 'from REST request with embedded fields', :api_private do
|
215
288
|
let(:id) { random_str }
|
216
289
|
let(:protocol_message_id) { random_str }
|
@@ -547,4 +620,28 @@ describe Ably::Models::Message do
|
|
547
620
|
end
|
548
621
|
end
|
549
622
|
end
|
623
|
+
|
624
|
+
context '#delta_extras (TM2i)' do
|
625
|
+
let(:delta_extras) { message.delta_extras }
|
626
|
+
|
627
|
+
context 'when delta' do
|
628
|
+
let(:message) { subject.new({ extras: { delta: { from: '1234-1234-5678-9009', format: 'vcdiff' } } }) }
|
629
|
+
|
630
|
+
it 'should return vcdiff format' do
|
631
|
+
expect(delta_extras.format).to eq('vcdiff')
|
632
|
+
end
|
633
|
+
|
634
|
+
it 'should return 1234-1234-5678-9009 message id' do
|
635
|
+
expect(delta_extras.from).to eq('1234-1234-5678-9009')
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
context 'when no delta' do
|
640
|
+
let(:message) { subject.new({ extras: {} }) }
|
641
|
+
|
642
|
+
it 'should return nil' do
|
643
|
+
expect(delta_extras).to eq(nil)
|
644
|
+
end
|
645
|
+
end
|
646
|
+
end
|
550
647
|
end
|
@@ -220,6 +220,55 @@ describe Ably::Models::PresenceMessage do
|
|
220
220
|
end
|
221
221
|
end
|
222
222
|
|
223
|
+
describe '#size' do
|
224
|
+
let(:model) { subject.new({ action: 'enter', data: data, client_id: client_id }, protocol_message: protocol_message) }
|
225
|
+
|
226
|
+
context 'String (#TO3l8a)' do
|
227
|
+
let(:data) { 'example string data' }
|
228
|
+
let(:client_id) { '1' }
|
229
|
+
|
230
|
+
it 'should return 20 bytes' do
|
231
|
+
expect(model.size).to eq(20)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'Object (#TO3l8b)' do
|
236
|
+
let(:data) { Object.new }
|
237
|
+
let(:client_id) { '10' }
|
238
|
+
|
239
|
+
it 'should return 32 bytes' do
|
240
|
+
expect(model.size).to eq(32)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'Array (#TO3l8b)' do
|
245
|
+
let(:data) { [1, 'two', :three] }
|
246
|
+
let(:client_id) { '2' }
|
247
|
+
|
248
|
+
it 'should return 18 bytes' do
|
249
|
+
expect(model.size).to eq(18)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'extras (#TO3l8d)' do
|
254
|
+
let(:data) { { example: 'value', score: 1, hash: { test: true } } }
|
255
|
+
let(:client_id) { '3' }
|
256
|
+
|
257
|
+
it 'should return 51 bytes' do
|
258
|
+
expect(model.size).to eq(51)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context 'nil (#TO3l8e)' do
|
263
|
+
let(:data) { nil }
|
264
|
+
let(:client_id) { '4' }
|
265
|
+
|
266
|
+
it 'should return 1 bytes' do
|
267
|
+
expect(model.size).to eq(1)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
223
272
|
context 'from REST request with embedded fields', :api_private do
|
224
273
|
let(:id) { random_str }
|
225
274
|
let(:message_time) { Time.now + 60 }
|
@@ -10,9 +10,9 @@ describe Ably::Models::ProtocolMessage do
|
|
10
10
|
subject.new({ action: 1 }.merge(options))
|
11
11
|
end
|
12
12
|
|
13
|
-
# TR4n, TR4b, TR4c, TR4d
|
13
|
+
# TR4n, TR4b, TR4c, TR4d
|
14
14
|
it_behaves_like 'a model',
|
15
|
-
with_simple_attributes: %w(id channel channel_serial connection_id
|
15
|
+
with_simple_attributes: %w(id channel channel_serial connection_id),
|
16
16
|
base_model_options: { action: 1 } do
|
17
17
|
|
18
18
|
let(:model_args) { [] }
|
@@ -176,6 +176,28 @@ describe Ably::Models::ProtocolMessage do
|
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
179
|
+
context 'when attach resumed flag' do
|
180
|
+
context 'flags is 34' do
|
181
|
+
let(:protocol_message) { new_protocol_message(flags: 34) }
|
182
|
+
|
183
|
+
it '#has_attach_resume_flag? is true' do
|
184
|
+
expect(protocol_message.has_attach_resume_flag?).to be_truthy
|
185
|
+
end
|
186
|
+
|
187
|
+
it '#has_attach_presence_flag? is false' do
|
188
|
+
expect(protocol_message.has_attach_presence_flag?).to be_falsey
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'flags is 0' do
|
193
|
+
let(:protocol_message) { new_protocol_message(flags: 0) }
|
194
|
+
|
195
|
+
it 'should raise an exception if flags is a float number' do
|
196
|
+
expect(protocol_message.has_attach_resume_flag?).to be_falsy
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
179
201
|
context 'when channel resumed and presence flags present' do
|
180
202
|
let(:protocol_message) { new_protocol_message(flags: 5) }
|
181
203
|
|
@@ -201,6 +223,24 @@ describe Ably::Models::ProtocolMessage do
|
|
201
223
|
end
|
202
224
|
end
|
203
225
|
|
226
|
+
context '#params (#RTL4k1)' do
|
227
|
+
let(:params) do
|
228
|
+
{ foo: :bar }
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'when present' do
|
232
|
+
specify do
|
233
|
+
expect(new_protocol_message({ params: params }).params).to eq(params)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'when empty' do
|
238
|
+
specify do
|
239
|
+
expect(new_protocol_message({}).params).to eq({})
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
204
244
|
context '#has_connection_serial?' do
|
205
245
|
context 'without connection_serial' do
|
206
246
|
let(:protocol_message) { new_protocol_message({}) }
|
@@ -308,6 +348,26 @@ describe Ably::Models::ProtocolMessage do
|
|
308
348
|
end
|
309
349
|
end
|
310
350
|
|
351
|
+
context '#messages (#RTL21)' do
|
352
|
+
let(:protocol_message) do
|
353
|
+
new_protocol_message(messages: [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }])
|
354
|
+
end
|
355
|
+
|
356
|
+
before do
|
357
|
+
message = Ably::Models::Message(name: 'test4')
|
358
|
+
message.assign_to_protocol_message(protocol_message)
|
359
|
+
protocol_message.add_message(message)
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'contains Message objects in ascending order' do
|
363
|
+
expect(protocol_message.messages.count).to eql(4)
|
364
|
+
protocol_message.messages.each_with_index do |message, index|
|
365
|
+
expect(message.protocol_message_index).to eql(index)
|
366
|
+
expect(message.name).to include('test')
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
311
371
|
context '#presence (#TR4l)' do
|
312
372
|
let(:protocol_message) { new_protocol_message(presence: [{ action: 1, data: 'test' }]) }
|
313
373
|
|
@@ -318,6 +378,54 @@ describe Ably::Models::ProtocolMessage do
|
|
318
378
|
end
|
319
379
|
end
|
320
380
|
|
381
|
+
context '#message_size (#TO3l8)' do
|
382
|
+
context 'on presence' do
|
383
|
+
let(:protocol_message) do
|
384
|
+
new_protocol_message(presence: [{ action: 1, data: 'test342343', client_id: 'sdf' }])
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'should return 13 bytes (sum in bytes: data and client_id)' do
|
388
|
+
expect(protocol_message.message_size).to eq(13)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
context 'on message' do
|
393
|
+
let(:protocol_message) do
|
394
|
+
new_protocol_message(messages: [{ action: 1, unknown: 'test', data: 'test342343', client_id: 'sdf', name: 'sf23ewrew', extras: { time: Time.now, time_zone: 'UTC' } }])
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should return 76 bytes (sum in bytes: data, client_id, name, extras)' do
|
398
|
+
expect(protocol_message.message_size).to eq(76)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
context '#has_correct_message_size? (#TO3l8)' do
|
404
|
+
context 'on presence' do
|
405
|
+
it 'should return true when a message has correct size' do
|
406
|
+
protocol_message = new_protocol_message(presence: [{ action: 1, data: 'x' * 100 }])
|
407
|
+
expect(protocol_message.has_correct_message_size?).to eq(true)
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'should return false when a message has not correct size' do
|
411
|
+
protocol_message = new_protocol_message(presence: [{ action: 1, data: 'x' * 65537 }])
|
412
|
+
expect(protocol_message.has_correct_message_size?).to eq(false)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context 'on message' do
|
417
|
+
it 'should return true when a message has correct size' do
|
418
|
+
protocol_message = new_protocol_message(messages: [{ name: 'x' * 100 }])
|
419
|
+
expect(protocol_message.has_correct_message_size?).to eq(true)
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'should return false when a message has not correct size' do
|
423
|
+
protocol_message = new_protocol_message(messages: [{ name: 'x' * 65537 }])
|
424
|
+
expect(protocol_message.has_correct_message_size?).to eq(false)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
321
429
|
context '#connection_details (#TR4o)' do
|
322
430
|
let(:connection_details) { protocol_message.connection_details }
|
323
431
|
|
@@ -369,41 +477,27 @@ describe Ably::Models::ProtocolMessage do
|
|
369
477
|
end
|
370
478
|
end
|
371
479
|
end
|
372
|
-
|
373
|
-
context '#connection_key (#TR4e)' do
|
374
|
-
context 'existing only in #connection_details.connection_key' do
|
375
|
-
let(:protocol_message) { new_protocol_message(connectionDetails: { connectionKey: 'key' }) }
|
376
|
-
|
377
|
-
it 'is returned' do
|
378
|
-
expect(protocol_message.connection_key).to eql('key')
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
context 'existing in both #connection_key and #connection_details.connection_key' do
|
383
|
-
let(:protocol_message) { new_protocol_message(connectionKey: 'deprecated', connectionDetails: { connectionKey: 'key' }) }
|
384
|
-
|
385
|
-
it 'returns #connection_details.connection_key as #connection_key will be deprecated > 0.8' do
|
386
|
-
expect(protocol_message.connection_key).to eql('key')
|
387
|
-
end
|
388
|
-
end
|
389
|
-
end
|
390
480
|
end
|
391
481
|
|
392
482
|
context '#to_json', :api_private do
|
393
483
|
let(:json_object) { JSON.parse(model.to_json) }
|
394
|
-
let(:
|
484
|
+
let(:message1) { { 'name' => 'event1', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
485
|
+
let(:message2) { { 'name' => 'event2', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
486
|
+
let(:message3) { { 'name' => 'event3', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
395
487
|
let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached }
|
396
488
|
let(:message_action) { Ably::Models::ProtocolMessage::ACTION.Message }
|
397
489
|
|
398
490
|
context 'with valid data' do
|
399
|
-
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [
|
491
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3] }) }
|
400
492
|
|
401
493
|
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
402
494
|
expect(json_object["channelSerial"]).to eql('unique')
|
403
495
|
end
|
404
496
|
|
405
497
|
it 'populates the messages' do
|
406
|
-
expect(json_object["messages"]
|
498
|
+
expect(json_object["messages"][0]).to include(message1)
|
499
|
+
expect(json_object["messages"][1]).to include(message2)
|
500
|
+
expect(json_object["messages"][2]).to include(message3)
|
407
501
|
end
|
408
502
|
end
|
409
503
|
|
@@ -416,7 +510,7 @@ describe Ably::Models::ProtocolMessage do
|
|
416
510
|
end
|
417
511
|
|
418
512
|
context 'is aliased by #to_s' do
|
419
|
-
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [
|
513
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3], :timestamp => as_since_epoch(Time.now) }) }
|
420
514
|
|
421
515
|
specify do
|
422
516
|
expect(json_object).to eql(JSON.parse("#{model}"))
|
@@ -425,14 +519,18 @@ describe Ably::Models::ProtocolMessage do
|
|
425
519
|
end
|
426
520
|
|
427
521
|
context '#to_msgpack', :api_private do
|
428
|
-
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [
|
429
|
-
let(:
|
522
|
+
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [message1, message2, message3] }) }
|
523
|
+
let(:message1) { { 'name' => 'event1', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
524
|
+
let(:message2) { { 'name' => 'event2', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
525
|
+
let(:message3) { { 'name' => 'event3', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
430
526
|
let(:packed) { model.to_msgpack }
|
431
527
|
let(:unpacked) { MessagePack.unpack(packed) }
|
432
528
|
|
433
529
|
it 'returns a unpackable msgpack object' do
|
434
530
|
expect(unpacked['connectionSerial']).to eq('unique')
|
435
|
-
expect(unpacked['messages'][0]['name']).to eq('
|
531
|
+
expect(unpacked['messages'][0]['name']).to eq('event1')
|
532
|
+
expect(unpacked['messages'][1]['name']).to eq('event2')
|
533
|
+
expect(unpacked['messages'][2]['name']).to eq('event3')
|
436
534
|
end
|
437
535
|
end
|
438
536
|
end
|
@@ -80,6 +80,20 @@ describe Ably::Models::TokenDetails do
|
|
80
80
|
expect(subject.expired?).to eql(false)
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
context 'with :from attribute' do
|
85
|
+
subject { Ably::Models::TokenDetails.new(expires: expire_time) }
|
86
|
+
|
87
|
+
let(:server_offset_time) { 2 * 60 * 60 } # 2 hours
|
88
|
+
|
89
|
+
it 'is false' do
|
90
|
+
expect(subject.expired?(from: (Time.now - server_offset_time))).to eql(false)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'is true' do
|
94
|
+
expect(subject.expired?(from: Time.now)).to eql(true)
|
95
|
+
end
|
96
|
+
end
|
83
97
|
end
|
84
98
|
end
|
85
99
|
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
require 'shared/protocol_msgbus_behaviour'
|
4
4
|
|
5
5
|
describe Ably::Realtime::Channel do
|
6
|
-
let(:client) {
|
6
|
+
let(:client) { Ably::Realtime::Client.new(token: 'valid') }
|
7
7
|
let(:channel_name) { 'test' }
|
8
8
|
|
9
9
|
subject do
|
@@ -68,9 +68,10 @@ describe Ably::Realtime::Channel do
|
|
68
68
|
|
69
69
|
describe '#publish name argument' do
|
70
70
|
let(:encoded_value) { random_str.encode(encoding) }
|
71
|
-
let(:message) { instance_double('Ably::Models::Message', client_id: nil) }
|
71
|
+
let(:message) { instance_double('Ably::Models::Message', client_id: nil, size: 0) }
|
72
72
|
|
73
73
|
before do
|
74
|
+
allow(subject).to receive(:enqueue_messages_on_connection).and_return(message)
|
74
75
|
allow(subject).to receive(:create_message).and_return(message)
|
75
76
|
allow(subject).to receive(:attach).and_return(:true)
|
76
77
|
end
|
@@ -3,39 +3,77 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe Ably::Realtime::Channels do
|
5
5
|
let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true, on_resume: true) }
|
6
|
-
let(:client)
|
6
|
+
let(:client) do
|
7
|
+
instance_double('Ably::Realtime::Client', connection: connection, client_id: 'clientId', logger: double('logger').as_null_object)
|
8
|
+
end
|
7
9
|
let(:channel_name) { 'unique' }
|
8
|
-
let(:options)
|
10
|
+
let(:options) do
|
11
|
+
{ params: { bizarre: 'value' } }
|
12
|
+
end
|
9
13
|
|
10
14
|
subject { Ably::Realtime::Channels.new(client) }
|
11
15
|
|
12
16
|
context 'creating channels' do
|
13
17
|
context '#get' do
|
14
|
-
|
15
|
-
|
16
|
-
|
18
|
+
context "when channel doesn't exist" do
|
19
|
+
shared_examples 'creates a channel' do
|
20
|
+
it 'creates a channel (RTS3a)' do
|
21
|
+
expect(Ably::Realtime::Channel).to receive(:new).with(client, channel_name, channel_options)
|
22
|
+
subject.get(channel_name, channel_options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'hash' do
|
27
|
+
let(:channel_options) { options }
|
28
|
+
it { expect(channel_options).to be_a(Hash) }
|
29
|
+
|
30
|
+
include_examples 'creates a channel'
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'ChannelOptions object' do
|
34
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
35
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
36
|
+
|
37
|
+
include_examples 'creates a channel'
|
38
|
+
end
|
17
39
|
end
|
18
40
|
|
19
41
|
context 'when an existing channel exists' do
|
20
|
-
|
21
|
-
channel
|
22
|
-
|
23
|
-
|
42
|
+
shared_examples 'reuse a channel object if it exists' do
|
43
|
+
it 'will reuse a channel object if it exists (RTS3a)' do
|
44
|
+
channel = subject.get(channel_name, channel_options)
|
45
|
+
expect(channel).to be_a(Ably::Realtime::Channel)
|
46
|
+
expect(subject.get(channel_name, channel_options).object_id).to eql(channel.object_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'hash' do
|
51
|
+
let(:channel_options) { options }
|
52
|
+
it { expect(channel_options).to be_a(Hash) }
|
53
|
+
|
54
|
+
include_examples 'reuse a channel object if it exists'
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'ChannelOptions object' do
|
58
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
59
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
60
|
+
|
61
|
+
include_examples 'reuse a channel object if it exists'
|
24
62
|
end
|
25
63
|
|
26
|
-
it 'will update the options on the channel if provided' do
|
64
|
+
it 'will update the options on the channel if provided (RSN3c)' do
|
27
65
|
channel = subject.get(channel_name, options)
|
28
|
-
expect(channel.options).to
|
29
|
-
expect(channel.options).to_not include(:encrypted)
|
66
|
+
expect(channel.options.to_h).to eq(options)
|
67
|
+
expect(channel.options.to_h).to_not include(:encrypted)
|
30
68
|
subject.get(channel_name, encrypted: true)
|
31
|
-
expect(channel.options[:encrypted]).to
|
69
|
+
expect(channel.options[:encrypted]).to eq(true)
|
32
70
|
end
|
33
71
|
|
34
72
|
it 'will leave the options intact on the channel if not provided' do
|
35
73
|
channel = subject.get(channel_name, options)
|
36
|
-
expect(channel.options).to
|
74
|
+
expect(channel.options.to_h).to eq(options)
|
37
75
|
subject.get(channel_name)
|
38
|
-
expect(channel.options).to
|
76
|
+
expect(channel.options.to_h).to eq(options)
|
39
77
|
end
|
40
78
|
end
|
41
79
|
end
|
@@ -32,5 +32,43 @@ describe Ably::Realtime::Client::IncomingMessageDispatcher, :api_private do
|
|
32
32
|
expect(subject).to receive_message_chain(:logger, :warn)
|
33
33
|
msgbus.publish :protocol_message, Ably::Models::ProtocolMessage.new(:action => :attached, channel: 'unknown')
|
34
34
|
end
|
35
|
+
|
36
|
+
context 'TO3l8' do
|
37
|
+
context 'on action presence' do
|
38
|
+
let(:presence) { 101.times.map { { data: 'x' * 655 } } }
|
39
|
+
|
40
|
+
let(:protocol_message) do
|
41
|
+
Ably::Models::ProtocolMessage.new(action: :presence, channel: 'default', presence: presence, connection_serial: 123123123)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should raise a protocol error when message size exceeded 65536 bytes' do
|
45
|
+
allow(connection).to receive(:serial).and_return(12312312)
|
46
|
+
allow(subject).to receive(:update_connection_recovery_info)
|
47
|
+
allow(subject).to receive_message_chain(:logger, :debug)
|
48
|
+
allow(subject).to receive_message_chain(:logger, :warn)
|
49
|
+
expect(subject).to receive_message_chain(:logger, :fatal)
|
50
|
+
|
51
|
+
msgbus.publish :protocol_message, protocol_message
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'on action message' do
|
56
|
+
let(:messages) { 101.times.map { { data: 'x' * 655 } } }
|
57
|
+
|
58
|
+
let(:protocol_message) do
|
59
|
+
Ably::Models::ProtocolMessage.new(action: :message, channel: 'default', messages: messages, connection_serial: 123123123)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should raise a protocol error when message size exceeded 65536 bytes' do
|
63
|
+
allow(connection).to receive(:serial).and_return(12312312)
|
64
|
+
allow(subject).to receive(:update_connection_recovery_info)
|
65
|
+
allow(subject).to receive_message_chain(:logger, :debug)
|
66
|
+
allow(subject).to receive_message_chain(:logger, :warn)
|
67
|
+
expect(subject).to receive_message_chain(:logger, :fatal)
|
68
|
+
|
69
|
+
msgbus.publish :protocol_message, protocol_message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
35
73
|
end
|
36
74
|
end
|