ably 1.2.5 → 1.2.7

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +2 -1
  3. data/CHANGELOG.md +25 -0
  4. data/README.md +24 -7
  5. data/SPEC.md +1738 -869
  6. data/ably.gemspec +1 -1
  7. data/lib/ably/auth.rb +19 -11
  8. data/lib/ably/models/protocol_message.rb +4 -26
  9. data/lib/ably/modules/safe_deferrable.rb +2 -2
  10. data/lib/ably/modules/state_emitter.rb +1 -1
  11. data/lib/ably/realtime/auth.rb +4 -0
  12. data/lib/ably/realtime/channel/channel_manager.rb +51 -48
  13. data/lib/ably/realtime/channel/channel_properties.rb +9 -0
  14. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -0
  15. data/lib/ably/realtime/channel.rb +4 -3
  16. data/lib/ably/realtime/channels.rb +20 -0
  17. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -13
  18. data/lib/ably/realtime/client.rb +14 -6
  19. data/lib/ably/realtime/connection/connection_manager.rb +21 -22
  20. data/lib/ably/realtime/connection.rb +77 -109
  21. data/lib/ably/realtime/presence/members_map.rb +41 -92
  22. data/lib/ably/realtime/presence/presence_manager.rb +12 -17
  23. data/lib/ably/realtime/presence.rb +15 -6
  24. data/lib/ably/realtime/push.rb +0 -27
  25. data/lib/ably/realtime/recovery_key_context.rb +36 -0
  26. data/lib/ably/rest/client.rb +4 -6
  27. data/lib/ably/rest/push/admin.rb +1 -1
  28. data/lib/ably/rest/push.rb +0 -19
  29. data/lib/ably/util/ably_extensions.rb +29 -0
  30. data/lib/ably/util/crypto.rb +2 -2
  31. data/lib/ably/util/safe_deferrable.rb +1 -1
  32. data/lib/ably/version.rb +5 -7
  33. data/spec/acceptance/realtime/auth_spec.rb +0 -7
  34. data/spec/acceptance/realtime/channel_history_spec.rb +8 -12
  35. data/spec/acceptance/realtime/channel_spec.rb +474 -300
  36. data/spec/acceptance/realtime/client_spec.rb +1 -1
  37. data/spec/acceptance/realtime/connection_failures_spec.rb +8 -25
  38. data/spec/acceptance/realtime/connection_spec.rb +28 -120
  39. data/spec/acceptance/realtime/message_spec.rb +24 -53
  40. data/spec/acceptance/realtime/presence_spec.rb +123 -92
  41. data/spec/acceptance/rest/channel_spec.rb +2 -2
  42. data/spec/acceptance/rest/client_spec.rb +9 -2
  43. data/spec/acceptance/rest/message_spec.rb +8 -11
  44. data/spec/acceptance/rest/push_admin_spec.rb +20 -15
  45. data/spec/shared/client_initializer_behaviour.rb +1 -1
  46. data/spec/support/markdown_spec_formatter.rb +1 -1
  47. data/spec/unit/models/protocol_message_spec.rb +0 -86
  48. data/spec/unit/models/token_details_spec.rb +4 -2
  49. data/spec/unit/realtime/channels_spec.rb +1 -1
  50. data/spec/unit/realtime/connection_spec.rb +0 -30
  51. data/spec/unit/realtime/recovery_key_context_spec.rb +36 -0
  52. data/spec/unit/util/crypto_spec.rb +15 -15
  53. metadata +8 -8
  54. data/spec/acceptance/realtime/push_spec.rb +0 -27
  55. data/spec/acceptance/rest/push_spec.rb +0 -25
@@ -127,14 +127,6 @@ describe Ably::Models::ProtocolMessage do
127
127
  end
128
128
  end
129
129
 
130
- context '#connection_serial' do
131
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
132
- it 'converts :connection_serial to an Integer' do
133
- expect(protocol_message.connection_serial).to be_a(Integer)
134
- expect(protocol_message.connection_serial).to eql(55)
135
- end
136
- end
137
-
138
130
  context '#flags (#TR4i)' do
139
131
  context 'when nil' do
140
132
  let(:protocol_message) { new_protocol_message({}) }
@@ -241,76 +233,6 @@ describe Ably::Models::ProtocolMessage do
241
233
  end
242
234
  end
243
235
 
244
- context '#has_connection_serial?' do
245
- context 'without connection_serial' do
246
- let(:protocol_message) { new_protocol_message({}) }
247
-
248
- it 'returns false' do
249
- expect(protocol_message.has_connection_serial?).to eql(false)
250
- end
251
- end
252
-
253
- context 'with connection_serial' do
254
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
255
-
256
- it 'returns true' do
257
- expect(protocol_message.has_connection_serial?).to eql(true)
258
- end
259
- end
260
- end
261
-
262
- context '#serial' do
263
- context 'with underlying msg_serial' do
264
- let(:protocol_message) { new_protocol_message(msg_serial: "55") }
265
- it 'converts :msg_serial to an Integer' do
266
- expect(protocol_message.serial).to be_a(Integer)
267
- expect(protocol_message.serial).to eql(55)
268
- end
269
- end
270
-
271
- context 'with underlying connection_serial' do
272
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
273
- it 'converts :connection_serial to an Integer' do
274
- expect(protocol_message.serial).to be_a(Integer)
275
- expect(protocol_message.serial).to eql(55)
276
- end
277
- end
278
-
279
- context 'with underlying connection_serial and msg_serial' do
280
- let(:protocol_message) { new_protocol_message(connection_serial: "99", msg_serial: "11") }
281
- it 'prefers connection_serial and converts :connection_serial to an Integer' do
282
- expect(protocol_message.serial).to be_a(Integer)
283
- expect(protocol_message.serial).to eql(99)
284
- end
285
- end
286
- end
287
-
288
- context '#has_serial?' do
289
- context 'without msg_serial or connection_serial' do
290
- let(:protocol_message) { new_protocol_message({}) }
291
-
292
- it 'returns false' do
293
- expect(protocol_message.has_serial?).to eql(false)
294
- end
295
- end
296
-
297
- context 'with msg_serial' do
298
- let(:protocol_message) { new_protocol_message(msg_serial: "55") }
299
-
300
- it 'returns true' do
301
- expect(protocol_message.has_serial?).to eql(true)
302
- end
303
- end
304
-
305
- context 'with connection_serial' do
306
- let(:protocol_message) { new_protocol_message(connection_serial: "55") }
307
-
308
- it 'returns true' do
309
- expect(protocol_message.has_serial?).to eql(true)
310
- end
311
- end
312
- end
313
-
314
236
  context '#error' do
315
237
  context 'with no error attribute' do
316
238
  let(:protocol_message) { new_protocol_message(action: 1) }
@@ -475,14 +397,6 @@ describe Ably::Models::ProtocolMessage do
475
397
  end
476
398
  end
477
399
 
478
- context 'with missing msg_serial for ack message' do
479
- let(:model) { new_protocol_message({ :action => message_action }) }
480
-
481
- it 'it raises an exception' do
482
- expect { model.to_json }.to raise_error TypeError, /msg_serial.*missing/
483
- end
484
- end
485
-
486
400
  context 'is aliased by #to_s' do
487
401
  let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3], :timestamp => as_since_epoch(Time.now) }) }
488
402
 
@@ -56,6 +56,7 @@ describe Ably::Models::TokenDetails do
56
56
 
57
57
  context '#expired?' do
58
58
  let(:expire_time) { Time.now + Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER }
59
+ let(:clock_skew) { 1 } # clock skew of 1 second
59
60
 
60
61
  context 'once grace period buffer has passed' do
61
62
  subject { Ably::Models::TokenDetails.new(expires: expire_time - 1) }
@@ -74,7 +75,7 @@ describe Ably::Models::TokenDetails do
74
75
  end
75
76
 
76
77
  context 'when expires is not available (i.e. string tokens)' do
77
- subject { Ably::Models::TokenDetails.new() }
78
+ subject { Ably::Models::TokenDetails.new }
78
79
 
79
80
  it 'is always false' do
80
81
  expect(subject.expired?).to eql(false)
@@ -90,8 +91,9 @@ describe Ably::Models::TokenDetails do
90
91
  expect(subject.expired?(from: (Time.now - server_offset_time))).to eql(false)
91
92
  end
92
93
 
94
+ # Test is flaky and fails on CI, so adding a bit of extra tolerance (clock_skew) to make it work
93
95
  it 'is true' do
94
- expect(subject.expired?(from: Time.now)).to eql(true)
96
+ expect(subject.expired?(from: Time.now + clock_skew)).to eql(true)
95
97
  end
96
98
  end
97
99
  end
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Ably::Realtime::Channels do
5
- let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true, on_resume: true) }
5
+ let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true) }
6
6
  let(:client) do
7
7
  instance_double('Ably::Realtime::Client', connection: connection, client_id: 'clientId', logger: double('logger').as_null_object)
8
8
  end
@@ -34,36 +34,6 @@ describe Ably::Realtime::Connection do
34
34
  it_behaves_like 'an incoming protocol message bus'
35
35
  it_behaves_like 'an outgoing protocol message bus'
36
36
 
37
- describe 'connection resume callbacks', api_private: true do
38
- let(:callbacks) { [] }
39
-
40
- describe '#trigger_resumed' do
41
- it 'executes the callbacks' do
42
- subject.on_resume { callbacks << true }
43
- subject.trigger_resumed
44
- expect(callbacks.count).to eql(1)
45
- end
46
- end
47
-
48
- describe '#on_resume' do
49
- it 'registers a callback' do
50
- subject.on_resume { callbacks << true }
51
- subject.trigger_resumed
52
- expect(callbacks.count).to eql(1)
53
- end
54
- end
55
-
56
- describe '#off_resume' do
57
- it 'registers a callback' do
58
- subject.on_resume { callbacks << true }
59
- additional_proc = lambda { raise 'This should not be called' }
60
- subject.off_resume(&additional_proc)
61
- subject.trigger_resumed
62
- expect(callbacks.count).to eql(1)
63
- end
64
- end
65
- end
66
-
67
37
  after(:all) do
68
38
  sleep 1 # let realtime library shut down any open clients
69
39
  end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'ably/realtime/recovery_key_context'
3
+
4
+ describe Ably::Realtime::RecoveryKeyContext do
5
+
6
+ context 'connection recovery key' do
7
+
8
+ it 'should encode recovery key - RTN16i, RTN16f, RTN16j' do
9
+ connection_key = 'key'
10
+ msg_serial = 123
11
+ channel_serials = {
12
+ 'channel1' => 'serial1',
13
+ 'channel2' => 'serial2'
14
+ }
15
+ recovery_context = Ably::Realtime::RecoveryKeyContext.new(connection_key, msg_serial, channel_serials)
16
+ encoded_recovery_key = recovery_context.to_json
17
+ expect(encoded_recovery_key).to eq "{\"connection_key\":\"key\",\"msg_serial\":123," <<
18
+ "\"channel_serials\":{\"channel1\":\"serial1\",\"channel2\":\"serial2\"}}"
19
+ end
20
+
21
+ it 'should decode recovery key - RTN16i, RTN16f, RTN16j' do
22
+ encoded_recovery_key = "{\"connection_key\":\"key\",\"msg_serial\":123," <<
23
+ "\"channel_serials\":{\"channel1\":\"serial1\",\"channel2\":\"serial2\"}}"
24
+ decoded_recovery_key = Ably::Realtime::RecoveryKeyContext.from_json(encoded_recovery_key)
25
+ expect(decoded_recovery_key.connection_key).to eq("key")
26
+ expect(decoded_recovery_key.msg_serial).to eq(123)
27
+ end
28
+
29
+ it 'should return nil for invalid recovery key - RTN16i, RTN16f, RTN16j' do
30
+ encoded_recovery_key = "{\"invalid key\"}"
31
+ decoded_recovery_key = Ably::Realtime::RecoveryKeyContext.from_json(encoded_recovery_key)
32
+ expect(decoded_recovery_key).to be_nil
33
+ end
34
+
35
+ end
36
+ end
@@ -72,26 +72,26 @@ describe Ably::Util::Crypto do
72
72
  end
73
73
  end
74
74
 
75
- context 'encrypts & decrypt' do
75
+ context '#encrypt & #decrypt' do
76
76
  let(:string) { random_str }
77
- let(:byte_array) { random_str.to_msgpack.unpack('C*') }
78
-
79
- specify '#encrypt encrypts a string' do
80
- encrypted = subject.encrypt(string)
81
- expect(subject.decrypt(encrypted)).to eql(string)
82
- end
77
+ let(:empty_string) { '' }
83
78
 
84
- specify '#decrypt decrypts a string' do
79
+ specify 'encrypts and decrypts a non-empty string' do
80
+ expect(string).to be_ascii_only
85
81
  encrypted = subject.encrypt(string)
86
- expect(subject.decrypt(encrypted)).to eql(string)
82
+ expect(encrypted).to be_truthy
83
+ decrypted = subject.decrypt(encrypted)
84
+ expect(decrypted).to eql(string)
85
+ expect(decrypted).to be_ascii_only
87
86
  end
88
- end
89
-
90
- context 'encrypting an empty string' do
91
- let(:empty_string) { '' }
92
87
 
93
- it 'raises an ArgumentError' do
94
- expect { subject.encrypt(empty_string) }.to raise_error ArgumentError, /data must not be empty/
88
+ specify 'encrypts and decrypts an empty string' do
89
+ expect(empty_string).to be_ascii_only
90
+ encrypted = subject.encrypt(empty_string)
91
+ expect(encrypted).to be_truthy
92
+ decrypted = subject.decrypt(encrypted)
93
+ expect(decrypted).to eql(empty_string)
94
+ expect(decrypted).to be_ascii_only
95
95
  end
96
96
  end
97
97
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ably
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
4
+ version: 1.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lewis Marshall
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-05-16 00:00:00.000000000 Z
12
+ date: 2024-09-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -283,14 +283,14 @@ dependencies:
283
283
  requirements:
284
284
  - - "~>"
285
285
  - !ruby/object:Gem::Version
286
- version: 0.21.2
286
+ version: 0.22.0
287
287
  type: :development
288
288
  prerelease: false
289
289
  version_requirements: !ruby/object:Gem::Requirement
290
290
  requirements:
291
291
  - - "~>"
292
292
  - !ruby/object:Gem::Version
293
- version: 0.21.2
293
+ version: 0.22.0
294
294
  - !ruby/object:Gem::Dependency
295
295
  name: simplecov-lcov
296
296
  requirement: !ruby/object:Gem::Requirement
@@ -469,6 +469,7 @@ files:
469
469
  - lib/ably/realtime/push/admin.rb
470
470
  - lib/ably/realtime/push/channel_subscriptions.rb
471
471
  - lib/ably/realtime/push/device_registrations.rb
472
+ - lib/ably/realtime/recovery_key_context.rb
472
473
  - lib/ably/rest.rb
473
474
  - lib/ably/rest/channel.rb
474
475
  - lib/ably/rest/channel/push_channel.rb
@@ -486,6 +487,7 @@ files:
486
487
  - lib/ably/rest/push/admin.rb
487
488
  - lib/ably/rest/push/channel_subscriptions.rb
488
489
  - lib/ably/rest/push/device_registrations.rb
490
+ - lib/ably/util/ably_extensions.rb
489
491
  - lib/ably/util/crypto.rb
490
492
  - lib/ably/util/pub_sub.rb
491
493
  - lib/ably/util/safe_deferrable.rb
@@ -501,7 +503,6 @@ files:
501
503
  - spec/acceptance/realtime/presence_history_spec.rb
502
504
  - spec/acceptance/realtime/presence_spec.rb
503
505
  - spec/acceptance/realtime/push_admin_spec.rb
504
- - spec/acceptance/realtime/push_spec.rb
505
506
  - spec/acceptance/realtime/stats_spec.rb
506
507
  - spec/acceptance/realtime/time_spec.rb
507
508
  - spec/acceptance/rest/auth_spec.rb
@@ -513,7 +514,6 @@ files:
513
514
  - spec/acceptance/rest/message_spec.rb
514
515
  - spec/acceptance/rest/presence_spec.rb
515
516
  - spec/acceptance/rest/push_admin_spec.rb
516
- - spec/acceptance/rest/push_spec.rb
517
517
  - spec/acceptance/rest/stats_spec.rb
518
518
  - spec/acceptance/rest/time_spec.rb
519
519
  - spec/lib/unit/models/channel_options_spec.rb
@@ -578,6 +578,7 @@ files:
578
578
  - spec/unit/realtime/presence_spec.rb
579
579
  - spec/unit/realtime/push_channel_spec.rb
580
580
  - spec/unit/realtime/realtime_spec.rb
581
+ - spec/unit/realtime/recovery_key_context_spec.rb
581
582
  - spec/unit/realtime/safe_deferrable_spec.rb
582
583
  - spec/unit/realtime/websocket_transport_spec.rb
583
584
  - spec/unit/rest/channel_spec.rb
@@ -622,7 +623,6 @@ test_files:
622
623
  - spec/acceptance/realtime/presence_history_spec.rb
623
624
  - spec/acceptance/realtime/presence_spec.rb
624
625
  - spec/acceptance/realtime/push_admin_spec.rb
625
- - spec/acceptance/realtime/push_spec.rb
626
626
  - spec/acceptance/realtime/stats_spec.rb
627
627
  - spec/acceptance/realtime/time_spec.rb
628
628
  - spec/acceptance/rest/auth_spec.rb
@@ -634,7 +634,6 @@ test_files:
634
634
  - spec/acceptance/rest/message_spec.rb
635
635
  - spec/acceptance/rest/presence_spec.rb
636
636
  - spec/acceptance/rest/push_admin_spec.rb
637
- - spec/acceptance/rest/push_spec.rb
638
637
  - spec/acceptance/rest/stats_spec.rb
639
638
  - spec/acceptance/rest/time_spec.rb
640
639
  - spec/lib/unit/models/channel_options_spec.rb
@@ -699,6 +698,7 @@ test_files:
699
698
  - spec/unit/realtime/presence_spec.rb
700
699
  - spec/unit/realtime/push_channel_spec.rb
701
700
  - spec/unit/realtime/realtime_spec.rb
701
+ - spec/unit/realtime/recovery_key_context_spec.rb
702
702
  - spec/unit/realtime/safe_deferrable_spec.rb
703
703
  - spec/unit/realtime/websocket_transport_spec.rb
704
704
  - spec/unit/rest/channel_spec.rb
@@ -1,27 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
-
4
- describe Ably::Realtime::Push, :event_machine do
5
- vary_by_protocol do
6
- let(:default_options) { { key: api_key, environment: environment, protocol: protocol} }
7
- let(:client_options) { default_options }
8
- let(:client) do
9
- Ably::Realtime::Client.new(client_options)
10
- end
11
- subject { client.push }
12
-
13
- describe '#activate' do
14
- it 'raises an unsupported exception' do
15
- expect { subject.activate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
16
- stop_reactor
17
- end
18
- end
19
-
20
- describe '#deactivate' do
21
- it 'raises an unsupported exception' do
22
- expect { subject.deactivate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
23
- stop_reactor
24
- end
25
- end
26
- end
27
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
-
4
- describe Ably::Rest::Push do
5
- vary_by_protocol do
6
- let(:default_options) { { key: api_key, environment: environment, protocol: protocol} }
7
- let(:client_options) { default_options }
8
- let(:client) do
9
- Ably::Rest::Client.new(client_options)
10
- end
11
- subject { client.push }
12
-
13
- describe '#activate' do
14
- it 'raises an unsupported exception' do
15
- expect { subject.activate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
16
- end
17
- end
18
-
19
- describe '#deactivate' do
20
- it 'raises an unsupported exception' do
21
- expect { subject.deactivate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
22
- end
23
- end
24
- end
25
- end