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