ably 1.1.0 → 1.1.4

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +27 -0
  3. data/CHANGELOG.md +68 -2
  4. data/COPYRIGHT +1 -0
  5. data/LICENSE +172 -11
  6. data/MAINTAINERS.md +1 -0
  7. data/README.md +3 -7
  8. data/SPEC.md +944 -914
  9. data/ably.gemspec +7 -7
  10. data/lib/ably/auth.rb +12 -2
  11. data/lib/ably/exceptions.rb +2 -2
  12. data/lib/ably/logger.rb +7 -1
  13. data/lib/ably/modules/state_machine.rb +1 -1
  14. data/lib/ably/realtime/channel.rb +7 -11
  15. data/lib/ably/realtime/channel/channel_manager.rb +2 -2
  16. data/lib/ably/realtime/channel/channel_properties.rb +24 -0
  17. data/lib/ably/realtime/client.rb +12 -3
  18. data/lib/ably/realtime/connection.rb +31 -19
  19. data/lib/ably/realtime/connection/connection_manager.rb +19 -3
  20. data/lib/ably/realtime/connection/websocket_transport.rb +67 -1
  21. data/lib/ably/realtime/presence.rb +0 -14
  22. data/lib/ably/rest/channel.rb +25 -17
  23. data/lib/ably/rest/client.rb +22 -11
  24. data/lib/ably/version.rb +1 -1
  25. data/spec/acceptance/realtime/auth_spec.rb +16 -13
  26. data/spec/acceptance/realtime/channel_history_spec.rb +26 -20
  27. data/spec/acceptance/realtime/channel_spec.rb +21 -8
  28. data/spec/acceptance/realtime/client_spec.rb +80 -20
  29. data/spec/acceptance/realtime/connection_failures_spec.rb +71 -5
  30. data/spec/acceptance/realtime/connection_spec.rb +153 -26
  31. data/spec/acceptance/realtime/message_spec.rb +17 -17
  32. data/spec/acceptance/realtime/presence_history_spec.rb +0 -58
  33. data/spec/acceptance/realtime/presence_spec.rb +250 -162
  34. data/spec/acceptance/realtime/push_admin_spec.rb +49 -25
  35. data/spec/acceptance/rest/auth_spec.rb +6 -75
  36. data/spec/acceptance/rest/channel_spec.rb +79 -4
  37. data/spec/acceptance/rest/channels_spec.rb +6 -0
  38. data/spec/acceptance/rest/client_spec.rb +72 -12
  39. data/spec/acceptance/rest/message_spec.rb +8 -27
  40. data/spec/acceptance/rest/push_admin_spec.rb +67 -27
  41. data/spec/shared/client_initializer_behaviour.rb +0 -8
  42. data/spec/spec_helper.rb +2 -1
  43. data/spec/support/debug_failure_helper.rb +9 -5
  44. data/spec/support/serialization_helper.rb +21 -0
  45. data/spec/support/test_app.rb +2 -2
  46. data/spec/unit/modules/enum_spec.rb +1 -1
  47. data/spec/unit/realtime/client_spec.rb +20 -7
  48. data/spec/unit/realtime/connection_spec.rb +1 -1
  49. metadata +40 -29
  50. data/.travis.yml +0 -16
@@ -75,8 +75,7 @@ describe Ably::Rest::Channel, 'messages' do
75
75
  end
76
76
 
77
77
  context 'JSON Array' do
78
- # TODO: Add nil type back in
79
- let(:data) { { 'push' => { 'data' => { 'key' => [ true, false, 55, 'string', { 'Hash' => true }, ['array'] ] } } } }
78
+ let(:data) { { 'push' => { 'data' => { 'key' => [ true, false, 55, nil, 'string', { 'Hash' => true }, ['array'] ] } } } }
80
79
 
81
80
  it 'is encoded and decoded to the same deep multi-type object' do
82
81
  channel.publish 'event', {}, extras: data
@@ -120,8 +119,6 @@ describe Ably::Rest::Channel, 'messages' do
120
119
  let(:message) { Ably::Models::Message.new(id: id, data: data) }
121
120
 
122
121
  specify 'three REST publishes result in only one message being published' do
123
- pending 'idempotency rolled out to global cluster'
124
-
125
122
  3.times { channel.publish [message] }
126
123
  expect(channel.history.items.length).to eql(1)
127
124
  expect(channel.history.items[0].id).to eql(id)
@@ -130,8 +127,6 @@ describe Ably::Rest::Channel, 'messages' do
130
127
 
131
128
  context 'with #publish arguments only' do
132
129
  it 'three REST publishes result in only one message being published' do
133
- pending 'idempotency rolled out to global cluster'
134
-
135
130
  3.times { channel.publish 'event', data, id: id }
136
131
  expect(channel.history.items.length).to eql(1)
137
132
  end
@@ -143,8 +138,6 @@ describe Ably::Rest::Channel, 'messages' do
143
138
  end
144
139
 
145
140
  specify 'for multiple messages in one publish operation (#RSL1k3)' do
146
- pending 'idempotency rolled out to global cluster'
147
-
148
141
  message_arr = 3.times.map { Ably::Models::Message.new(id: id, data: data) }
149
142
  expect { channel.publish message_arr }.to raise_error do |error|
150
143
  expect(error.code).to eql(40031) # Invalid publish request (invalid client-specified id), see https://github.com/ably/ably-common/pull/30
@@ -152,12 +145,10 @@ describe Ably::Rest::Channel, 'messages' do
152
145
  end
153
146
 
154
147
  specify 'for multiple messages in one publish operation with IDs following the required format described in RSL1k1 (#RSL1k3)' do
155
- pending 'idempotency rolled out to global cluster'
156
-
157
148
  message_arr = 3.times.map { |index| Ably::Models::Message.new(id: "#{id}:#{index}", data: data) }
158
149
  channel.publish message_arr
159
- expect(channel.history.items[0].id).to eql("{id}:0")
160
- expect(channel.history.items[2].id).to eql("{id}:2")
150
+ expect(channel.history.items[2].id).to eql("#{id}:0")
151
+ expect(channel.history.items[0].id).to eql("#{id}:2")
161
152
  expect(channel.history.items.length).to eql(3)
162
153
  end
163
154
  end
@@ -174,7 +165,7 @@ describe Ably::Rest::Channel, 'messages' do
174
165
  end
175
166
 
176
167
  context 'when idempotent publishing is enabled in the client library ClientOptions (#TO3n)' do
177
- let(:client_options) { default_client_options.merge(idempotent_rest_publishing: true, log_level: :error) }
168
+ let(:client_options) { default_client_options.merge(idempotent_rest_publishing: true, log_level: :error, fallback_hosts: ["#{environment}-realtime.ably.io"]) }
178
169
 
179
170
  context 'when there is a network failure triggering an automatic retry (#RSL1k4)' do
180
171
  def mock_for_two_publish_failures
@@ -195,8 +186,6 @@ describe Ably::Rest::Channel, 'messages' do
195
186
  before { mock_for_two_publish_failures }
196
187
 
197
188
  specify 'two REST publish retries result in only one message being published' do
198
- pending 'idempotency rolled out to global cluster'
199
-
200
189
  channel.publish [message]
201
190
  expect(channel.history.items.length).to eql(1)
202
191
  expect(@failed_http_posts).to eql(2)
@@ -207,8 +196,6 @@ describe Ably::Rest::Channel, 'messages' do
207
196
  before { mock_for_two_publish_failures }
208
197
 
209
198
  specify 'two REST publish retries result in only one message being published' do
210
- pending 'idempotency rolled out to global cluster'
211
-
212
199
  channel.publish 'event', data
213
200
  expect(channel.history.items.length).to eql(1)
214
201
  expect(@failed_http_posts).to eql(2)
@@ -221,8 +208,6 @@ describe Ably::Rest::Channel, 'messages' do
221
208
  before { mock_for_two_publish_failures }
222
209
 
223
210
  specify 'two REST publish retries result in only one message being published' do
224
- pending 'idempotency rolled out to global cluster'
225
-
226
211
  channel.publish 'event', data, id: id
227
212
  expect(channel.history.items.length).to eql(1)
228
213
  expect(channel.history.items[0].id).to eql(id)
@@ -231,11 +216,9 @@ describe Ably::Rest::Channel, 'messages' do
231
216
  end
232
217
 
233
218
  specify 'for multiple messages in one publish operation' do
234
- pending 'idempotency rolled out to global cluster'
235
-
236
219
  message_arr = 3.times.map { Ably::Models::Message.new(data: data) }
237
220
  3.times { channel.publish message_arr }
238
- expect(channel.history.items.length).to eql(message_arr.length)
221
+ expect(channel.history.items.length).to eql(message_arr.length * 3)
239
222
  end
240
223
  end
241
224
 
@@ -248,13 +231,11 @@ describe Ably::Rest::Channel, 'messages' do
248
231
 
249
232
  context 'when publishing a batch of messages' do
250
233
  specify 'the ID is populated with a single random ID and sequence of serials from this lib (#RSL1k1)' do
251
- pending 'idempotency rolled out to global cluster'
252
-
253
234
  message = { name: 'event' }
254
235
  channel.publish [message, message, message]
255
- expect(channel.history.items[0].length).to eql(3)
256
- expect(channel.history.items[0].id).to match(/^[A-Za-z0-9\+\/]+:0$/)
257
- expect(channel.history.items[2].id).to match(/^[A-Za-z0-9\+\/]+:2$/)
236
+ expect(channel.history.items.length).to eql(3)
237
+ expect(channel.history.items[0].id).to match(/^[A-Za-z0-9\+\/]+:2$/)
238
+ expect(channel.history.items[2].id).to match(/^[A-Za-z0-9\+\/]+:0$/)
258
239
  base_64_id = channel.history.items[0].id.split(':')[0]
259
240
  expect(Base64.decode64(base_64_id).length).to eql(9)
260
241
  end
@@ -89,31 +89,15 @@ describe Ably::Rest::Push::Admin do
89
89
  end
90
90
  end
91
91
 
92
- def request_body(request, protocol)
93
- if protocol == :msgpack
94
- MessagePack.unpack(request.body)
95
- else
96
- JSON.parse(request.body)
97
- end
98
- end
99
-
100
- def serialize(object, protocol)
101
- if protocol == :msgpack
102
- MessagePack.pack(object)
103
- else
104
- JSON.dump(object)
105
- end
106
- end
107
-
108
92
  let!(:publish_stub) do
109
93
  stub_request(:post, "#{client.endpoint}/push/publish").
110
94
  with do |request|
111
- expect(request_body(request, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
112
- expect(request_body(request, protocol)['recipient']).to_not have_key('camel_case')
95
+ expect(deserialize_body(request.body, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
96
+ expect(deserialize_body(request.body, protocol)['recipient']).to_not have_key('camel_case')
113
97
  true
114
98
  end.to_return(
115
99
  :status => 201,
116
- :body => serialize({}, protocol),
100
+ :body => serialize_body({}, protocol),
117
101
  :headers => { 'Content-Type' => content_type }
118
102
  )
119
103
  end
@@ -181,6 +165,12 @@ describe Ably::Rest::Push::Admin do
181
165
  let(:client_id) { random_str }
182
166
  let(:fixture_count) { 6 }
183
167
 
168
+ before(:all) do
169
+ # As push tests often use the global scope (devices),
170
+ # we need to ensure tests cannot conflict
171
+ reload_test_app
172
+ end
173
+
184
174
  before do
185
175
  fixture_count.times.map do |index|
186
176
  Thread.new do
@@ -244,6 +234,12 @@ describe Ably::Rest::Push::Admin do
244
234
  let(:fixture_count) { 2 }
245
235
  let(:client_id) { random_str }
246
236
 
237
+ before(:all) do
238
+ # As push tests often use the global scope (devices),
239
+ # we need to ensure tests cannot conflict
240
+ reload_test_app
241
+ end
242
+
247
243
  before do
248
244
  fixture_count.times.map do |index|
249
245
  Thread.new do
@@ -318,6 +314,12 @@ describe Ably::Rest::Push::Admin do
318
314
  }
319
315
  end
320
316
 
317
+ before(:all) do
318
+ # As push tests often use the global scope (devices),
319
+ # we need to ensure tests cannot conflict
320
+ reload_test_app
321
+ end
322
+
321
323
  after do
322
324
  subject.remove_where client_id: client_id, full_wait: true
323
325
  end
@@ -444,6 +446,12 @@ describe Ably::Rest::Push::Admin do
444
446
  let(:device_id) { random_str }
445
447
  let(:client_id) { random_str }
446
448
 
449
+ before(:all) do
450
+ # As push tests often use the global scope (devices),
451
+ # we need to ensure tests cannot conflict
452
+ reload_test_app
453
+ end
454
+
447
455
  before do
448
456
  [
449
457
  Thread.new do
@@ -501,6 +509,12 @@ describe Ably::Rest::Push::Admin do
501
509
  let(:device_id) { random_str }
502
510
  let(:client_id) { random_str }
503
511
 
512
+ before(:all) do
513
+ # As push tests often use the global scope (devices),
514
+ # we need to ensure tests cannot conflict
515
+ reload_test_app
516
+ end
517
+
504
518
  before do
505
519
  [
506
520
  Thread.new do
@@ -585,8 +599,8 @@ describe Ably::Rest::Push::Admin do
585
599
  # and two device with the unique device_id and no client_id
586
600
  before do
587
601
  [
588
- lambda { device_registrations.save(default_device_attr.merge(id: device_id)) },
589
- lambda { device_registrations.save(default_device_attr.merge(id: device_id_2)) },
602
+ lambda { device_registrations.save(default_device_attr.merge(id: device_id, client_id: nil)) },
603
+ lambda { device_registrations.save(default_device_attr.merge(id: device_id_2, client_id: nil)) },
590
604
  lambda { device_registrations.save(default_device_attr.merge(client_id: client_id, id: random_str)) },
591
605
  lambda { device_registrations.save(default_device_attr.merge(client_id: client_id, id: random_str)) }
592
606
  ].map do |proc|
@@ -602,6 +616,12 @@ describe Ably::Rest::Push::Admin do
602
616
  describe '#list (#RSH1c1)' do
603
617
  let(:fixture_count) { 6 }
604
618
 
619
+ before(:all) do
620
+ # As push tests often use the global scope (devices),
621
+ # we need to ensure tests cannot conflict
622
+ reload_test_app
623
+ end
624
+
605
625
  before do
606
626
  fixture_count.times.map do |index|
607
627
  Thread.new { subject.save(channel: "pushenabled:#{random_str}", client_id: client_id) }
@@ -670,11 +690,14 @@ describe Ably::Rest::Push::Admin do
670
690
  describe '#list_channels (#RSH1c2)' do
671
691
  let(:fixture_count) { 6 }
672
692
 
673
- before(:context) do
674
- reload_test_app # TODO: Review if necessary late, currently other tests may affect list_channels
693
+ before(:all) do
694
+ # As push tests often use the global scope (devices),
695
+ # we need to ensure tests cannot conflict
696
+ reload_test_app
675
697
  end
676
698
 
677
699
  before do
700
+ # Create 6 channel subscriptions to the client ID for this test
678
701
  fixture_count.times.map do |index|
679
702
  Thread.new do
680
703
  subject.save(channel: "pushenabled:#{index}:#{random_str}", client_id: client_id)
@@ -694,9 +717,6 @@ describe Ably::Rest::Push::Admin do
694
717
  end
695
718
 
696
719
  it 'supports paging' do
697
- skip 'Channel lists with limits is not reliable immediately after fixture creation'
698
- # TODO: Remove this once list channels with limits is reliable immediately after fixtures created
699
- # See https://github.com/ably/realtime/issues/1882
700
720
  subject.list_channels
701
721
  page = subject.list_channels(limit: 3)
702
722
  expect(page).to be_a(Ably::Models::PaginatedResult)
@@ -730,6 +750,12 @@ describe Ably::Rest::Push::Admin do
730
750
  let(:client_id) { random_str }
731
751
  let(:device_id) { random_str }
732
752
 
753
+ before(:all) do
754
+ # As push tests often use the global scope (devices),
755
+ # we need to ensure tests cannot conflict
756
+ reload_test_app
757
+ end
758
+
733
759
  it 'saves the new client_id PushChannelSubscription Hash object' do
734
760
  subject.save(channel: channel, client_id: client_id)
735
761
 
@@ -802,6 +828,12 @@ describe Ably::Rest::Push::Admin do
802
828
 
803
829
  let(:fixture_count) { 6 }
804
830
 
831
+ before(:all) do
832
+ # As push tests often use the global scope (devices),
833
+ # we need to ensure tests cannot conflict
834
+ reload_test_app
835
+ end
836
+
805
837
  before do
806
838
  fixture_count.times.map do |index|
807
839
  [
@@ -814,8 +846,10 @@ describe Ably::Rest::Push::Admin do
814
846
  end.each(&:join) # Wait for all threads to complete
815
847
  end
816
848
 
849
+ # TODO: Reinstate once delete subscriptions by channel is possible
850
+ # See https://github.com/ably/realtime/issues/1359
817
851
  it 'removes matching channels' do
818
- skip 'Delete by channel is not yet supported'
852
+ skip 'deleting subscriptions is not yet supported realtime#1359'
819
853
  subject.remove_where channel: fixed_channel, full_wait: true
820
854
  expect(subject.list(channel: fixed_channel).items.count).to eql(0)
821
855
  expect(subject.list(client_id: client_id).items.count).to eql(0)
@@ -852,6 +886,12 @@ describe Ably::Rest::Push::Admin do
852
886
  let(:client_id) { random_str }
853
887
  let(:device_id) { random_str }
854
888
 
889
+ before(:all) do
890
+ # As push tests often use the global scope (devices),
891
+ # we need to ensure tests cannot conflict
892
+ reload_test_app
893
+ end
894
+
855
895
  before do
856
896
  [
857
897
  lambda { subject.save(channel: channel, client_id: client_id) },
@@ -69,14 +69,6 @@ shared_examples 'a client initializer' do
69
69
  expect { subject }.to raise_error(ArgumentError, /key and key_name or key_secret are mutually exclusive/)
70
70
  end
71
71
  end
72
-
73
- context 'client_id as only option' do
74
- let(:client_options) { { client_id: 'valid' } }
75
-
76
- it 'requires a valid key' do
77
- expect { subject }.to raise_error(ArgumentError, /client_id cannot be provided without a complete API key or means to authenticate/)
78
- end
79
- end
80
72
  end
81
73
 
82
74
  context 'with valid arguments' do
data/spec/spec_helper.rb CHANGED
@@ -4,7 +4,7 @@ def console(message)
4
4
  puts "\033[31m[#{Time.now.strftime('%H:%M:%S.%L')}]\033[0m \033[33m#{message}\033[0m"
5
5
  end
6
6
 
7
- unless RUBY_VERSION.match(/^1/)
7
+ unless RUBY_VERSION.match(/^1\./)
8
8
  require 'coveralls'
9
9
  Coveralls.wear!
10
10
  end
@@ -19,6 +19,7 @@ require 'support/event_emitter_helper'
19
19
  require 'support/private_api_formatter'
20
20
  require 'support/protocol_helper'
21
21
  require 'support/random_helper'
22
+ require 'support/serialization_helper'
22
23
  require 'support/test_logger_helper'
23
24
 
24
25
  require 'rspec_config'
@@ -2,6 +2,8 @@ RSpec.configure do |config|
2
2
  config.before(:example) do |example|
3
3
  next if example.metadata[:prevent_log_stubbing]
4
4
 
5
+ log_mutex = Mutex.new
6
+
5
7
  @log_output = []
6
8
  %w(fatal error warn info debug).each do |method_name|
7
9
  allow_any_instance_of(Ably::Logger).to receive(method_name.to_sym).and_wrap_original do |method, *args, &block|
@@ -10,11 +12,13 @@ RSpec.configure do |config|
10
12
 
11
13
  prefix = "#{Time.now.strftime('%H:%M:%S.%L')} [\e[33m#{method_name}\e[0m] "
12
14
 
13
- begin
14
- args << block.call unless block.nil?
15
- @log_output << "#{prefix}#{args.compact.join(' ')}"
16
- rescue StandardError => e
17
- @log_output << "#{prefix}Failed to log block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}}"
15
+ log_mutex.synchronize do
16
+ begin
17
+ args << block.call unless block.nil?
18
+ @log_output << "#{prefix}#{args.compact.join(' ')}"
19
+ rescue StandardError => e
20
+ @log_output << "#{prefix}Failed to log block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}}"
21
+ end
18
22
  end
19
23
 
20
24
  # Call original
@@ -0,0 +1,21 @@
1
+ module SerializationHelper
2
+ def serialize_body(object, protocol)
3
+ if protocol == :msgpack
4
+ MessagePack.pack(object)
5
+ else
6
+ JSON.dump(object)
7
+ end
8
+ end
9
+
10
+ def deserialize_body(object, protocol)
11
+ if protocol == :msgpack
12
+ MessagePack.unpack(object)
13
+ else
14
+ JSON.parse(object)
15
+ end
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ config.include self
20
+ end
21
+ end
@@ -4,11 +4,11 @@ class TestApp
4
4
  TEST_RESOURCES_PATH = File.expand_path('../../../lib/submodules/ably-common/test-resources', __FILE__)
5
5
 
6
6
  # App configuration for test app
7
- # See https://github.com/ably/ably-common/blob/master/test-resources/test-app-setup.json
7
+ # See https://github.com/ably/ably-common/blob/main/test-resources/test-app-setup.json
8
8
  APP_SPEC = JSON.parse(File.read(File.join(TEST_RESOURCES_PATH, 'test-app-setup.json')))['post_apps']
9
9
 
10
10
  # Cipher details used for client_encoded presence data in test app
11
- # See https://github.com/ably/ably-common/blob/master/test-resources/test-app-setup.json
11
+ # See https://github.com/ably/ably-common/blob/main/test-resources/test-app-setup.json
12
12
  APP_SPEC_CIPHER = JSON.parse(File.read(File.join(TEST_RESOURCES_PATH, 'test-app-setup.json')))['cipher']
13
13
 
14
14
  # If an app has already been created and we need a new app, create a new test app
@@ -53,7 +53,7 @@ describe Ably::Modules::Enum, :api_private do
53
53
  end
54
54
 
55
55
  it 'allows different type comparison 2' do
56
- skip 'Unless we monkeypath Symbols, the == operator is never invoked'
56
+ skip 'Unless we monkeypatch Symbols, the == operator is never invoked'
57
57
  expect([:value_zero].include?(subject.ValueZero)).to eql(true)
58
58
  end
59
59
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  require 'shared/client_initializer_behaviour'
4
4
 
5
5
  describe Ably::Realtime::Client do
6
- subject do
6
+ subject(:realtime_client) do
7
7
  Ably::Realtime::Client.new(client_options)
8
8
  end
9
9
 
@@ -13,30 +13,43 @@ describe Ably::Realtime::Client do
13
13
  let(:client_options) { { key: 'appid.keyuid:keysecret', auto_connect: false } }
14
14
 
15
15
  it 'passes on the options to the initializer' do
16
- rest_client = instance_double('Ably::Rest::Client', auth: instance_double('Ably::Auth'), options: client_options)
16
+ rest_client = instance_double('Ably::Rest::Client', auth: instance_double('Ably::Auth'), options: client_options, environment: 'production', use_tls?: true, custom_tls_port: nil)
17
17
  expect(Ably::Rest::Client).to receive(:new).with(hash_including(client_options)).and_return(rest_client)
18
- subject
18
+ realtime_client
19
19
  end
20
20
 
21
21
  context 'for attribute' do
22
22
  [:environment, :use_tls?, :log_level, :custom_host].each do |attribute|
23
23
  specify "##{attribute}" do
24
- expect(subject.rest_client).to receive(attribute)
25
- subject.public_send attribute
24
+ expect(realtime_client.rest_client).to receive(attribute)
25
+ realtime_client.public_send attribute
26
26
  end
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
+ context 'when :transport_params option is passed' do
32
+ let(:expected_transport_params) do
33
+ { 'heartbeats' => 'true', 'v' => '1.0', 'extra_param' => 'extra_param' }
34
+ end
35
+ let(:client_options) do
36
+ { key: 'appid.keyuid:keysecret', transport_params: { heartbeats: true, v: 1.0, extra_param: 'extra_param'} }
37
+ end
38
+
39
+ it 'converts options to strings' do
40
+ expect(realtime_client.transport_params).to eq(expected_transport_params)
41
+ end
42
+ end
43
+
31
44
  context 'push' do
32
45
  let(:client_options) { { key: 'appid.keyuid:keysecret' } }
33
46
 
34
47
  specify '#device is not supported and raises an exception' do
35
- expect { subject.device }.to raise_error Ably::Exceptions::PushNotificationsNotSupported
48
+ expect { realtime_client.device }.to raise_error Ably::Exceptions::PushNotificationsNotSupported
36
49
  end
37
50
 
38
51
  specify '#push returns a Push object' do
39
- expect(subject.push).to be_a(Ably::Realtime::Push)
52
+ expect(realtime_client.push).to be_a(Ably::Realtime::Push)
40
53
  end
41
54
  end
42
55