ably-rest 1.1.2 → 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/.travis.yml +3 -0
- data/CHANGELOG.md +1 -1
- data/MAINTAINERS.md +1 -0
- data/README.md +4 -2
- data/ably-rest.gemspec +15 -18
- data/lib/ably-rest.rb +2 -0
- data/lib/submodules/ably-ruby/.github/workflows/check.yml +50 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +200 -0
- data/lib/submodules/ably-ruby/COPYRIGHT +1 -0
- data/lib/submodules/ably-ruby/LICENSE +172 -11
- data/lib/submodules/ably-ruby/MAINTAINERS.md +1 -0
- data/lib/submodules/ably-ruby/README.md +24 -22
- data/lib/submodules/ably-ruby/SPEC.md +1020 -929
- data/lib/submodules/ably-ruby/UPDATING.md +30 -0
- data/lib/submodules/ably-ruby/ably.gemspec +16 -23
- data/lib/submodules/ably-ruby/lib/ably/agent.rb +3 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +20 -10
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/models/channel_details.rb +59 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_metrics.rb +84 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_occupancy.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_options.rb +97 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_status.rb +53 -0
- data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +8 -0
- data/lib/submodules/ably-ruby/lib/ably/models/delta_extras.rb +29 -0
- data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +6 -2
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +28 -3
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +31 -14
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +7 -2
- data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +11 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +19 -7
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_properties.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +6 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +56 -28
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +9 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +13 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +67 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +6 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +0 -14
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +44 -29
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +60 -29
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +5 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -14
- data/lib/submodules/ably-ruby/lib/ably.rb +1 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +476 -21
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +72 -16
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +85 -13
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +301 -34
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +77 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +3 -59
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +84 -158
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +3 -19
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +24 -75
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +8 -4
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +141 -10
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -6
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +146 -47
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +61 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +3 -19
- data/lib/submodules/ably-ruby/spec/lib/unit/models/channel_options_spec.rb +52 -0
- data/lib/submodules/ably-ruby/spec/run_parallel_tests +2 -7
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +131 -8
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +1 -1
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +12 -2
- data/lib/submodules/ably-ruby/spec/support/serialization_helper.rb +21 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +6 -14
- data/lib/submodules/ably-ruby/spec/unit/models/channel_details_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_metrics_spec.rb +42 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_occupancy_spec.rb +17 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_status_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/models/delta_extras_spec.rb +14 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +17 -1
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +97 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +49 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +125 -27
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +14 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +3 -2
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +53 -15
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +19 -6
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +44 -1
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +81 -14
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +47 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/unit/client_spec.rb +30 -0
- metadata +88 -25
- data/lib/submodules/ably-ruby/.travis.yml +0 -19
|
@@ -89,31 +89,15 @@ describe Ably::Rest::Push::Admin do
|
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
def request_body(request, protocol)
|
|
93
|
-
if protocol == :msgpack
|
|
94
|
-
MessagePack.unpack(request.body)
|
|
95
|
-
else
|
|
96
|
-
JSON.parse(request.body)
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def serialize(object, protocol)
|
|
101
|
-
if protocol == :msgpack
|
|
102
|
-
MessagePack.pack(object)
|
|
103
|
-
else
|
|
104
|
-
JSON.dump(object)
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
92
|
let!(:publish_stub) do
|
|
109
93
|
stub_request(:post, "#{client.endpoint}/push/publish").
|
|
110
94
|
with do |request|
|
|
111
|
-
expect(
|
|
112
|
-
expect(
|
|
95
|
+
expect(deserialize_body(request.body, protocol)['recipient']['camelCase']['secondLevelCamelCase']).to eql('val')
|
|
96
|
+
expect(deserialize_body(request.body, protocol)['recipient']).to_not have_key('camel_case')
|
|
113
97
|
true
|
|
114
98
|
end.to_return(
|
|
115
99
|
:status => 201,
|
|
116
|
-
:body =>
|
|
100
|
+
:body => serialize_body({}, protocol),
|
|
117
101
|
:headers => { 'Content-Type' => content_type }
|
|
118
102
|
)
|
|
119
103
|
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
|
|
@@ -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
|
|
@@ -69,14 +69,6 @@ shared_examples 'a client initializer' do
|
|
|
69
69
|
expect { subject }.to raise_error(ArgumentError, /key and key_name or key_secret are mutually exclusive/)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
|
-
|
|
73
|
-
context 'client_id as only option' do
|
|
74
|
-
let(:client_options) { { client_id: 'valid' } }
|
|
75
|
-
|
|
76
|
-
it 'requires a valid key' do
|
|
77
|
-
expect { subject }.to raise_error(ArgumentError, /client_id cannot be provided without a complete API key or means to authenticate/)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
72
|
end
|
|
81
73
|
|
|
82
74
|
context 'with valid arguments' do
|
|
@@ -273,6 +265,137 @@ shared_examples 'a client initializer' do
|
|
|
273
265
|
end
|
|
274
266
|
end
|
|
275
267
|
end
|
|
268
|
+
|
|
269
|
+
context 'environment' do
|
|
270
|
+
context 'when set without custom fallback hosts configured' do
|
|
271
|
+
let(:environment) { 'foo' }
|
|
272
|
+
let(:client_options) { default_options.merge(environment: environment) }
|
|
273
|
+
let(:default_fallbacks) { %w(a b c d e).map { |id| "#{environment}-#{id}-fallback.ably-realtime.com" } }
|
|
274
|
+
|
|
275
|
+
it 'sets the environment attribute' do
|
|
276
|
+
expect(subject.environment).to eql(environment)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'uses the default fallback hosts (#TBC, see https://github.com/ably/wiki/issues/361)' do
|
|
280
|
+
expect(subject.fallback_hosts.sort).to eql(default_fallbacks)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
context 'when set with custom fallback hosts configured' do
|
|
285
|
+
let(:environment) { 'foo' }
|
|
286
|
+
let(:custom_fallbacks) { %w(a b c).map { |id| "#{environment}-#{id}.foo.com" } }
|
|
287
|
+
let(:client_options) { default_options.merge(environment: environment, fallback_hosts: custom_fallbacks) }
|
|
288
|
+
|
|
289
|
+
it 'sets the environment attribute' do
|
|
290
|
+
expect(subject.environment).to eql(environment)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it 'uses the custom provided fallback hosts (#RSC15a)' do
|
|
294
|
+
expect(subject.fallback_hosts.sort).to eql(custom_fallbacks)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
context 'when set with fallback_hosts_use_default' do
|
|
299
|
+
let(:environment) { 'foo' }
|
|
300
|
+
let(:custom_fallbacks) { %w(a b c).map { |id| "#{environment}-#{id}.foo.com" } }
|
|
301
|
+
let(:default_production_fallbacks) { %w(a b c d e).map { |id| "#{id}.ably-realtime.com" } }
|
|
302
|
+
let(:client_options) { default_options.merge(environment: environment, fallback_hosts_use_default: true) }
|
|
303
|
+
|
|
304
|
+
it 'sets the environment attribute' do
|
|
305
|
+
expect(subject.environment).to eql(environment)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'uses the production default fallback hosts (#RTN17b)' do
|
|
309
|
+
expect(subject.fallback_hosts.sort).to eql(default_production_fallbacks)
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
context 'rest_host' do
|
|
315
|
+
context 'when set without custom fallback hosts configured' do
|
|
316
|
+
let(:custom_rest_host) { 'foo.com' }
|
|
317
|
+
let(:client_options) { default_options.merge(rest_host: custom_rest_host) }
|
|
318
|
+
|
|
319
|
+
it 'sets the custom_host attribute' do
|
|
320
|
+
expect(subject.custom_host).to eql(custom_rest_host)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it 'has no default fallback hosts' do
|
|
324
|
+
expect(subject.fallback_hosts).to be_empty
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
context 'when set with environment and without custom fallback hosts configured' do
|
|
329
|
+
let(:environment) { 'foobar' }
|
|
330
|
+
let(:custom_rest_host) { 'foo.com' }
|
|
331
|
+
let(:client_options) { default_options.merge(environment: environment, rest_host: custom_rest_host) }
|
|
332
|
+
|
|
333
|
+
it 'sets the environment attribute' do
|
|
334
|
+
expect(subject.environment).to eql(environment)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it 'sets the custom_host attribute' do
|
|
338
|
+
expect(subject.custom_host).to eql(custom_rest_host)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
it 'has no default fallback hosts' do
|
|
342
|
+
expect(subject.fallback_hosts).to be_empty
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
context 'when set with custom fallback hosts configured' do
|
|
347
|
+
let(:custom_rest_host) { 'foo.com' }
|
|
348
|
+
let(:custom_fallbacks) { %w(a b c).map { |id| "#{environment}-#{id}.foo.com" } }
|
|
349
|
+
let(:client_options) { default_options.merge(rest_host: custom_rest_host, fallback_hosts: custom_fallbacks) }
|
|
350
|
+
|
|
351
|
+
it 'sets the custom_host attribute' do
|
|
352
|
+
expect(subject.custom_host).to eql(custom_rest_host)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it 'has no default fallback hosts' do
|
|
356
|
+
expect(subject.fallback_hosts.sort).to eql(custom_fallbacks)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
context 'realtime_host' do
|
|
362
|
+
context 'when set without custom fallback hosts configured' do
|
|
363
|
+
let(:custom_realtime_host) { 'realtime.foo.com' }
|
|
364
|
+
let(:client_options) { default_options.merge(realtime_host: custom_realtime_host) }
|
|
365
|
+
|
|
366
|
+
# These tests are shared between realtime & rest clients
|
|
367
|
+
# So don't test for the attribute, instead test the options
|
|
368
|
+
it 'sets the realtime_host option' do
|
|
369
|
+
expect(subject.options[:realtime_host]).to eql(custom_realtime_host)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it 'has no default fallback hosts' do
|
|
373
|
+
expect(subject.fallback_hosts).to be_empty
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
context 'custom port' do
|
|
379
|
+
context 'when set without custom fallback hosts configured' do
|
|
380
|
+
let(:custom_port) { 555 }
|
|
381
|
+
let(:client_options) { default_options.merge(port: custom_port) }
|
|
382
|
+
|
|
383
|
+
it 'has no default fallback hosts' do
|
|
384
|
+
expect(subject.fallback_hosts).to be_empty
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
context 'custom TLS port' do
|
|
390
|
+
context 'when set without custom fallback hosts configured' do
|
|
391
|
+
let(:custom_port) { 555 }
|
|
392
|
+
let(:client_options) { default_options.merge(tls_port: custom_port) }
|
|
393
|
+
|
|
394
|
+
it 'has no default fallback hosts' do
|
|
395
|
+
expect(subject.fallback_hosts).to be_empty
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
end
|
|
276
399
|
end
|
|
277
400
|
|
|
278
401
|
context 'delegators' do
|
|
@@ -19,7 +19,7 @@ shared_examples 'a model' do |shared_options = {}|
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
context '#attributes', :api_private do
|
|
22
|
-
let(:model_options) { { action: 5 } }
|
|
22
|
+
let(:model_options) { { action: 5, max_message_size: 65536, max_frame_size: 524288 } }
|
|
23
23
|
|
|
24
24
|
it 'provides access to #attributes' do
|
|
25
25
|
expect(model.attributes).to eq(model_options)
|
|
@@ -5,8 +5,17 @@ def console(message)
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
unless RUBY_VERSION.match(/^1\./)
|
|
8
|
-
require '
|
|
9
|
-
|
|
8
|
+
require 'simplecov'
|
|
9
|
+
|
|
10
|
+
SimpleCov.start do
|
|
11
|
+
require 'simplecov-lcov'
|
|
12
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
|
13
|
+
c.report_with_single_file = true
|
|
14
|
+
c.single_report_path = 'coverage/lcov.info'
|
|
15
|
+
end
|
|
16
|
+
formatter SimpleCov::Formatter::LcovFormatter
|
|
17
|
+
add_filter %w[vendor spec]
|
|
18
|
+
end
|
|
10
19
|
end
|
|
11
20
|
|
|
12
21
|
require 'webmock/rspec'
|
|
@@ -19,6 +28,7 @@ require 'support/event_emitter_helper'
|
|
|
19
28
|
require 'support/private_api_formatter'
|
|
20
29
|
require 'support/protocol_helper'
|
|
21
30
|
require 'support/random_helper'
|
|
31
|
+
require 'support/serialization_helper'
|
|
22
32
|
require 'support/test_logger_helper'
|
|
23
33
|
|
|
24
34
|
require 'rspec_config'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module SerializationHelper
|
|
2
|
+
def serialize_body(object, protocol)
|
|
3
|
+
if protocol == :msgpack
|
|
4
|
+
MessagePack.pack(object)
|
|
5
|
+
else
|
|
6
|
+
JSON.dump(object)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def deserialize_body(object, protocol)
|
|
11
|
+
if protocol == :msgpack
|
|
12
|
+
MessagePack.unpack(object)
|
|
13
|
+
else
|
|
14
|
+
JSON.parse(object)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
RSpec.configure do |config|
|
|
19
|
+
config.include self
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -4,11 +4,11 @@ class TestApp
|
|
|
4
4
|
TEST_RESOURCES_PATH = File.expand_path('../../../lib/submodules/ably-common/test-resources', __FILE__)
|
|
5
5
|
|
|
6
6
|
# App configuration for test app
|
|
7
|
-
# See https://github.com/ably/ably-common/blob/
|
|
7
|
+
# See https://github.com/ably/ably-common/blob/main/test-resources/test-app-setup.json
|
|
8
8
|
APP_SPEC = JSON.parse(File.read(File.join(TEST_RESOURCES_PATH, 'test-app-setup.json')))['post_apps']
|
|
9
9
|
|
|
10
10
|
# Cipher details used for client_encoded presence data in test app
|
|
11
|
-
# See https://github.com/ably/ably-common/blob/
|
|
11
|
+
# See https://github.com/ably/ably-common/blob/main/test-resources/test-app-setup.json
|
|
12
12
|
APP_SPEC_CIPHER = JSON.parse(File.read(File.join(TEST_RESOURCES_PATH, 'test-app-setup.json')))['cipher']
|
|
13
13
|
|
|
14
14
|
# If an app has already been created and we need a new app, create a new test app
|
|
@@ -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)
|
|
@@ -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
|
|
@@ -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) }
|
|
@@ -211,6 +211,79 @@ describe Ably::Models::Message do
|
|
|
211
211
|
end
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
+
describe '#size' do
|
|
215
|
+
let(:model) { subject.new({ name: name, data: data, client_id: client_id, extras: extras }, protocol_message: protocol_message) }
|
|
216
|
+
|
|
217
|
+
context 'String (#TO3l8a)' do
|
|
218
|
+
let(:data) { 'example string data' }
|
|
219
|
+
let(:client_id) { '1' }
|
|
220
|
+
let(:name) { 'My Name' }
|
|
221
|
+
let(:extras) { 'extras' }
|
|
222
|
+
|
|
223
|
+
it 'should return 33 bytes' do
|
|
224
|
+
expect(model.size).to eq(33)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
context 'Object (#TO3l8b)' do
|
|
229
|
+
let(:data) { Object.new }
|
|
230
|
+
let(:client_id) { String('10') }
|
|
231
|
+
let(:name) { 'John' }
|
|
232
|
+
let(:extras) { Hash.new }
|
|
233
|
+
|
|
234
|
+
it 'should return 38 bytes' do
|
|
235
|
+
expect(model.size).to eq(38)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
context 'Array (#TO3l8b)' do
|
|
240
|
+
let(:data) { [1, 'two', :three] }
|
|
241
|
+
let(:client_id) { '2' }
|
|
242
|
+
let(:name) { 'Kate' }
|
|
243
|
+
let(:extras) { [] }
|
|
244
|
+
|
|
245
|
+
it 'should return 24 bytes' do
|
|
246
|
+
expect(model.size).to eq(24)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
context 'extras (#TO3l8d)' do
|
|
251
|
+
let(:data) { { example: 'value', score: 1, hash: { test: true } } }
|
|
252
|
+
let(:client_id) { '3' }
|
|
253
|
+
let(:name) { 'John' }
|
|
254
|
+
let(:extras) { {} }
|
|
255
|
+
|
|
256
|
+
it 'should return 57 bytes' do
|
|
257
|
+
expect(model.size).to eq(57)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
context 'nil (#TO3l8e)' do
|
|
262
|
+
let(:data) { nil }
|
|
263
|
+
let(:client_id) { '' }
|
|
264
|
+
let(:name) { '' }
|
|
265
|
+
let(:extras) { nil}
|
|
266
|
+
|
|
267
|
+
it 'should return 19 bytes' do
|
|
268
|
+
expect(model.size).to eq(0)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
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
|
+
|
|
214
287
|
context 'from REST request with embedded fields', :api_private do
|
|
215
288
|
let(:id) { random_str }
|
|
216
289
|
let(:protocol_message_id) { random_str }
|
|
@@ -547,4 +620,28 @@ describe Ably::Models::Message do
|
|
|
547
620
|
end
|
|
548
621
|
end
|
|
549
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
|
|
550
647
|
end
|