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