dhc 1.0.0

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 (185) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rubocop.yml +27 -0
  3. data/.github/workflows/test.yml +27 -0
  4. data/.gitignore +37 -0
  5. data/.rubocop.yml +105 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +5 -0
  8. data/LICENSE +674 -0
  9. data/README.md +999 -0
  10. data/Rakefile +25 -0
  11. data/dhc.gemspec +40 -0
  12. data/lib/core_ext/hash/deep_transform_values.rb +48 -0
  13. data/lib/dhc.rb +77 -0
  14. data/lib/dhc/concerns/dhc/basic_methods_concern.rb +42 -0
  15. data/lib/dhc/concerns/dhc/configuration_concern.rb +20 -0
  16. data/lib/dhc/concerns/dhc/fix_invalid_encoding_concern.rb +42 -0
  17. data/lib/dhc/concerns/dhc/formats_concern.rb +25 -0
  18. data/lib/dhc/concerns/dhc/request/user_agent_concern.rb +25 -0
  19. data/lib/dhc/config.rb +47 -0
  20. data/lib/dhc/endpoint.rb +119 -0
  21. data/lib/dhc/error.rb +82 -0
  22. data/lib/dhc/errors/client_error.rb +73 -0
  23. data/lib/dhc/errors/parser_error.rb +4 -0
  24. data/lib/dhc/errors/server_error.rb +28 -0
  25. data/lib/dhc/errors/timeout.rb +4 -0
  26. data/lib/dhc/errors/unknown_error.rb +4 -0
  27. data/lib/dhc/format.rb +18 -0
  28. data/lib/dhc/formats.rb +8 -0
  29. data/lib/dhc/formats/form.rb +45 -0
  30. data/lib/dhc/formats/json.rb +55 -0
  31. data/lib/dhc/formats/multipart.rb +45 -0
  32. data/lib/dhc/formats/plain.rb +42 -0
  33. data/lib/dhc/interceptor.rb +36 -0
  34. data/lib/dhc/interceptors.rb +26 -0
  35. data/lib/dhc/interceptors/auth.rb +94 -0
  36. data/lib/dhc/interceptors/caching.rb +148 -0
  37. data/lib/dhc/interceptors/default_timeout.rb +16 -0
  38. data/lib/dhc/interceptors/logging.rb +37 -0
  39. data/lib/dhc/interceptors/monitoring.rb +92 -0
  40. data/lib/dhc/interceptors/prometheus.rb +51 -0
  41. data/lib/dhc/interceptors/retry.rb +41 -0
  42. data/lib/dhc/interceptors/rollbar.rb +36 -0
  43. data/lib/dhc/interceptors/throttle.rb +86 -0
  44. data/lib/dhc/interceptors/zipkin.rb +110 -0
  45. data/lib/dhc/railtie.rb +9 -0
  46. data/lib/dhc/request.rb +161 -0
  47. data/lib/dhc/response.rb +60 -0
  48. data/lib/dhc/response/data.rb +28 -0
  49. data/lib/dhc/response/data/base.rb +18 -0
  50. data/lib/dhc/response/data/collection.rb +16 -0
  51. data/lib/dhc/response/data/item.rb +29 -0
  52. data/lib/dhc/rspec.rb +11 -0
  53. data/lib/dhc/test/cache_helper.rb +3 -0
  54. data/lib/dhc/version.rb +5 -0
  55. data/script/ci/build.sh +19 -0
  56. data/spec/basic_methods/delete_spec.rb +34 -0
  57. data/spec/basic_methods/get_spec.rb +49 -0
  58. data/spec/basic_methods/post_spec.rb +42 -0
  59. data/spec/basic_methods/put_spec.rb +48 -0
  60. data/spec/basic_methods/request_spec.rb +19 -0
  61. data/spec/basic_methods/request_without_rails_spec.rb +29 -0
  62. data/spec/config/endpoints_spec.rb +63 -0
  63. data/spec/config/placeholders_spec.rb +32 -0
  64. data/spec/core_ext/hash/deep_transform_values_spec.rb +24 -0
  65. data/spec/dummy/README.rdoc +28 -0
  66. data/spec/dummy/Rakefile +8 -0
  67. data/spec/dummy/app/assets/config/manifest.js +3 -0
  68. data/spec/dummy/app/assets/images/.keep +0 -0
  69. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  70. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  71. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  72. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  73. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  74. data/spec/dummy/app/mailers/.keep +0 -0
  75. data/spec/dummy/app/models/.keep +0 -0
  76. data/spec/dummy/app/models/concerns/.keep +0 -0
  77. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  78. data/spec/dummy/bin/bundle +5 -0
  79. data/spec/dummy/bin/rails +6 -0
  80. data/spec/dummy/bin/rake +6 -0
  81. data/spec/dummy/config.ru +6 -0
  82. data/spec/dummy/config/application.rb +16 -0
  83. data/spec/dummy/config/boot.rb +7 -0
  84. data/spec/dummy/config/environment.rb +7 -0
  85. data/spec/dummy/config/environments/development.rb +36 -0
  86. data/spec/dummy/config/environments/production.rb +77 -0
  87. data/spec/dummy/config/environments/test.rb +41 -0
  88. data/spec/dummy/config/initializers/assets.rb +10 -0
  89. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  90. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  91. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  92. data/spec/dummy/config/initializers/inflections.rb +18 -0
  93. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  94. data/spec/dummy/config/initializers/session_store.rb +5 -0
  95. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  96. data/spec/dummy/config/locales/en.yml +23 -0
  97. data/spec/dummy/config/routes.rb +58 -0
  98. data/spec/dummy/config/secrets.yml +22 -0
  99. data/spec/dummy/lib/assets/.keep +0 -0
  100. data/spec/dummy/log/.keep +0 -0
  101. data/spec/dummy/public/404.html +67 -0
  102. data/spec/dummy/public/422.html +67 -0
  103. data/spec/dummy/public/500.html +66 -0
  104. data/spec/dummy/public/favicon.ico +0 -0
  105. data/spec/endpoint/compile_spec.rb +35 -0
  106. data/spec/endpoint/match_spec.rb +41 -0
  107. data/spec/endpoint/placeholders_spec.rb +30 -0
  108. data/spec/endpoint/remove_interpolated_params_spec.rb +17 -0
  109. data/spec/endpoint/values_as_params_spec.rb +31 -0
  110. data/spec/error/dup_spec.rb +12 -0
  111. data/spec/error/find_spec.rb +57 -0
  112. data/spec/error/response_spec.rb +17 -0
  113. data/spec/error/timeout_spec.rb +14 -0
  114. data/spec/error/to_s_spec.rb +85 -0
  115. data/spec/formats/form_spec.rb +27 -0
  116. data/spec/formats/json_spec.rb +66 -0
  117. data/spec/formats/multipart_spec.rb +26 -0
  118. data/spec/formats/plain_spec.rb +29 -0
  119. data/spec/interceptors/after_request_spec.rb +20 -0
  120. data/spec/interceptors/after_response_spec.rb +39 -0
  121. data/spec/interceptors/auth/basic_auth_spec.rb +17 -0
  122. data/spec/interceptors/auth/bearer_spec.rb +19 -0
  123. data/spec/interceptors/auth/body_spec.rb +36 -0
  124. data/spec/interceptors/auth/long_basic_auth_credentials_spec.rb +17 -0
  125. data/spec/interceptors/auth/no_instance_var_for_options_spec.rb +27 -0
  126. data/spec/interceptors/auth/reauthentication_configuration_spec.rb +61 -0
  127. data/spec/interceptors/auth/reauthentication_spec.rb +44 -0
  128. data/spec/interceptors/before_request_spec.rb +21 -0
  129. data/spec/interceptors/before_response_spec.rb +20 -0
  130. data/spec/interceptors/caching/hydra_spec.rb +26 -0
  131. data/spec/interceptors/caching/main_spec.rb +73 -0
  132. data/spec/interceptors/caching/methods_spec.rb +42 -0
  133. data/spec/interceptors/caching/multilevel_cache_spec.rb +139 -0
  134. data/spec/interceptors/caching/options_spec.rb +78 -0
  135. data/spec/interceptors/caching/parameters_spec.rb +24 -0
  136. data/spec/interceptors/caching/response_status_spec.rb +29 -0
  137. data/spec/interceptors/caching/to_cache_spec.rb +16 -0
  138. data/spec/interceptors/default_interceptors_spec.rb +15 -0
  139. data/spec/interceptors/default_timeout/main_spec.rb +34 -0
  140. data/spec/interceptors/define_spec.rb +30 -0
  141. data/spec/interceptors/dup_spec.rb +19 -0
  142. data/spec/interceptors/logging/main_spec.rb +37 -0
  143. data/spec/interceptors/monitoring/caching_spec.rb +66 -0
  144. data/spec/interceptors/monitoring/main_spec.rb +97 -0
  145. data/spec/interceptors/prometheus_spec.rb +54 -0
  146. data/spec/interceptors/response_competition_spec.rb +39 -0
  147. data/spec/interceptors/retry/main_spec.rb +73 -0
  148. data/spec/interceptors/return_response_spec.rb +38 -0
  149. data/spec/interceptors/rollbar/invalid_encoding_spec.rb +43 -0
  150. data/spec/interceptors/rollbar/main_spec.rb +57 -0
  151. data/spec/interceptors/throttle/main_spec.rb +236 -0
  152. data/spec/interceptors/throttle/reset_track_spec.rb +53 -0
  153. data/spec/interceptors/zipkin/distributed_tracing_spec.rb +135 -0
  154. data/spec/rails_helper.rb +6 -0
  155. data/spec/request/body_spec.rb +39 -0
  156. data/spec/request/encoding_spec.rb +38 -0
  157. data/spec/request/error_handling_spec.rb +88 -0
  158. data/spec/request/headers_spec.rb +12 -0
  159. data/spec/request/ignore_errors_spec.rb +73 -0
  160. data/spec/request/option_dup_spec.rb +13 -0
  161. data/spec/request/parallel_requests_spec.rb +59 -0
  162. data/spec/request/params_encoding_spec.rb +26 -0
  163. data/spec/request/request_without_rails_spec.rb +15 -0
  164. data/spec/request/url_patterns_spec.rb +54 -0
  165. data/spec/request/user_agent_spec.rb +26 -0
  166. data/spec/request/user_agent_without_rails_spec.rb +27 -0
  167. data/spec/response/body_spec.rb +16 -0
  168. data/spec/response/code_spec.rb +16 -0
  169. data/spec/response/data_accessor_spec.rb +29 -0
  170. data/spec/response/data_spec.rb +85 -0
  171. data/spec/response/effective_url_spec.rb +16 -0
  172. data/spec/response/headers_spec.rb +18 -0
  173. data/spec/response/options_spec.rb +18 -0
  174. data/spec/response/success_spec.rb +13 -0
  175. data/spec/response/time_spec.rb +21 -0
  176. data/spec/spec_helper.rb +9 -0
  177. data/spec/support/fixtures/json/feedback.json +11 -0
  178. data/spec/support/fixtures/json/feedbacks.json +164 -0
  179. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  180. data/spec/support/load_json.rb +5 -0
  181. data/spec/support/reset_config.rb +8 -0
  182. data/spec/support/zipkin_mock.rb +114 -0
  183. data/spec/timeouts/no_signal_spec.rb +13 -0
  184. data/spec/timeouts/timings_spec.rb +55 -0
  185. metadata +527 -0
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Throttle do
6
+ let(:provider) { 'depay.fi' }
7
+ let(:limit) { 10_000 }
8
+ let(:remaining) { 1900 }
9
+ let(:options) do
10
+ {
11
+ throttle: {
12
+ provider: provider,
13
+ track: true,
14
+ limit: limit_options,
15
+ remaining: { header: 'Rate-Limit-Remaining' },
16
+ expires: { header: 'Rate-Limit-Reset' },
17
+ break: '80%'
18
+ }
19
+ }
20
+ end
21
+ let(:limit_options) { { header: 'Rate-Limit-Limit' } }
22
+ let(:break_option) { false }
23
+ let(:expires_in) { (Time.zone.now + 1.hour).to_i }
24
+
25
+ before(:each) do
26
+ DHC::Throttle.track = nil
27
+ DHC.config.interceptors = [DHC::Throttle]
28
+
29
+ stub_request(:get, 'http://depay.fi')
30
+ .to_return(
31
+ headers: {
32
+ 'Rate-Limit-Limit' => limit,
33
+ 'Rate-Limit-Remaining' => remaining,
34
+ 'Rate-Limit-Reset' => expires_in
35
+ }
36
+ )
37
+ end
38
+
39
+ # If DHC::Trottle.track would be kept accross multiple tests,
40
+ # at least 2/3 of the following would fail
41
+
42
+ it 'resets track accross multiple tests 1/3' do
43
+ DHC.get('http://depay.fi', options)
44
+ end
45
+
46
+ it 'resets track accross multiple tests 2/3' do
47
+ DHC.get('http://depay.fi', options)
48
+ end
49
+
50
+ it 'resets track accross multiple tests 3/3' do
51
+ DHC.get('http://depay.fi', options)
52
+ end
53
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Zipkin do
6
+ before(:each) do
7
+ DHC.config.interceptors = [described_class]
8
+ DHC.config.endpoint(:local, 'http://depay.fi')
9
+ stub_request(:get, 'http://depay.fi').to_return(status: 200, body: 'The Website')
10
+ end
11
+
12
+ context 'with zipkin tracer integration' do
13
+ before(:all) do
14
+ ::ZipkinTracer::TraceContainer.setup_mock(
15
+ trace_id: 'trace_id',
16
+ parent_id: 'parent_id',
17
+ span_id: 'span_id',
18
+ sampled: true,
19
+ flags: 'flags'
20
+ )
21
+ end
22
+
23
+ it 'adds the proper X-B3 headers and trace the request' do
24
+ expect(::ZipkinTracer::TraceContainer).to receive(:with_trace_id).and_call_original
25
+ headers = DHC.get(:local).request.headers
26
+ expect(headers['X-B3-TraceId']).to eq('trace_id')
27
+ expect(headers['X-B3-ParentSpanId']).to eq('parent_id')
28
+ expect(headers['X-B3-SpanId']).to eq('span_id')
29
+ expect(headers['X-B3-Sampled']).to eq('true')
30
+ expect(headers['X-B3-Flags']).to eq('flags')
31
+ end
32
+ end
33
+
34
+ describe 'creating new spans' do
35
+ context 'sampled? is false' do
36
+ before(:all) do
37
+ ::ZipkinTracer::TraceContainer.setup_mock(
38
+ trace_id: 'trace_id',
39
+ parent_id: 'parent_id',
40
+ span_id: 'span_id',
41
+ sampled: false,
42
+ flags: 'flags'
43
+ )
44
+ end
45
+
46
+ it 'adds the proper X-B3 headers' do
47
+ headers = DHC.get(:local).request.headers
48
+ expect(headers['X-B3-TraceId']).to eq('trace_id')
49
+ expect(headers['X-B3-ParentSpanId']).to eq('parent_id')
50
+ expect(headers['X-B3-SpanId']).to eq('span_id')
51
+ expect(headers['X-B3-Sampled']).to eq('false')
52
+ expect(headers['X-B3-Flags']).to eq('flags')
53
+ end
54
+
55
+ it 'does not register a new span' do
56
+ # ensure no span was registered, by checking no call on span
57
+ expect_any_instance_of(described_class).not_to receive(:span).and_call_original
58
+ DHC.get(:local)
59
+ end
60
+ end
61
+
62
+ context 'sampled? is true' do
63
+ before(:all) do
64
+ ::ZipkinTracer::TraceContainer.setup_mock(
65
+ trace_id: 'trace_id',
66
+ parent_id: 'parent_id',
67
+ span_id: 'span_id',
68
+ sampled: true,
69
+ flags: 'flags'
70
+ )
71
+ end
72
+
73
+ it 'adds the proper X-B3 headers' do
74
+ headers = DHC.get(:local).request.headers
75
+ expect(headers['X-B3-TraceId']).to eq('trace_id')
76
+ expect(headers['X-B3-ParentSpanId']).to eq('parent_id')
77
+ expect(headers['X-B3-SpanId']).to eq('span_id')
78
+ expect(headers['X-B3-Sampled']).to eq('true')
79
+ expect(headers['X-B3-Flags']).to eq('flags')
80
+ end
81
+
82
+ it 'does register a new span' do
83
+ # ensure a span was registered, by checking call on span
84
+ expect_any_instance_of(described_class).to receive(:span).at_least(:once).and_call_original
85
+ DHC.get(:local)
86
+ end
87
+ end
88
+ end
89
+
90
+ %w[ZipkinTracer Trace].each do |klass|
91
+ context "without #{klass}" do
92
+ before(:all) do
93
+ TemporaryClass = Object.send(:const_get, klass)
94
+ Object.send(:remove_const, klass)
95
+ end
96
+
97
+ after(:all) do
98
+ Object.send(:const_set, klass, TemporaryClass)
99
+ end
100
+
101
+ it 'does not trace the request' do
102
+ headers = nil
103
+ expect { headers = DHC.get(:local).request.headers }.not_to raise_error
104
+ expect(headers['X-B3-TraceId']).to be_nil
105
+ expect(headers['X-B3-ParentSpanId']).to be_nil
106
+ expect(headers['X-B3-SpanId']).to be_nil
107
+ expect(headers['X-B3-Sampled']).to be_nil
108
+ expect(headers['X-B3-Flags']).to be_nil
109
+ end
110
+ end
111
+ end
112
+
113
+ %w[Annotation BinaryAnnotation Endpoint].each do |klass|
114
+ context "without Trace::#{klass}" do
115
+ before(:all) do
116
+ TemporaryClass = Trace.send(:const_get, klass)
117
+ Trace.send(:remove_const, klass)
118
+ end
119
+
120
+ after(:all) do
121
+ Trace.send(:const_set, klass, TemporaryClass)
122
+ end
123
+
124
+ it 'does not trace the request' do
125
+ headers = nil
126
+ expect { headers = DHC.get(:local).request.headers }.not_to raise_error
127
+ expect(headers['X-B3-TraceId']).to be_nil
128
+ expect(headers['X-B3-ParentSpanId']).to be_nil
129
+ expect(headers['X-B3-SpanId']).to be_nil
130
+ expect(headers['X-B3-Sampled']).to be_nil
131
+ expect(headers['X-B3-Flags']).to be_nil
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ ENV['RAILS_ENV'] ||= 'test'
5
+
6
+ require File.expand_path('dummy/config/environment', __dir__)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Request do
6
+ context 'encode body' do
7
+ let(:encoded_data) { data.to_json }
8
+
9
+ before do
10
+ stub_request(:post, 'http://datastore/q')
11
+ .with(body: encoded_data)
12
+ .to_return(status: 200)
13
+ end
14
+
15
+ context 'hash' do
16
+ let(:data) { { name: 'Steve' } }
17
+
18
+ it 'encodes the request body to the given format' do
19
+ DHC.post('http://datastore/q', body: data)
20
+ end
21
+
22
+ it 'does not encode the request body if it is already a string' do
23
+ DHC.post('http://datastore/q', body: encoded_data)
24
+ end
25
+ end
26
+
27
+ context 'array' do
28
+ let(:data) { [{ name: 'Steve' }] }
29
+
30
+ it 'encodes the request body to the given format' do
31
+ DHC.post('http://datastore/q', body: data)
32
+ end
33
+
34
+ it 'does not encode the request body if it is already a string' do
35
+ DHC.post('http://datastore/q', body: encoded_data)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'addressable'
4
+ require 'rails_helper'
5
+
6
+ describe DHC::Request do
7
+ context 'encoding url' do
8
+ let(:url) { 'http://depay.fi/something with spaces' }
9
+
10
+ it 'can request urls with spaces inside' do
11
+ stub_request(:get, Addressable::URI.encode(url))
12
+ DHC.get(url)
13
+ end
14
+ end
15
+
16
+ context 'encoding params' do
17
+ let(:url) { 'http://depay.fi/api/search?name=:name' }
18
+
19
+ it 'can do requests with params including spaces' do
20
+ stub_request(:get, 'http://depay.fi/api/search?name=My%20name%20is%20rabbit')
21
+ DHC.get(url, params: { name: 'My name is rabbit' })
22
+ end
23
+ end
24
+
25
+ context 'skip encoding' do
26
+ let(:url) { 'http://depay.fi/api/search?names[]=seba&names[]=david' }
27
+
28
+ it 'does not encode if encoding is skipped' do
29
+ stub_request(:get, 'http://depay.fi/api/search?names%5B%5D%3Dseba%26names%5B%5D%3Ddavid')
30
+ DHC.get('http://depay.fi/api/search?names%5B%5D%3Dseba%26names%5B%5D%3Ddavid', url_encoding: false)
31
+ end
32
+
33
+ it 'does double encoding, if you really want to' do
34
+ stub_request(:get, 'http://depay.fi/api/search?names%255B%255D%253Dseba%2526names%255B%255D%253Ddavid')
35
+ DHC.get('http://depay.fi/api/search?names%5B%5D%3Dseba%26names%5B%5D%3Ddavid')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Request do
6
+ context 'error handling' do
7
+ def to_fail_with(error)
8
+ raise_error(error)
9
+ end
10
+
11
+ def expect_status_code(status_code)
12
+ stub_request(:get, "http://something/#{status_code}").to_return(status: status_code)
13
+ expect(
14
+ -> { DHC::Request.new(url: "http://something/#{status_code}") }
15
+ ).to yield
16
+ end
17
+
18
+ it 'raises errors for anything but 2XX response codes' do
19
+ expect_status_code(0) { to_fail_with(DHC::UnknownError) }
20
+ expect_status_code(400) { to_fail_with(DHC::BadRequest) }
21
+ expect_status_code(401) { to_fail_with(DHC::Unauthorized) }
22
+ expect_status_code(402) { to_fail_with(DHC::PaymentRequired) }
23
+ expect_status_code(403) { to_fail_with(DHC::Forbidden) }
24
+ expect_status_code(403) { to_fail_with(DHC::Forbidden) }
25
+ expect_status_code(404) { to_fail_with(DHC::NotFound) }
26
+ expect_status_code(405) { to_fail_with(DHC::MethodNotAllowed) }
27
+ expect_status_code(406) { to_fail_with(DHC::NotAcceptable) }
28
+ expect_status_code(407) { to_fail_with(DHC::ProxyAuthenticationRequired) }
29
+ expect_status_code(408) { to_fail_with(DHC::RequestTimeout) }
30
+ expect_status_code(409) { to_fail_with(DHC::Conflict) }
31
+ expect_status_code(410) { to_fail_with(DHC::Gone) }
32
+ expect_status_code(411) { to_fail_with(DHC::LengthRequired) }
33
+ expect_status_code(412) { to_fail_with(DHC::PreconditionFailed) }
34
+ expect_status_code(413) { to_fail_with(DHC::RequestEntityTooLarge) }
35
+ expect_status_code(414) { to_fail_with(DHC::RequestUriToLong) }
36
+ expect_status_code(415) { to_fail_with(DHC::UnsupportedMediaType) }
37
+ expect_status_code(416) { to_fail_with(DHC::RequestedRangeNotSatisfiable) }
38
+ expect_status_code(417) { to_fail_with(DHC::ExpectationFailed) }
39
+ expect_status_code(422) { to_fail_with(DHC::UnprocessableEntity) }
40
+ expect_status_code(423) { to_fail_with(DHC::Locked) }
41
+ expect_status_code(424) { to_fail_with(DHC::FailedDependency) }
42
+ expect_status_code(426) { to_fail_with(DHC::UpgradeRequired) }
43
+ expect_status_code(500) { to_fail_with(DHC::InternalServerError) }
44
+ expect_status_code(501) { to_fail_with(DHC::NotImplemented) }
45
+ expect_status_code(502) { to_fail_with(DHC::BadGateway) }
46
+ expect_status_code(503) { to_fail_with(DHC::ServiceUnavailable) }
47
+ expect_status_code(504) { to_fail_with(DHC::GatewayTimeout) }
48
+ expect_status_code(505) { to_fail_with(DHC::HttpVersionNotSupported) }
49
+ expect_status_code(507) { to_fail_with(DHC::InsufficientStorage) }
50
+ expect_status_code(510) { to_fail_with(DHC::NotExtended) }
51
+ end
52
+ end
53
+
54
+ context 'parsing error' do
55
+ before(:each) do
56
+ stub_request(:get, 'http://datastore/v2/feedbacks').to_return(body: 'invalid json')
57
+ end
58
+
59
+ it 'requests json and parses response body' do
60
+ expect(-> {
61
+ DHC.json.get('http://datastore/v2/feedbacks').data
62
+ }).to raise_error(DHC::ParserError)
63
+ end
64
+ end
65
+
66
+ context 'custom error handler' do
67
+ it 'handles errors with the provided handler and does not raise them' do
68
+ stub_request(:get, 'http://something').to_return(status: 400)
69
+ handler = double('handler', call: -> {})
70
+ DHC::Request.new(url: 'http://something', rescue: handler)
71
+ expect(handler).to have_received(:call)
72
+ end
73
+
74
+ it 'exchanges body with handlers return if the handler returns something' do
75
+ stub_request(:get, 'http://something').to_return(status: 400)
76
+ handler = ->(_response) { { name: 'unknown' }.to_json }
77
+ request = DHC::Request.new(url: 'http://something', rescue: handler)
78
+ expect(request.response.data.name).to eq 'unknown'
79
+ end
80
+
81
+ it 'does not exchange body with handlers return if the handler returns nil' do
82
+ stub_request(:get, 'http://something').to_return(status: 400, body: { message: 'an error occurred' }.to_json)
83
+ handler = ->(_response) { nil }
84
+ request = DHC::Request.new(url: 'http://something', rescue: handler)
85
+ expect(request.response.data.message).to eq 'an error occurred'
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Request do
6
+ it 'provides request headers' do
7
+ stub_request(:get, 'http://depay.fi')
8
+ response = DHC.get('http://depay.fi')
9
+ request = response.request
10
+ expect(request.headers.keys).to include 'User-Agent'
11
+ end
12
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Request do
6
+ context 'ignoring DHC::NotFound' do
7
+ let(:response) { DHC.get('http://depay.fi', ignore: [DHC::NotFound]) }
8
+
9
+ before { stub_request(:get, 'http://depay.fi').to_return(status: 404) }
10
+
11
+ it 'does not raise an error' do
12
+ expect { response }.not_to raise_error
13
+ end
14
+
15
+ it 'body is nil' do
16
+ expect(response.body).to eq nil
17
+ end
18
+
19
+ it 'data is nil' do
20
+ expect(response.data).to eq nil
21
+ end
22
+
23
+ it 'does raise an error for 500' do
24
+ stub_request(:get, 'http://depay.fi').to_return(status: 500)
25
+ expect { response }.to raise_error DHC::InternalServerError
26
+ end
27
+
28
+ it 'provides the information if the error was ignored' do
29
+ expect(response.error_ignored?).to eq true
30
+ expect(response.request.error_ignored?).to eq true
31
+ end
32
+ end
33
+
34
+ context 'inheritance when ignoring errors' do
35
+ before { stub_request(:get, 'http://depay.fi').to_return(status: 404) }
36
+
37
+ it "does not raise an error when it's a subclass of the ignored error" do
38
+ expect {
39
+ DHC.get('http://depay.fi', ignore: [DHC::Error])
40
+ }.not_to raise_error
41
+ end
42
+
43
+ it "does raise an error if it's not a subclass of the ignored error" do
44
+ expect {
45
+ DHC.get('http://depay.fi', ignore: [ArgumentError])
46
+ }.to raise_error(DHC::NotFound)
47
+ end
48
+ end
49
+
50
+ context 'does not raise exception if ignored errors is set to nil' do
51
+ before { stub_request(:get, 'http://depay.fi').to_return(status: 404) }
52
+
53
+ it 'does not raise an error when ignored errors is set to array with nil' do
54
+ expect {
55
+ DHC.get('http://depay.fi', ignore: [nil])
56
+ }.to raise_error(DHC::NotFound)
57
+ end
58
+
59
+ it 'does not raise an error when ignored errors is set to nil' do
60
+ expect {
61
+ DHC.get('http://depay.fi', ignore: nil)
62
+ }.to raise_error(DHC::NotFound)
63
+ end
64
+ end
65
+
66
+ context 'passing keys instead of arrays' do
67
+ before { stub_request(:get, 'http://depay.fi').to_return(status: 404) }
68
+
69
+ it 'does not raise an error when ignored errors is a key instead of an array' do
70
+ DHC.get('http://depay.fi', ignore: DHC::NotFound)
71
+ end
72
+ end
73
+ end