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.
- checksums.yaml +7 -0
- data/.github/workflows/rubocop.yml +27 -0
- data/.github/workflows/test.yml +27 -0
- data/.gitignore +37 -0
- data/.rubocop.yml +105 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -0
- data/LICENSE +674 -0
- data/README.md +999 -0
- data/Rakefile +25 -0
- data/dhc.gemspec +40 -0
- data/lib/core_ext/hash/deep_transform_values.rb +48 -0
- data/lib/dhc.rb +77 -0
- data/lib/dhc/concerns/dhc/basic_methods_concern.rb +42 -0
- data/lib/dhc/concerns/dhc/configuration_concern.rb +20 -0
- data/lib/dhc/concerns/dhc/fix_invalid_encoding_concern.rb +42 -0
- data/lib/dhc/concerns/dhc/formats_concern.rb +25 -0
- data/lib/dhc/concerns/dhc/request/user_agent_concern.rb +25 -0
- data/lib/dhc/config.rb +47 -0
- data/lib/dhc/endpoint.rb +119 -0
- data/lib/dhc/error.rb +82 -0
- data/lib/dhc/errors/client_error.rb +73 -0
- data/lib/dhc/errors/parser_error.rb +4 -0
- data/lib/dhc/errors/server_error.rb +28 -0
- data/lib/dhc/errors/timeout.rb +4 -0
- data/lib/dhc/errors/unknown_error.rb +4 -0
- data/lib/dhc/format.rb +18 -0
- data/lib/dhc/formats.rb +8 -0
- data/lib/dhc/formats/form.rb +45 -0
- data/lib/dhc/formats/json.rb +55 -0
- data/lib/dhc/formats/multipart.rb +45 -0
- data/lib/dhc/formats/plain.rb +42 -0
- data/lib/dhc/interceptor.rb +36 -0
- data/lib/dhc/interceptors.rb +26 -0
- data/lib/dhc/interceptors/auth.rb +94 -0
- data/lib/dhc/interceptors/caching.rb +148 -0
- data/lib/dhc/interceptors/default_timeout.rb +16 -0
- data/lib/dhc/interceptors/logging.rb +37 -0
- data/lib/dhc/interceptors/monitoring.rb +92 -0
- data/lib/dhc/interceptors/prometheus.rb +51 -0
- data/lib/dhc/interceptors/retry.rb +41 -0
- data/lib/dhc/interceptors/rollbar.rb +36 -0
- data/lib/dhc/interceptors/throttle.rb +86 -0
- data/lib/dhc/interceptors/zipkin.rb +110 -0
- data/lib/dhc/railtie.rb +9 -0
- data/lib/dhc/request.rb +161 -0
- data/lib/dhc/response.rb +60 -0
- data/lib/dhc/response/data.rb +28 -0
- data/lib/dhc/response/data/base.rb +18 -0
- data/lib/dhc/response/data/collection.rb +16 -0
- data/lib/dhc/response/data/item.rb +29 -0
- data/lib/dhc/rspec.rb +11 -0
- data/lib/dhc/test/cache_helper.rb +3 -0
- data/lib/dhc/version.rb +5 -0
- data/script/ci/build.sh +19 -0
- data/spec/basic_methods/delete_spec.rb +34 -0
- data/spec/basic_methods/get_spec.rb +49 -0
- data/spec/basic_methods/post_spec.rb +42 -0
- data/spec/basic_methods/put_spec.rb +48 -0
- data/spec/basic_methods/request_spec.rb +19 -0
- data/spec/basic_methods/request_without_rails_spec.rb +29 -0
- data/spec/config/endpoints_spec.rb +63 -0
- data/spec/config/placeholders_spec.rb +32 -0
- data/spec/core_ext/hash/deep_transform_values_spec.rb +24 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +7 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +4 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +5 -0
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/bin/rake +6 -0
- data/spec/dummy/config.ru +6 -0
- data/spec/dummy/config/application.rb +16 -0
- data/spec/dummy/config/boot.rb +7 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +36 -0
- data/spec/dummy/config/environments/production.rb +77 -0
- data/spec/dummy/config/environments/test.rb +41 -0
- data/spec/dummy/config/initializers/assets.rb +10 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/dummy/config/initializers/inflections.rb +18 -0
- data/spec/dummy/config/initializers/mime_types.rb +6 -0
- data/spec/dummy/config/initializers/session_store.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/endpoint/compile_spec.rb +35 -0
- data/spec/endpoint/match_spec.rb +41 -0
- data/spec/endpoint/placeholders_spec.rb +30 -0
- data/spec/endpoint/remove_interpolated_params_spec.rb +17 -0
- data/spec/endpoint/values_as_params_spec.rb +31 -0
- data/spec/error/dup_spec.rb +12 -0
- data/spec/error/find_spec.rb +57 -0
- data/spec/error/response_spec.rb +17 -0
- data/spec/error/timeout_spec.rb +14 -0
- data/spec/error/to_s_spec.rb +85 -0
- data/spec/formats/form_spec.rb +27 -0
- data/spec/formats/json_spec.rb +66 -0
- data/spec/formats/multipart_spec.rb +26 -0
- data/spec/formats/plain_spec.rb +29 -0
- data/spec/interceptors/after_request_spec.rb +20 -0
- data/spec/interceptors/after_response_spec.rb +39 -0
- data/spec/interceptors/auth/basic_auth_spec.rb +17 -0
- data/spec/interceptors/auth/bearer_spec.rb +19 -0
- data/spec/interceptors/auth/body_spec.rb +36 -0
- data/spec/interceptors/auth/long_basic_auth_credentials_spec.rb +17 -0
- data/spec/interceptors/auth/no_instance_var_for_options_spec.rb +27 -0
- data/spec/interceptors/auth/reauthentication_configuration_spec.rb +61 -0
- data/spec/interceptors/auth/reauthentication_spec.rb +44 -0
- data/spec/interceptors/before_request_spec.rb +21 -0
- data/spec/interceptors/before_response_spec.rb +20 -0
- data/spec/interceptors/caching/hydra_spec.rb +26 -0
- data/spec/interceptors/caching/main_spec.rb +73 -0
- data/spec/interceptors/caching/methods_spec.rb +42 -0
- data/spec/interceptors/caching/multilevel_cache_spec.rb +139 -0
- data/spec/interceptors/caching/options_spec.rb +78 -0
- data/spec/interceptors/caching/parameters_spec.rb +24 -0
- data/spec/interceptors/caching/response_status_spec.rb +29 -0
- data/spec/interceptors/caching/to_cache_spec.rb +16 -0
- data/spec/interceptors/default_interceptors_spec.rb +15 -0
- data/spec/interceptors/default_timeout/main_spec.rb +34 -0
- data/spec/interceptors/define_spec.rb +30 -0
- data/spec/interceptors/dup_spec.rb +19 -0
- data/spec/interceptors/logging/main_spec.rb +37 -0
- data/spec/interceptors/monitoring/caching_spec.rb +66 -0
- data/spec/interceptors/monitoring/main_spec.rb +97 -0
- data/spec/interceptors/prometheus_spec.rb +54 -0
- data/spec/interceptors/response_competition_spec.rb +39 -0
- data/spec/interceptors/retry/main_spec.rb +73 -0
- data/spec/interceptors/return_response_spec.rb +38 -0
- data/spec/interceptors/rollbar/invalid_encoding_spec.rb +43 -0
- data/spec/interceptors/rollbar/main_spec.rb +57 -0
- data/spec/interceptors/throttle/main_spec.rb +236 -0
- data/spec/interceptors/throttle/reset_track_spec.rb +53 -0
- data/spec/interceptors/zipkin/distributed_tracing_spec.rb +135 -0
- data/spec/rails_helper.rb +6 -0
- data/spec/request/body_spec.rb +39 -0
- data/spec/request/encoding_spec.rb +38 -0
- data/spec/request/error_handling_spec.rb +88 -0
- data/spec/request/headers_spec.rb +12 -0
- data/spec/request/ignore_errors_spec.rb +73 -0
- data/spec/request/option_dup_spec.rb +13 -0
- data/spec/request/parallel_requests_spec.rb +59 -0
- data/spec/request/params_encoding_spec.rb +26 -0
- data/spec/request/request_without_rails_spec.rb +15 -0
- data/spec/request/url_patterns_spec.rb +54 -0
- data/spec/request/user_agent_spec.rb +26 -0
- data/spec/request/user_agent_without_rails_spec.rb +27 -0
- data/spec/response/body_spec.rb +16 -0
- data/spec/response/code_spec.rb +16 -0
- data/spec/response/data_accessor_spec.rb +29 -0
- data/spec/response/data_spec.rb +85 -0
- data/spec/response/effective_url_spec.rb +16 -0
- data/spec/response/headers_spec.rb +18 -0
- data/spec/response/options_spec.rb +18 -0
- data/spec/response/success_spec.rb +13 -0
- data/spec/response/time_spec.rb +21 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/fixtures/json/feedback.json +11 -0
- data/spec/support/fixtures/json/feedbacks.json +164 -0
- data/spec/support/fixtures/json/localina_content_ad.json +23 -0
- data/spec/support/load_json.rb +5 -0
- data/spec/support/reset_config.rb +8 -0
- data/spec/support/zipkin_mock.rb +114 -0
- data/spec/timeouts/no_signal_spec.rb +13 -0
- data/spec/timeouts/timings_spec.rb +55 -0
- 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,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
|