ably 1.1.0 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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