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
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/model_helper'
|
3
|
+
|
4
|
+
describe Ably::Models::Message do
|
5
|
+
include Ably::Modules::Conversions
|
6
|
+
|
7
|
+
subject { Ably::Models::Message }
|
8
|
+
let(:protocol_message_timestamp) { as_since_epoch(Time.now) }
|
9
|
+
let(:protocol_message) { Ably::Models::ProtocolMessage.new(action: 1, timestamp: protocol_message_timestamp) }
|
10
|
+
|
11
|
+
it_behaves_like 'a model', with_simple_attributes: %w(name client_id data) do
|
12
|
+
let(:model_args) { [protocol_message] }
|
13
|
+
end
|
14
|
+
|
15
|
+
context '#timestamp' do
|
16
|
+
let(:model) { subject.new({}, protocol_message) }
|
17
|
+
it 'retrieves attribute :timestamp from ProtocolMessage' do
|
18
|
+
expect(model.timestamp).to be_a(Time)
|
19
|
+
expect(model.timestamp.to_i).to be_within(1).of(Time.now.to_i)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'Java naming' do
|
24
|
+
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
25
|
+
|
26
|
+
it 'converts the attribute to ruby symbol naming convention' do
|
27
|
+
expect(model.client_id).to eql('joe')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#to_json' do
|
32
|
+
let(:json_object) { JSON.parse(model.to_json) }
|
33
|
+
|
34
|
+
context 'with valid data' do
|
35
|
+
let(:model) { subject.new({ name: 'test', clientId: 'joe' }, protocol_message) }
|
36
|
+
|
37
|
+
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
38
|
+
expect(json_object["clientId"]).to eql('joe')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with invalid data' do
|
43
|
+
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
44
|
+
|
45
|
+
it 'raises an exception' do
|
46
|
+
expect { model.to_json }.to raise_error RuntimeError, /cannot generate a valid Hash/
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'from REST request with embedded fields' do
|
52
|
+
let(:id) { SecureRandom.hex }
|
53
|
+
let(:message_time) { Time.now + 60 }
|
54
|
+
let(:timestamp) { as_since_epoch(message_time) }
|
55
|
+
let(:model) { subject.new(id: id, timestamp: timestamp) }
|
56
|
+
|
57
|
+
context 'with protocol message' do
|
58
|
+
specify '#id prefers embedded ID' do
|
59
|
+
expect(model.id).to eql(id)
|
60
|
+
end
|
61
|
+
|
62
|
+
specify '#timestamp prefers embedded timestamp' do
|
63
|
+
expect(model.timestamp.to_i).to be_within(1).of(message_time.to_i)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'without protocol message' do
|
68
|
+
specify '#id uses embedded ID' do
|
69
|
+
expect(model.id).to eql(id)
|
70
|
+
end
|
71
|
+
|
72
|
+
specify '#timestamp uses embedded timestamp' do
|
73
|
+
expect(model.timestamp.to_i).to be_within(1).of(message_time.to_i)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'part of ProtocolMessage' do
|
79
|
+
let(:ably_time) { Time.now + 5 }
|
80
|
+
let(:message_serial) { SecureRandom.random_number(1_000_000) }
|
81
|
+
let(:connection_id) { SecureRandom.hex }
|
82
|
+
|
83
|
+
let(:message_0_payload) do
|
84
|
+
{
|
85
|
+
'string_key' => 'string_value',
|
86
|
+
1 => 2,
|
87
|
+
true => false
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:message_0_json) do
|
92
|
+
{
|
93
|
+
name: 'zero',
|
94
|
+
data: message_0_payload
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
let(:message_1_json) do
|
99
|
+
{
|
100
|
+
name: 'one',
|
101
|
+
data: 'simple string'
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:protocol_message_id) { SecureRandom.hex }
|
106
|
+
let(:protocol_message) do
|
107
|
+
Ably::Models::ProtocolMessage.new({
|
108
|
+
action: :message,
|
109
|
+
timestamp: ably_time.to_i,
|
110
|
+
msg_serial: message_serial,
|
111
|
+
id: protocol_message_id,
|
112
|
+
messages: [
|
113
|
+
message_0_json, message_1_json
|
114
|
+
]
|
115
|
+
})
|
116
|
+
end
|
117
|
+
|
118
|
+
let(:message_0) { protocol_message.messages.first }
|
119
|
+
let(:message_1) { protocol_message.messages.last }
|
120
|
+
|
121
|
+
it 'should generate a message ID from the index, serial and connection id' do
|
122
|
+
expect(message_0.id).to eql("#{protocol_message_id}:0")
|
123
|
+
expect(message_1.id).to eql("#{protocol_message_id}:1")
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should not modify the data payload' do
|
127
|
+
expect(message_0.data['string_key']).to eql('string_value')
|
128
|
+
expect(message_0.data[1]).to eql(2)
|
129
|
+
expect(message_0.data[true]).to eql(false)
|
130
|
+
expect(message_0.data).to eql(message_0_payload)
|
131
|
+
|
132
|
+
expect(message_1.data).to eql('simple string')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should not allow changes to the payload' do
|
136
|
+
expect { message_0.data["test"] = true }.to raise_error RuntimeError, /can't modify frozen Hash/
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'Message conversion method' do
|
141
|
+
let(:json) { { name: 'test', data: 'conversion' } }
|
142
|
+
|
143
|
+
context 'with JSON' do
|
144
|
+
context 'without ProtocolMessage' do
|
145
|
+
subject { Ably::Models.Message(json) }
|
146
|
+
|
147
|
+
it 'returns a Message object' do
|
148
|
+
expect(subject).to be_a(Ably::Models::Message)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'initializes with the JSON' do
|
152
|
+
expect(subject.name).to eql('test')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'raises an exception when accessing ProtocolMessage' do
|
156
|
+
expect { subject.protocol_message }.to raise_error RuntimeError
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'has no ProtocolMessage' do
|
160
|
+
expect(subject.assigned_to_protocol_message?).to eql(false)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'with ProtocolMessage' do
|
165
|
+
subject { Ably::Models.Message(json, protocol_message) }
|
166
|
+
|
167
|
+
it 'returns a Message object' do
|
168
|
+
expect(subject).to be_a(Ably::Models::Message)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'initializes with the JSON' do
|
172
|
+
expect(subject.name).to eql('test')
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'provides access to ProtocolMessage' do
|
176
|
+
expect(subject.protocol_message).to eql(protocol_message)
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'has a ProtocolMessage' do
|
180
|
+
expect(subject.assigned_to_protocol_message?).to eql(true)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'with another Message' do
|
186
|
+
let(:message) { Ably::Models::Message.new(json) }
|
187
|
+
|
188
|
+
context 'without ProtocolMessage' do
|
189
|
+
subject { Ably::Models.Message(message) }
|
190
|
+
|
191
|
+
it 'returns a Message object' do
|
192
|
+
expect(subject).to be_a(Ably::Models::Message)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'initializes with the JSON' do
|
196
|
+
expect(subject.name).to eql('test')
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'raises an exception when accessing ProtocolMessage' do
|
200
|
+
expect { subject.protocol_message }.to raise_error RuntimeError
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'has no ProtocolMessage' do
|
204
|
+
expect(subject.assigned_to_protocol_message?).to eql(false)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'with ProtocolMessage' do
|
209
|
+
subject { Ably::Models.Message(message, protocol_message) }
|
210
|
+
|
211
|
+
it 'returns a Message object' do
|
212
|
+
expect(subject).to be_a(Ably::Models::Message)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'initializes with the JSON' do
|
216
|
+
expect(subject.name).to eql('test')
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'provides access to ProtocolMessage' do
|
220
|
+
expect(subject.protocol_message).to eql(protocol_message)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'has a ProtocolMessage' do
|
224
|
+
expect(subject.assigned_to_protocol_message?).to eql(true)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
|
-
describe Ably::
|
5
|
-
let(:
|
4
|
+
describe Ably::Models::PaginatedResource do
|
5
|
+
let(:paginated_resource_class) { Ably::Models::PaginatedResource }
|
6
6
|
let(:headers) { Hash.new }
|
7
7
|
let(:client) do
|
8
|
-
|
8
|
+
instance_double('Ably::Rest::Client').tap do |client|
|
9
9
|
allow(client).to receive(:get).and_return(http_response)
|
10
10
|
end
|
11
11
|
end
|
@@ -16,15 +16,15 @@ describe Ably::Rest::Models::PagedResource do
|
|
16
16
|
]
|
17
17
|
end
|
18
18
|
let(:http_response) do
|
19
|
-
|
19
|
+
instance_double('Faraday::Response', {
|
20
20
|
body: body,
|
21
21
|
headers: headers
|
22
22
|
})
|
23
23
|
end
|
24
24
|
let(:base_url) { 'http://rest.ably.io/channels/channel_name' }
|
25
25
|
let(:full_url) { "#{base_url}/whatever?param=exists" }
|
26
|
-
let(:
|
27
|
-
let(:first_paged_request) {
|
26
|
+
let(:paginated_resource_options) { Hash.new }
|
27
|
+
let(:first_paged_request) { paginated_resource_class.new(http_response, full_url, client, paginated_resource_options) }
|
28
28
|
subject { first_paged_request }
|
29
29
|
|
30
30
|
it 'returns correct length from body' do
|
@@ -50,8 +50,16 @@ describe Ably::Rest::Models::PagedResource do
|
|
50
50
|
expect(subject[2]).to be_nil
|
51
51
|
end
|
52
52
|
|
53
|
+
specify '#first gets the first item in page' do
|
54
|
+
expect(subject.first[:id]).to eql(body[0][:id])
|
55
|
+
end
|
56
|
+
|
57
|
+
specify '#last gets the last item in page' do
|
58
|
+
expect(subject.last[:id]).to eql(body[1][:id])
|
59
|
+
end
|
60
|
+
|
53
61
|
context 'with coercion' do
|
54
|
-
let(:
|
62
|
+
let(:paginated_resource_options) { { coerce_into: 'OpenStruct' } }
|
55
63
|
|
56
64
|
it 'returns coerced objects' do
|
57
65
|
expect(subject.first).to be_a(OpenStruct)
|
@@ -130,8 +138,8 @@ describe Ably::Rest::Models::PagedResource do
|
|
130
138
|
expect(client).to receive(:get).with("#{base_url}/history?index=1").and_return(next_http_response).once
|
131
139
|
end
|
132
140
|
|
133
|
-
it 'returns another
|
134
|
-
expect(subject).to be_a(
|
141
|
+
it 'returns another PaginatedResource' do
|
142
|
+
expect(subject).to be_a(paginated_resource_class)
|
135
143
|
end
|
136
144
|
|
137
145
|
it 'retrieves the next page of results' do
|
@@ -158,8 +166,8 @@ describe Ably::Rest::Models::PagedResource do
|
|
158
166
|
end
|
159
167
|
subject { first_paged_request.next_page.first_page }
|
160
168
|
|
161
|
-
it 'returns a
|
162
|
-
expect(subject).to be_a(
|
169
|
+
it 'returns a PaginatedResource' do
|
170
|
+
expect(subject).to be_a(paginated_resource_class)
|
163
171
|
end
|
164
172
|
|
165
173
|
it 'retrieves the first page of results' do
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/model_helper'
|
3
|
+
|
4
|
+
describe Ably::Models::PresenceMessage do
|
5
|
+
include Ably::Modules::Conversions
|
6
|
+
|
7
|
+
subject { Ably::Models::PresenceMessage }
|
8
|
+
let(:protocol_message_timestamp) { as_since_epoch(Time.now) }
|
9
|
+
let(:protocol_message) { Ably::Models::ProtocolMessage.new(action: 1, timestamp: protocol_message_timestamp) }
|
10
|
+
|
11
|
+
it_behaves_like 'a model', with_simple_attributes: %w(client_id member_id client_data) do
|
12
|
+
let(:model_args) { [protocol_message] }
|
13
|
+
end
|
14
|
+
|
15
|
+
context '#timestamp' do
|
16
|
+
let(:model) { subject.new({}, protocol_message) }
|
17
|
+
it 'retrieves attribute :timestamp from ProtocolMessage' do
|
18
|
+
expect(model.timestamp).to be_a(Time)
|
19
|
+
expect(model.timestamp.to_i).to be_within(1).of(Time.now.to_i)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'Java naming' do
|
24
|
+
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
25
|
+
|
26
|
+
it 'converts the attribute to ruby symbol naming convention' do
|
27
|
+
expect(model.client_id).to eql('joe')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with action' do
|
32
|
+
let(:model) { subject.new({ action: 0 }, protocol_message) }
|
33
|
+
|
34
|
+
it 'provides action as an Enum' do
|
35
|
+
expect(model.action).to eq(:enter)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'without action' do
|
40
|
+
let(:model) { subject.new({}, protocol_message) }
|
41
|
+
|
42
|
+
it 'raises an exception when accessed' do
|
43
|
+
expect { model.action }.to raise_error KeyError
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context '#to_json' do
|
48
|
+
let(:json_object) { JSON.parse(model.to_json) }
|
49
|
+
|
50
|
+
context 'with valid data' do
|
51
|
+
let(:model) { subject.new({ action: 'enter', clientId: 'joe' }, protocol_message) }
|
52
|
+
|
53
|
+
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
54
|
+
expect(json_object["clientId"]).to eql('joe')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with invalid data' do
|
59
|
+
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
60
|
+
|
61
|
+
it 'raises an exception' do
|
62
|
+
expect { model.to_json }.to raise_error KeyError, /cannot generate a valid Hash/
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'from REST request with embedded fields' do
|
68
|
+
let(:id) { SecureRandom.hex }
|
69
|
+
let(:message_time) { Time.now + 60 }
|
70
|
+
let(:timestamp) { as_since_epoch(message_time) }
|
71
|
+
let(:model) { subject.new(id: id, timestamp: timestamp) }
|
72
|
+
|
73
|
+
context 'with protocol message' do
|
74
|
+
specify '#id prefers embedded ID' do
|
75
|
+
expect(model.id).to eql(id)
|
76
|
+
end
|
77
|
+
|
78
|
+
specify '#timestamp prefers embedded timestamp' do
|
79
|
+
expect(model.timestamp.to_i).to be_within(1).of(message_time.to_i)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'without protocol message' do
|
84
|
+
specify '#id uses embedded ID' do
|
85
|
+
expect(model.id).to eql(id)
|
86
|
+
end
|
87
|
+
|
88
|
+
specify '#timestamp uses embedded timestamp' do
|
89
|
+
expect(model.timestamp.to_i).to be_within(1).of(message_time.to_i)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'part of ProtocolMessage' do
|
95
|
+
let(:ably_time) { Time.now + 5 }
|
96
|
+
let(:message_serial) { SecureRandom.random_number(1_000_000) }
|
97
|
+
let(:connection_id) { SecureRandom.hex }
|
98
|
+
|
99
|
+
let(:presence_0_payload) { SecureRandom.hex(8) }
|
100
|
+
let(:presence_0_json) do
|
101
|
+
{
|
102
|
+
client_id: 'zero',
|
103
|
+
client_data: presence_0_payload
|
104
|
+
}
|
105
|
+
end
|
106
|
+
let(:presence_1_payload) { SecureRandom.hex(8) }
|
107
|
+
let(:presence_1_json) do
|
108
|
+
{
|
109
|
+
client_id: 'one',
|
110
|
+
client_data: presence_1_payload
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
let(:protocol_message_id) { SecureRandom.hex }
|
115
|
+
let(:protocol_message) do
|
116
|
+
Ably::Models::ProtocolMessage.new({
|
117
|
+
action: :message,
|
118
|
+
timestamp: ably_time.to_i,
|
119
|
+
msg_serial: message_serial,
|
120
|
+
id: protocol_message_id,
|
121
|
+
presence: [
|
122
|
+
presence_0_json, presence_1_json
|
123
|
+
]
|
124
|
+
})
|
125
|
+
end
|
126
|
+
|
127
|
+
let(:presence_0) { protocol_message.presence.first }
|
128
|
+
let(:presence_1) { protocol_message.presence.last }
|
129
|
+
|
130
|
+
it 'should generate a message ID from the index, serial and connection id' do
|
131
|
+
expect(presence_0.id).to eql("#{protocol_message_id}:0")
|
132
|
+
expect(presence_1.id).to eql("#{protocol_message_id}:1")
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should not modify the data payload' do
|
136
|
+
expect(presence_0.client_data).to eql(presence_0_payload)
|
137
|
+
expect(presence_1.client_data).to eql(presence_1_payload)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'PresenceMessage conversion method' do
|
142
|
+
let(:json) { { client_id: 'test' } }
|
143
|
+
|
144
|
+
context 'with JSON' do
|
145
|
+
context 'without ProtocolMessage' do
|
146
|
+
subject { Ably::Models.PresenceMessage(json) }
|
147
|
+
|
148
|
+
it 'returns a PresenceMessage object' do
|
149
|
+
expect(subject).to be_a(Ably::Models::PresenceMessage)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'initializes with the JSON' do
|
153
|
+
expect(subject.client_id).to eql('test')
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'raises an exception when accessing ProtocolMessage' do
|
157
|
+
expect { subject.protocol_message }.to raise_error RuntimeError
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'has no ProtocolMessage' do
|
161
|
+
expect(subject.assigned_to_protocol_message?).to eql(false)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'with ProtocolMessage' do
|
166
|
+
subject { Ably::Models.PresenceMessage(json, protocol_message) }
|
167
|
+
|
168
|
+
it 'returns a PresenceMessage object' do
|
169
|
+
expect(subject).to be_a(Ably::Models::PresenceMessage)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'initializes with the JSON' do
|
173
|
+
expect(subject.client_id).to eql('test')
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'provides access to ProtocolMessage' do
|
177
|
+
expect(subject.protocol_message).to eql(protocol_message)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'has a ProtocolMessage' do
|
181
|
+
expect(subject.assigned_to_protocol_message?).to eql(true)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'with another PresenceMessage' do
|
187
|
+
let(:message) { Ably::Models::PresenceMessage.new(json) }
|
188
|
+
|
189
|
+
context 'without ProtocolMessage' do
|
190
|
+
subject { Ably::Models.PresenceMessage(message) }
|
191
|
+
|
192
|
+
it 'returns a PresenceMessage object' do
|
193
|
+
expect(subject).to be_a(Ably::Models::PresenceMessage)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'initializes with the JSON' do
|
197
|
+
expect(subject.client_id).to eql('test')
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'raises an exception when accessing ProtocolMessage' do
|
201
|
+
expect { subject.protocol_message }.to raise_error RuntimeError
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'has no ProtocolMessage' do
|
205
|
+
expect(subject.assigned_to_protocol_message?).to eql(false)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'with ProtocolMessage' do
|
210
|
+
subject { Ably::Models.PresenceMessage(message, protocol_message) }
|
211
|
+
|
212
|
+
it 'returns a PresenceMessage object' do
|
213
|
+
expect(subject).to be_a(Ably::Models::PresenceMessage)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'initializes with the JSON' do
|
217
|
+
expect(subject.client_id).to eql('test')
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'provides access to ProtocolMessage' do
|
221
|
+
expect(subject.protocol_message).to eql(protocol_message)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'has a ProtocolMessage' do
|
225
|
+
expect(subject.assigned_to_protocol_message?).to eql(true)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|