ably-rest 0.7.1 → 0.7.3
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.
- checksums.yaml +13 -5
- data/.gitmodules +1 -1
- data/.rspec +1 -0
- data/.travis.yml +7 -3
- data/SPEC.md +495 -419
- data/ably-rest.gemspec +19 -5
- data/lib/ably-rest.rb +9 -1
- data/lib/submodules/ably-ruby/.gitignore +6 -0
- data/lib/submodules/ably-ruby/.rspec +1 -0
- data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
- data/lib/submodules/ably-ruby/.travis.yml +10 -0
- data/lib/submodules/ably-ruby/Gemfile +4 -0
- data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
- data/lib/submodules/ably-ruby/README.md +122 -0
- data/lib/submodules/ably-ruby/Rakefile +34 -0
- data/lib/submodules/ably-ruby/SPEC.md +1794 -0
- data/lib/submodules/ably-ruby/ably.gemspec +36 -0
- data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
- data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
- data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
- data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
- data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
- data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
- data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
- data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
- metadata +182 -27
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module ProtocolHelper
|
|
3
|
+
PROTOCOLS = if ENV['TEST_LIMIT_PROTOCOLS']
|
|
4
|
+
JSON.parse(ENV['TEST_LIMIT_PROTOCOLS'])
|
|
5
|
+
else
|
|
6
|
+
{
|
|
7
|
+
json: 'JSON',
|
|
8
|
+
msgpack: 'MsgPack'
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def vary_by_protocol(&block)
|
|
13
|
+
RSpec::ProtocolHelper::PROTOCOLS.each do |protocol, description|
|
|
14
|
+
context("using #{description} protocol", protocol: protocol, &block)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
RSpec.configure do |config|
|
|
21
|
+
config.extend RSpec::ProtocolHelper
|
|
22
|
+
|
|
23
|
+
config.before(:context, protocol: :json) do |context|
|
|
24
|
+
context.class.let(:protocol) { :json }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
config.before(:context, protocol: :msgpack) do |context|
|
|
28
|
+
context.class.let(:protocol) { :msgpack }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
module RandomHelper
|
|
4
|
+
def random_str(length = 16)
|
|
5
|
+
SecureRandom.hex(length).encode(Encoding::UTF_8)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def random_int_str(size = 1_000_000_000)
|
|
9
|
+
SecureRandom.random_number(size).to_s.encode(Encoding::UTF_8)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
RSpec.configure do |config|
|
|
13
|
+
config.include self
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# If a test fails and RSPEC_RETRY is set to true, create a new
|
|
2
|
+
# application before retrying the RSpec test again
|
|
3
|
+
#
|
|
4
|
+
RSpec.configure do |config|
|
|
5
|
+
config.around(:example) do |example|
|
|
6
|
+
example.run
|
|
7
|
+
|
|
8
|
+
next if example.metadata[:webmock] # new app is not needed for a mocked test
|
|
9
|
+
|
|
10
|
+
if example.exception && ENV['RSPEC_RETRY']
|
|
11
|
+
reload_test_app
|
|
12
|
+
puts "** Test app reloaded before next retry **"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
class TestApp
|
|
4
|
+
APP_SPEC = {
|
|
5
|
+
'keys' => [
|
|
6
|
+
{},
|
|
7
|
+
{
|
|
8
|
+
'capability' => '{ "cansubscribe:*":["subscribe"], "canpublish:*":["publish"], "canpublish:andpresence":["presence","publish"] }'
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
'namespaces' => [
|
|
12
|
+
{ 'id' => 'persisted', 'persisted' => true }
|
|
13
|
+
],
|
|
14
|
+
'channels' => [
|
|
15
|
+
{
|
|
16
|
+
'name' => 'persisted:presence_fixtures',
|
|
17
|
+
'presence' => [
|
|
18
|
+
{ 'clientId' => 'client_bool', 'clientData' => 'true' },
|
|
19
|
+
{ 'clientId' => 'client_int', 'clientData' => '24' },
|
|
20
|
+
{ 'clientId' => 'client_string', 'clientData' => 'This is a string clientData payload' },
|
|
21
|
+
{ 'clientId' => 'client_json', 'clientData' => '{ "test" => \'This is a JSONObject clientData payload\'}' }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# If an app has already been created and we need a new app, create a new test app
|
|
28
|
+
# This is sometimes needed when a test needs to be isolated from any other tests
|
|
29
|
+
def self.reload
|
|
30
|
+
if instance_variable_get('@singleton__instance__')
|
|
31
|
+
instance.delete
|
|
32
|
+
instance.create_test_app
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
include Singleton
|
|
37
|
+
|
|
38
|
+
def initialize
|
|
39
|
+
create_test_app
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def app_id
|
|
43
|
+
@attributes["appId"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def key
|
|
47
|
+
@attributes["keys"].first
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def restricted_key
|
|
51
|
+
@attributes["keys"][1]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def key_id
|
|
55
|
+
"#{app_id}.#{key['id']}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def key_value
|
|
59
|
+
key['value']
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def api_key
|
|
63
|
+
"#{key_id}:#{key_value}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def restricted_api_key
|
|
67
|
+
"#{app_id}.#{restricted_key['id']}:#{restricted_key['value']}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def delete
|
|
71
|
+
return unless TestApp.instance_variable_get('@singleton__instance__')
|
|
72
|
+
|
|
73
|
+
url = "#{sandbox_client.endpoint}/apps/#{app_id}"
|
|
74
|
+
|
|
75
|
+
basic_auth = Base64.encode64(api_key).chomp
|
|
76
|
+
headers = { "Authorization" => "Basic #{basic_auth}" }
|
|
77
|
+
|
|
78
|
+
Faraday.delete(url, nil, headers)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def environment
|
|
82
|
+
'sandbox'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def create_test_app
|
|
86
|
+
url = "#{sandbox_client.endpoint}/apps"
|
|
87
|
+
|
|
88
|
+
headers = {
|
|
89
|
+
'Accept' => 'application/json',
|
|
90
|
+
'Content-Type' => 'application/json'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@attributes = JSON.parse(Faraday.post(url, APP_SPEC.to_json, headers).body)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def host
|
|
97
|
+
sandbox_client.endpoint.host
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def realtime_host
|
|
101
|
+
host.gsub(/rest/, 'realtime')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def create_test_stats(stats)
|
|
105
|
+
client = Ably::Rest::Client.new(api_key: api_key, environment: environment)
|
|
106
|
+
client.post('/stats', stats)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
def sandbox_client
|
|
111
|
+
@sandbox_client ||= Ably::Rest::Client.new(api_key: 'app.key:secret', tls: true, environment: environment)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'shared/protocol_msgbus_behaviour'
|
|
3
|
+
|
|
4
|
+
describe Ably::Auth do
|
|
5
|
+
let(:client) { double('client').as_null_object }
|
|
6
|
+
let(:client_id) { nil }
|
|
7
|
+
let(:options) { { api_key: 'appid.keyuid:keysecret', client_id: client_id } }
|
|
8
|
+
|
|
9
|
+
subject do
|
|
10
|
+
Ably::Auth.new(client, options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe 'client_id option' do
|
|
14
|
+
let(:client_id) { random_str.encode(encoding) }
|
|
15
|
+
|
|
16
|
+
context 'with nil value' do
|
|
17
|
+
let(:client_id) { nil }
|
|
18
|
+
|
|
19
|
+
it 'is permitted' do
|
|
20
|
+
expect(subject.client_id).to be_nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'as UTF_8 string' do
|
|
25
|
+
let(:encoding) { Encoding::UTF_8 }
|
|
26
|
+
|
|
27
|
+
it 'is permitted' do
|
|
28
|
+
expect(subject.client_id).to eql(client_id)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'remains as UTF-8' do
|
|
32
|
+
expect(subject.client_id.encoding).to eql(encoding)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'as SHIFT_JIS string' do
|
|
37
|
+
let(:encoding) { Encoding::SHIFT_JIS }
|
|
38
|
+
|
|
39
|
+
it 'gets converted to UTF-8' do
|
|
40
|
+
expect(subject.client_id.encoding).to eql(Encoding::UTF_8)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'is compatible with original encoding' do
|
|
44
|
+
expect(subject.client_id.encode(encoding)).to eql(client_id)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'as ASCII_8BIT string' do
|
|
49
|
+
let(:encoding) { Encoding::ASCII_8BIT }
|
|
50
|
+
|
|
51
|
+
it 'gets converted to UTF-8' do
|
|
52
|
+
expect(subject.client_id.encoding).to eql(Encoding::UTF_8)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'is compatible with original encoding' do
|
|
56
|
+
expect(subject.client_id.encode(encoding)).to eql(client_id)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'as Integer' do
|
|
61
|
+
let(:client_id) { 1 }
|
|
62
|
+
|
|
63
|
+
it 'raises an argument error' do
|
|
64
|
+
expect { subject.client_id }.to raise_error ArgumentError, /must be a String/
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Ably::Logger do
|
|
4
|
+
let(:rest_client) do
|
|
5
|
+
instance_double('Ably::Rest::Client')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO) }
|
|
9
|
+
|
|
10
|
+
def uncolorize(string)
|
|
11
|
+
regex_pattern = /\033\[[0-9]+m(.+?)\033\[0m/m
|
|
12
|
+
string.gsub(regex_pattern, '\1')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'uses the language provided Logger by default' do
|
|
16
|
+
expect(subject.logger).to be_a(Logger)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context 'internals', :api_private do
|
|
20
|
+
it 'delegates to the logger object' do
|
|
21
|
+
expect(subject.logger).to receive(:warn).with('message')
|
|
22
|
+
subject.warn 'message'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'formatter' do
|
|
26
|
+
context 'when debugging' do
|
|
27
|
+
it 'uses short time format' do
|
|
28
|
+
formatted = subject.logger.formatter.call(Logger::DEBUG, Time.now, 'progid', 'unique_message')
|
|
29
|
+
formatted = uncolorize(formatted)
|
|
30
|
+
expect(formatted).to match(/^\d+:\d+:\d+.\d{3} DEBUG/)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'when info -> fatal' do
|
|
35
|
+
it 'uses long time format' do
|
|
36
|
+
formatted = subject.logger.formatter.call(Logger::INFO, Time.now, 'progid', 'unique_message')
|
|
37
|
+
formatted = uncolorize(formatted)
|
|
38
|
+
expect(formatted).to match(/^\d+-\d+-\d+ \d+:\d+:\d+.\d{3} INFO/)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if defined?(Ably::Realtime)
|
|
43
|
+
context 'with Realtime client' do
|
|
44
|
+
let(:new_realtime_client) do
|
|
45
|
+
instance_double('Ably::Realtime::Client', connection: instance_double('Ably::Realtime::Connection', id: nil))
|
|
46
|
+
end
|
|
47
|
+
let(:connected_realtime_client) do
|
|
48
|
+
instance_double('Ably::Realtime::Client', connection: instance_double('Ably::Realtime::Connection', id: '0000'))
|
|
49
|
+
end
|
|
50
|
+
before do
|
|
51
|
+
allow(new_realtime_client).to receive(:kind_of?).with(Ably::Realtime::Client).and_return(true)
|
|
52
|
+
allow(connected_realtime_client).to receive(:kind_of?).with(Ably::Realtime::Client).and_return(true)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'with Realtime disconnected client' do
|
|
56
|
+
subject { Ably::Logger.new(new_realtime_client, Logger::INFO) }
|
|
57
|
+
|
|
58
|
+
it 'formats logs with an empty client ID' do
|
|
59
|
+
formatted = subject.logger.formatter.call(Logger::DEBUG, Time.now, 'progid', 'unique_message')
|
|
60
|
+
formatted = uncolorize(formatted)
|
|
61
|
+
expect(formatted).to match(/\[ \-\- \]/)
|
|
62
|
+
expect(formatted).to match(%r{unique_message$})
|
|
63
|
+
expect(formatted).to match(%r{DEBUG})
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'with Realtime connected client' do
|
|
68
|
+
subject { Ably::Logger.new(connected_realtime_client, Logger::INFO) }
|
|
69
|
+
|
|
70
|
+
it 'formats logs with a client ID' do
|
|
71
|
+
formatted = subject.logger.formatter.call(Logger::DEBUG, Time.now, 'progid', 'unique_message')
|
|
72
|
+
formatted = uncolorize(formatted)
|
|
73
|
+
expect(formatted).to match(/\[0000\]/)
|
|
74
|
+
expect(formatted).to match(%r{unique_message$})
|
|
75
|
+
expect(formatted).to match(%r{DEBUG})
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'with REST client' do
|
|
82
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO) }
|
|
83
|
+
|
|
84
|
+
it 'formats logs without a client ID' do
|
|
85
|
+
formatted = subject.logger.formatter.call(Logger::FATAL, Time.now, 'progid', 'unique_message')
|
|
86
|
+
formatted = uncolorize(formatted)
|
|
87
|
+
expect(formatted).to_not match(/\[.*\]/)
|
|
88
|
+
expect(formatted).to match(%r{unique_message$})
|
|
89
|
+
expect(formatted).to match(%r{FATAL})
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context 'severity argument' do
|
|
94
|
+
it 'can be an Integer' do
|
|
95
|
+
formatted = subject.logger.formatter.call(Logger::INFO, Time.now, 'progid', 'unique_message')
|
|
96
|
+
formatted = uncolorize(formatted)
|
|
97
|
+
expect(formatted).to match(/^\d+-\d+-\d+ \d+:\d+:\d+.\d{3} INFO/)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'can be a string' do
|
|
101
|
+
formatted = subject.logger.formatter.call('INFO', Time.now, 'progid', 'unique_message')
|
|
102
|
+
formatted = uncolorize(formatted)
|
|
103
|
+
expect(formatted).to match(/^\d+-\d+-\d+ \d+:\d+:\d+.\d{3} INFO/)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context 'with a custom Logger' do
|
|
110
|
+
context 'with an invalid interface' do
|
|
111
|
+
let(:custom_logger_with_bad_interface) do
|
|
112
|
+
Class.new.new
|
|
113
|
+
end
|
|
114
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO, custom_logger_with_bad_interface) }
|
|
115
|
+
|
|
116
|
+
it 'raises an exception' do
|
|
117
|
+
expect { subject }.to raise_error ArgumentError, /The custom Logger's interface does not provide the method/
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context 'with a valid interface' do
|
|
122
|
+
let(:custom_logger) do
|
|
123
|
+
Class.new do
|
|
124
|
+
extend Forwardable
|
|
125
|
+
def initialize
|
|
126
|
+
@logger = Logger.new(STDOUT)
|
|
127
|
+
end
|
|
128
|
+
def_delegators :@logger, :fatal, :error, :warn, :info, :debug, :level, :level=
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
let(:custom_logger_object) { custom_logger.new }
|
|
132
|
+
|
|
133
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO, custom_logger_object) }
|
|
134
|
+
|
|
135
|
+
it 'is used' do
|
|
136
|
+
expect { subject }.to_not raise_error
|
|
137
|
+
expect(subject.logger.class).to eql(custom_logger)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'delegates log messages to logger', :api_private do
|
|
141
|
+
expect(custom_logger_object).to receive(:fatal).with('message')
|
|
142
|
+
subject.fatal 'message'
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'shared/model_behaviour'
|
|
3
|
+
|
|
4
|
+
describe Ably::Models::ErrorInfo do
|
|
5
|
+
subject { Ably::Models::ErrorInfo }
|
|
6
|
+
|
|
7
|
+
it_behaves_like 'a model', with_simple_attributes: %w(code status_code message) do
|
|
8
|
+
let(:model_args) { [] }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context '#status' do
|
|
12
|
+
subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
|
|
13
|
+
it 'is an alias for #status_code' do
|
|
14
|
+
expect(subject.status).to eql(subject.status_code)
|
|
15
|
+
expect(subject.status).to eql(401)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Ably::Models::IdiomaticRubyWrapper, :api_private do
|
|
4
|
+
include Ably::Modules::Conversions
|
|
5
|
+
|
|
6
|
+
let(:mixed_case_data) do
|
|
7
|
+
{
|
|
8
|
+
'mixedCase' => 'true',
|
|
9
|
+
'simple' => 'without case',
|
|
10
|
+
'hashObject' => {
|
|
11
|
+
'mixedCaseChild' => 'exists'
|
|
12
|
+
},
|
|
13
|
+
'arrayObject' => [
|
|
14
|
+
{
|
|
15
|
+
'mixedCaseChild' => 'exists'
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
subject { Ably::Models::IdiomaticRubyWrapper.new(mixed_case_data) }
|
|
21
|
+
|
|
22
|
+
context 'Kernel.Array like method to create a IdiomaticRubyWrapper' do
|
|
23
|
+
it 'will return the same IdiomaticRubyWrapper if passed in' do
|
|
24
|
+
expect(IdiomaticRubyWrapper(subject)).to eql(subject)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'will return the same IdiomaticRubyWrapper if passed in' do
|
|
28
|
+
expect(IdiomaticRubyWrapper(mixed_case_data)).to be_a(Ably::Models::IdiomaticRubyWrapper)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'provides accessor method to values using snake_case' do
|
|
33
|
+
expect(subject[:mixed_case]).to eql('true')
|
|
34
|
+
expect(subject[:simple]).to eql('without case')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'provides methods to read values using snake_case' do
|
|
38
|
+
expect(subject.mixed_case).to eql('true')
|
|
39
|
+
expect(subject.simple).to eql('without case')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'provides accessor set method to values using snake_case' do
|
|
43
|
+
subject[:mixed_case] = 'mixedCase'
|
|
44
|
+
subject[:simple] = 'simple'
|
|
45
|
+
expect(subject[:mixed_case]).to eql('mixedCase')
|
|
46
|
+
expect(subject[:simple]).to eql('simple')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'provides methods to write values using snake_case' do
|
|
50
|
+
subject.mixed_case = 'mixedCase'
|
|
51
|
+
subject.simple = 'simple'
|
|
52
|
+
expect(subject.mixed_case).to eql('mixedCase')
|
|
53
|
+
expect(subject.simple).to eql('simple')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'does not provide methods for keys that are missing' do
|
|
57
|
+
expect { subject.no_key_exists_for_this }.to raise_error NoMethodError
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
specify '#hash returns raw Hash object' do
|
|
61
|
+
expect(subject.hash).to eql(mixed_case_data)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'recursively wrapping child objects' do
|
|
65
|
+
it 'wraps Hashes' do
|
|
66
|
+
expect(subject.hash_object.mixed_case_child).to eql('exists')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'ignores arrays' do
|
|
70
|
+
expect(subject.array_object.first).to include('mixedCaseChild' => 'exists')
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context ':stop_at option' do
|
|
74
|
+
subject { Ably::Models::IdiomaticRubyWrapper.new(mixed_case_data, stop_at: stop_at) }
|
|
75
|
+
|
|
76
|
+
context 'with symbol' do
|
|
77
|
+
let(:stop_at) { :hash_object }
|
|
78
|
+
|
|
79
|
+
it 'does not wrap the matching key' do
|
|
80
|
+
expect(subject.hash_object).to include('mixedCaseChild' => 'exists')
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context 'with string' do
|
|
85
|
+
let(:stop_at) { ['hashObject'] }
|
|
86
|
+
|
|
87
|
+
it 'does not wrap the matching key' do
|
|
88
|
+
expect(subject.hash_object).to include('mixedCaseChild' => 'exists')
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context 'non standard mixedCaseData' do
|
|
95
|
+
let(:data) do
|
|
96
|
+
{
|
|
97
|
+
:symbol => 'aSymbolValue',
|
|
98
|
+
:snake_case_symbol => 'snake_case_symbolValue',
|
|
99
|
+
:mixedCaseSymbol => 'mixedCaseSymbolValue',
|
|
100
|
+
'snake_case_string' => 'snake_case_stringValue',
|
|
101
|
+
'mixedCaseString' => 'mixedCaseStringFirstChoiceValue',
|
|
102
|
+
:mixedCaseString => 'mixedCaseStringFallbackValue',
|
|
103
|
+
:CamelCaseSymbol => 'CamelCaseSymbolValue',
|
|
104
|
+
'CamelCaseString' => 'camel_case_stringValue',
|
|
105
|
+
:lowercasesymbol => 'lowercasesymbolValue',
|
|
106
|
+
'lowercasestring' => 'lowercasestringValue'
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
let(:unique_value) { random_str }
|
|
110
|
+
|
|
111
|
+
subject { Ably::Models::IdiomaticRubyWrapper.new(data) }
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
:symbol => 'aSymbolValue',
|
|
115
|
+
:snake_case_symbol => 'snake_case_symbolValue',
|
|
116
|
+
:mixed_case_symbol => 'mixedCaseSymbolValue',
|
|
117
|
+
:snake_case_string => 'snake_case_stringValue',
|
|
118
|
+
:mixed_case_string => 'mixedCaseStringFirstChoiceValue',
|
|
119
|
+
:camel_case_symbol => 'CamelCaseSymbolValue',
|
|
120
|
+
:camel_case_string => 'camel_case_stringValue',
|
|
121
|
+
:lower_case_symbol => 'lowercasesymbolValue',
|
|
122
|
+
:lower_case_string => 'lowercasestringValue'
|
|
123
|
+
}.each do |symbol_accessor, expected_value|
|
|
124
|
+
context symbol_accessor do
|
|
125
|
+
it 'allows access to non conformant keys but prefers correct mixedCaseSyntax' do
|
|
126
|
+
expect(subject[symbol_accessor]).to eql(expected_value)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context 'updates' do
|
|
130
|
+
before do
|
|
131
|
+
subject[symbol_accessor] = unique_value
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'returns the new value' do
|
|
135
|
+
expect(subject[symbol_accessor]).to eql(unique_value)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'returns the new value in the JSON' do
|
|
139
|
+
expect(subject.to_json).to include(unique_value)
|
|
140
|
+
expect(subject.to_json).to_not include(expected_value)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'returns nil for non existent keys' do
|
|
147
|
+
expect(subject[:non_existent_key]).to eql(nil)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context 'new keys' do
|
|
151
|
+
before do
|
|
152
|
+
subject[:new_key] = 'new_value'
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it 'uses mixedCase' do
|
|
156
|
+
expect(subject.hash['newKey']).to eql('new_value')
|
|
157
|
+
expect(subject.new_key).to eql('new_value')
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context 'acts like a duck' do
|
|
163
|
+
let(:parsed_json) { JSON.parse(subject.to_json) }
|
|
164
|
+
specify '#to_json returns JSON stringified' do
|
|
165
|
+
expect(subject.to_json).to eql(mixed_case_data.to_json)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
specify '#to_json returns child JSON objects in the JSON stringified' do
|
|
169
|
+
expect(parsed_json['arrayObject']).to eql(mixed_case_data['arrayObject'])
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
context 'with snake case JSON' do
|
|
173
|
+
let(:subject) { Ably::Models::IdiomaticRubyWrapper.new('wrong_case' => 'will_be_corrected')}
|
|
174
|
+
specify '#to_json uses mixedCase for any non mixedCase keys' do
|
|
175
|
+
expect(parsed_json['wrongCase']).to eql('will_be_corrected')
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
context '#to_json with changes' do
|
|
180
|
+
before do
|
|
181
|
+
@original_mixed_case_data = mixed_case_data.to_json
|
|
182
|
+
subject[:mixed_case] = 'new_value'
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it 'returns stringified JSON with changes' do
|
|
186
|
+
expect(subject.to_json).to_not eql(@original_mixed_case_data)
|
|
187
|
+
expect(subject.to_json).to match('new_value')
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it 'returns correct size' do
|
|
192
|
+
expect(subject.size).to eql(mixed_case_data.size)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it 'supports Hash-like #keys' do
|
|
196
|
+
expect(subject.keys.length).to eql(mixed_case_data.keys.length)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it 'supports Hash-like #values' do
|
|
200
|
+
expect(subject.values.length).to eql(mixed_case_data.values.length)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it 'is Enumerable' do
|
|
204
|
+
expect(subject).to be_kind_of(Enumerable)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
context 'iterable' do
|
|
208
|
+
subject { Ably::Models::IdiomaticRubyWrapper.new(mixed_case_data, stop_at: [:hash_object, :array_object]) }
|
|
209
|
+
|
|
210
|
+
let(:expected_keys) { [:mixed_case, :simple, :hash_object, :array_object] }
|
|
211
|
+
let(:expected_vals) { mixed_case_data.map { |k,v| v } }
|
|
212
|
+
|
|
213
|
+
it 'yields key value pairs' do
|
|
214
|
+
expect(subject.map { |k,v| k }).to eql(expected_keys)
|
|
215
|
+
expect(subject.map { |k,v| v }).to eql(expected_vals)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context '#each' do
|
|
219
|
+
it 'returns an enumerator' do
|
|
220
|
+
expect(subject.each).to be_a(Enumerator)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it 'yields key value pairs' do
|
|
224
|
+
emitted = {}
|
|
225
|
+
subject.each do |key, val|
|
|
226
|
+
emitted[key] = val
|
|
227
|
+
end
|
|
228
|
+
expect(emitted.keys).to eql(expected_keys)
|
|
229
|
+
expect(emitted.values).to eql(expected_vals)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
context '#fetch' do
|
|
235
|
+
it 'fetches the key' do
|
|
236
|
+
expect(subject.fetch(:mixed_case)).to eql('true')
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it 'raise an exception if key does not exist' do
|
|
240
|
+
expect { subject.fetch(:non_existent) }.to raise_error KeyError, /key not found: non_existent/
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it 'allows a default value argument' do
|
|
244
|
+
expect(subject.fetch(:non_existent, 'default')).to eql('default')
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it 'calls the block if key does not exist' do
|
|
248
|
+
expect(subject.fetch(:non_existent) { 'block_default' } ).to eql('block_default')
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
context '#==' do
|
|
253
|
+
let(:mixed_case_data) do
|
|
254
|
+
{
|
|
255
|
+
'key' => 'value'
|
|
256
|
+
}
|
|
257
|
+
end
|
|
258
|
+
let(:presented_as_data) do
|
|
259
|
+
{
|
|
260
|
+
:key => 'value'
|
|
261
|
+
}
|
|
262
|
+
end
|
|
263
|
+
let(:invalid_match) do
|
|
264
|
+
{
|
|
265
|
+
:key => 'other value'
|
|
266
|
+
}
|
|
267
|
+
end
|
|
268
|
+
let(:other) { Ably::Models::IdiomaticRubyWrapper.new(mixed_case_data) }
|
|
269
|
+
let(:other_invalid) { Ably::Models::IdiomaticRubyWrapper.new(invalid_match) }
|
|
270
|
+
|
|
271
|
+
it 'presents itself as a symbolized version of the object' do
|
|
272
|
+
expect(subject).to eq(presented_as_data)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'returns false if different values to another Hash' do
|
|
276
|
+
expect(subject).to_not eq(invalid_match)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'compares with itself' do
|
|
280
|
+
expect(subject).to eq(other)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it 'returns false if different values to another IdiomaticRubyWrapper' do
|
|
284
|
+
expect(subject).to_not eq(other_invalid)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
it 'returns false if comparing with a non Hash/IdiomaticRubyWrapper object' do
|
|
288
|
+
expect(subject).to_not eq(Object)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
context '#to_hash' do
|
|
293
|
+
let(:mixed_case_data) do
|
|
294
|
+
{
|
|
295
|
+
'key' => 'value',
|
|
296
|
+
'childObject' => {
|
|
297
|
+
'child' => true
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it 'returns a hash' do
|
|
303
|
+
expect(subject.to_hash).to include(key: 'value')
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it 'converts hashes within hashes' do
|
|
307
|
+
expect(subject.to_hash[:child_object]).to include(child: true)
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
context '#to_msgpack' do
|
|
312
|
+
let(:mixed_case_data) do
|
|
313
|
+
{
|
|
314
|
+
'key' => 'value',
|
|
315
|
+
'child' => {
|
|
316
|
+
'with_attributes' => true
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
end
|
|
320
|
+
let(:msg_packed) { subject.to_msgpack }
|
|
321
|
+
let(:unpacked) { MessagePack.unpack(msg_packed) }
|
|
322
|
+
|
|
323
|
+
it 'returns a msgpack object' do
|
|
324
|
+
expect(unpacked).to include('key' => 'value')
|
|
325
|
+
expect(unpacked).to include('child' => { 'withAttributes' => true })
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
context '#dup' do
|
|
330
|
+
let(:mixed_case_data) do
|
|
331
|
+
{
|
|
332
|
+
'key' => 'value'
|
|
333
|
+
}.freeze
|
|
334
|
+
end
|
|
335
|
+
let(:dupe) { subject.dup }
|
|
336
|
+
|
|
337
|
+
it 'returns a new object with the underlying JSON duped' do
|
|
338
|
+
expect(subject.hash).to be_frozen
|
|
339
|
+
expect(dupe.hash).to_not be_frozen
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
it 'returns a new IdiomaticRubyWrapper with the same underlying Hash object' do
|
|
343
|
+
expect(dupe).to be_a(Ably::Models::IdiomaticRubyWrapper)
|
|
344
|
+
expect(dupe.hash).to be_a(Hash)
|
|
345
|
+
expect(dupe.hash).to eql(mixed_case_data)
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end
|