ably-rest 0.9.3 → 1.0.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/ably-rest.gemspec +2 -1
  3. data/lib/submodules/ably-ruby/.travis.yml +6 -4
  4. data/lib/submodules/ably-ruby/CHANGELOG.md +52 -61
  5. data/lib/submodules/ably-ruby/README.md +10 -0
  6. data/lib/submodules/ably-ruby/SPEC.md +1473 -852
  7. data/lib/submodules/ably-ruby/ably.gemspec +2 -1
  8. data/lib/submodules/ably-ruby/lib/ably/auth.rb +57 -25
  9. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +34 -8
  10. data/lib/submodules/ably-ruby/lib/ably/logger.rb +10 -1
  11. data/lib/submodules/ably-ruby/lib/ably/models/auth_details.rb +42 -0
  12. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +18 -4
  13. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +6 -3
  14. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +4 -3
  15. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +1 -1
  16. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +12 -1
  17. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +101 -97
  18. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +13 -1
  19. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +20 -3
  20. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +7 -3
  21. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +17 -7
  22. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +29 -14
  23. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +7 -4
  24. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -4
  25. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +7 -3
  26. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +2 -0
  27. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +79 -31
  28. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +62 -26
  29. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +154 -65
  30. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
  31. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +16 -3
  32. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
  33. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
  34. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +108 -49
  35. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +165 -59
  36. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
  37. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -10
  38. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +67 -45
  39. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +198 -36
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +30 -6
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
  42. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -3
  43. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +21 -8
  44. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -3
  45. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +2 -2
  46. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
  47. data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +1 -1
  48. data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +26 -0
  49. data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -2
  50. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +416 -99
  51. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +5 -3
  52. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +1011 -160
  53. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +2 -2
  54. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
  55. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +436 -97
  56. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +52 -23
  57. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +5 -3
  58. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1160 -105
  59. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +151 -22
  60. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +1 -1
  61. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +88 -27
  62. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +42 -15
  63. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
  64. data/lib/submodules/ably-ruby/spec/rspec_config.rb +2 -1
  65. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +2 -2
  66. data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +6 -2
  67. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +20 -4
  68. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +32 -1
  69. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +4 -11
  70. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +28 -2
  71. data/lib/submodules/ably-ruby/spec/unit/models/auth_details_spec.rb +49 -0
  72. data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +23 -3
  73. data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +12 -1
  74. data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +15 -4
  75. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +34 -2
  76. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +73 -2
  77. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +64 -6
  78. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +1 -1
  79. data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +1 -1
  80. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -1
  81. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +69 -0
  82. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +149 -22
  83. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +9 -3
  84. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
  85. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +8 -5
  86. data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
  87. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +4 -3
  88. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +1 -1
  89. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +3 -3
  90. metadata +7 -5
@@ -61,6 +61,33 @@ describe Ably::Rest::Channel, 'messages' do
61
61
  end
62
62
  end
63
63
 
64
+ context 'with supported extra payload content type (#RSL1h, #RSL6a2)' do
65
+ context 'JSON Object (Hash)' do
66
+ let(:data) { { 'push' => { 'title' => 'Testing' } } }
67
+
68
+ it 'is encoded and decoded to the same hash' do
69
+ channel.publish 'event', {}, extras: data
70
+ expect(channel.history.items.first.extras).to eql(data)
71
+ end
72
+ end
73
+
74
+ context 'JSON Array' do
75
+ let(:data) { { 'push' => [ nil, true, false, 55, 'string', { 'Hash' => true }, ['array'] ] } }
76
+
77
+ it 'is encoded and decoded to the same Array' do
78
+ channel.publish 'event', {}, extras: data
79
+ expect(channel.history.items.first.extras).to eql(data)
80
+ end
81
+ end
82
+
83
+ context 'nil' do
84
+ it 'is encoded and decoded to the same Array' do
85
+ channel.publish 'event', {}, extras: nil
86
+ expect(channel.history.items.first.extras).to be_nil
87
+ end
88
+ end
89
+ end
90
+
64
91
  context 'with unsupported data payload content type' do
65
92
  context 'Integer' do
66
93
  let(:data) { 1 }
@@ -134,7 +161,7 @@ describe Ably::Rest::Channel, 'messages' do
134
161
  end
135
162
  end
136
163
 
137
- it 'encrypts message automatically when published' do
164
+ it 'encrypts message automatically when published (#RTL7d)' do
138
165
  expect(client).to receive(:post) do |path, message|
139
166
  if protocol == :json
140
167
  expect(message['encoding']).to eql(encrypted_encoding)
@@ -149,7 +176,7 @@ describe Ably::Rest::Channel, 'messages' do
149
176
  encrypted_channel.publish 'example', encoded_data_decoded
150
177
  end
151
178
 
152
- it 'sends and retrieves messages that are encrypted & decrypted by the Ably library' do
179
+ it 'sends and retrieves messages that are encrypted & decrypted by the Ably library (#RTL7d)' do
153
180
  encrypted_channel.publish 'example', encoded_data_decoded
154
181
 
155
182
  message = encrypted_channel.history.items.first
@@ -168,12 +195,12 @@ describe Ably::Rest::Channel, 'messages' do
168
195
  end
169
196
  end
170
197
 
171
- context 'with AES-128-CBC using crypto-data-128.json fixtures' do
198
+ context 'with AES-128-CBC using crypto-data-128.json fixtures (#RTL7d)' do
172
199
  data = JSON.parse(File.read(File.join(resources_root, 'crypto-data-128.json')))
173
200
  add_tests_for_data data
174
201
  end
175
202
 
176
- context 'with AES-256-CBC using crypto-data-256.json fixtures' do
203
+ context 'with AES-256-CBC using crypto-data-256.json fixtures (#RTL7d)' do
177
204
  data = JSON.parse(File.read(File.join(resources_root, 'crypto-data-256.json')))
178
205
  add_tests_for_data data
179
206
  end
@@ -246,21 +273,21 @@ describe Ably::Rest::Channel, 'messages' do
246
273
  encrypted_channel.publish 'example', payload
247
274
  end
248
275
 
249
- it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
276
+ it 'retrieves the message that remains encrypted with an encrypted encoding attribute (#RTL7e)' do
250
277
  message = other_client_unencrypted_channel.history.items.first
251
278
  expect(message.data).to_not eql(payload)
252
279
  expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
253
280
  end
254
281
 
255
- it 'logs a Cipher exception' do
256
- expect(other_client.logger).to receive(:error) do |message|
257
- expect(message).to match(/Message cannot be decrypted/)
282
+ it 'logs a Cipher exception (#RTL7e)' do
283
+ expect(other_client.logger).to receive(:error) do |*args, &block|
284
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/Message cannot be decrypted/)
258
285
  end
259
286
  other_client_unencrypted_channel.history
260
287
  end
261
288
  end
262
289
 
263
- context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client' do
290
+ context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client (#RTL7e)' do
264
291
  let(:client_options) { default_client_options.merge(log_level: :fatal) }
265
292
  let(:cipher_options_client1) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
266
293
  let(:encrypted_channel_client1) { client.channel(channel_name, cipher: cipher_options_client1) }
@@ -273,15 +300,15 @@ describe Ably::Rest::Channel, 'messages' do
273
300
  encrypted_channel_client1.publish 'example', payload
274
301
  end
275
302
 
276
- it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
303
+ it 'retrieves the message that remains encrypted with an encrypted encoding attribute (#RTL7e)' do
277
304
  message = encrypted_channel_client2.history.items.first
278
305
  expect(message.data).to_not eql(payload)
279
306
  expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
280
307
  end
281
308
 
282
- it 'logs a Cipher exception' do
283
- expect(other_client.logger).to receive(:error) do |message|
284
- expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
309
+ it 'logs a Cipher exception (#RTL7e)' do
310
+ expect(other_client.logger).to receive(:error) do |*args, &block|
311
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/Cipher algorithm [\w-]+ does not match/)
285
312
  end
286
313
  encrypted_channel_client2.history
287
314
  end
@@ -307,8 +334,8 @@ describe Ably::Rest::Channel, 'messages' do
307
334
  end
308
335
 
309
336
  it 'logs a Cipher exception' do
310
- expect(other_client.logger).to receive(:error) do |message|
311
- expect(message).to match(/CipherError decrypting data/)
337
+ expect(other_client.logger).to receive(:error) do |*args, &block|
338
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/CipherError decrypting data/)
312
339
  end
313
340
  encrypted_channel_client2.history
314
341
  end
@@ -399,8 +399,8 @@ describe Ably::Rest::Presence do
399
399
  end
400
400
 
401
401
  it 'logs a cipher error' do
402
- expect(client.logger).to receive(:error) do |message|
403
- expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
402
+ expect(client.logger).to receive(:error) do |*args, &block|
403
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/Cipher algorithm [\w-]+ does not match/)
404
404
  end
405
405
  presence.get
406
406
  end
@@ -423,8 +423,8 @@ describe Ably::Rest::Presence do
423
423
  end
424
424
 
425
425
  it 'logs a cipher error' do
426
- expect(client.logger).to receive(:error) do |message|
427
- expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
426
+ expect(client.logger).to receive(:error) do |*args, &block|
427
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/Cipher algorithm [\w-]+ does not match/)
428
428
  end
429
429
  presence.history
430
430
  end
@@ -41,7 +41,7 @@ RSpec.configure do |config|
41
41
  end
42
42
 
43
43
  if defined?(EventMachine)
44
- config.before(:example) do
44
+ config.before(:example, :event_machine) do
45
45
  # Ensure EventMachine shutdown hooks are deregistered for every test
46
46
  EventMachine.instance_variable_set '@tails', []
47
47
  end
@@ -52,6 +52,7 @@ RSpec.configure do |config|
52
52
  if ENV['RSPEC_RETRY']
53
53
  puts 'Running tests using RSpec retry'
54
54
  config.verbose_retry = true # show retry status in spec process
55
+ config.display_try_failure_messages = true # show exception that triggered the try
55
56
  config.default_retry_count = 3
56
57
  config.default_sleep_interval = 2
57
58
  end
@@ -154,9 +154,9 @@ shared_examples 'a client initializer' do
154
154
  end
155
155
 
156
156
  context 'with token_params' do
157
- let(:client_options) { { token_params: { ttl: 777, client_id: 'john' }, token: 'token', auto_connect: false } }
157
+ let(:client_options) { { default_token_params: { ttl: 777, client_id: 'john' }, token: 'token', auto_connect: false } }
158
158
 
159
- it 'configures the default token_params' do
159
+ it 'configures default_token_params' do
160
160
  expect(subject.auth.token_params.fetch(:ttl)).to eql(777)
161
161
  expect(subject.auth.token_params.fetch(:client_id)).to eql('john')
162
162
  end
@@ -20,7 +20,9 @@ shared_examples 'a safe Deferrable' do
20
20
  end
21
21
 
22
22
  it 'catches exceptions in the callback and logs the error to the logger' do
23
- expect(subject.send(:logger)).to receive(:error).with(/#{exception.message}/)
23
+ expect(subject.send(:logger)).to receive(:error) do |*args, &block|
24
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/#{exception.message}/)
25
+ end
24
26
  subject.errback do
25
27
  raise exception
26
28
  end
@@ -49,7 +51,9 @@ shared_examples 'a safe Deferrable' do
49
51
  end
50
52
 
51
53
  it 'catches exceptions in the callback and logs the error to the logger' do
52
- expect(subject.send(:logger)).to receive(:error).with(/#{exception.message}/)
54
+ expect(subject.send(:logger)).to receive(:error) do |*args, &block|
55
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/#{exception.message}/)
56
+ end
53
57
  subject.callback do
54
58
  raise exception
55
59
  end
@@ -1,15 +1,31 @@
1
1
  RSpec.configure do |config|
2
- config.before(:example) do
2
+ config.before(:example) do |example|
3
+ next if example.metadata[:prevent_log_stubbing]
4
+
3
5
  @log_output = []
4
6
  %w(fatal error warn info debug).each do |method_name|
5
- allow_any_instance_of(Ably::Logger).to receive(method_name.to_sym).and_wrap_original do |method, *args|
6
- @log_output << "#{Time.now.strftime('%H:%M:%S.%L')} [\e[33m#{method_name}\e[0m] #{args[0]}"
7
- method.call(*args)
7
+ allow_any_instance_of(Ably::Logger).to receive(method_name.to_sym).and_wrap_original do |method, *args, &block|
8
+ # Don't log shutdown sequence to keep log noise to a minimum
9
+ next if RSpec.const_defined?(:EventMachine) && RSpec::EventMachine.reactor_stopping?
10
+
11
+ prefix = "#{Time.now.strftime('%H:%M:%S.%L')} [\e[33m#{method_name}\e[0m] "
12
+
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")}}"
18
+ end
19
+
20
+ # Call original
21
+ method.call(*args, &block)
8
22
  end
9
23
  end
10
24
  end
11
25
 
12
26
  config.after(:example) do |example|
27
+ next if example.metadata[:prevent_log_stubbing]
28
+
13
29
  exception = example.exception
14
30
  puts "\n#{'-'*34}\n\e[36mVerbose Ably log from test failure\e[0m\n#{'-'*34}\n#{@log_output.join("\n")}\n\n" if exception
15
31
  end
@@ -9,6 +9,8 @@ module RSpec
9
9
  DEFAULT_TIMEOUT = 15
10
10
 
11
11
  def run_reactor(timeout = DEFAULT_TIMEOUT)
12
+ @reactor_stopping = false
13
+
12
14
  Timeout::timeout(timeout + 0.5) do
13
15
  ::EventMachine.run do
14
16
  yield
@@ -16,7 +18,13 @@ module RSpec
16
18
  end
17
19
  end
18
20
 
21
+ def reactor_stopping?
22
+ @reactor_stopping
23
+ end
24
+
19
25
  def stop_reactor
26
+ mark_reactor_stopping
27
+
20
28
  unless realtime_clients.empty?
21
29
  realtime_clients.shift.tap do |client|
22
30
  # Ensure close appens outside of the caller as this can cause errbacks on Deferrables
@@ -45,6 +53,10 @@ module RSpec
45
53
  @realtime_clients ||= []
46
54
  end
47
55
 
56
+ def mark_reactor_stopping
57
+ @reactor_stopping = true
58
+ end
59
+
48
60
  # Allows multiple Deferrables to be passed in and calls the provided block when
49
61
  # all success callbacks have completed
50
62
  def when_all(*deferrables)
@@ -123,8 +135,27 @@ RSpec.configure do |config|
123
135
  example.run
124
136
  end
125
137
 
126
- config.before(:example) do
138
+ config.before(:example, :event_machine) do
127
139
  # Ensure EventMachine shutdown hooks are deregistered for every test
128
140
  EventMachine.instance_variable_set '@tails', []
129
141
  end
130
142
  end
143
+
144
+ module RSpec
145
+ module Expectations
146
+ module ExpectationHelper
147
+ class << self
148
+ # This is very hacky and ties into the internals of RSpec which is likely to break in future versions
149
+ # However, this is just a convenience to reduce log noise when the reactor is stopping
150
+ # i.e. debug_failure_helper logs the verbose messages generated by the libraries, however it also often
151
+ # catches all the shutdown messages which is unnecessary
152
+ alias_method :orig_handle_failure, :handle_failure
153
+
154
+ def handle_failure(*args, &block)
155
+ RSpec::EventMachine.mark_reactor_stopping
156
+ orig_handle_failure(*args, &block)
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -68,19 +68,12 @@ describe Ably::Auth do
68
68
  end
69
69
 
70
70
  context 'defaults' do
71
- let(:one_hour) { 60 * 60 }
72
- let(:all_capabilities) { { "*" => ["*"] } }
73
-
74
- it 'should default TTL to 1 hour' do
75
- expect(Ably::Auth::TOKEN_DEFAULTS.fetch(:ttl)).to eql(one_hour)
76
- end
77
-
78
- it 'should default capability to all' do
79
- expect(Ably::Auth::TOKEN_DEFAULTS.fetch(:capability)).to eql(all_capabilities)
71
+ it 'should have no default TTL' do
72
+ expect(Ably::Auth::TOKEN_DEFAULTS[:ttl]).to be_nil
80
73
  end
81
74
 
82
- it 'should have defaults for :ttl and :capability' do
83
- expect(Ably::Auth::TOKEN_DEFAULTS.keys).to include(:ttl, :capability)
75
+ it 'should have no default capability' do
76
+ expect(Ably::Auth::TOKEN_DEFAULTS[:capability]).to be_nil
84
77
  end
85
78
  end
86
79
  end
@@ -18,7 +18,9 @@ describe Ably::Logger do
18
18
 
19
19
  context 'internals', :api_private do
20
20
  it 'delegates to the logger object' do
21
- expect(subject.logger).to receive(:warn).with('message')
21
+ expect(subject.logger).to receive(:warn) do |*args, &block|
22
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/message/)
23
+ end
22
24
  subject.warn 'message'
23
25
  end
24
26
 
@@ -138,9 +140,33 @@ describe Ably::Logger do
138
140
  end
139
141
 
140
142
  it 'delegates log messages to logger', :api_private do
141
- expect(custom_logger_object).to receive(:fatal).with('message')
143
+ expect(custom_logger_object).to receive(:fatal) do |*args, &block|
144
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/message/)
145
+ end
142
146
  subject.fatal 'message'
143
147
  end
144
148
  end
145
149
  end
150
+
151
+ context 'with blocks', :prevent_log_stubbing do
152
+ it 'does not call the block unless the log level is met' do
153
+ log_level_blocks = []
154
+ subject.warn { log_level_blocks << :warn }
155
+ subject.info { log_level_blocks << :info }
156
+ subject.debug { log_level_blocks << :debug }
157
+ expect(log_level_blocks).to contain_exactly(:warn, :info)
158
+ end
159
+
160
+ context 'with an exception in the logger block' do
161
+ before do
162
+ expect(subject.logger).to receive(:error) do |*args, &block|
163
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/Raise an error in the block/)
164
+ end
165
+ end
166
+
167
+ it 'catches the error and continues' do
168
+ subject.info { raise "Raise an error in the block" }
169
+ end
170
+ end
171
+ end
146
172
  end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'shared/model_behaviour'
3
+
4
+ describe Ably::Models::AuthDetails do
5
+ include Ably::Modules::Conversions
6
+
7
+ subject { Ably::Models::AuthDetails }
8
+
9
+ # Spec model items AD2*
10
+ it_behaves_like 'a model', with_simple_attributes: %w(access_token) do
11
+ let(:model_args) { [] }
12
+ end
13
+
14
+ context '==' do
15
+ let(:attributes) { { access_token: 'unique' } }
16
+
17
+ it 'is true when attributes are the same' do
18
+ auth_details = -> { Ably::Models::AuthDetails.new(attributes) }
19
+ expect(auth_details.call).to eq(auth_details.call)
20
+ end
21
+
22
+ it 'is false when attributes are not the same' do
23
+ expect(Ably::Models::AuthDetails.new(access_token: '1')).to_not eq(Ably::Models::AuthDetails.new(access_token: '2'))
24
+ end
25
+
26
+ it 'is false when class type differs' do
27
+ expect(Ably::Models::AuthDetails.new(access_token: '1')).to_not eq(nil)
28
+ end
29
+ end
30
+
31
+ context 'AuthDetails conversion methods', :api_private do
32
+ context 'with a AuthDetails object' do
33
+ let(:details) { Ably::Models::AuthDetails.new(access_token: random_str) }
34
+
35
+ it 'returns the AuthDetails object' do
36
+ expect(Ably::Models::AuthDetails(details)).to eql(details)
37
+ end
38
+ end
39
+
40
+ context 'with a JSON object' do
41
+ let(:access_token) { random_str }
42
+ let(:details_json) { { access_token: access_token } }
43
+
44
+ it 'returns a new AuthDetails object from the JSON' do
45
+ expect(Ably::Models::AuthDetails(details_json).access_token).to eql(access_token)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,7 +6,7 @@ describe Ably::Models::ChannelStateChange do
6
6
 
7
7
  subject { Ably::Models::ChannelStateChange }
8
8
 
9
- context '#current' do
9
+ context '#current (#TH1)' do
10
10
  it 'is required' do
11
11
  expect { subject.new(previous: true) }.to raise_error ArgumentError
12
12
  end
@@ -16,7 +16,7 @@ describe Ably::Models::ChannelStateChange do
16
16
  end
17
17
  end
18
18
 
19
- context '#previous' do
19
+ context '#previous (#TH2)' do
20
20
  it 'is required' do
21
21
  expect { subject.new(current: true) }.to raise_error ArgumentError
22
22
  end
@@ -26,7 +26,17 @@ describe Ably::Models::ChannelStateChange do
26
26
  end
27
27
  end
28
28
 
29
- context '#reason' do
29
+ context '#event (#TH5)' do
30
+ it 'is not required' do
31
+ expect { subject.new(previous: true, current: true) }.to_not raise_error
32
+ end
33
+
34
+ it 'is an attribute' do
35
+ expect(subject.new(event: unique, previous: unique, current: true).event).to eql(unique)
36
+ end
37
+ end
38
+
39
+ context '#reason (#TH3)' do
30
40
  it 'is not required' do
31
41
  expect { subject.new(previous: true, current: true) }.to_not raise_error
32
42
  end
@@ -36,6 +46,16 @@ describe Ably::Models::ChannelStateChange do
36
46
  end
37
47
  end
38
48
 
49
+ context '#resumed (#TH4)' do
50
+ it 'is false when ommitted' do
51
+ expect(subject.new(previous: true, current: true).resumed).to be_falsey
52
+ end
53
+
54
+ it 'is true when provided' do
55
+ expect(subject.new(previous: true, current: true, resumed: true).resumed).to be_truthy
56
+ end
57
+ end
58
+
39
59
  context 'invalid attributes' do
40
60
  it 'raises an argument error' do
41
61
  expect { subject.new(invalid: true, current: true, previous: true) }.to raise_error ArgumentError