lhc 12.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +37 -0
- data/.rubocop.localch.yml +325 -0
- data/.rubocop.yml +61 -0
- data/.ruby-version +1 -0
- data/Gemfile +13 -0
- data/Gemfile.activesupport4 +4 -0
- data/Gemfile.activesupport5 +4 -0
- data/Gemfile.activesupport6 +4 -0
- data/LICENSE +674 -0
- data/README.md +984 -0
- data/Rakefile +25 -0
- data/cider-ci.yml +6 -0
- data/cider-ci/bin/bundle +51 -0
- data/cider-ci/bin/ruby_install +8 -0
- data/cider-ci/bin/ruby_version +25 -0
- data/cider-ci/jobs/rspec-activesupport-4.yml +28 -0
- data/cider-ci/jobs/rspec-activesupport-5.yml +27 -0
- data/cider-ci/jobs/rspec-activesupport-6.yml +28 -0
- data/cider-ci/jobs/rubocop.yml +18 -0
- data/cider-ci/task_components/bundle.yml +22 -0
- data/cider-ci/task_components/rspec.yml +36 -0
- data/cider-ci/task_components/rubocop.yml +29 -0
- data/cider-ci/task_components/ruby.yml +15 -0
- data/friday.yml +3 -0
- data/lhc.gemspec +39 -0
- data/lib/core_ext/hash/deep_transform_values.rb +48 -0
- data/lib/lhc.rb +136 -0
- data/lib/lhc/concerns/lhc/basic_methods_concern.rb +42 -0
- data/lib/lhc/concerns/lhc/configuration_concern.rb +20 -0
- data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +42 -0
- data/lib/lhc/concerns/lhc/formats_concern.rb +25 -0
- data/lib/lhc/concerns/lhc/request/user_agent_concern.rb +25 -0
- data/lib/lhc/config.rb +47 -0
- data/lib/lhc/endpoint.rb +119 -0
- data/lib/lhc/error.rb +80 -0
- data/lib/lhc/errors/client_error.rb +73 -0
- data/lib/lhc/errors/parser_error.rb +4 -0
- data/lib/lhc/errors/server_error.rb +28 -0
- data/lib/lhc/errors/timeout.rb +4 -0
- data/lib/lhc/errors/unknown_error.rb +4 -0
- data/lib/lhc/format.rb +18 -0
- data/lib/lhc/formats.rb +8 -0
- data/lib/lhc/formats/form.rb +45 -0
- data/lib/lhc/formats/json.rb +55 -0
- data/lib/lhc/formats/multipart.rb +45 -0
- data/lib/lhc/formats/plain.rb +42 -0
- data/lib/lhc/interceptor.rb +32 -0
- data/lib/lhc/interceptors.rb +26 -0
- data/lib/lhc/interceptors/auth.rb +98 -0
- data/lib/lhc/interceptors/caching.rb +127 -0
- data/lib/lhc/interceptors/default_timeout.rb +16 -0
- data/lib/lhc/interceptors/logging.rb +37 -0
- data/lib/lhc/interceptors/monitoring.rb +63 -0
- data/lib/lhc/interceptors/prometheus.rb +51 -0
- data/lib/lhc/interceptors/retry.rb +41 -0
- data/lib/lhc/interceptors/rollbar.rb +36 -0
- data/lib/lhc/interceptors/throttle.rb +81 -0
- data/lib/lhc/interceptors/zipkin.rb +110 -0
- data/lib/lhc/railtie.rb +10 -0
- data/lib/lhc/request.rb +157 -0
- data/lib/lhc/response.rb +60 -0
- data/lib/lhc/response/data.rb +28 -0
- data/lib/lhc/response/data/base.rb +22 -0
- data/lib/lhc/response/data/collection.rb +16 -0
- data/lib/lhc/response/data/item.rb +29 -0
- data/lib/lhc/rspec.rb +12 -0
- data/lib/lhc/test/cache_helper.rb +3 -0
- data/lib/lhc/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 +80 -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/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/options_spec.rb +89 -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 +29 -0
- data/spec/interceptors/dup_spec.rb +19 -0
- data/spec/interceptors/logging/main_spec.rb +37 -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 +41 -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 +106 -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 +37 -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 +61 -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 +8 -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 +7 -0
- data/spec/support/zipkin_mock.rb +113 -0
- data/spec/timeouts/no_signal_spec.rb +13 -0
- data/spec/timeouts/timings_spec.rb +55 -0
- metadata +534 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
# due to the fact that options passed into LHC get dup'ed
|
6
|
+
# we need a class where we can setup method expectations
|
7
|
+
# with `expect_any_instance`
|
8
|
+
class CacheMock
|
9
|
+
def fetch(*_); end
|
10
|
+
|
11
|
+
def write(*_); end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe LHC::Caching do
|
15
|
+
let(:default_cache) { LHC::Caching.cache }
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website')
|
19
|
+
LHC.config.interceptors = [LHC::Caching]
|
20
|
+
default_cache.clear
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'maps deprecated cache options' do
|
24
|
+
expected_options = { expires_in: 5.minutes, race_condition_ttl: 15.seconds }
|
25
|
+
expected_key = "LHC_CACHE(v1): key"
|
26
|
+
expect(default_cache).to receive(:write).with(expected_key, anything, expected_options)
|
27
|
+
expect(lambda {
|
28
|
+
LHC.get('http://local.ch', cache: true, cache_expires_in: 5.minutes, cache_key: 'key', cache_race_condition_ttl: 15.seconds)
|
29
|
+
}).to output(
|
30
|
+
/Cache options have changed! cache_expires_in, cache_key, cache_race_condition_ttl are deprecated and will be removed in future versions./
|
31
|
+
).to_stderr
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'does cache' do
|
35
|
+
expect(default_cache).to receive(:fetch)
|
36
|
+
expect(default_cache).to receive(:write)
|
37
|
+
LHC.get('http://local.ch', cache: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not cache' do
|
41
|
+
expect(default_cache).not_to receive(:fetch)
|
42
|
+
expect(default_cache).not_to receive(:write)
|
43
|
+
LHC.get('http://local.ch')
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'options - directly via LHC.get' do
|
47
|
+
it 'uses the default cache' do
|
48
|
+
expect(default_cache).to receive(:fetch)
|
49
|
+
expect(default_cache).to receive(:write)
|
50
|
+
LHC.get('http://local.ch', cache: true)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'uses the provided cache' do
|
54
|
+
expect_any_instance_of(CacheMock).to receive(:fetch)
|
55
|
+
expect_any_instance_of(CacheMock).to receive(:write)
|
56
|
+
LHC.get('http://local.ch', cache: { use: CacheMock.new })
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'cache options are properly forwarded to the cache' do
|
60
|
+
cache_options = { expires_in: 5.minutes, race_condition_ttl: 15.seconds }
|
61
|
+
expect(default_cache).to receive(:write).with(anything, anything, cache_options)
|
62
|
+
LHC.get('http://local.ch', cache: cache_options)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'options - via endpoint configuration' do
|
67
|
+
it 'uses the default cache' do
|
68
|
+
LHC.config.endpoint(:local, 'http://local.ch', cache: true)
|
69
|
+
expect(default_cache).to receive(:fetch)
|
70
|
+
expect(default_cache).to receive(:write)
|
71
|
+
LHC.get(:local)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'uses the provided cache' do
|
75
|
+
options = { cache: { use: CacheMock.new } }
|
76
|
+
LHC.config.endpoint(:local, 'http://local.ch', options)
|
77
|
+
expect_any_instance_of(CacheMock).to receive(:fetch)
|
78
|
+
expect_any_instance_of(CacheMock).to receive(:write)
|
79
|
+
LHC.get(:local)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'cache options are properly forwarded to the cache' do
|
83
|
+
cache_options = { expires_in: 5.minutes, race_condition_ttl: 15.seconds }
|
84
|
+
LHC.config.endpoint(:local, 'http://local.ch', cache: cache_options)
|
85
|
+
expect(default_cache).to receive(:write).with(anything, anything, cache_options)
|
86
|
+
LHC.get(:local)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Caching do
|
6
|
+
context 'parameters' do
|
7
|
+
before(:each) do
|
8
|
+
LHC.config.interceptors = [LHC::Caching]
|
9
|
+
Rails.cache.clear
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'considers parameters when writing/reading from cache' do
|
13
|
+
LHC.config.endpoint(:local, 'http://local.ch', cache: true)
|
14
|
+
stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website')
|
15
|
+
stub_request(:get, 'http://local.ch?location=zuerich').to_return(status: 200, body: 'The Website for Zuerich')
|
16
|
+
expect(
|
17
|
+
LHC.get(:local).body
|
18
|
+
).to eq 'The Website'
|
19
|
+
expect(
|
20
|
+
LHC.get(:local, params: { location: 'zuerich' }).body
|
21
|
+
).to eq 'The Website for Zuerich'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Caching do
|
6
|
+
before(:each) do
|
7
|
+
LHC.config.interceptors = [LHC::Caching]
|
8
|
+
LHC.config.endpoint(:local, 'http://local.ch', cache: true)
|
9
|
+
Rails.cache.clear
|
10
|
+
# leverage the Typhoeus internal mock attribute in order to get Typhoeus evaluate the return_code
|
11
|
+
# lib/typhoeus/response/status.rb:48
|
12
|
+
allow_any_instance_of(Typhoeus::Response).to receive(:mock).and_return(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
let!(:stub) { stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website') }
|
16
|
+
|
17
|
+
it 'provides the correct response status for responses from cache' do
|
18
|
+
stub
|
19
|
+
# the real request provides the return_code
|
20
|
+
allow_any_instance_of(Typhoeus::Response).to receive(:options)
|
21
|
+
.and_return(code: 200, status_message: '', body: 'The Website', headers: nil, return_code: :ok)
|
22
|
+
response = LHC.get(:local)
|
23
|
+
expect(response.success?).to eq true
|
24
|
+
# the cached response should get it from the cache
|
25
|
+
allow_any_instance_of(Typhoeus::Response).to receive(:options).and_call_original
|
26
|
+
cached_response = LHC.get(:local)
|
27
|
+
expect(cached_response.success?).to eq true
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Caching do
|
6
|
+
context 'to_cache' do
|
7
|
+
it 'returns a marshalable object to store in the cache' do
|
8
|
+
expect do
|
9
|
+
response = Typhoeus::Response.new(headers: { 'Accept' => 'application/json' })
|
10
|
+
Marshal.dump(
|
11
|
+
LHC::Caching.new(response).send(:to_cache, response)
|
12
|
+
)
|
13
|
+
end.not_to raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC do
|
6
|
+
context 'default interceptors' do
|
7
|
+
before(:each) do
|
8
|
+
LHC.configure {}
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'alwayses return a list for default interceptors' do
|
12
|
+
expect(LHC.config.interceptors).to eq []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::DefaultTimeout do
|
6
|
+
before(:each) do
|
7
|
+
LHC.config.interceptors = [LHC::DefaultTimeout]
|
8
|
+
LHC::DefaultTimeout.timeout = nil
|
9
|
+
LHC::DefaultTimeout.connecttimeout = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:stub) { stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website') }
|
13
|
+
|
14
|
+
it 'applies default timeouts to all requests made' do
|
15
|
+
stub
|
16
|
+
expect_any_instance_of(Ethon::Easy).to receive(:http_request)
|
17
|
+
.with(anything, anything, hash_including(timeout: 15, connecttimeout: 2)).and_call_original
|
18
|
+
LHC.get('http://local.ch')
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with changed default timesouts' do
|
22
|
+
before(:each) do
|
23
|
+
LHC::DefaultTimeout.timeout = 10
|
24
|
+
LHC::DefaultTimeout.connecttimeout = 3
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'applies custom default timeouts to all requests made' do
|
28
|
+
stub
|
29
|
+
expect_any_instance_of(Ethon::Easy).to receive(:http_request)
|
30
|
+
.with(anything, anything, hash_including(timeout: 10, connecttimeout: 3)).and_call_original
|
31
|
+
LHC.get('http://local.ch')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC do
|
6
|
+
context 'interceptor' do
|
7
|
+
before(:each) do
|
8
|
+
class SomeInterceptor < LHC::Interceptor
|
9
|
+
end
|
10
|
+
class AnotherInterceptor < LHC::Interceptor
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'performs interceptor when they are set globally' do
|
15
|
+
LHC.configure { |c| c.interceptors = [SomeInterceptor] }
|
16
|
+
expect_any_instance_of(SomeInterceptor).to receive(:before_request)
|
17
|
+
stub_request(:get, 'http://local.ch')
|
18
|
+
LHC.get('http://local.ch')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'overrides interceptors on request level' do
|
22
|
+
LHC.configure { |c| c.interceptors = [SomeInterceptor] }
|
23
|
+
expect_any_instance_of(AnotherInterceptor).to receive(:before_request)
|
24
|
+
expect_any_instance_of(SomeInterceptor).not_to receive(:before_request)
|
25
|
+
stub_request(:get, 'http://local.ch')
|
26
|
+
LHC.get('http://local.ch', interceptors: [AnotherInterceptor])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC do
|
6
|
+
context 'interceptor' do
|
7
|
+
before(:each) do
|
8
|
+
class SomeInterceptor < LHC::Interceptor
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'does not dup' do
|
13
|
+
options = { interceptors: [SomeInterceptor] }
|
14
|
+
expect(
|
15
|
+
options.deep_dup[:interceptors].include?(SomeInterceptor)
|
16
|
+
).to eq true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Logging do
|
6
|
+
let(:logger) { spy('logger') }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
LHC.config.interceptors = [LHC::Logging]
|
10
|
+
LHC::Logging.logger = logger
|
11
|
+
stub_request(:get, 'http://local.ch').to_return(status: 200)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'does log information before and after every request made with LHC' do
|
15
|
+
LHC.get('http://local.ch')
|
16
|
+
expect(logger).to have_received(:info).once.with(
|
17
|
+
%r{Before LHC request <\d+> GET http://local.ch at \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2} Params={} Headers={.*?}}
|
18
|
+
)
|
19
|
+
expect(logger).to have_received(:info).once.with(
|
20
|
+
%r{After LHC response for request <\d+> GET http://local.ch at \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2} Time=0ms URL=http://local.ch:80/}
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'source' do
|
25
|
+
let(:source) { '/Users/Sebastian/LHC/test.rb' }
|
26
|
+
|
27
|
+
it 'does log the source if provided as option' do
|
28
|
+
LHC.get('http://local.ch', source: source)
|
29
|
+
expect(logger).to have_received(:info).once.with(
|
30
|
+
%r{Before LHC request <\d+> GET http://local.ch at \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2} Params={} Headers={.*?} \nCalled from #{source}}
|
31
|
+
)
|
32
|
+
expect(logger).to have_received(:info).once.with(
|
33
|
+
%r{After LHC response for request <\d+> GET http://local.ch at \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2} Time=0ms URL=http://local.ch:80/ \nCalled from #{source}}
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Monitoring do
|
6
|
+
let(:stub) { stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website') }
|
7
|
+
let(:endpoint_configuration) { LHC.config.endpoint(:local, 'http://local.ch') }
|
8
|
+
|
9
|
+
module Statsd
|
10
|
+
def self.count(_path, _value); end
|
11
|
+
|
12
|
+
def self.timing(_path, _value); end
|
13
|
+
end
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
LHC.config.interceptors = [LHC::Monitoring]
|
17
|
+
LHC::Monitoring.statsd = Statsd
|
18
|
+
Rails.cache.clear
|
19
|
+
endpoint_configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'does not report anything if no statsd is configured' do
|
23
|
+
stub
|
24
|
+
LHC.get(:local) # and also does not crash ;)
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'statsd configured' do
|
28
|
+
it 'reports trial, response and timing by default ' do
|
29
|
+
stub
|
30
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.before_request', 1)
|
31
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.after_request', 1)
|
32
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.count', 1)
|
33
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.200', 1)
|
34
|
+
expect(Statsd).to receive(:timing).with('lhc.dummy.test.local_ch.get.time', anything)
|
35
|
+
LHC.get(:local)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'does not report timing when response failed' do
|
39
|
+
stub_request(:get, 'http://local.ch').to_return(status: 500)
|
40
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.before_request', 1)
|
41
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.after_request', 1)
|
42
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.count', 1)
|
43
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.500', 1)
|
44
|
+
expect(Statsd).not_to receive(:timing)
|
45
|
+
expect { LHC.get(:local) }.to raise_error LHC::ServerError
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'reports timeout instead of status code if response timed out' do
|
49
|
+
stub_request(:get, 'http://local.ch').to_timeout
|
50
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.before_request', 1)
|
51
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.after_request', 1)
|
52
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.count', 1)
|
53
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.timeout', 1)
|
54
|
+
expect(Statsd).not_to receive(:timing)
|
55
|
+
expect { LHC.get(:local) }.to raise_error LHC::Timeout
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'allows to set the stats key for request' do
|
59
|
+
stub
|
60
|
+
expect(Statsd).to receive(:count).with('defined_key.before_request', 1)
|
61
|
+
expect(Statsd).to receive(:count).with('defined_key.after_request', 1)
|
62
|
+
expect(Statsd).to receive(:count).with('defined_key.count', 1)
|
63
|
+
expect(Statsd).to receive(:count).with('defined_key.200', 1)
|
64
|
+
expect(Statsd).to receive(:timing).with('defined_key.time', anything)
|
65
|
+
LHC.get(:local, monitoring_key: 'defined_key')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'without protocol' do
|
70
|
+
let(:endpoint_configuration) { LHC.config.endpoint(:local, 'local.ch') }
|
71
|
+
|
72
|
+
it 'reports trial, response and timing by default ' do
|
73
|
+
stub
|
74
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.before_request', 1)
|
75
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.after_request', 1)
|
76
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.count', 1)
|
77
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.test.local_ch.get.200', 1)
|
78
|
+
expect(Statsd).to receive(:timing).with('lhc.dummy.test.local_ch.get.time', anything)
|
79
|
+
LHC.get(:local)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with configured environment' do
|
84
|
+
before do
|
85
|
+
LHC::Monitoring.env = 'beta'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'uses the configured env' do
|
89
|
+
stub
|
90
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.beta.local_ch.get.before_request', 1)
|
91
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.beta.local_ch.get.after_request', 1)
|
92
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.beta.local_ch.get.count', 1)
|
93
|
+
expect(Statsd).to receive(:count).with('lhc.dummy.beta.local_ch.get.200', 1)
|
94
|
+
LHC.get(:local)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
require 'prometheus/client'
|
5
|
+
|
6
|
+
describe LHC::Prometheus do
|
7
|
+
before(:each) do
|
8
|
+
LHC.config.interceptors = [LHC::Prometheus]
|
9
|
+
LHC::Prometheus.client = Prometheus::Client
|
10
|
+
LHC::Prometheus.namespace = 'test_app'
|
11
|
+
stub_request(:get, 'http://local.ch')
|
12
|
+
expect(Prometheus::Client).to receive(:registry).and_call_original.at_least(:once)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:client) { double("prometheus/client") }
|
16
|
+
|
17
|
+
context 'registering' do
|
18
|
+
it 'creates a counter and histogram registry in the prometheus client' do
|
19
|
+
expect(Prometheus::Client.registry).to receive(:counter).and_call_original.once
|
20
|
+
.with(:lhc_requests, 'Counter of all LHC requests.')
|
21
|
+
expect(Prometheus::Client.registry).to receive(:histogram).and_call_original.once
|
22
|
+
.with(:lhc_request_seconds, 'Request timings for all LHC requests in seconds.')
|
23
|
+
|
24
|
+
LHC.get('http://local.ch')
|
25
|
+
LHC.get('http://local.ch') # second request, registration should happen only once
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'logging' do
|
30
|
+
let(:requests_registry_double) { double('requests_registry_double') }
|
31
|
+
let(:times_registry_double) { double('times_registry_double') }
|
32
|
+
|
33
|
+
it 'logs monitoring information to the created registries' do
|
34
|
+
expect(Prometheus::Client.registry).to receive(:get).and_return(requests_registry_double).once
|
35
|
+
.with(:lhc_requests)
|
36
|
+
expect(Prometheus::Client.registry).to receive(:get).and_return(times_registry_double).once
|
37
|
+
.with(:lhc_request_seconds)
|
38
|
+
|
39
|
+
expect(requests_registry_double).to receive(:increment).once
|
40
|
+
.with(
|
41
|
+
code: 200,
|
42
|
+
success: true,
|
43
|
+
timeout: false,
|
44
|
+
app: 'test_app',
|
45
|
+
host: 'local.ch'
|
46
|
+
)
|
47
|
+
|
48
|
+
expect(times_registry_double).to receive(:observe).once
|
49
|
+
.with({ host: 'local.ch', app: 'test_app' }, 0)
|
50
|
+
|
51
|
+
LHC.get('http://local.ch')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|