ably 1.1.7 → 1.2.1
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/.github/workflows/check.yml +1 -1
- data/CHANGELOG.md +99 -0
- data/COPYRIGHT +1 -1
- data/README.md +2 -2
- data/SPEC.md +0 -7
- data/UPDATING.md +30 -0
- data/ably.gemspec +11 -24
- data/lib/ably/auth.rb +8 -8
- data/lib/ably/logger.rb +4 -4
- data/lib/ably/models/channel_options.rb +97 -0
- data/lib/ably/models/connection_details.rb +8 -2
- data/lib/ably/models/delta_extras.rb +29 -0
- data/lib/ably/models/device_details.rb +1 -1
- data/lib/ably/models/error_info.rb +6 -2
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/ably/models/message.rb +14 -3
- data/lib/ably/models/protocol_message.rb +23 -14
- data/lib/ably/models/token_details.rb +7 -2
- data/lib/ably/models/token_request.rb +1 -1
- data/lib/ably/modules/ably.rb +1 -1
- data/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/ably/modules/conversions.rb +34 -0
- data/lib/ably/realtime/auth.rb +2 -2
- data/lib/ably/realtime/channel/channel_manager.rb +16 -4
- data/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
- data/lib/ably/realtime/channel/publisher.rb +3 -2
- data/lib/ably/realtime/channel.rb +54 -22
- data/lib/ably/realtime/channels.rb +1 -1
- data/lib/ably/realtime/connection/connection_manager.rb +13 -4
- data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
- data/lib/ably/realtime/connection.rb +0 -3
- data/lib/ably/rest/channel.rb +28 -35
- data/lib/ably/rest/client.rb +23 -8
- data/lib/ably/rest/middleware/encoder.rb +1 -1
- data/lib/ably/rest/middleware/exceptions.rb +1 -1
- data/lib/ably/rest/middleware/external_exceptions.rb +1 -1
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +1 -1
- data/lib/ably/rest/middleware/logger.rb +1 -1
- data/lib/ably/rest/middleware/parse_json.rb +1 -1
- data/lib/ably/rest/middleware/parse_message_pack.rb +1 -1
- data/lib/ably/util/crypto.rb +1 -1
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/channel_spec.rb +458 -27
- data/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/spec/acceptance/realtime/connection_failures_spec.rb +56 -1
- data/spec/acceptance/realtime/connection_spec.rb +270 -1
- data/spec/acceptance/realtime/message_spec.rb +77 -0
- data/spec/acceptance/realtime/presence_spec.rb +18 -1
- data/spec/acceptance/rest/auth_spec.rb +18 -0
- data/spec/acceptance/rest/channel_spec.rb +73 -11
- data/spec/acceptance/rest/channels_spec.rb +23 -6
- data/spec/acceptance/rest/client_spec.rb +3 -3
- data/spec/acceptance/rest/message_spec.rb +61 -3
- data/spec/lib/unit/models/channel_options_spec.rb +52 -0
- data/spec/run_parallel_tests +2 -7
- data/spec/support/test_app.rb +1 -1
- data/spec/unit/logger_spec.rb +6 -14
- data/spec/unit/models/delta_extras_spec.rb +14 -0
- data/spec/unit/models/error_info_spec.rb +17 -1
- data/spec/unit/models/message_spec.rb +38 -0
- data/spec/unit/models/protocol_message_spec.rb +77 -27
- data/spec/unit/models/token_details_spec.rb +14 -0
- data/spec/unit/realtime/channel_spec.rb +2 -1
- data/spec/unit/realtime/channels_spec.rb +53 -15
- data/spec/unit/rest/channel_spec.rb +40 -7
- data/spec/unit/rest/channels_spec.rb +81 -14
- data/spec/unit/rest/client_spec.rb +27 -0
- metadata +46 -11
@@ -1081,7 +1081,7 @@ describe Ably::Rest::Client do
|
|
1081
1081
|
end
|
1082
1082
|
|
1083
1083
|
context 'version headers', :webmock do
|
1084
|
-
[nil, 'ably-ruby/1.1.1 ruby/1.
|
1084
|
+
[nil, 'ably-ruby/1.1.1 ruby/3.1.1'].each do |agent|
|
1085
1085
|
context "with #{agent ? "custom #{agent}" : 'default'} agent" do
|
1086
1086
|
let(:client_options) { default_options.merge(key: api_key, agent: agent) }
|
1087
1087
|
|
@@ -1097,7 +1097,7 @@ describe Ably::Rest::Client do
|
|
1097
1097
|
it 'sends a protocol version and lib version header (#G4, #RSC7a, #RSC7b)' do
|
1098
1098
|
client.channels.get('foo').publish("event")
|
1099
1099
|
expect(publish_message_stub).to have_been_requested
|
1100
|
-
expect(Ably::PROTOCOL_VERSION).to eql('1.
|
1100
|
+
expect(Ably::PROTOCOL_VERSION).to eql('1.2')
|
1101
1101
|
end
|
1102
1102
|
end
|
1103
1103
|
end
|
@@ -1231,7 +1231,7 @@ describe Ably::Rest::Client do
|
|
1231
1231
|
end
|
1232
1232
|
end
|
1233
1233
|
|
1234
|
-
context 'request_id generation' do
|
1234
|
+
context 'request_id generation (#RSC7c)' do
|
1235
1235
|
context 'Timeout error' do
|
1236
1236
|
context 'with option add_request_ids: true and no fallback hosts', :webmock, :prevent_log_stubbing do
|
1237
1237
|
let(:custom_logger_object) { TestLogger.new }
|
@@ -24,6 +24,57 @@ describe Ably::Rest::Channel, 'messages' do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
context 'a single Message object (#RSL1a)' do
|
28
|
+
let(:name) { random_str }
|
29
|
+
let(:data) { random_str }
|
30
|
+
let(:message) { Ably::Models::Message.new(name: name, data: data) }
|
31
|
+
|
32
|
+
it 'publishes the message' do
|
33
|
+
channel.publish(message)
|
34
|
+
expect(channel.history.items.length).to eql(1)
|
35
|
+
message = channel.history.items.first
|
36
|
+
expect(message.name).to eq(name)
|
37
|
+
expect(message.data).to eq(data)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'an array of Message objects (#RSL1a)' do
|
42
|
+
let(:data) { random_str }
|
43
|
+
let(:message1) { Ably::Models::Message.new(name: random_str, data: data) }
|
44
|
+
let(:message2) { Ably::Models::Message.new(name: random_str, data: data) }
|
45
|
+
let(:message3) { Ably::Models::Message.new(name: random_str, data: data) }
|
46
|
+
|
47
|
+
it 'publishes three messages' do
|
48
|
+
channel.publish([message1, message2, message3])
|
49
|
+
expect(channel.history.items.length).to eql(3)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'an array of hashes (#RSL1a)' do
|
54
|
+
let(:data) { random_str }
|
55
|
+
let(:message1) { { name: random_str, data: data } }
|
56
|
+
let(:message2) { { name: random_str, data: data } }
|
57
|
+
let(:message3) { { name: random_str, data: data } }
|
58
|
+
|
59
|
+
it 'publishes three messages' do
|
60
|
+
channel.publish([message1, message2, message3])
|
61
|
+
expect(channel.history.items.length).to eql(3)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'a name with data payload (#RSL1a, #RSL1b)' do
|
66
|
+
let(:name) { random_str }
|
67
|
+
let(:data) { random_str }
|
68
|
+
|
69
|
+
it 'publishes the message' do
|
70
|
+
channel.publish(name, data)
|
71
|
+
expect(channel.history.items.length).to eql(1)
|
72
|
+
message = channel.history.items.first
|
73
|
+
expect(message.name).to eq(name)
|
74
|
+
expect(message.data).to eq(data)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
27
78
|
context 'with supported data payload content type' do
|
28
79
|
context 'JSON Object (Hash)' do
|
29
80
|
let(:data) { { 'Hash' => 'true' } }
|
@@ -153,13 +204,20 @@ describe Ably::Rest::Channel, 'messages' do
|
|
153
204
|
end
|
154
205
|
end
|
155
206
|
|
156
|
-
specify 'idempotent publishing is disabled by default with 1.1 (#TO3n)' do
|
207
|
+
specify 'idempotent publishing is disabled by default with <= 1.1 (#TO3n)' do
|
208
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.0'
|
209
|
+
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
210
|
+
expect(client.idempotent_rest_publishing).to be_falsey
|
211
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.1'
|
157
212
|
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
158
213
|
expect(client.idempotent_rest_publishing).to be_falsey
|
159
214
|
end
|
160
215
|
|
161
|
-
specify 'idempotent publishing is enabled by default with 1.2 (#TO3n)' do
|
162
|
-
stub_const 'Ably::
|
216
|
+
specify 'idempotent publishing is enabled by default with >= 1.2 (#TO3n)' do
|
217
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.2'
|
218
|
+
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
219
|
+
expect(client.idempotent_rest_publishing).to be_truthy
|
220
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.3'
|
163
221
|
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
164
222
|
expect(client.idempotent_rest_publishing).to be_truthy
|
165
223
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Ably::Models::ChannelOptions do
|
6
|
+
let(:modes) { nil }
|
7
|
+
let(:params) { {} }
|
8
|
+
let(:options) { described_class.new(modes: modes, params: params) }
|
9
|
+
|
10
|
+
describe '#modes_to_flags' do
|
11
|
+
let(:modes) { %w[publish subscribe presence_subscribe] }
|
12
|
+
|
13
|
+
subject(:protocol_message) do
|
14
|
+
Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Attach, flags: options.modes_to_flags)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'converts modes to ProtocolMessage#flags correctly' do
|
18
|
+
expect(protocol_message.has_attach_publish_flag?).to eq(true)
|
19
|
+
expect(protocol_message.has_attach_subscribe_flag?).to eq(true)
|
20
|
+
expect(protocol_message.has_attach_presence_subscribe_flag?).to eq(true)
|
21
|
+
|
22
|
+
expect(protocol_message.has_attach_resume_flag?).to eq(false)
|
23
|
+
expect(protocol_message.has_attach_presence_flag?).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#set_modes_from_flags' do
|
28
|
+
let(:subscribe_flag) { 262144 }
|
29
|
+
|
30
|
+
it 'converts flags to ChannelOptions#modes correctly' do
|
31
|
+
result = options.set_modes_from_flags(subscribe_flag)
|
32
|
+
|
33
|
+
expect(result).to eq(options.modes)
|
34
|
+
expect(options.modes.map(&:to_sym)).to eq(%i[subscribe])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#set_params' do
|
39
|
+
let(:previous_params) { { example_attribute: 1 } }
|
40
|
+
let(:new_params) { { new_attribute: 1 } }
|
41
|
+
let(:params) { previous_params }
|
42
|
+
|
43
|
+
it 'should be able to overwrite attributes' do
|
44
|
+
expect { options.set_params(new_params) }.to \
|
45
|
+
change { options.params }.from(previous_params).to(new_params)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should be able to make params empty' do # (1)
|
49
|
+
expect { options.set_params({}) }.to change { options.params }.from(previous_params).to({})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/run_parallel_tests
CHANGED
@@ -11,13 +11,8 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
|
11
11
|
bundle exec rspec "${DIR}/unit"
|
12
12
|
unit_status=$?
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
# So it will be jumbled sadly for 1.9.*
|
17
|
-
bundle exec parallel_rspec "${DIR}/acceptance"
|
18
|
-
else
|
19
|
-
bundle exec parallel_rspec "${DIR}/acceptance" --prefix-output-with-test-env-number
|
20
|
-
fi
|
14
|
+
bundle exec parallel_rspec "${DIR}/acceptance" --prefix-output-with-test-env-number
|
15
|
+
|
21
16
|
acceptance_status=$?
|
22
17
|
|
23
18
|
if [ $unit_status -ne 0 ]; then
|
data/spec/support/test_app.rb
CHANGED
@@ -59,7 +59,7 @@ class TestApp
|
|
59
59
|
|
60
60
|
url = "#{sandbox_client.endpoint}/apps/#{app_id}"
|
61
61
|
|
62
|
-
basic_auth = Base64.
|
62
|
+
basic_auth = Base64.urlsafe_encode64(api_key).chomp
|
63
63
|
headers = { "Authorization" => "Basic #{basic_auth}" }
|
64
64
|
|
65
65
|
Faraday.delete(url, nil, headers)
|
data/spec/unit/logger_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Ably::Logger do
|
3
|
+
describe Ably::Logger, :prevent_log_stubbing do
|
4
4
|
let(:rest_client) do
|
5
5
|
instance_double('Ably::Rest::Client')
|
6
6
|
end
|
@@ -18,14 +18,10 @@ describe Ably::Logger do
|
|
18
18
|
|
19
19
|
context 'internals', :api_private do
|
20
20
|
it 'delegates to the default Logger object' do
|
21
|
-
received = false
|
22
21
|
expect(subject.logger).to be_a(::Logger)
|
23
|
-
|
24
|
-
|
25
|
-
received = true
|
26
|
-
end
|
22
|
+
expect(subject.logger).to receive(:warn).with('message')
|
23
|
+
|
27
24
|
subject.warn 'message'
|
28
|
-
expect(received).to be_truthy
|
29
25
|
end
|
30
26
|
|
31
27
|
context 'formatter' do
|
@@ -136,18 +132,14 @@ describe Ably::Logger do
|
|
136
132
|
end
|
137
133
|
|
138
134
|
it 'delegates log messages to logger', :api_private do
|
139
|
-
|
140
|
-
|
141
|
-
expect(args.concat([block ? block.call : nil]).join(',')).to match(/message/)
|
142
|
-
received = true
|
143
|
-
end
|
135
|
+
expect(custom_logger_object).to receive(:fatal).with('message')
|
136
|
+
|
144
137
|
subject.fatal 'message'
|
145
|
-
expect(received).to be_truthy
|
146
138
|
end
|
147
139
|
end
|
148
140
|
end
|
149
141
|
|
150
|
-
context 'with blocks'
|
142
|
+
context 'with blocks' do
|
151
143
|
it 'does not call the block unless the log level is met' do
|
152
144
|
log_level_blocks = []
|
153
145
|
subject.warn { log_level_blocks << :warn }
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Ably::Models::DeltaExtras do
|
5
|
+
subject { described_class.new({ format: 'vcdiff', from: '1234-4567-8910-1001-1111'}) }
|
6
|
+
|
7
|
+
it 'should have `from` attribute' do
|
8
|
+
expect(subject.from).to eq('1234-4567-8910-1001-1111')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have `format` attribute' do
|
12
|
+
expect(subject.format).to eq('vcdiff')
|
13
|
+
end
|
14
|
+
end
|
@@ -5,7 +5,7 @@ describe Ably::Models::ErrorInfo do
|
|
5
5
|
subject { Ably::Models::ErrorInfo }
|
6
6
|
|
7
7
|
context '#TI1, #TI4' do
|
8
|
-
it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message) do
|
8
|
+
it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message request_id cause) do
|
9
9
|
let(:model_args) { [] }
|
10
10
|
end
|
11
11
|
end
|
@@ -18,6 +18,22 @@ describe Ably::Models::ErrorInfo do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
context '#request_id #RSC7c' do
|
22
|
+
subject { Ably::Models::ErrorInfo.new('request_id' => '123-456-789-001') }
|
23
|
+
|
24
|
+
it 'should return request ID' do
|
25
|
+
expect(subject.request_id).to eql('123-456-789-001')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#cause #TI1' do
|
30
|
+
subject { Ably::Models::ErrorInfo.new('cause' => Ably::Models::ErrorInfo.new({})) }
|
31
|
+
|
32
|
+
it 'should return cause attribute' do
|
33
|
+
expect(subject.cause).to be_kind_of(Ably::Models::ErrorInfo)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
21
37
|
context 'log entries container help link #TI5' do
|
22
38
|
context 'without an error code' do
|
23
39
|
subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
|
@@ -270,6 +270,20 @@ describe Ably::Models::Message do
|
|
270
270
|
end
|
271
271
|
end
|
272
272
|
|
273
|
+
describe '#protocol_message_index (#RTL21)' do
|
274
|
+
let(:messages) { [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }] }
|
275
|
+
|
276
|
+
let(:protocol_message) do
|
277
|
+
Ably::Models::ProtocolMessage.new({ action: 1 }.merge(messages: messages))
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should return correct protocol_message_index' do
|
281
|
+
expect(protocol_message.messages[0].protocol_message_index).to eq(0)
|
282
|
+
expect(protocol_message.messages[1].protocol_message_index).to eq(1)
|
283
|
+
expect(protocol_message.messages[2].protocol_message_index).to eq(2)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
273
287
|
context 'from REST request with embedded fields', :api_private do
|
274
288
|
let(:id) { random_str }
|
275
289
|
let(:protocol_message_id) { random_str }
|
@@ -606,4 +620,28 @@ describe Ably::Models::Message do
|
|
606
620
|
end
|
607
621
|
end
|
608
622
|
end
|
623
|
+
|
624
|
+
context '#delta_extras (TM2i)' do
|
625
|
+
let(:delta_extras) { message.delta_extras }
|
626
|
+
|
627
|
+
context 'when delta' do
|
628
|
+
let(:message) { subject.new({ extras: { delta: { from: '1234-1234-5678-9009', format: 'vcdiff' } } }) }
|
629
|
+
|
630
|
+
it 'should return vcdiff format' do
|
631
|
+
expect(delta_extras.format).to eq('vcdiff')
|
632
|
+
end
|
633
|
+
|
634
|
+
it 'should return 1234-1234-5678-9009 message id' do
|
635
|
+
expect(delta_extras.from).to eq('1234-1234-5678-9009')
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
context 'when no delta' do
|
640
|
+
let(:message) { subject.new({ extras: {} }) }
|
641
|
+
|
642
|
+
it 'should return nil' do
|
643
|
+
expect(delta_extras).to eq(nil)
|
644
|
+
end
|
645
|
+
end
|
646
|
+
end
|
609
647
|
end
|
@@ -10,9 +10,9 @@ describe Ably::Models::ProtocolMessage do
|
|
10
10
|
subject.new({ action: 1 }.merge(options))
|
11
11
|
end
|
12
12
|
|
13
|
-
# TR4n, TR4b, TR4c, TR4d
|
13
|
+
# TR4n, TR4b, TR4c, TR4d
|
14
14
|
it_behaves_like 'a model',
|
15
|
-
with_simple_attributes: %w(id channel channel_serial connection_id
|
15
|
+
with_simple_attributes: %w(id channel channel_serial connection_id),
|
16
16
|
base_model_options: { action: 1 } do
|
17
17
|
|
18
18
|
let(:model_args) { [] }
|
@@ -176,6 +176,28 @@ describe Ably::Models::ProtocolMessage do
|
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
179
|
+
context 'when attach resumed flag' do
|
180
|
+
context 'flags is 34' do
|
181
|
+
let(:protocol_message) { new_protocol_message(flags: 34) }
|
182
|
+
|
183
|
+
it '#has_attach_resume_flag? is true' do
|
184
|
+
expect(protocol_message.has_attach_resume_flag?).to be_truthy
|
185
|
+
end
|
186
|
+
|
187
|
+
it '#has_attach_presence_flag? is false' do
|
188
|
+
expect(protocol_message.has_attach_presence_flag?).to be_falsey
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'flags is 0' do
|
193
|
+
let(:protocol_message) { new_protocol_message(flags: 0) }
|
194
|
+
|
195
|
+
it 'should raise an exception if flags is a float number' do
|
196
|
+
expect(protocol_message.has_attach_resume_flag?).to be_falsy
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
179
201
|
context 'when channel resumed and presence flags present' do
|
180
202
|
let(:protocol_message) { new_protocol_message(flags: 5) }
|
181
203
|
|
@@ -201,6 +223,24 @@ describe Ably::Models::ProtocolMessage do
|
|
201
223
|
end
|
202
224
|
end
|
203
225
|
|
226
|
+
context '#params (#RTL4k1)' do
|
227
|
+
let(:params) do
|
228
|
+
{ foo: :bar }
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'when present' do
|
232
|
+
specify do
|
233
|
+
expect(new_protocol_message({ params: params }).params).to eq(params)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'when empty' do
|
238
|
+
specify do
|
239
|
+
expect(new_protocol_message({}).params).to eq({})
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
204
244
|
context '#has_connection_serial?' do
|
205
245
|
context 'without connection_serial' do
|
206
246
|
let(:protocol_message) { new_protocol_message({}) }
|
@@ -308,6 +348,26 @@ describe Ably::Models::ProtocolMessage do
|
|
308
348
|
end
|
309
349
|
end
|
310
350
|
|
351
|
+
context '#messages (#RTL21)' do
|
352
|
+
let(:protocol_message) do
|
353
|
+
new_protocol_message(messages: [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }])
|
354
|
+
end
|
355
|
+
|
356
|
+
before do
|
357
|
+
message = Ably::Models::Message(name: 'test4')
|
358
|
+
message.assign_to_protocol_message(protocol_message)
|
359
|
+
protocol_message.add_message(message)
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'contains Message objects in ascending order' do
|
363
|
+
expect(protocol_message.messages.count).to eql(4)
|
364
|
+
protocol_message.messages.each_with_index do |message, index|
|
365
|
+
expect(message.protocol_message_index).to eql(index)
|
366
|
+
expect(message.name).to include('test')
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
311
371
|
context '#presence (#TR4l)' do
|
312
372
|
let(:protocol_message) { new_protocol_message(presence: [{ action: 1, data: 'test' }]) }
|
313
373
|
|
@@ -417,41 +477,27 @@ describe Ably::Models::ProtocolMessage do
|
|
417
477
|
end
|
418
478
|
end
|
419
479
|
end
|
420
|
-
|
421
|
-
context '#connection_key (#TR4e)' do
|
422
|
-
context 'existing only in #connection_details.connection_key' do
|
423
|
-
let(:protocol_message) { new_protocol_message(connectionDetails: { connectionKey: 'key' }) }
|
424
|
-
|
425
|
-
it 'is returned' do
|
426
|
-
expect(protocol_message.connection_key).to eql('key')
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
context 'existing in both #connection_key and #connection_details.connection_key' do
|
431
|
-
let(:protocol_message) { new_protocol_message(connectionKey: 'deprecated', connectionDetails: { connectionKey: 'key' }) }
|
432
|
-
|
433
|
-
it 'returns #connection_details.connection_key as #connection_key will be deprecated > 0.8' do
|
434
|
-
expect(protocol_message.connection_key).to eql('key')
|
435
|
-
end
|
436
|
-
end
|
437
|
-
end
|
438
480
|
end
|
439
481
|
|
440
482
|
context '#to_json', :api_private do
|
441
483
|
let(:json_object) { JSON.parse(model.to_json) }
|
442
|
-
let(:
|
484
|
+
let(:message1) { { 'name' => 'event1', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
485
|
+
let(:message2) { { 'name' => 'event2', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
486
|
+
let(:message3) { { 'name' => 'event3', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
443
487
|
let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached }
|
444
488
|
let(:message_action) { Ably::Models::ProtocolMessage::ACTION.Message }
|
445
489
|
|
446
490
|
context 'with valid data' do
|
447
|
-
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [
|
491
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3] }) }
|
448
492
|
|
449
493
|
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
450
494
|
expect(json_object["channelSerial"]).to eql('unique')
|
451
495
|
end
|
452
496
|
|
453
497
|
it 'populates the messages' do
|
454
|
-
expect(json_object["messages"]
|
498
|
+
expect(json_object["messages"][0]).to include(message1)
|
499
|
+
expect(json_object["messages"][1]).to include(message2)
|
500
|
+
expect(json_object["messages"][2]).to include(message3)
|
455
501
|
end
|
456
502
|
end
|
457
503
|
|
@@ -464,7 +510,7 @@ describe Ably::Models::ProtocolMessage do
|
|
464
510
|
end
|
465
511
|
|
466
512
|
context 'is aliased by #to_s' do
|
467
|
-
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [
|
513
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3], :timestamp => as_since_epoch(Time.now) }) }
|
468
514
|
|
469
515
|
specify do
|
470
516
|
expect(json_object).to eql(JSON.parse("#{model}"))
|
@@ -473,14 +519,18 @@ describe Ably::Models::ProtocolMessage do
|
|
473
519
|
end
|
474
520
|
|
475
521
|
context '#to_msgpack', :api_private do
|
476
|
-
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [
|
477
|
-
let(:
|
522
|
+
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [message1, message2, message3] }) }
|
523
|
+
let(:message1) { { 'name' => 'event1', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
524
|
+
let(:message2) { { 'name' => 'event2', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
525
|
+
let(:message3) { { 'name' => 'event3', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
478
526
|
let(:packed) { model.to_msgpack }
|
479
527
|
let(:unpacked) { MessagePack.unpack(packed) }
|
480
528
|
|
481
529
|
it 'returns a unpackable msgpack object' do
|
482
530
|
expect(unpacked['connectionSerial']).to eq('unique')
|
483
|
-
expect(unpacked['messages'][0]['name']).to eq('
|
531
|
+
expect(unpacked['messages'][0]['name']).to eq('event1')
|
532
|
+
expect(unpacked['messages'][1]['name']).to eq('event2')
|
533
|
+
expect(unpacked['messages'][2]['name']).to eq('event3')
|
484
534
|
end
|
485
535
|
end
|
486
536
|
end
|
@@ -80,6 +80,20 @@ describe Ably::Models::TokenDetails do
|
|
80
80
|
expect(subject.expired?).to eql(false)
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
context 'with :from attribute' do
|
85
|
+
subject { Ably::Models::TokenDetails.new(expires: expire_time) }
|
86
|
+
|
87
|
+
let(:server_offset_time) { 2 * 60 * 60 } # 2 hours
|
88
|
+
|
89
|
+
it 'is false' do
|
90
|
+
expect(subject.expired?(from: (Time.now - server_offset_time))).to eql(false)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'is true' do
|
94
|
+
expect(subject.expired?(from: Time.now)).to eql(true)
|
95
|
+
end
|
96
|
+
end
|
83
97
|
end
|
84
98
|
end
|
85
99
|
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
require 'shared/protocol_msgbus_behaviour'
|
4
4
|
|
5
5
|
describe Ably::Realtime::Channel do
|
6
|
-
let(:client) {
|
6
|
+
let(:client) { Ably::Realtime::Client.new(token: 'valid') }
|
7
7
|
let(:channel_name) { 'test' }
|
8
8
|
|
9
9
|
subject do
|
@@ -71,6 +71,7 @@ describe Ably::Realtime::Channel do
|
|
71
71
|
let(:message) { instance_double('Ably::Models::Message', client_id: nil, size: 0) }
|
72
72
|
|
73
73
|
before do
|
74
|
+
allow(subject).to receive(:enqueue_messages_on_connection).and_return(message)
|
74
75
|
allow(subject).to receive(:create_message).and_return(message)
|
75
76
|
allow(subject).to receive(:attach).and_return(:true)
|
76
77
|
end
|
@@ -3,39 +3,77 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe Ably::Realtime::Channels do
|
5
5
|
let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true, on_resume: true) }
|
6
|
-
let(:client)
|
6
|
+
let(:client) do
|
7
|
+
instance_double('Ably::Realtime::Client', connection: connection, client_id: 'clientId', logger: double('logger').as_null_object)
|
8
|
+
end
|
7
9
|
let(:channel_name) { 'unique' }
|
8
|
-
let(:options)
|
10
|
+
let(:options) do
|
11
|
+
{ params: { bizarre: 'value' } }
|
12
|
+
end
|
9
13
|
|
10
14
|
subject { Ably::Realtime::Channels.new(client) }
|
11
15
|
|
12
16
|
context 'creating channels' do
|
13
17
|
context '#get' do
|
14
|
-
|
15
|
-
|
16
|
-
|
18
|
+
context "when channel doesn't exist" do
|
19
|
+
shared_examples 'creates a channel' do
|
20
|
+
it 'creates a channel (RTS3a)' do
|
21
|
+
expect(Ably::Realtime::Channel).to receive(:new).with(client, channel_name, channel_options)
|
22
|
+
subject.get(channel_name, channel_options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'hash' do
|
27
|
+
let(:channel_options) { options }
|
28
|
+
it { expect(channel_options).to be_a(Hash) }
|
29
|
+
|
30
|
+
include_examples 'creates a channel'
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'ChannelOptions object' do
|
34
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
35
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
36
|
+
|
37
|
+
include_examples 'creates a channel'
|
38
|
+
end
|
17
39
|
end
|
18
40
|
|
19
41
|
context 'when an existing channel exists' do
|
20
|
-
|
21
|
-
channel
|
22
|
-
|
23
|
-
|
42
|
+
shared_examples 'reuse a channel object if it exists' do
|
43
|
+
it 'will reuse a channel object if it exists (RTS3a)' do
|
44
|
+
channel = subject.get(channel_name, channel_options)
|
45
|
+
expect(channel).to be_a(Ably::Realtime::Channel)
|
46
|
+
expect(subject.get(channel_name, channel_options).object_id).to eql(channel.object_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'hash' do
|
51
|
+
let(:channel_options) { options }
|
52
|
+
it { expect(channel_options).to be_a(Hash) }
|
53
|
+
|
54
|
+
include_examples 'reuse a channel object if it exists'
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'ChannelOptions object' do
|
58
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
59
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
60
|
+
|
61
|
+
include_examples 'reuse a channel object if it exists'
|
24
62
|
end
|
25
63
|
|
26
|
-
it 'will update the options on the channel if provided' do
|
64
|
+
it 'will update the options on the channel if provided (RSN3c)' do
|
27
65
|
channel = subject.get(channel_name, options)
|
28
|
-
expect(channel.options).to
|
29
|
-
expect(channel.options).to_not include(:encrypted)
|
66
|
+
expect(channel.options.to_h).to eq(options)
|
67
|
+
expect(channel.options.to_h).to_not include(:encrypted)
|
30
68
|
subject.get(channel_name, encrypted: true)
|
31
|
-
expect(channel.options[:encrypted]).to
|
69
|
+
expect(channel.options[:encrypted]).to eq(true)
|
32
70
|
end
|
33
71
|
|
34
72
|
it 'will leave the options intact on the channel if not provided' do
|
35
73
|
channel = subject.get(channel_name, options)
|
36
|
-
expect(channel.options).to
|
74
|
+
expect(channel.options.to_h).to eq(options)
|
37
75
|
subject.get(channel_name)
|
38
|
-
expect(channel.options).to
|
76
|
+
expect(channel.options.to_h).to eq(options)
|
39
77
|
end
|
40
78
|
end
|
41
79
|
end
|