ably-rest 0.8.6 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/SPEC.md +1049 -1001
  3. data/lib/submodules/ably-ruby/CHANGELOG.md +75 -3
  4. data/lib/submodules/ably-ruby/LICENSE +2 -2
  5. data/lib/submodules/ably-ruby/README.md +81 -20
  6. data/lib/submodules/ably-ruby/SPEC.md +1209 -693
  7. data/lib/submodules/ably-ruby/ably.gemspec +4 -4
  8. data/lib/submodules/ably-ruby/lib/ably/auth.rb +13 -4
  9. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +10 -1
  10. data/lib/submodules/ably-ruby/lib/ably/logger.rb +3 -1
  11. data/lib/submodules/ably-ruby/lib/ably/models/cipher_params.rb +114 -0
  12. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +10 -7
  13. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +3 -3
  14. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +28 -21
  15. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +19 -17
  16. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +10 -9
  17. data/lib/submodules/ably-ruby/lib/ably/models/paginated_result.rb +27 -1
  18. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +20 -18
  19. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +26 -19
  20. data/lib/submodules/ably-ruby/lib/ably/models/{stat.rb → stats.rb} +21 -19
  21. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +14 -12
  22. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +16 -14
  23. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +2 -2
  24. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +11 -1
  25. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +10 -10
  26. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +18 -2
  27. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +3 -3
  28. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +13 -5
  29. data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +1 -1
  30. data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +2 -2
  31. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +8 -8
  32. data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +2 -2
  33. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +4 -2
  34. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
  35. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +6 -2
  36. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +7 -6
  37. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +7 -1
  38. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +7 -12
  39. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +9 -2
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +7 -1
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +19 -8
  42. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +16 -9
  43. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +12 -3
  44. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +35 -64
  45. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +23 -9
  46. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +9 -10
  47. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +1 -1
  48. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +16 -4
  49. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +7 -5
  50. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +50 -40
  51. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  52. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +4 -4
  53. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +2 -4
  54. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +46 -8
  55. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +20 -20
  56. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +7 -7
  57. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +114 -111
  58. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +9 -9
  59. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +5 -5
  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 +1 -1
  62. data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +4 -4
  63. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +15 -15
  64. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
  65. data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +7 -7
  66. data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +4 -4
  67. data/lib/submodules/ably-ruby/spec/unit/models/cipher_params_spec.rb +140 -0
  68. data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +15 -8
  69. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +28 -22
  70. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +24 -0
  71. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +3 -3
  72. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +20 -18
  73. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +2 -2
  74. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +6 -6
  75. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +4 -4
  76. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +1 -1
  77. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +5 -5
  78. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +50 -17
  79. metadata +5 -3
@@ -18,7 +18,7 @@ describe Ably::Auth do
18
18
  :client_id,
19
19
  :timestamp,
20
20
  :nonce
21
- ].map { |key| "#{token_request.hash[key]}\n" }.join("")
21
+ ].map { |key| "#{token_request.attributes[key]}\n" }.join("")
22
22
 
23
23
  encode64(
24
24
  OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, secret, text)
@@ -689,12 +689,12 @@ describe Ably::Auth do
689
689
  stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0
690
690
  old_token_defaults = Ably::Auth::TOKEN_DEFAULTS
691
691
  stub_const 'Ably::Auth::TOKEN_DEFAULTS', old_token_defaults.merge(renew_token_buffer: 0)
692
+ @block_called = 0
692
693
  end
693
694
 
694
695
  let(:token_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, token_params: { ttl: 3 })) }
695
696
  let(:client_options) {
696
697
  default_options.merge(token: token_client.auth.request_token.token, auth_callback: Proc.new do
697
- @block_called ||= 0
698
698
  @block_called += 1
699
699
  token_client.auth.create_token_request
700
700
  end)
@@ -702,7 +702,7 @@ describe Ably::Auth do
702
702
 
703
703
  it 'calls the Proc once the token has expired and the new token is used' do
704
704
  client.stats
705
- expect(@block_called).to be_nil
705
+ expect(@block_called).to eql(0)
706
706
  sleep 3.5
707
707
  expect { client.stats }.to change { client.auth.current_token_details }
708
708
  expect(@block_called).to eql(1)
@@ -824,9 +824,9 @@ describe Ably::Auth do
824
824
  context 'with additional invalid attributes' do
825
825
  let(:token_params) { { nonce: 'valid', is_not_used_by_token_request: 'invalid' } }
826
826
  specify 'are ignored' do
827
- expect(subject.hash.keys).to_not include(:is_not_used_by_token_request)
828
- expect(subject.hash.keys).to_not include(convert_to_mixed_case(:is_not_used_by_token_request))
829
- expect(subject.hash.keys).to include(:nonce)
827
+ expect(subject.attributes.keys).to_not include(:is_not_used_by_token_request)
828
+ expect(subject.attributes.keys).to_not include(convert_to_mixed_case(:is_not_used_by_token_request))
829
+ expect(subject.attributes.keys).to include(:nonce)
830
830
  expect(subject.nonce).to eql('valid')
831
831
  end
832
832
  end
@@ -890,7 +890,7 @@ describe Ably::Auth do
890
890
  end
891
891
 
892
892
  it 'generates a valid HMAC' do
893
- hmac = hmac_for(Ably::Models::TokenRequest(token_request_attributes).hash, key_secret)
893
+ hmac = hmac_for(Ably::Models::TokenRequest(token_request_attributes).attributes, key_secret)
894
894
  expect(subject['mac']).to eql(hmac)
895
895
  end
896
896
  end
@@ -918,7 +918,7 @@ describe Ably::Auth do
918
918
 
919
919
  it 'disallows publishing on unspecified capability channels' do
920
920
  expect { token_auth_client.channel('bar').publish('event', 'data') }.to raise_error do |error|
921
- expect(error).to be_a(Ably::Exceptions::InvalidRequest)
921
+ expect(error).to be_a(Ably::Exceptions::UnauthorizedRequest)
922
922
  expect(error.status).to eql(401)
923
923
  expect(error.code).to eql(40160)
924
924
  end
@@ -926,7 +926,7 @@ describe Ably::Auth do
926
926
 
927
927
  it 'fails if timestamp is invalid' do
928
928
  expect { auth.request_token(timestamp: Time.now - 180) }.to raise_error do |error|
929
- expect(error).to be_a(Ably::Exceptions::InvalidRequest)
929
+ expect(error).to be_a(Ably::Exceptions::UnauthorizedRequest)
930
930
  expect(error.status).to eql(401)
931
931
  expect(error.code).to eql(40101)
932
932
  end
@@ -75,10 +75,10 @@ describe Ably::Rest do
75
75
  it 'should raise an InvalidRequest exception with a valid error message and code' do
76
76
  invalid_client = Ably::Rest::Client.new(key: 'appid.keyuid:keysecret', environment: environment)
77
77
  expect { invalid_client.channel('test').publish('foo', 'choo') }.to raise_error do |error|
78
- expect(error).to be_a(Ably::Exceptions::InvalidRequest)
79
- expect(error.message).to match(/invalid credentials/)
80
- expect(error.code).to eql(40100)
81
- expect(error.status).to eql(401)
78
+ expect(error).to be_a(Ably::Exceptions::ResourceMissing)
79
+ expect(error.message).to match(/No application found/)
80
+ expect(error.code).to eql(40400)
81
+ expect(error.status).to eql(404)
82
82
  end
83
83
  end
84
84
  end
@@ -130,7 +130,7 @@ describe Ably::Rest do
130
130
  if [1, 3].include?(@publish_attempts)
131
131
  { status: 201, :body => '[]', :headers => { 'Content-Type' => 'application/json' } }
132
132
  else
133
- raise Ably::Exceptions::TokenExpired.new('Authentication failure', 401, 40140)
133
+ raise Ably::Exceptions::TokenExpired.new('Authentication failure', 401, 40142)
134
134
  end
135
135
  end
136
136
  end
@@ -87,7 +87,7 @@ describe Ably::Rest::Channel do
87
87
  let(:client_options) { default_options.merge(use_token_auth: true, token_params: { capability: capability }) }
88
88
 
89
89
  it 'raises a permission error when publishing' do
90
- expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::InvalidRequest, /not permitted/)
90
+ expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::UnauthorizedRequest, /not permitted/)
91
91
  end
92
92
  end
93
93
 
@@ -382,7 +382,7 @@ describe Ably::Rest::Client do
382
382
  end
383
383
 
384
384
  it 'does not attempt the fallback hosts as this is an authentication failure' do
385
- expect { publish_block.call }.to raise_error(Ably::Exceptions::InvalidRequest)
385
+ expect { publish_block.call }.to raise_error(Ably::Exceptions::UnauthorizedRequest)
386
386
  expect(default_host_request_stub).to have_been_requested
387
387
  expect(first_fallback_request_stub).to_not have_been_requested
388
388
  expect(second_fallback_request_stub).to_not have_been_requested
@@ -9,12 +9,12 @@ describe Ably::Models::MessageEncoders do
9
9
  let(:channel) { client.channel('test', channel_options) }
10
10
  let(:response) { instance_double('Faraday::Response', status: 201) }
11
11
 
12
- let(:cipher_params) { { key: random_str, algorithm: 'aes', mode: 'cbc', key_length: 128 } }
12
+ let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
13
13
  let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
14
14
 
15
15
  let(:utf_8_data) { random_str.encode(Encoding::UTF_8) }
16
16
  let(:binary_data) { MessagePack.pack(random_str).encode(Encoding::ASCII_8BIT) }
17
- let(:json_data) { { 'key' => random_str } }
17
+ let(:json_data) { { 'some_id' => random_str } }
18
18
 
19
19
  after do
20
20
  channel.publish 'event', published_data
@@ -70,7 +70,7 @@ describe Ably::Models::MessageEncoders do
70
70
  end
71
71
 
72
72
  context 'with encryption' do
73
- let(:channel_options) { { encrypted: true, cipher_params: cipher_params } }
73
+ let(:channel_options) { { cipher: cipher_params } }
74
74
 
75
75
  context 'with UTF-8 data' do
76
76
  let(:published_data) { utf_8_data }
@@ -146,7 +146,7 @@ describe Ably::Models::MessageEncoders do
146
146
  end
147
147
 
148
148
  context 'with encryption' do
149
- let(:channel_options) { { encrypted: true, cipher_params: cipher_params } }
149
+ let(:channel_options) { { cipher: cipher_params } }
150
150
 
151
151
  context 'with UTF-8 data' do
152
152
  let(:published_data) { utf_8_data }
@@ -97,8 +97,8 @@ describe Ably::Rest::Channel, 'messages' do
97
97
 
98
98
  describe 'encryption and encoding' do
99
99
  let(:channel_name) { "persisted:#{random_str}" }
100
- let(:cipher_options) { { key: random_str(32) } }
101
- let(:encrypted_channel) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
100
+ let(:encrypted_channel) { client.channel(channel_name, cipher: cipher_options) }
101
+ let(:cipher_options) { { key: Ably::Util::Crypto.generate_random_key } }
102
102
 
103
103
  context 'with #publish and #history' do
104
104
  shared_examples 'an Ably encrypter and decrypter' do |item, data|
@@ -108,7 +108,7 @@ describe Ably::Rest::Channel, 'messages' do
108
108
  let(:secret_key) { Base64.decode64(data['key']) }
109
109
  let(:iv) { Base64.decode64(data['iv']) }
110
110
 
111
- let(:cipher_options) { { key: secret_key, iv: iv, algorithm: algorithm, mode: mode, key_length: key_length } }
111
+ let(:cipher_options) { { key: secret_key, fixed_iv: iv, algorithm: algorithm, mode: mode, key_length: key_length } }
112
112
 
113
113
  let(:encoded) { item['encoded'] }
114
114
  let(:encoded_data) { encoded['data'] }
@@ -200,7 +200,7 @@ describe Ably::Rest::Channel, 'messages' do
200
200
  context 'when retrieving #history with a different protocol' do
201
201
  let(:other_protocol) { protocol == :msgpack ? :json : :msgpack }
202
202
  let(:other_client) { Ably::Rest::Client.new(default_client_options.merge(protocol: other_protocol)) }
203
- let(:other_client_channel) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
203
+ let(:other_client_channel) { other_client.channel(channel_name, cipher: cipher_options) }
204
204
 
205
205
  before do
206
206
  expect(other_client.protocol_binary?).to_not eql(client.protocol_binary?)
@@ -221,7 +221,7 @@ describe Ably::Rest::Channel, 'messages' do
221
221
 
222
222
  context 'when publishing on an unencrypted channel and retrieving with #history on an encrypted channel' do
223
223
  let(:unencrypted_channel) { client.channel(channel_name) }
224
- let(:other_client_encrypted_channel) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
224
+ let(:other_client_encrypted_channel) { other_client.channel(channel_name, cipher: cipher_options) }
225
225
 
226
226
  let(:payload) { MessagePack.pack({ 'key' => random_str }) }
227
227
 
@@ -236,8 +236,8 @@ describe Ably::Rest::Channel, 'messages' do
236
236
 
237
237
  context 'when publishing on an encrypted channel and retrieving with #history on an unencrypted channel' do
238
238
  let(:client_options) { default_client_options.merge(log_level: :fatal) }
239
- let(:cipher_options) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
240
- let(:encrypted_channel) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
239
+ let(:cipher_options) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
240
+ let(:encrypted_channel) { client.channel(channel_name, cipher: cipher_options) }
241
241
  let(:other_client_unencrypted_channel) { other_client.channel(channel_name) }
242
242
 
243
243
  let(:payload) { MessagePack.pack({ 'key' => random_str }) }
@@ -262,10 +262,10 @@ describe Ably::Rest::Channel, 'messages' do
262
262
 
263
263
  context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client' do
264
264
  let(:client_options) { default_client_options.merge(log_level: :fatal) }
265
- let(:cipher_options_client1) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
266
- let(:encrypted_channel_client1) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client1) }
267
- let(:cipher_options_client2) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
268
- let(:encrypted_channel_client2) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client2) }
265
+ let(:cipher_options_client1) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
266
+ let(:encrypted_channel_client1) { client.channel(channel_name, cipher: cipher_options_client1) }
267
+ let(:cipher_options_client2) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
268
+ let(:encrypted_channel_client2) { other_client.channel(channel_name, cipher: cipher_options_client2) }
269
269
 
270
270
  let(:payload) { MessagePack.pack({ 'key' => random_str }) }
271
271
 
@@ -289,10 +289,10 @@ describe Ably::Rest::Channel, 'messages' do
289
289
 
290
290
  context 'publishing on an encrypted channel and subscribing with a different key on another client' do
291
291
  let(:client_options) { default_client_options.merge(log_level: :fatal) }
292
- let(:cipher_options_client1) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
293
- let(:encrypted_channel_client1) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client1) }
294
- let(:cipher_options_client2) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
295
- let(:encrypted_channel_client2) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client2) }
292
+ let(:cipher_options_client1) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
293
+ let(:encrypted_channel_client1) { client.channel(channel_name, cipher: cipher_options_client1) }
294
+ let(:cipher_options_client2) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
295
+ let(:encrypted_channel_client2) { other_client.channel(channel_name, cipher: cipher_options_client2) }
296
296
 
297
297
  let(:payload) { MessagePack.pack({ 'key' => random_str }) }
298
298
 
@@ -26,8 +26,8 @@ describe Ably::Rest::Presence do
26
26
  let(:secret_key) { Base64.decode64(cipher_details.fetch('key')) }
27
27
  let(:iv) { Base64.decode64(cipher_details.fetch('iv')) }
28
28
 
29
- let(:cipher_options) { { key: secret_key, algorithm: algorithm, mode: mode, key_length: key_length, iv: iv } }
30
- let(:fixtures_channel) { client.channel('persisted:presence_fixtures', encrypted: true, cipher_params: cipher_options, iv: iv) }
29
+ let(:cipher_options) { { key: secret_key, algorithm: algorithm, mode: mode, key_length: key_length, fixed_iv: iv } }
30
+ let(:fixtures_channel) { client.channel('persisted:presence_fixtures', cipher: cipher_options, fixed_iv: iv) }
31
31
 
32
32
  context 'tested against presence fixture data set up in test app' do
33
33
  before(:context) do
@@ -321,8 +321,8 @@ describe Ably::Rest::Presence do
321
321
 
322
322
  let(:data) { random_str(32) }
323
323
  let(:channel_name) { "persisted:#{random_str(4)}" }
324
- let(:cipher_options) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
325
- let(:presence) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options).presence }
324
+ let(:cipher_options) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
325
+ let(:presence) { client.channel(channel_name, cipher: cipher_options).presence }
326
326
 
327
327
  let(:crypto) { Ably::Util::Crypto.new(cipher_options) }
328
328
 
@@ -18,18 +18,18 @@ shared_examples 'a model' do |shared_options = {}|
18
18
  end
19
19
  end
20
20
 
21
- context '#hash', :api_private do
21
+ context '#attributes', :api_private do
22
22
  let(:model_options) { { action: 5 } }
23
23
 
24
- it 'provides access to #hash' do
25
- expect(model.hash).to eq(model_options)
24
+ it 'provides access to #attributes' do
25
+ expect(model.attributes).to eq(model_options)
26
26
  end
27
27
  end
28
28
 
29
29
  context '#[]', :api_private do
30
30
  let(:model_options) { { unusual: 'attribute' } }
31
31
 
32
- it 'provides accessor method to #hash' do
32
+ it 'provides accessor method to #attributes' do
33
33
  expect(model[:unusual]).to eql('attribute')
34
34
  end
35
35
  end
@@ -74,13 +74,13 @@ shared_examples 'a model' do |shared_options = {}|
74
74
  let(:model_options) { { channel: 'name' } }
75
75
 
76
76
  it 'prevents changes' do
77
- expect { model.hash[:channel] = 'new' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
77
+ expect { model.attributes[:channel] = 'new' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
78
78
  end
79
79
 
80
80
  it 'dups options' do
81
- expect(model.hash[:channel]).to eql('name')
81
+ expect(model.attributes[:channel]).to eql('name')
82
82
  model_options[:channel] = 'new'
83
- expect(model.hash[:channel]).to eql('name')
83
+ expect(model.attributes[:channel]).to eql('name')
84
84
  end
85
85
  end
86
86
  end
@@ -16,7 +16,7 @@ shared_examples 'a safe Deferrable' do
16
16
  subject.errback do |*args|
17
17
  expect(args).to eql(arguments)
18
18
  end
19
- subject.fail *arguments
19
+ subject.fail(*arguments)
20
20
  end
21
21
 
22
22
  it 'catches exceptions in the callback and logs the error to the logger' do
@@ -34,7 +34,7 @@ shared_examples 'a safe Deferrable' do
34
34
  subject.errback { errback_calls << true }
35
35
  subject.callback { success_calls << true }
36
36
  end
37
- subject.fail *arguments
37
+ subject.fail(*arguments)
38
38
  expect(errback_calls.count).to eql(3)
39
39
  expect(success_calls.count).to eql(0)
40
40
  end
@@ -45,7 +45,7 @@ shared_examples 'a safe Deferrable' do
45
45
  subject.callback do |*args|
46
46
  expect(args).to eql(arguments)
47
47
  end
48
- subject.succeed *arguments
48
+ subject.succeed(*arguments)
49
49
  end
50
50
 
51
51
  it 'catches exceptions in the callback and logs the error to the logger' do
@@ -63,7 +63,7 @@ shared_examples 'a safe Deferrable' do
63
63
  subject.errback { errback_calls << true }
64
64
  subject.callback { success_calls << true }
65
65
  end
66
- subject.succeed *arguments
66
+ subject.succeed(*arguments)
67
67
  expect(success_calls.count).to eql(3)
68
68
  expect(errback_calls.count).to eql(0)
69
69
  end
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+ require 'base64'
3
+
4
+ describe Ably::Models::CipherParams do
5
+ context ':key missing from constructor' do
6
+ subject { Ably::Models::CipherParams.new }
7
+
8
+ it 'raises an exception' do
9
+ expect { subject }.to raise_error(/key.*required/)
10
+ end
11
+ end
12
+
13
+ describe '#key' do
14
+ context 'with :key in constructor' do
15
+ subject { Ably::Models::CipherParams.new(key: key) }
16
+
17
+ context 'as nil' do
18
+ let(:key) { nil }
19
+
20
+ it 'raises an exception' do
21
+ expect { subject }.to raise_error(/key.*required/)
22
+ end
23
+ end
24
+
25
+ context 'as a base64 encoded string' do
26
+ let(:binary_key) { Ably::Util::Crypto.generate_random_key }
27
+ let(:key) { Base64.encode64(binary_key) }
28
+
29
+ it 'is a binary representation of the base64 encoded string' do
30
+ expect(subject.key).to eql(binary_key)
31
+ expect(subject.key.encoding).to eql(Encoding::ASCII_8BIT)
32
+ end
33
+ end
34
+
35
+ context 'as a URL safe base64 encoded string' do
36
+ let(:base64_key) { "t+8lK21q7/44/YTpKTpHa6Icc/a08wIATyhxbVBb4RE=\n" }
37
+ let(:binary_key) { Base64.decode64(base64_key) }
38
+ let(:key) { base64_key.gsub('/', '_').gsub('+', '-') }
39
+
40
+ it 'is a binary representation of the URL safe base64 encoded string' do
41
+ expect(subject.key).to eql(binary_key)
42
+ end
43
+ end
44
+
45
+ context 'as a binary encoded string' do
46
+ let(:key) { Ably::Util::Crypto.generate_random_key }
47
+
48
+ it 'contains the binary string' do
49
+ expect(subject.key).to eql(key)
50
+ expect(subject.key.encoding).to eql(Encoding::ASCII_8BIT)
51
+ end
52
+ end
53
+
54
+ context 'with an incompatible :key_length constructor param' do
55
+ let(:key) { Ably::Util::Crypto.generate_random_key(256) }
56
+ subject { Ably::Models::CipherParams.new(key: key, key_length: 128) }
57
+
58
+ it 'raises an exception' do
59
+ expect { subject }.to raise_error(/Incompatible.*key.*length/)
60
+ end
61
+ end
62
+
63
+ context 'with an unsupported :key_length for aes-cbc encryption' do
64
+ let(:key) { "A" * 48 }
65
+ subject { Ably::Models::CipherParams.new(key: key, algorithm: 'aes', mode: 'cbc') }
66
+
67
+ it 'raises an exception' do
68
+ expect { subject }.to raise_error(/Unsupported key length/)
69
+ end
70
+ end
71
+
72
+ context 'with an invalid type' do
73
+ let(:key) { 111 }
74
+ subject { Ably::Models::CipherParams.new(key: key) }
75
+
76
+ it 'raises an exception' do
77
+ expect { subject }.to raise_error(/key param must/)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ context 'with specified params in the constructor' do
84
+ let(:key) { Ably::Util::Crypto.generate_random_key(128) }
85
+ subject { Ably::Models::CipherParams.new(key: key, algorithm: 'aes', key_length: 128, mode: 'cbc') }
86
+
87
+ describe '#cipher_type' do
88
+ it 'contains the complete algorithm string as an upper case string' do
89
+ expect(subject.cipher_type).to eql ('AES-128-CBC')
90
+ end
91
+ end
92
+
93
+ describe '#mode' do
94
+ it 'contains the mode' do
95
+ expect(subject.mode).to eql ('cbc')
96
+ end
97
+ end
98
+
99
+ describe '#algorithm' do
100
+ it 'contains the algorithm' do
101
+ expect(subject.algorithm).to eql ('aes')
102
+ end
103
+ end
104
+
105
+ describe '#key_length' do
106
+ it 'contains the key_length' do
107
+ expect(subject.key_length).to eql(128)
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'with combined param in the constructor' do
113
+ let(:key) { Ably::Util::Crypto.generate_random_key(128) }
114
+ subject { Ably::Models::CipherParams.new(key: key, combined: "FOO-128-BAR") }
115
+
116
+ describe '#cipher_type' do
117
+ it 'contains the complete algorithm string as an upper case string' do
118
+ expect(subject.cipher_type).to eql ('FOO-128-BAR')
119
+ end
120
+ end
121
+
122
+ describe '#mode' do
123
+ it 'contains the mode' do
124
+ expect(subject.mode).to eql ('bar')
125
+ end
126
+ end
127
+
128
+ describe '#algorithm' do
129
+ it 'contains the algorithm' do
130
+ expect(subject.algorithm).to eql ('foo')
131
+ end
132
+ end
133
+
134
+ describe '#key_length' do
135
+ it 'contains the key_length' do
136
+ expect(subject.key_length).to eql(128)
137
+ end
138
+ end
139
+ end
140
+ end