ably-rest 1.0.6 → 1.1.4.rc

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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/README.md +23 -15
  4. data/ably-rest.gemspec +6 -6
  5. data/lib/submodules/ably-ruby/.editorconfig +14 -0
  6. data/lib/submodules/ably-ruby/.travis.yml +10 -8
  7. data/lib/submodules/ably-ruby/CHANGELOG.md +75 -3
  8. data/lib/submodules/ably-ruby/LICENSE +1 -3
  9. data/lib/submodules/ably-ruby/README.md +12 -7
  10. data/lib/submodules/ably-ruby/Rakefile +32 -0
  11. data/lib/submodules/ably-ruby/SPEC.md +1277 -835
  12. data/lib/submodules/ably-ruby/ably.gemspec +15 -10
  13. data/lib/submodules/ably-ruby/lib/ably/auth.rb +30 -4
  14. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +10 -4
  15. data/lib/submodules/ably-ruby/lib/ably/logger.rb +7 -1
  16. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +1 -1
  17. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +1 -1
  18. data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +87 -0
  19. data/lib/submodules/ably-ruby/lib/ably/models/device_push_details.rb +86 -0
  20. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +23 -2
  21. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
  22. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +32 -2
  23. data/lib/submodules/ably-ruby/lib/ably/models/push_channel_subscription.rb +89 -0
  24. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +1 -1
  25. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +1 -1
  26. data/lib/submodules/ably-ruby/lib/ably/modules/exception_codes.rb +128 -0
  27. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +15 -2
  28. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
  29. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
  30. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +1 -1
  31. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +24 -102
  32. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +2 -6
  33. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
  34. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +74 -0
  35. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/push_channel.rb +62 -0
  36. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +91 -3
  37. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
  38. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
  39. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +34 -20
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +25 -9
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +1 -1
  42. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +4 -4
  43. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +3 -3
  44. data/lib/submodules/ably-ruby/lib/ably/realtime/push.rb +40 -0
  45. data/lib/submodules/ably-ruby/lib/ably/realtime/push/admin.rb +61 -0
  46. data/lib/submodules/ably-ruby/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  47. data/lib/submodules/ably-ruby/lib/ably/realtime/push/device_registrations.rb +105 -0
  48. data/lib/submodules/ably-ruby/lib/ably/rest.rb +1 -0
  49. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +53 -17
  50. data/lib/submodules/ably-ruby/lib/ably/rest/channel/push_channel.rb +62 -0
  51. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +162 -35
  52. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
  53. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
  54. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
  55. data/lib/submodules/ably-ruby/lib/ably/rest/push.rb +42 -0
  56. data/lib/submodules/ably-ruby/lib/ably/rest/push/admin.rb +54 -0
  57. data/lib/submodules/ably-ruby/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  58. data/lib/submodules/ably-ruby/lib/ably/rest/push/device_registrations.rb +103 -0
  59. data/lib/submodules/ably-ruby/lib/ably/version.rb +7 -2
  60. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +245 -17
  61. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +26 -20
  62. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +177 -59
  63. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +153 -0
  64. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +72 -6
  65. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +129 -18
  66. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +36 -34
  67. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +201 -167
  68. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +736 -0
  69. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_spec.rb +27 -0
  70. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +41 -3
  71. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +2 -2
  72. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +79 -4
  73. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +6 -0
  74. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +129 -10
  75. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +158 -6
  76. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +952 -0
  77. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_spec.rb +25 -0
  78. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +1 -1
  79. data/lib/submodules/ably-ruby/spec/run_parallel_tests +33 -0
  80. data/lib/submodules/ably-ruby/spec/spec_helper.rb +1 -1
  81. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +9 -5
  82. data/lib/submodules/ably-ruby/spec/support/test_app.rb +2 -2
  83. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +10 -3
  84. data/lib/submodules/ably-ruby/spec/unit/models/device_details_spec.rb +102 -0
  85. data/lib/submodules/ably-ruby/spec/unit/models/device_push_details_spec.rb +101 -0
  86. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +51 -3
  87. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +17 -2
  88. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
  89. data/lib/submodules/ably-ruby/spec/unit/models/push_channel_subscription_spec.rb +86 -0
  90. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +1 -1
  91. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +13 -1
  92. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +1 -1
  93. data/lib/submodules/ably-ruby/spec/unit/realtime/push_channel_spec.rb +36 -0
  94. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +8 -1
  95. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +30 -0
  96. data/lib/submodules/ably-ruby/spec/unit/rest/push_channel_spec.rb +36 -0
  97. metadata +46 -21
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Ably::Rest::Push do
5
+ vary_by_protocol do
6
+ let(:default_options) { { key: api_key, environment: environment, protocol: protocol} }
7
+ let(:client_options) { default_options }
8
+ let(:client) do
9
+ Ably::Rest::Client.new(client_options)
10
+ end
11
+ subject { client.push }
12
+
13
+ describe '#activate' do
14
+ it 'raises an unsupported exception' do
15
+ expect { subject.activate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
16
+ end
17
+ end
18
+
19
+ describe '#deactivate' do
20
+ it 'raises an unsupported exception' do
21
+ expect { subject.deactivate('foo') }.to raise_error(Ably::Exceptions::PushNotificationsNotSupported)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -13,7 +13,7 @@ describe Ably::Rest::Client, '#time' do
13
13
 
14
14
  context 'with reconfigured HTTP timeout' do
15
15
  let(:client) do
16
- Ably::Rest::Client.new(http_request_timeout: 0.0001, key: api_key, environment: environment, protocol: protocol)
16
+ Ably::Rest::Client.new(http_request_timeout: 0.0001, key: api_key, environment: environment, protocol: protocol, log_retries_as_info: true)
17
17
  end
18
18
 
19
19
  it 'should raise a timeout exception' do
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+ #
3
+ # Run the unit tests first without RSpec parallel, then run acceptance tests in parallel
4
+ #
5
+ # When splitting all tests across all parallel processes, it's quite plausible
6
+ # that some processes only run a majority of unit tests, whilst others only run a
7
+ # a majority of acceptance tests. This ensures acceptance tests are split out.
8
+
9
+ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
10
+
11
+ bundle exec rspec "${DIR}/unit"
12
+ unit_status=$?
13
+
14
+ if ruby -v | grep -e "1.9"; then
15
+ # Output with test ID is not supported with this old version of RSpec
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
21
+ acceptance_status=$?
22
+
23
+ if [ $unit_status -ne 0 ]; then
24
+ echo -e "\e[31m⚠ Note: Unit tests have also failed, but are not listed in the test failures above. Scroll up to the unit tests ⚠\e[0m"
25
+ fi
26
+
27
+ if [ $unit_status -ne 0 ] || [ $acceptance_status -ne 0 ]; then
28
+ echo "Unit tests exit code: ${unit_status}"
29
+ echo "Acceptance tests exit code: ${acceptance_status}"
30
+ exit 1
31
+ fi
32
+
33
+
@@ -4,7 +4,7 @@ def console(message)
4
4
  puts "\033[31m[#{Time.now.strftime('%H:%M:%S.%L')}]\033[0m \033[33m#{message}\033[0m"
5
5
  end
6
6
 
7
- unless RUBY_VERSION.match(/^1/)
7
+ unless RUBY_VERSION.match(/^1\./)
8
8
  require 'coveralls'
9
9
  Coveralls.wear!
10
10
  end
@@ -2,6 +2,8 @@ RSpec.configure do |config|
2
2
  config.before(:example) do |example|
3
3
  next if example.metadata[:prevent_log_stubbing]
4
4
 
5
+ log_mutex = Mutex.new
6
+
5
7
  @log_output = []
6
8
  %w(fatal error warn info debug).each do |method_name|
7
9
  allow_any_instance_of(Ably::Logger).to receive(method_name.to_sym).and_wrap_original do |method, *args, &block|
@@ -10,11 +12,13 @@ RSpec.configure do |config|
10
12
 
11
13
  prefix = "#{Time.now.strftime('%H:%M:%S.%L')} [\e[33m#{method_name}\e[0m] "
12
14
 
13
- begin
14
- args << block.call unless block.nil?
15
- @log_output << "#{prefix}#{args.compact.join(' ')}"
16
- rescue StandardError => e
17
- @log_output << "#{prefix}Failed to log block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}}"
15
+ log_mutex.synchronize do
16
+ begin
17
+ args << block.call unless block.nil?
18
+ @log_output << "#{prefix}#{args.compact.join(' ')}"
19
+ rescue StandardError => e
20
+ @log_output << "#{prefix}Failed to log block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}}"
21
+ end
18
22
  end
19
23
 
20
24
  # Call original
@@ -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/master/test-resources/test-app-setup.json
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/master/test-resources/test-app-setup.json
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
@@ -17,11 +17,15 @@ describe Ably::Logger do
17
17
  end
18
18
 
19
19
  context 'internals', :api_private do
20
- it 'delegates to the logger object' do
21
- expect(subject.logger).to receive(:warn) do |*args, &block|
20
+ it 'delegates to the default Logger object' do
21
+ received = false
22
+ expect(subject.logger).to be_a(::Logger)
23
+ allow_any_instance_of(::Logger).to receive(:warn) do |*args, &block|
22
24
  expect(args.concat([block ? block.call : nil]).join(',')).to match(/message/)
25
+ received = true
23
26
  end
24
27
  subject.warn 'message'
28
+ expect(received).to be_truthy
25
29
  end
26
30
 
27
31
  context 'formatter' do
@@ -132,10 +136,13 @@ describe Ably::Logger do
132
136
  end
133
137
 
134
138
  it 'delegates log messages to logger', :api_private do
135
- expect(custom_logger_object).to receive(:fatal) do |*args, &block|
139
+ received = false
140
+ allow(custom_logger_object).to receive(:fatal) do |*args, &block|
136
141
  expect(args.concat([block ? block.call : nil]).join(',')).to match(/message/)
142
+ received = true
137
143
  end
138
144
  subject.fatal 'message'
145
+ expect(received).to be_truthy
139
146
  end
140
147
  end
141
148
  end
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'shared/model_behaviour'
4
+
5
+ describe Ably::Models::DeviceDetails do
6
+ include Ably::Modules::Conversions
7
+
8
+ subject { Ably::Models::DeviceDetails }
9
+
10
+ %w(id platform form_factor client_id device_secret).each do |string_attribute|
11
+ let(:empty_device_details) { subject.new }
12
+
13
+ describe "##{string_attribute} and ##{string_attribute}=" do
14
+ let(:new_val) { random_str }
15
+
16
+ specify 'setter accepts a string value and getter returns the new value' do
17
+ expect(empty_device_details.public_send(string_attribute)).to be_nil
18
+ empty_device_details.public_send("#{string_attribute}=", new_val)
19
+ expect(empty_device_details.public_send(string_attribute)).to eql(new_val)
20
+ end
21
+
22
+ specify 'setter accepts nil' do
23
+ empty_device_details.public_send("#{string_attribute}=", new_val)
24
+ expect(empty_device_details.public_send(string_attribute)).to eql(new_val)
25
+ empty_device_details.public_send("#{string_attribute}=", nil)
26
+ expect(empty_device_details.public_send(string_attribute)).to be_nil
27
+ end
28
+
29
+ specify 'rejects non string or nil values' do
30
+ expect { empty_device_details.public_send("#{string_attribute}=", {}) }.to raise_error(ArgumentError)
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'camelCase constructor attributes' do
36
+ let(:client_id) { random_str }
37
+ let(:device_details) { subject.new("clientId" => client_id ) }
38
+
39
+ specify 'are rubyfied and exposed as underscore case' do
40
+ expect(device_details.client_id).to eql(client_id)
41
+ end
42
+
43
+ specify 'are generated when the object is serialised to JSON' do
44
+ expect(JSON.parse(device_details.to_json)["clientId"]).to eql(client_id)
45
+ end
46
+ end
47
+
48
+ describe "#metadata and #metadata=" do
49
+ let(:new_val) { { foo: random_str } }
50
+
51
+ specify 'setter accepts a Hash value and getter returns the new value' do
52
+ expect(empty_device_details.metadata).to eql({})
53
+ empty_device_details.metadata = new_val
54
+ expect(empty_device_details.metadata.to_json).to eql(new_val.to_json)
55
+ end
56
+
57
+ specify 'setter accepts nil but always returns an empty hash' do
58
+ empty_device_details.metadata = new_val
59
+ expect(empty_device_details.metadata.to_json).to eql(new_val.to_json)
60
+ empty_device_details.metadata = nil
61
+ expect(empty_device_details.metadata).to eql({})
62
+ end
63
+
64
+ specify 'rejects non Hash or nil values' do
65
+ expect { empty_device_details.metadata = "foo" }.to raise_error(ArgumentError)
66
+ end
67
+ end
68
+
69
+ describe "#push and #push=" do
70
+ let(:transport_type) { random_str }
71
+ let(:new_val) { { recipient: { transport_type: transport_type } } }
72
+ let(:json_val) { { recipient: { transportType: transport_type } }.to_json }
73
+
74
+ specify 'setter accepts a DevicePushDetails object and getter returns a DevicePushDetails object' do
75
+ expect(empty_device_details.push.to_json).to eql({}.to_json)
76
+ empty_device_details.push = DevicePushDetails(new_val)
77
+ expect(empty_device_details.push).to be_a(Ably::Models::DevicePushDetails)
78
+ expect(empty_device_details.push.recipient[:transport_type]).to eql(transport_type)
79
+ expect(empty_device_details.push.to_json).to eql(json_val)
80
+ end
81
+
82
+ specify 'setter accepts a Hash value and getter returns a DevicePushDetails object' do
83
+ expect(empty_device_details.push.to_json).to eql({}.to_json)
84
+ empty_device_details.push = new_val
85
+ expect(empty_device_details.push).to be_a(Ably::Models::DevicePushDetails)
86
+ expect(empty_device_details.push.recipient[:transport_type]).to eql(transport_type)
87
+ expect(empty_device_details.push.to_json).to eql(json_val)
88
+ end
89
+
90
+ specify 'setter accepts nil but always returns a DevicePushDetails object' do
91
+ empty_device_details.push = new_val
92
+ expect(empty_device_details.push.to_json).to eql(json_val)
93
+ empty_device_details.push = nil
94
+ expect(empty_device_details.push).to be_a(Ably::Models::DevicePushDetails)
95
+ expect(empty_device_details.push.to_json).to eql({}.to_json)
96
+ end
97
+
98
+ specify 'rejects non Hash, DevicePushDetails or nil values' do
99
+ expect { empty_device_details.metadata = "foo" }.to raise_error(ArgumentError)
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'shared/model_behaviour'
4
+
5
+ describe Ably::Models::DevicePushDetails do
6
+ include Ably::Modules::Conversions
7
+
8
+ subject { Ably::Models::DevicePushDetails }
9
+
10
+ %w(state).each do |string_attribute|
11
+ let(:empty_push_details) { subject.new }
12
+
13
+ describe "##{string_attribute} and ##{string_attribute}=" do
14
+ let(:new_val) { random_str }
15
+
16
+ specify 'setter accepts a string value and getter returns the new value' do
17
+ expect(empty_push_details.public_send(string_attribute)).to be_nil
18
+ empty_push_details.public_send("#{string_attribute}=", new_val)
19
+ expect(empty_push_details.public_send(string_attribute)).to eql(new_val)
20
+ end
21
+
22
+ specify 'setter accepts nil' do
23
+ empty_push_details.public_send("#{string_attribute}=", new_val)
24
+ expect(empty_push_details.public_send(string_attribute)).to eql(new_val)
25
+ empty_push_details.public_send("#{string_attribute}=", nil)
26
+ expect(empty_push_details.public_send(string_attribute)).to be_nil
27
+ end
28
+
29
+ specify 'rejects non string or nil values' do
30
+ expect { empty_push_details.public_send("#{string_attribute}=", {}) }.to raise_error(ArgumentError)
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'camelCase constructor attributes' do
36
+ let(:transport_type) { random_str }
37
+ let(:push_details) { subject.new('errorReason' => { 'message' => 'foo' }, 'recipient' => { 'transportType' => transport_type }) }
38
+
39
+ specify 'are rubyfied and exposed as underscore case' do
40
+ expect(push_details.recipient[:transport_type]).to eql(transport_type)
41
+ expect(push_details.error_reason.message).to eql('foo')
42
+ end
43
+
44
+ specify 'are generated when the object is serialised to JSON' do
45
+ expect(JSON.parse(push_details.to_json)['recipient']['transportType']).to eql(transport_type)
46
+ end
47
+ end
48
+
49
+ describe "#recipient and #recipient=" do
50
+ let(:new_val) { { foo: random_str } }
51
+
52
+ specify 'setter accepts a Hash value and getter returns the new value' do
53
+ expect(empty_push_details.recipient).to eql({})
54
+ empty_push_details.recipient = new_val
55
+ expect(empty_push_details.recipient.to_json).to eql(new_val.to_json)
56
+ end
57
+
58
+ specify 'setter accepts nil but always returns an empty hash' do
59
+ empty_push_details.recipient = new_val
60
+ expect(empty_push_details.recipient.to_json).to eql(new_val.to_json)
61
+ empty_push_details.recipient = nil
62
+ expect(empty_push_details.recipient).to eql({})
63
+ end
64
+
65
+ specify 'rejects non Hash or nil values' do
66
+ expect { empty_push_details.recipient = "foo" }.to raise_error(ArgumentError)
67
+ end
68
+ end
69
+
70
+ describe "#error_reason and #error_reason=" do
71
+ let(:error_message) { random_str }
72
+ let(:error_attributes) { { message: error_message } }
73
+
74
+ specify 'setter accepts a ErrorInfo object and getter returns a ErrorInfo object' do
75
+ expect(empty_push_details.error_reason).to be_nil
76
+ empty_push_details.error_reason = ErrorInfo(error_attributes)
77
+ expect(empty_push_details.error_reason).to be_a(Ably::Models::ErrorInfo)
78
+ expect(empty_push_details.error_reason.message).to eql(error_message)
79
+ expect(empty_push_details.error_reason.to_json).to eql(error_attributes.to_json)
80
+ end
81
+
82
+ specify 'setter accepts a Hash value and getter returns a ErrorInfo object' do
83
+ expect(empty_push_details.error_reason).to be_nil
84
+ empty_push_details.error_reason = error_attributes
85
+ expect(empty_push_details.error_reason).to be_a(Ably::Models::ErrorInfo)
86
+ expect(empty_push_details.error_reason.message).to eql(error_message)
87
+ expect(empty_push_details.error_reason.to_json).to eql(error_attributes.to_json)
88
+ end
89
+
90
+ specify 'setter accepts nil values' do
91
+ empty_push_details.error_reason = error_attributes
92
+ expect(empty_push_details.error_reason.to_json).to eql(error_attributes.to_json)
93
+ empty_push_details.error_reason = nil
94
+ expect(empty_push_details.error_reason).to be_nil
95
+ end
96
+
97
+ specify 'rejects non Hash, ErrorInfo or nil values' do
98
+ expect { empty_push_details.error_reason = "foo" }.to raise_error(ArgumentError)
99
+ end
100
+ end
101
+ end
@@ -4,15 +4,63 @@ require 'shared/model_behaviour'
4
4
  describe Ably::Models::ErrorInfo do
5
5
  subject { Ably::Models::ErrorInfo }
6
6
 
7
- it_behaves_like 'a model', with_simple_attributes: %w(code status_code message) do
8
- let(:model_args) { [] }
7
+ context '#TI1, #TI4' do
8
+ it_behaves_like 'a model', with_simple_attributes: %w(code status_code href message) do
9
+ let(:model_args) { [] }
10
+ end
9
11
  end
10
12
 
11
- context '#status' do
13
+ context '#status #TI1, #TI2' do
12
14
  subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
13
15
  it 'is an alias for #status_code' do
14
16
  expect(subject.status).to eql(subject.status_code)
15
17
  expect(subject.status).to eql(401)
16
18
  end
17
19
  end
20
+
21
+ context 'log entries container help link #TI5' do
22
+ context 'without an error code' do
23
+ subject { Ably::Models::ErrorInfo.new('statusCode' => 401) }
24
+
25
+ it 'does not include the help URL' do
26
+ expect(subject.to_s.scan(/help\.ably\.io/)).to be_empty
27
+ end
28
+ end
29
+
30
+ context 'with a specified error code' do
31
+ subject { Ably::Models::ErrorInfo.new('code' => 44444) }
32
+
33
+ it 'includes https://help.ably.io/error/[CODE] in the stringified object' do
34
+ expect(subject.to_s).to include('https://help.ably.io/error/44444')
35
+ end
36
+ end
37
+
38
+ context 'with an error code and an href attribute' do
39
+ subject { Ably::Models::ErrorInfo.new('code' => 44444, 'href' => 'http://foo.bar.com/') }
40
+
41
+ it 'includes the specified href in the stringified object' do
42
+ expect(subject.to_s).to include('http://foo.bar.com/')
43
+ expect(subject.to_s).to_not include('https://help.ably.io/error/44444')
44
+ end
45
+ end
46
+
47
+ context 'with an error code and a message with the same error URL' do
48
+ subject { Ably::Models::ErrorInfo.new('message' => 'error https://help.ably.io/error/44444', 'code' => 44444) }
49
+
50
+ it 'includes the specified error URL only once in the stringified object' do
51
+ expect(subject.to_s.scan(/help.ably.io/).length).to eql(1)
52
+ end
53
+ end
54
+
55
+ context 'with an error code and a message with a different error URL' do
56
+ subject { Ably::Models::ErrorInfo.new('message' => 'error https://help.ably.io/error/123123', 'code' => 44444) }
57
+
58
+ it 'includes the specified error URL from the message and the error code URL in the stringified object' do
59
+ puts subject.to_s
60
+ expect(subject.to_s.scan(/help.ably.io/).length).to eql(2)
61
+ expect(subject.to_s.scan(%r{error/123123}).length).to eql(1)
62
+ expect(subject.to_s.scan(%r{error/44444}).length).to eql(1)
63
+ end
64
+ end
65
+ end
18
66
  end
@@ -12,8 +12,23 @@ describe Ably::Models::Message do
12
12
  let(:protocol_message_timestamp) { as_since_epoch(Time.now) }
13
13
  let(:protocol_message) { Ably::Models::ProtocolMessage.new(action: 1, timestamp: protocol_message_timestamp) }
14
14
 
15
- it_behaves_like 'a model', with_simple_attributes: %w(id name client_id data encoding) do
16
- let(:model_args) { [protocol_message: protocol_message] }
15
+ context 'serialization of the Message object (#RSL1j)' do
16
+ it_behaves_like 'a model', with_simple_attributes: %w(id name client_id data encoding) do
17
+ let(:model_args) { [protocol_message: protocol_message] }
18
+ end
19
+ end
20
+
21
+ context '#id (#RSL1j)' do
22
+ let(:id) { random_str }
23
+ let(:model) { subject.new(id: id) }
24
+
25
+ it 'exposes the #id attribute' do
26
+ expect(model.id).to eql(id)
27
+ end
28
+
29
+ specify '#as_json exposes the #id attribute' do
30
+ expect(model.as_json['id']).to eql(id)
31
+ end
17
32
  end
18
33
 
19
34
  context '#timestamp' do