ably 1.1.8 → 1.2.2
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 +14 -5
- data/CHANGELOG.md +48 -0
- data/README.md +2 -2
- data/UPDATING.md +30 -0
- data/ably.gemspec +12 -24
- data/lib/ably/auth.rb +8 -8
- data/lib/ably/logger.rb +4 -4
- data/lib/ably/models/channel_details.rb +59 -0
- data/lib/ably/models/channel_metrics.rb +84 -0
- data/lib/ably/models/channel_occupancy.rb +43 -0
- data/lib/ably/models/channel_options.rb +97 -0
- data/lib/ably/models/channel_status.rb +53 -0
- data/lib/ably/models/device_details.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/ably/models/message.rb +4 -4
- data/lib/ably/models/protocol_message.rb +19 -7
- 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 +5 -0
- data/lib/ably/realtime/channel.rb +54 -24
- data/lib/ably/realtime/channels.rb +1 -1
- data/lib/ably/rest/channel.rb +33 -34
- data/lib/ably/rest/client.rb +8 -5
- 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 +247 -21
- data/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/spec/acceptance/realtime/connection_spec.rb +21 -1
- data/spec/acceptance/realtime/message_spec.rb +77 -0
- data/spec/acceptance/rest/auth_spec.rb +18 -0
- data/spec/acceptance/rest/channel_spec.rb +19 -1
- data/spec/acceptance/rest/channels_spec.rb +22 -5
- 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/unit/logger_spec.rb +6 -14
- data/spec/unit/models/channel_details_spec.rb +30 -0
- data/spec/unit/models/channel_metrics_spec.rb +42 -0
- data/spec/unit/models/channel_occupancy_spec.rb +17 -0
- data/spec/unit/models/channel_status_spec.rb +36 -0
- data/spec/unit/models/message_spec.rb +14 -0
- data/spec/unit/models/protocol_message_spec.rb +53 -7
- data/spec/unit/models/token_details_spec.rb +14 -0
- data/spec/unit/realtime/channels_spec.rb +52 -14
- data/spec/unit/rest/channels_spec.rb +81 -14
- metadata +69 -11
@@ -5,11 +5,11 @@ describe Ably::Rest::Channels do
|
|
5
5
|
shared_examples 'a channel' do
|
6
6
|
it 'returns a channel object' do
|
7
7
|
expect(channel).to be_a Ably::Rest::Channel
|
8
|
-
expect(channel.name).to
|
8
|
+
expect(channel.name).to eq(channel_name)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns channel object and passes the provided options' do
|
12
|
-
expect(channel_with_options.options).to
|
12
|
+
expect(channel_with_options.options.to_h).to eq(options)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -32,12 +32,29 @@ describe Ably::Rest::Channels do
|
|
32
32
|
it_behaves_like 'a channel'
|
33
33
|
end
|
34
34
|
|
35
|
+
describe '#set_options (#RTL16)' do
|
36
|
+
let(:channel) { client.channel(channel_name) }
|
37
|
+
|
38
|
+
it "updates channel's options" do
|
39
|
+
expect { channel.options = options }.to change { channel.options.to_h }.from({}).to(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when providing Ably::Models::ChannelOptions object' do
|
43
|
+
let(:options_object) { Ably::Models::ChannelOptions.new(options) }
|
44
|
+
|
45
|
+
it "updates channel's options" do
|
46
|
+
expect { channel.options = options_object}.to change { channel.options.to_h }.from({}).to(options)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
35
51
|
describe 'accessing an existing channel object with different options' do
|
36
52
|
let(:new_channel_options) { { encrypted: true } }
|
37
53
|
let(:original_channel) { client.channels.get(channel_name, options) }
|
38
54
|
|
39
55
|
it 'overrides the existing channel options and returns the channel object (RSN3c)' do
|
40
|
-
expect(original_channel.options).to_not include(:encrypted)
|
56
|
+
expect(original_channel.options.to_h).to_not include(:encrypted)
|
57
|
+
|
41
58
|
new_channel = client.channels.get(channel_name, new_channel_options)
|
42
59
|
expect(new_channel).to be_a(Ably::Rest::Channel)
|
43
60
|
expect(new_channel.options[:encrypted]).to eql(true)
|
@@ -48,10 +65,10 @@ describe Ably::Rest::Channels do
|
|
48
65
|
let(:original_channel) { client.channels.get(channel_name, options) }
|
49
66
|
|
50
67
|
it 'returns the existing channel without modifying the channel options' do
|
51
|
-
expect(original_channel.options).to
|
68
|
+
expect(original_channel.options.to_h).to eq(options)
|
52
69
|
new_channel = client.channels.get(channel_name)
|
53
70
|
expect(new_channel).to be_a(Ably::Rest::Channel)
|
54
|
-
expect(original_channel.options).to
|
71
|
+
expect(original_channel.options.to_h).to eq(options)
|
55
72
|
end
|
56
73
|
end
|
57
74
|
|
@@ -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/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,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/model_behaviour'
|
3
|
+
|
4
|
+
describe Ably::Models::ChannelDetails do
|
5
|
+
subject { Ably::Models::ChannelDetails(channel_id: 'channel-id-123-xyz', name: 'name', status: { isActive: 'true', occupancy: { metrics: { connections: 1, presence_connections: 2, presence_members: 2, presence_subscribers: 5, publishers: 7, subscribers: 9 } } }) }
|
6
|
+
|
7
|
+
describe '#channel_id' do
|
8
|
+
it 'should return channel id' do
|
9
|
+
expect(subject.channel_id).to eq('channel-id-123-xyz')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#name' do
|
14
|
+
it 'should return name' do
|
15
|
+
expect(subject.name).to eq('name')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#status' do
|
20
|
+
it 'should return status' do
|
21
|
+
expect(subject.status).to be_a(Ably::Models::ChannelStatus)
|
22
|
+
expect(subject.status.occupancy.metrics.connections).to eq(1)
|
23
|
+
expect(subject.status.occupancy.metrics.presence_connections).to eq(2)
|
24
|
+
expect(subject.status.occupancy.metrics.presence_members).to eq(2)
|
25
|
+
expect(subject.status.occupancy.metrics.presence_subscribers).to eq(5)
|
26
|
+
expect(subject.status.occupancy.metrics.publishers).to eq(7)
|
27
|
+
expect(subject.status.occupancy.metrics.subscribers).to eq(9)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/model_behaviour'
|
3
|
+
|
4
|
+
describe Ably::Models::ChannelMetrics do
|
5
|
+
subject { Ably::Models::ChannelMetrics(connections: 1, presence_connections: 2, presence_members: 2, presence_subscribers: 5, publishers: 7, subscribers: 9) }
|
6
|
+
|
7
|
+
describe '#connections' do
|
8
|
+
it 'should return integer' do
|
9
|
+
expect(subject.connections).to eq(1)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#presence_connections' do
|
14
|
+
it 'should return integer' do
|
15
|
+
expect(subject.presence_connections).to eq(2)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#presence_members' do
|
20
|
+
it 'should return integer' do
|
21
|
+
expect(subject.presence_members).to eq(2)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#presence_subscribers' do
|
26
|
+
it 'should return integer' do
|
27
|
+
expect(subject.presence_subscribers).to eq(5)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#publishers' do
|
32
|
+
it 'should return integer' do
|
33
|
+
expect(subject.publishers).to eq(7)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#subscribers' do
|
38
|
+
it 'should return integer' do
|
39
|
+
expect(subject.subscribers).to eq(9)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/model_behaviour'
|
3
|
+
|
4
|
+
describe Ably::Models::ChannelOccupancy do
|
5
|
+
subject { Ably::Models::ChannelOccupancy({ metrics: { connections: 1, presence_connections: 2, presence_members: 2, presence_subscribers: 5, publishers: 7, subscribers: 9 } }) }
|
6
|
+
|
7
|
+
describe '#metrics' do
|
8
|
+
it 'should return attributes' do
|
9
|
+
expect(subject.metrics.connections).to eq(1)
|
10
|
+
expect(subject.metrics.presence_connections).to eq(2)
|
11
|
+
expect(subject.metrics.presence_members).to eq(2)
|
12
|
+
expect(subject.metrics.presence_subscribers).to eq(5)
|
13
|
+
expect(subject.metrics.publishers).to eq(7)
|
14
|
+
expect(subject.metrics.subscribers).to eq(9)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/model_behaviour'
|
3
|
+
|
4
|
+
describe Ably::Models::ChannelStatus do
|
5
|
+
subject { Ably::Models::ChannelStatus({ isActive: 'true', occupancy: { metrics: { connections: 1, presence_connections: 2, presence_members: 2, presence_subscribers: 5, publishers: 7, subscribers: 9 } } }) }
|
6
|
+
|
7
|
+
describe '#is_active' do
|
8
|
+
context 'when occupancy is active' do
|
9
|
+
subject { Ably::Models::ChannelStatus({ isActive: true, occupancy: { metrics: { connections: 1, presence_connections: 2, presence_members: 2, presence_subscribers: 5, publishers: 7, subscribers: 9 } } }) }
|
10
|
+
|
11
|
+
it 'should return true' do
|
12
|
+
expect(subject.is_active).to eq(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when occupancy is not active' do
|
17
|
+
subject { Ably::Models::ChannelStatus({ isActive: false, occupancy: { metrics: { connections: 1, presence_connections: 2, presence_members: 2, presence_subscribers: 5, publishers: 7, subscribers: 9 } } }) }
|
18
|
+
|
19
|
+
it 'should return false' do
|
20
|
+
expect(subject.is_active).to eq(false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#occupancy' do
|
26
|
+
it 'should return occupancy object' do
|
27
|
+
expect(subject.occupancy).to be_a(Ably::Models::ChannelOccupancy)
|
28
|
+
expect(subject.occupancy.metrics.connections).to eq(1)
|
29
|
+
expect(subject.occupancy.metrics.presence_connections).to eq(2)
|
30
|
+
expect(subject.occupancy.metrics.presence_members).to eq(2)
|
31
|
+
expect(subject.occupancy.metrics.presence_subscribers).to eq(5)
|
32
|
+
expect(subject.occupancy.metrics.publishers).to eq(7)
|
33
|
+
expect(subject.occupancy.metrics.subscribers).to eq(9)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -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 }
|
@@ -223,6 +223,24 @@ describe Ably::Models::ProtocolMessage do
|
|
223
223
|
end
|
224
224
|
end
|
225
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
|
+
|
226
244
|
context '#has_connection_serial?' do
|
227
245
|
context 'without connection_serial' do
|
228
246
|
let(:protocol_message) { new_protocol_message({}) }
|
@@ -330,6 +348,26 @@ describe Ably::Models::ProtocolMessage do
|
|
330
348
|
end
|
331
349
|
end
|
332
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
|
+
|
333
371
|
context '#presence (#TR4l)' do
|
334
372
|
let(:protocol_message) { new_protocol_message(presence: [{ action: 1, data: 'test' }]) }
|
335
373
|
|
@@ -443,19 +481,23 @@ describe Ably::Models::ProtocolMessage do
|
|
443
481
|
|
444
482
|
context '#to_json', :api_private do
|
445
483
|
let(:json_object) { JSON.parse(model.to_json) }
|
446
|
-
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) } }
|
447
487
|
let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached }
|
448
488
|
let(:message_action) { Ably::Models::ProtocolMessage::ACTION.Message }
|
449
489
|
|
450
490
|
context 'with valid data' do
|
451
|
-
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] }) }
|
452
492
|
|
453
493
|
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
454
494
|
expect(json_object["channelSerial"]).to eql('unique')
|
455
495
|
end
|
456
496
|
|
457
497
|
it 'populates the messages' do
|
458
|
-
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)
|
459
501
|
end
|
460
502
|
end
|
461
503
|
|
@@ -468,7 +510,7 @@ describe Ably::Models::ProtocolMessage do
|
|
468
510
|
end
|
469
511
|
|
470
512
|
context 'is aliased by #to_s' do
|
471
|
-
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) }) }
|
472
514
|
|
473
515
|
specify do
|
474
516
|
expect(json_object).to eql(JSON.parse("#{model}"))
|
@@ -477,14 +519,18 @@ describe Ably::Models::ProtocolMessage do
|
|
477
519
|
end
|
478
520
|
|
479
521
|
context '#to_msgpack', :api_private do
|
480
|
-
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [
|
481
|
-
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) } }
|
482
526
|
let(:packed) { model.to_msgpack }
|
483
527
|
let(:unpacked) { MessagePack.unpack(packed) }
|
484
528
|
|
485
529
|
it 'returns a unpackable msgpack object' do
|
486
530
|
expect(unpacked['connectionSerial']).to eq('unique')
|
487
|
-
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')
|
488
534
|
end
|
489
535
|
end
|
490
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,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
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
|