ably 1.1.6 → 1.2.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +15 -1
  3. data/CHANGELOG.md +131 -0
  4. data/COPYRIGHT +1 -1
  5. data/README.md +14 -2
  6. data/SPEC.md +0 -7
  7. data/UPDATING.md +30 -0
  8. data/ably.gemspec +12 -7
  9. data/lib/ably/agent.rb +3 -0
  10. data/lib/ably/auth.rb +3 -3
  11. data/lib/ably/exceptions.rb +6 -0
  12. data/lib/ably/models/channel_options.rb +97 -0
  13. data/lib/ably/models/connection_details.rb +8 -0
  14. data/lib/ably/models/delta_extras.rb +29 -0
  15. data/lib/ably/models/error_info.rb +6 -2
  16. data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
  17. data/lib/ably/models/message.rb +28 -3
  18. data/lib/ably/models/presence_message.rb +14 -0
  19. data/lib/ably/models/protocol_message.rb +29 -12
  20. data/lib/ably/models/token_details.rb +7 -2
  21. data/lib/ably/modules/channels_collection.rb +22 -2
  22. data/lib/ably/modules/conversions.rb +34 -0
  23. data/lib/ably/realtime/channel/channel_manager.rb +18 -6
  24. data/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
  25. data/lib/ably/realtime/channel/publisher.rb +6 -0
  26. data/lib/ably/realtime/channel.rb +54 -22
  27. data/lib/ably/realtime/channels.rb +1 -1
  28. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
  29. data/lib/ably/realtime/connection/connection_manager.rb +13 -4
  30. data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
  31. data/lib/ably/realtime/connection.rb +2 -2
  32. data/lib/ably/rest/channel.rb +31 -31
  33. data/lib/ably/rest/client.rb +27 -12
  34. data/lib/ably/util/crypto.rb +1 -1
  35. data/lib/ably/version.rb +2 -14
  36. data/lib/ably.rb +1 -0
  37. data/spec/acceptance/realtime/auth_spec.rb +1 -1
  38. data/spec/acceptance/realtime/channel_history_spec.rb +25 -0
  39. data/spec/acceptance/realtime/channel_spec.rb +466 -21
  40. data/spec/acceptance/realtime/channels_spec.rb +59 -7
  41. data/spec/acceptance/realtime/connection_failures_spec.rb +59 -2
  42. data/spec/acceptance/realtime/connection_spec.rb +256 -28
  43. data/spec/acceptance/realtime/message_spec.rb +77 -0
  44. data/spec/acceptance/realtime/presence_history_spec.rb +3 -1
  45. data/spec/acceptance/realtime/presence_spec.rb +31 -159
  46. data/spec/acceptance/rest/auth_spec.rb +18 -0
  47. data/spec/acceptance/rest/channel_spec.rb +84 -9
  48. data/spec/acceptance/rest/channels_spec.rb +23 -6
  49. data/spec/acceptance/rest/client_spec.rb +25 -21
  50. data/spec/acceptance/rest/message_spec.rb +61 -3
  51. data/spec/lib/unit/models/channel_options_spec.rb +52 -0
  52. data/spec/shared/model_behaviour.rb +1 -1
  53. data/spec/spec_helper.rb +11 -2
  54. data/spec/support/test_app.rb +1 -1
  55. data/spec/unit/models/delta_extras_spec.rb +14 -0
  56. data/spec/unit/models/error_info_spec.rb +17 -1
  57. data/spec/unit/models/message_spec.rb +97 -0
  58. data/spec/unit/models/presence_message_spec.rb +49 -0
  59. data/spec/unit/models/protocol_message_spec.rb +125 -27
  60. data/spec/unit/models/token_details_spec.rb +14 -0
  61. data/spec/unit/realtime/channel_spec.rb +3 -2
  62. data/spec/unit/realtime/channels_spec.rb +53 -15
  63. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
  64. data/spec/unit/rest/channel_spec.rb +44 -1
  65. data/spec/unit/rest/channels_spec.rb +81 -14
  66. data/spec/unit/rest/client_spec.rb +47 -0
  67. 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 'coveralls'
9
- Coveralls.wear!
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'
@@ -59,7 +59,7 @@ class TestApp
59
59
 
60
60
  url = "#{sandbox_client.endpoint}/apps/#{app_id}"
61
61
 
62
- basic_auth = Base64.encode64(api_key).chomp
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, TR4e
13
+ # TR4n, TR4b, TR4c, TR4d
14
14
  it_behaves_like 'a model',
15
- with_simple_attributes: %w(id channel channel_serial connection_id connection_key),
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(:message) { { 'name' => 'event', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
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: [message] }) }
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"].first).to include(message)
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: [message], :timestamp => as_since_epoch(Time.now) }) }
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: [message] }) }
429
- let(:message) { { 'name' => 'event', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
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('event')
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) { double('client').as_null_object }
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) { instance_double('Ably::Realtime::Client', connection: connection, client_id: 'clientId') }
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) { { 'bizarre' => 'value' } }
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
- it 'creates a channel if it does not exist' do
15
- expect(Ably::Realtime::Channel).to receive(:new).with(client, channel_name, options)
16
- subject.get(channel_name, options)
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
- it 'will reuse a channel object if it exists' do
21
- channel = subject.get(channel_name, options)
22
- expect(channel).to be_a(Ably::Realtime::Channel)
23
- expect(subject.get(channel_name, options).object_id).to eql(channel.object_id)
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 eql(options)
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 eql(true)
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 eql(options)
74
+ expect(channel.options.to_h).to eq(options)
37
75
  subject.get(channel_name)
38
- expect(channel.options).to eql(options)
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