ably 0.1.5 → 0.1.6
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 +4 -4
- data/README.md +11 -1
- data/ably.gemspec +4 -3
- data/lib/ably.rb +6 -2
- data/lib/ably/auth.rb +24 -16
- data/lib/ably/exceptions.rb +16 -5
- data/lib/ably/{realtime/models → models}/error_info.rb +9 -11
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +57 -26
- data/lib/ably/{realtime/models → models}/message.rb +45 -38
- data/lib/ably/{realtime/models → models}/nil_channel.rb +4 -4
- data/lib/ably/{rest/models/paged_resource.rb → models/paginated_resource.rb} +21 -10
- data/lib/ably/models/presence_message.rb +126 -0
- data/lib/ably/{realtime/models → models}/protocol_message.rb +76 -38
- data/lib/ably/models/token.rb +74 -0
- data/lib/ably/modules/channels_collection.rb +49 -0
- data/lib/ably/modules/conversions.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +43 -8
- data/lib/ably/modules/event_machine_helpers.rb +1 -0
- data/lib/ably/modules/http_helpers.rb +9 -2
- data/lib/ably/modules/message_pack.rb +14 -0
- data/lib/ably/modules/model_common.rb +29 -0
- data/lib/ably/modules/{state.rb → state_emitter.rb} +8 -7
- data/lib/ably/realtime.rb +37 -7
- data/lib/ably/realtime/channel.rb +154 -31
- data/lib/ably/realtime/channels.rb +47 -0
- data/lib/ably/realtime/client.rb +39 -33
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +50 -21
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +9 -11
- data/lib/ably/realtime/connection.rb +148 -79
- data/lib/ably/realtime/connection/connection_state_machine.rb +111 -0
- data/lib/ably/realtime/connection/websocket_transport.rb +161 -0
- data/lib/ably/realtime/presence.rb +270 -0
- data/lib/ably/rest.rb +14 -3
- data/lib/ably/rest/channel.rb +3 -3
- data/lib/ably/rest/channels.rb +26 -12
- data/lib/ably/rest/client.rb +42 -25
- data/lib/ably/rest/middleware/exceptions.rb +21 -23
- data/lib/ably/rest/middleware/external_exceptions.rb +8 -10
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/ably/rest/middleware/parse_json.rb +9 -2
- data/lib/ably/rest/middleware/parse_message_pack.rb +6 -2
- data/lib/ably/rest/presence.rb +4 -4
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +125 -0
- data/spec/acceptance/realtime/channel_spec.rb +135 -63
- data/spec/acceptance/realtime/connection_spec.rb +86 -0
- data/spec/acceptance/realtime/message_spec.rb +116 -94
- data/spec/acceptance/realtime/presence_history_spec.rb +0 -0
- data/spec/acceptance/realtime/presence_spec.rb +277 -0
- data/spec/acceptance/rest/auth_spec.rb +351 -347
- data/spec/acceptance/rest/base_spec.rb +43 -26
- data/spec/acceptance/rest/channel_spec.rb +88 -83
- data/spec/acceptance/rest/channels_spec.rb +32 -28
- data/spec/acceptance/rest/presence_spec.rb +83 -63
- data/spec/acceptance/rest/stats_spec.rb +38 -37
- data/spec/acceptance/rest/time_spec.rb +10 -6
- data/spec/integration/modules/{state_spec.rb → state_emitter_spec.rb} +16 -2
- data/spec/spec_helper.rb +14 -0
- data/spec/support/api_helper.rb +4 -0
- data/spec/support/model_helper.rb +28 -9
- data/spec/support/protocol_msgbus_helper.rb +8 -1
- data/spec/support/test_app.rb +24 -14
- data/spec/unit/{realtime → models}/error_info_spec.rb +4 -4
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +46 -9
- data/spec/unit/models/message_spec.rb +229 -0
- data/spec/unit/{rest/paged_resource_spec.rb → models/paginated_resource_spec.rb} +19 -11
- data/spec/unit/models/presence_message_spec.rb +230 -0
- data/spec/unit/models/protocol_message_spec.rb +280 -0
- data/spec/unit/{token_spec.rb → models/token_spec.rb} +18 -22
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/event_emitter_spec.rb +36 -4
- data/spec/unit/realtime/channel_spec.rb +76 -2
- data/spec/unit/realtime/channels_spec.rb +50 -0
- data/spec/unit/realtime/client_spec.rb +31 -1
- data/spec/unit/realtime/connection_spec.rb +8 -15
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +6 -6
- data/spec/unit/realtime/presence_spec.rb +100 -0
- data/spec/unit/rest/channels_spec.rb +48 -0
- metadata +72 -38
- data/lib/ably/realtime/models/shared.rb +0 -17
- data/lib/ably/rest/models/message.rb +0 -64
- data/lib/ably/rest/models/presence_message.rb +0 -21
- data/lib/ably/token.rb +0 -80
- data/spec/unit/realtime/message_spec.rb +0 -117
- data/spec/unit/realtime/protocol_message_spec.rb +0 -172
- data/spec/unit/rest/message_spec.rb +0 -75
@@ -2,54 +2,55 @@ require "spec_helper"
|
|
2
2
|
require "securerandom"
|
3
3
|
|
4
4
|
describe "REST" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def number_of_messages_per_channel() 5 end
|
5
|
+
[:json, :msgpack].each do |protocol|
|
6
|
+
context "over #{protocol}" do
|
7
|
+
describe "fetching application stats" do
|
8
|
+
before(:context) do
|
9
|
+
reload_test_app
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
def number_of_channels() 3 end
|
13
|
+
def number_of_messages_per_channel() 5 end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
service_time = @context_client.time
|
19
|
-
@interval_start = (service_time.to_i / 60 + 1) * 60
|
20
|
-
sleep_time = @interval_start - Time.now.to_i
|
15
|
+
before(:context) do
|
16
|
+
@context_client = Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol)
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
# Wait until the start of the next minute according to the service
|
19
|
+
# time because stats are created in 1 minute intervals
|
20
|
+
service_time = @context_client.time
|
21
|
+
@interval_start = (service_time.to_i / 60 + 1) * 60
|
22
|
+
sleep_time = @interval_start - Time.now.to_i
|
27
23
|
|
28
|
-
|
29
|
-
|
24
|
+
if sleep_time > 30
|
25
|
+
@interval_start -= 60 # there is enough time to generate the stats in this minute interval
|
26
|
+
elsif sleep_time > 0
|
27
|
+
sleep sleep_time
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
30
|
+
number_of_channels.times do |i|
|
31
|
+
channel = @context_client.channel("stats-#{i}")
|
35
32
|
|
36
|
-
|
37
|
-
|
33
|
+
number_of_messages_per_channel.times do |j|
|
34
|
+
channel.publish("event-#{j}", "data-#{j}") || raise("Unable to publish message")
|
35
|
+
end
|
36
|
+
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
it "should return all the stats for the application" do
|
42
|
-
stats = @context_client.stats(start: @interval_start * 1000, by: interval.to_s, direction: 'forwards')
|
38
|
+
sleep(10)
|
39
|
+
end
|
43
40
|
|
44
|
-
|
41
|
+
[:minute, :hour, :day, :month].each do |interval|
|
42
|
+
context "by #{interval}" do
|
43
|
+
it "should return all the stats for the application" do
|
44
|
+
stats = @context_client.stats(start: @interval_start * 1000, by: interval.to_s, direction: 'forwards')
|
45
45
|
|
46
|
-
|
46
|
+
expect(stats.size).to eql(1)
|
47
47
|
|
48
|
-
|
49
|
-
expect(stat[:inbound][:rest][:all][:count]).to eql(number_of_channels * number_of_messages_per_channel)
|
48
|
+
stat = stats.first
|
50
49
|
|
51
|
-
|
52
|
-
|
50
|
+
expect(stat[:inbound][:all][:messages][:count]).to eql(number_of_channels * number_of_messages_per_channel)
|
51
|
+
expect(stat[:inbound][:rest][:messages][:count]).to eql(number_of_channels * number_of_messages_per_channel)
|
52
|
+
end
|
53
|
+
end
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
@@ -2,13 +2,17 @@ require "spec_helper"
|
|
2
2
|
require "securerandom"
|
3
3
|
|
4
4
|
describe "REST" do
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
[:msgpack, :json].each do |protocol|
|
6
|
+
context "over #{protocol}" do
|
7
|
+
let(:client) do
|
8
|
+
Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol)
|
9
|
+
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
describe "fetching the service time" do
|
12
|
+
it "should return the service time as a Time object" do
|
13
|
+
expect(client.time).to be_within(2).of(Time.now)
|
14
|
+
end
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Ably::Modules::
|
3
|
+
describe Ably::Modules::StateEmitter do
|
4
4
|
class ExampleStateWithEventEmitter
|
5
5
|
include Ably::Modules::EventEmitter
|
6
6
|
extend Ably::Modules::Enum
|
@@ -11,7 +11,7 @@ describe Ably::Modules::State do
|
|
11
11
|
:connected,
|
12
12
|
:disconnected
|
13
13
|
)
|
14
|
-
include Ably::Modules::
|
14
|
+
include Ably::Modules::StateEmitter
|
15
15
|
|
16
16
|
def initialize
|
17
17
|
@state = :initializing
|
@@ -34,6 +34,20 @@ describe Ably::Modules::State do
|
|
34
34
|
expect { subject.change_state :connecting }.to change { subject.state }.to(:connecting)
|
35
35
|
end
|
36
36
|
|
37
|
+
context '#change_state with arguments' do
|
38
|
+
let(:args) { [5,3,1] }
|
39
|
+
let(:callback_status) { { called: false } }
|
40
|
+
|
41
|
+
it 'passes the arguments through to the triggered callback' do
|
42
|
+
subject.on(:connecting) do |*callback_args|
|
43
|
+
expect(callback_args).to eql(args)
|
44
|
+
callback_status[:called] = true
|
45
|
+
end
|
46
|
+
expect { subject.change_state :connecting, *args }.to change { subject.state }.to(:connecting)
|
47
|
+
expect(callback_status).to eql(called: true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
37
51
|
context '#state?' do
|
38
52
|
it 'returns true if state matches' do
|
39
53
|
expect(subject.state?(initial_state)).to eql(true)
|
data/spec/spec_helper.rb
CHANGED
@@ -16,6 +16,14 @@ RSpec.configure do |config|
|
|
16
16
|
config.run_all_when_everything_filtered = true
|
17
17
|
config.filter_run :focus
|
18
18
|
|
19
|
+
config.mock_with :rspec do |mocks|
|
20
|
+
# This option should be set when all dependencies are being loaded
|
21
|
+
# before a spec run, as is the case in a typical spec helper. It will
|
22
|
+
# cause any verifying double instantiation for a class that does not
|
23
|
+
# exist to raise, protecting against incorrectly spelt names.
|
24
|
+
mocks.verify_doubled_constant_names = true
|
25
|
+
end
|
26
|
+
|
19
27
|
# Run specs in random order to surface order dependencies. If you find an
|
20
28
|
# order dependency and want to debug it, you can fix the order by providing
|
21
29
|
# the seed, which is printed after each run.
|
@@ -27,6 +35,12 @@ RSpec.configure do |config|
|
|
27
35
|
end
|
28
36
|
|
29
37
|
config.before(:example, :webmock => true) do
|
38
|
+
allow(TestApp).to receive(:instance).and_return(instance_double('TestApp',
|
39
|
+
app_id: 'app_id',
|
40
|
+
key_id: 'app_id.key_id',
|
41
|
+
api_key: 'app_id.key_id:secret',
|
42
|
+
environment: 'sandbox'
|
43
|
+
))
|
30
44
|
WebMock.enable!
|
31
45
|
end
|
32
46
|
end
|
data/spec/support/api_helper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
|
3
|
-
shared_examples 'a
|
4
|
-
let(:
|
3
|
+
shared_examples 'a model' do |shared_options = {}|
|
4
|
+
let(:base_model_options) { shared_options.fetch(:base_model_options, {}) }
|
5
|
+
let(:args) { ([base_model_options.merge(model_options)] + model_args) }
|
5
6
|
let(:model) { subject.new(*args) }
|
6
7
|
|
7
8
|
context 'attributes' do
|
@@ -17,18 +18,18 @@ shared_examples 'a realtime model' do |shared_options = {}|
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
context '#
|
21
|
+
context '#hash' do
|
21
22
|
let(:model_options) { { action: 5 } }
|
22
23
|
|
23
|
-
it 'provides access to #
|
24
|
-
expect(model.
|
24
|
+
it 'provides access to #hash' do
|
25
|
+
expect(model.hash).to eq(model_options)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
context '#[]' do
|
29
30
|
let(:model_options) { { unusual: 'attribute' } }
|
30
31
|
|
31
|
-
it 'provides accessor method to #
|
32
|
+
it 'provides accessor method to #hash' do
|
32
33
|
expect(model[:unusual]).to eql('attribute')
|
33
34
|
end
|
34
35
|
end
|
@@ -51,17 +52,35 @@ shared_examples 'a realtime model' do |shared_options = {}|
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
55
|
+
context '#to_msgpack' do
|
56
|
+
let(:model_options) { { name: 'test', action: 0, channel_snake_case: 'unique' } }
|
57
|
+
let(:serialized) { model.to_msgpack }
|
58
|
+
|
59
|
+
it 'returns a msgpack object with Ably payload naming' do
|
60
|
+
expect(MessagePack.unpack(serialized)).to include('channelSnakeCase' => 'unique')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context '#to_json' do
|
65
|
+
let(:model_options) { { name: 'test', action: 0, channel_snake_case: 'unique' } }
|
66
|
+
let(:serialized) { model.to_json }
|
67
|
+
|
68
|
+
it 'returns a JSON string with Ably payload naming' do
|
69
|
+
expect(JSON.parse(serialized)).to include('channelSnakeCase' => 'unique')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
54
73
|
context 'is immutable' do
|
55
74
|
let(:model_options) { { channel: 'name' } }
|
56
75
|
|
57
76
|
it 'prevents changes' do
|
58
|
-
expect { model.
|
77
|
+
expect { model.hash[:channel] = 'new' }.to raise_error RuntimeError, /can't modify frozen Hash/
|
59
78
|
end
|
60
79
|
|
61
80
|
it 'dups options' do
|
62
|
-
expect(model.
|
81
|
+
expect(model.hash[:channel]).to eql('name')
|
63
82
|
model_options[:channel] = 'new'
|
64
|
-
expect(model.
|
83
|
+
expect(model.hash[:channel]).to eql('name')
|
65
84
|
end
|
66
85
|
end
|
67
86
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
shared_examples 'a protocol message bus' do
|
2
2
|
describe '__protocol_msgbus__ PubSub' do
|
3
|
-
let(:message)
|
3
|
+
let(:message) do
|
4
|
+
Ably::Models::ProtocolMessage.new(
|
5
|
+
action: 15,
|
6
|
+
channel: 'channel',
|
7
|
+
msg_serial: 0,
|
8
|
+
messages: []
|
9
|
+
)
|
10
|
+
end
|
4
11
|
|
5
12
|
specify 'supports valid ProtocolMessage messages' do
|
6
13
|
received = 0
|
data/spec/support/test_app.rb
CHANGED
@@ -5,7 +5,7 @@ class TestApp
|
|
5
5
|
'keys' => [
|
6
6
|
{},
|
7
7
|
{
|
8
|
-
'capability' => '{ "
|
8
|
+
'capability' => '{ "cansubscribe:*":["subscribe"], "canpublish:*":["publish"], "canpublish:andpresence":["presence","publish"] }'
|
9
9
|
}
|
10
10
|
],
|
11
11
|
'namespaces' => [
|
@@ -15,28 +15,25 @@ class TestApp
|
|
15
15
|
{
|
16
16
|
'name' => 'persisted:presence_fixtures',
|
17
17
|
'presence' => [
|
18
|
-
{ 'clientId' => 'client_bool', 'clientData' => true },
|
19
|
-
{ 'clientId' => 'client_int', 'clientData' => 24 },
|
18
|
+
{ 'clientId' => 'client_bool', 'clientData' => 'true' },
|
19
|
+
{ 'clientId' => 'client_int', 'clientData' => '24' },
|
20
20
|
{ 'clientId' => 'client_string', 'clientData' => 'This is a string clientData payload' },
|
21
|
-
{ 'clientId' => 'client_json', 'clientData' => { "test" => 'This is a JSONObject clientData payload'} }
|
21
|
+
{ 'clientId' => 'client_json', 'clientData' => '{ "test" => \'This is a JSONObject clientData payload\'}' }
|
22
22
|
]
|
23
23
|
}
|
24
24
|
]
|
25
25
|
}
|
26
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
|
+
instance.create_test_app if instance_variable_get('@singleton__instance__')
|
31
|
+
end
|
32
|
+
|
27
33
|
include Singleton
|
28
34
|
|
29
35
|
def initialize
|
30
|
-
|
31
|
-
|
32
|
-
headers = {
|
33
|
-
"Accept" => "application/json",
|
34
|
-
"Content-Type" => "application/json"
|
35
|
-
}
|
36
|
-
|
37
|
-
response = Faraday.post(url, APP_SPEC.to_json, headers)
|
38
|
-
|
39
|
-
@attributes = JSON.parse(response.body)
|
36
|
+
create_test_app
|
40
37
|
end
|
41
38
|
|
42
39
|
def app_id
|
@@ -80,6 +77,19 @@ class TestApp
|
|
80
77
|
'sandbox'
|
81
78
|
end
|
82
79
|
|
80
|
+
def create_test_app
|
81
|
+
url = "#{sandbox_client.endpoint}/apps"
|
82
|
+
|
83
|
+
headers = {
|
84
|
+
"Accept" => "application/json",
|
85
|
+
"Content-Type" => "application/json"
|
86
|
+
}
|
87
|
+
|
88
|
+
response = Faraday.post(url, APP_SPEC.to_json, headers)
|
89
|
+
|
90
|
+
@attributes = JSON.parse(response.body)
|
91
|
+
end
|
92
|
+
|
83
93
|
private
|
84
94
|
def sandbox_client
|
85
95
|
@sandbox_client ||= Ably::Rest::Client.new(api_key: 'app.key:secret', tls: true, environment: environment)
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'support/model_helper'
|
3
3
|
|
4
|
-
describe Ably::
|
5
|
-
subject { Ably::
|
4
|
+
describe Ably::Models::ErrorInfo do
|
5
|
+
subject { Ably::Models::ErrorInfo }
|
6
6
|
|
7
|
-
it_behaves_like 'a
|
7
|
+
it_behaves_like 'a model', with_simple_attributes: %w(code status_code message) do
|
8
8
|
let(:model_args) { [] }
|
9
9
|
end
|
10
10
|
|
11
11
|
context '#status' do
|
12
|
-
subject { Ably::
|
12
|
+
subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
|
13
13
|
it 'is an alias for #status_code' do
|
14
14
|
expect(subject.status).to eql(subject.status_code)
|
15
15
|
expect(subject.status).to eql(401)
|
@@ -15,7 +15,7 @@ describe Ably::Models::IdiomaticRubyWrapper do
|
|
15
15
|
{
|
16
16
|
'mixedCaseChild' => 'exists'
|
17
17
|
}
|
18
|
-
]
|
18
|
+
]
|
19
19
|
}
|
20
20
|
end
|
21
21
|
subject { Ably::Models::IdiomaticRubyWrapper.new(mixed_case_data) }
|
@@ -58,8 +58,8 @@ describe Ably::Models::IdiomaticRubyWrapper do
|
|
58
58
|
expect { subject.no_key_exists_for_this }.to raise_error NoMethodError
|
59
59
|
end
|
60
60
|
|
61
|
-
specify '#
|
62
|
-
expect(subject.
|
61
|
+
specify '#hash returns raw Hash object' do
|
62
|
+
expect(subject.hash).to eql(mixed_case_data)
|
63
63
|
end
|
64
64
|
|
65
65
|
context 'recursively wrapping child objects' do
|
@@ -154,17 +154,29 @@ describe Ably::Models::IdiomaticRubyWrapper do
|
|
154
154
|
end
|
155
155
|
|
156
156
|
it 'uses mixedCase' do
|
157
|
-
expect(subject.
|
157
|
+
expect(subject.hash['newKey']).to eql('new_value')
|
158
158
|
expect(subject.new_key).to eql('new_value')
|
159
159
|
end
|
160
160
|
end
|
161
161
|
end
|
162
162
|
|
163
163
|
context 'acts like a duck' do
|
164
|
+
let(:parsed_json) { JSON.parse(subject.to_json) }
|
164
165
|
specify '#to_json returns JSON stringified' do
|
165
166
|
expect(subject.to_json).to eql(mixed_case_data.to_json)
|
166
167
|
end
|
167
168
|
|
169
|
+
specify '#to_json returns child JSON objects in the JSON stringified' do
|
170
|
+
expect(parsed_json['arrayObject']).to eql(mixed_case_data['arrayObject'])
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'with snake case JSON' do
|
174
|
+
let(:subject) { Ably::Models::IdiomaticRubyWrapper.new('wrong_case' => 'will_be_corrected')}
|
175
|
+
specify '#to_json uses mixedCase for any non mixedCase keys' do
|
176
|
+
expect(parsed_json['wrongCase']).to eql('will_be_corrected')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
168
180
|
context '#to_json with changes' do
|
169
181
|
before do
|
170
182
|
@original_mixed_case_data = mixed_case_data.to_json
|
@@ -263,13 +275,38 @@ describe Ably::Models::IdiomaticRubyWrapper do
|
|
263
275
|
context '#to_hash' do
|
264
276
|
let(:mixed_case_data) do
|
265
277
|
{
|
266
|
-
'key' => 'value'
|
278
|
+
'key' => 'value',
|
279
|
+
'childObject' => {
|
280
|
+
'child' => true
|
281
|
+
}
|
267
282
|
}
|
268
283
|
end
|
269
284
|
|
270
285
|
it 'returns a hash' do
|
271
286
|
expect(subject.to_hash).to include(key: 'value')
|
272
287
|
end
|
288
|
+
|
289
|
+
it 'converts hashes within hashes' do
|
290
|
+
expect(subject.to_hash[:child_object]).to include(child: true)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context '#to_msgpack' do
|
295
|
+
let(:mixed_case_data) do
|
296
|
+
{
|
297
|
+
'key' => 'value',
|
298
|
+
'child' => {
|
299
|
+
'with_attributes' => true
|
300
|
+
}
|
301
|
+
}
|
302
|
+
end
|
303
|
+
let(:msg_packed) { subject.to_msgpack }
|
304
|
+
let(:unpacked) { MessagePack.unpack(msg_packed) }
|
305
|
+
|
306
|
+
it 'returns a msgpack object' do
|
307
|
+
expect(unpacked).to include('key' => 'value')
|
308
|
+
expect(unpacked).to include('child' => { 'withAttributes' => true })
|
309
|
+
end
|
273
310
|
end
|
274
311
|
|
275
312
|
context '#dup' do
|
@@ -281,14 +318,14 @@ describe Ably::Models::IdiomaticRubyWrapper do
|
|
281
318
|
let(:dupe) { subject.dup }
|
282
319
|
|
283
320
|
it 'returns a new object with the underlying JSON duped' do
|
284
|
-
expect(subject.
|
285
|
-
expect(dupe.
|
321
|
+
expect(subject.hash).to be_frozen
|
322
|
+
expect(dupe.hash).to_not be_frozen
|
286
323
|
end
|
287
324
|
|
288
325
|
it 'returns a new IdiomaticRubyWrapper with the same underlying Hash object' do
|
289
326
|
expect(dupe).to be_a(Ably::Models::IdiomaticRubyWrapper)
|
290
|
-
expect(dupe.
|
291
|
-
expect(dupe.
|
327
|
+
expect(dupe.hash).to be_a(Hash)
|
328
|
+
expect(dupe.hash).to eql(mixed_case_data)
|
292
329
|
end
|
293
330
|
end
|
294
331
|
end
|