lhc 12.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.rubocop.localch.yml +325 -0
  4. data/.rubocop.yml +61 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +13 -0
  7. data/Gemfile.activesupport4 +4 -0
  8. data/Gemfile.activesupport5 +4 -0
  9. data/Gemfile.activesupport6 +4 -0
  10. data/LICENSE +674 -0
  11. data/README.md +984 -0
  12. data/Rakefile +25 -0
  13. data/cider-ci.yml +6 -0
  14. data/cider-ci/bin/bundle +51 -0
  15. data/cider-ci/bin/ruby_install +8 -0
  16. data/cider-ci/bin/ruby_version +25 -0
  17. data/cider-ci/jobs/rspec-activesupport-4.yml +28 -0
  18. data/cider-ci/jobs/rspec-activesupport-5.yml +27 -0
  19. data/cider-ci/jobs/rspec-activesupport-6.yml +28 -0
  20. data/cider-ci/jobs/rubocop.yml +18 -0
  21. data/cider-ci/task_components/bundle.yml +22 -0
  22. data/cider-ci/task_components/rspec.yml +36 -0
  23. data/cider-ci/task_components/rubocop.yml +29 -0
  24. data/cider-ci/task_components/ruby.yml +15 -0
  25. data/friday.yml +3 -0
  26. data/lhc.gemspec +39 -0
  27. data/lib/core_ext/hash/deep_transform_values.rb +48 -0
  28. data/lib/lhc.rb +136 -0
  29. data/lib/lhc/concerns/lhc/basic_methods_concern.rb +42 -0
  30. data/lib/lhc/concerns/lhc/configuration_concern.rb +20 -0
  31. data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +42 -0
  32. data/lib/lhc/concerns/lhc/formats_concern.rb +25 -0
  33. data/lib/lhc/concerns/lhc/request/user_agent_concern.rb +25 -0
  34. data/lib/lhc/config.rb +47 -0
  35. data/lib/lhc/endpoint.rb +119 -0
  36. data/lib/lhc/error.rb +80 -0
  37. data/lib/lhc/errors/client_error.rb +73 -0
  38. data/lib/lhc/errors/parser_error.rb +4 -0
  39. data/lib/lhc/errors/server_error.rb +28 -0
  40. data/lib/lhc/errors/timeout.rb +4 -0
  41. data/lib/lhc/errors/unknown_error.rb +4 -0
  42. data/lib/lhc/format.rb +18 -0
  43. data/lib/lhc/formats.rb +8 -0
  44. data/lib/lhc/formats/form.rb +45 -0
  45. data/lib/lhc/formats/json.rb +55 -0
  46. data/lib/lhc/formats/multipart.rb +45 -0
  47. data/lib/lhc/formats/plain.rb +42 -0
  48. data/lib/lhc/interceptor.rb +32 -0
  49. data/lib/lhc/interceptors.rb +26 -0
  50. data/lib/lhc/interceptors/auth.rb +98 -0
  51. data/lib/lhc/interceptors/caching.rb +127 -0
  52. data/lib/lhc/interceptors/default_timeout.rb +16 -0
  53. data/lib/lhc/interceptors/logging.rb +37 -0
  54. data/lib/lhc/interceptors/monitoring.rb +63 -0
  55. data/lib/lhc/interceptors/prometheus.rb +51 -0
  56. data/lib/lhc/interceptors/retry.rb +41 -0
  57. data/lib/lhc/interceptors/rollbar.rb +36 -0
  58. data/lib/lhc/interceptors/throttle.rb +81 -0
  59. data/lib/lhc/interceptors/zipkin.rb +110 -0
  60. data/lib/lhc/railtie.rb +10 -0
  61. data/lib/lhc/request.rb +157 -0
  62. data/lib/lhc/response.rb +60 -0
  63. data/lib/lhc/response/data.rb +28 -0
  64. data/lib/lhc/response/data/base.rb +22 -0
  65. data/lib/lhc/response/data/collection.rb +16 -0
  66. data/lib/lhc/response/data/item.rb +29 -0
  67. data/lib/lhc/rspec.rb +12 -0
  68. data/lib/lhc/test/cache_helper.rb +3 -0
  69. data/lib/lhc/version.rb +5 -0
  70. data/script/ci/build.sh +19 -0
  71. data/spec/basic_methods/delete_spec.rb +34 -0
  72. data/spec/basic_methods/get_spec.rb +49 -0
  73. data/spec/basic_methods/post_spec.rb +42 -0
  74. data/spec/basic_methods/put_spec.rb +48 -0
  75. data/spec/basic_methods/request_spec.rb +19 -0
  76. data/spec/basic_methods/request_without_rails_spec.rb +29 -0
  77. data/spec/config/endpoints_spec.rb +63 -0
  78. data/spec/config/placeholders_spec.rb +32 -0
  79. data/spec/core_ext/hash/deep_transform_values_spec.rb +24 -0
  80. data/spec/dummy/README.rdoc +28 -0
  81. data/spec/dummy/Rakefile +8 -0
  82. data/spec/dummy/app/assets/config/manifest.js +3 -0
  83. data/spec/dummy/app/assets/images/.keep +0 -0
  84. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  85. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  86. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  87. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  88. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  89. data/spec/dummy/app/mailers/.keep +0 -0
  90. data/spec/dummy/app/models/.keep +0 -0
  91. data/spec/dummy/app/models/concerns/.keep +0 -0
  92. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  93. data/spec/dummy/bin/bundle +5 -0
  94. data/spec/dummy/bin/rails +6 -0
  95. data/spec/dummy/bin/rake +6 -0
  96. data/spec/dummy/config.ru +6 -0
  97. data/spec/dummy/config/application.rb +16 -0
  98. data/spec/dummy/config/boot.rb +7 -0
  99. data/spec/dummy/config/environment.rb +7 -0
  100. data/spec/dummy/config/environments/development.rb +36 -0
  101. data/spec/dummy/config/environments/production.rb +77 -0
  102. data/spec/dummy/config/environments/test.rb +41 -0
  103. data/spec/dummy/config/initializers/assets.rb +10 -0
  104. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  105. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  106. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  107. data/spec/dummy/config/initializers/inflections.rb +18 -0
  108. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  109. data/spec/dummy/config/initializers/session_store.rb +5 -0
  110. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  111. data/spec/dummy/config/locales/en.yml +23 -0
  112. data/spec/dummy/config/routes.rb +58 -0
  113. data/spec/dummy/config/secrets.yml +22 -0
  114. data/spec/dummy/lib/assets/.keep +0 -0
  115. data/spec/dummy/log/.keep +0 -0
  116. data/spec/dummy/public/404.html +67 -0
  117. data/spec/dummy/public/422.html +67 -0
  118. data/spec/dummy/public/500.html +66 -0
  119. data/spec/dummy/public/favicon.ico +0 -0
  120. data/spec/endpoint/compile_spec.rb +35 -0
  121. data/spec/endpoint/match_spec.rb +41 -0
  122. data/spec/endpoint/placeholders_spec.rb +30 -0
  123. data/spec/endpoint/remove_interpolated_params_spec.rb +17 -0
  124. data/spec/endpoint/values_as_params_spec.rb +31 -0
  125. data/spec/error/dup_spec.rb +12 -0
  126. data/spec/error/find_spec.rb +57 -0
  127. data/spec/error/response_spec.rb +17 -0
  128. data/spec/error/timeout_spec.rb +14 -0
  129. data/spec/error/to_s_spec.rb +80 -0
  130. data/spec/formats/form_spec.rb +27 -0
  131. data/spec/formats/json_spec.rb +66 -0
  132. data/spec/formats/multipart_spec.rb +26 -0
  133. data/spec/formats/plain_spec.rb +29 -0
  134. data/spec/interceptors/after_request_spec.rb +20 -0
  135. data/spec/interceptors/after_response_spec.rb +39 -0
  136. data/spec/interceptors/auth/basic_auth_spec.rb +17 -0
  137. data/spec/interceptors/auth/bearer_spec.rb +19 -0
  138. data/spec/interceptors/auth/reauthentication_configuration_spec.rb +61 -0
  139. data/spec/interceptors/auth/reauthentication_spec.rb +44 -0
  140. data/spec/interceptors/before_request_spec.rb +21 -0
  141. data/spec/interceptors/before_response_spec.rb +20 -0
  142. data/spec/interceptors/caching/hydra_spec.rb +26 -0
  143. data/spec/interceptors/caching/main_spec.rb +73 -0
  144. data/spec/interceptors/caching/methods_spec.rb +42 -0
  145. data/spec/interceptors/caching/options_spec.rb +89 -0
  146. data/spec/interceptors/caching/parameters_spec.rb +24 -0
  147. data/spec/interceptors/caching/response_status_spec.rb +29 -0
  148. data/spec/interceptors/caching/to_cache_spec.rb +16 -0
  149. data/spec/interceptors/default_interceptors_spec.rb +15 -0
  150. data/spec/interceptors/default_timeout/main_spec.rb +34 -0
  151. data/spec/interceptors/define_spec.rb +29 -0
  152. data/spec/interceptors/dup_spec.rb +19 -0
  153. data/spec/interceptors/logging/main_spec.rb +37 -0
  154. data/spec/interceptors/monitoring/main_spec.rb +97 -0
  155. data/spec/interceptors/prometheus_spec.rb +54 -0
  156. data/spec/interceptors/response_competition_spec.rb +41 -0
  157. data/spec/interceptors/retry/main_spec.rb +73 -0
  158. data/spec/interceptors/return_response_spec.rb +38 -0
  159. data/spec/interceptors/rollbar/invalid_encoding_spec.rb +43 -0
  160. data/spec/interceptors/rollbar/main_spec.rb +57 -0
  161. data/spec/interceptors/throttle/main_spec.rb +106 -0
  162. data/spec/interceptors/throttle/reset_track_spec.rb +53 -0
  163. data/spec/interceptors/zipkin/distributed_tracing_spec.rb +135 -0
  164. data/spec/rails_helper.rb +6 -0
  165. data/spec/request/body_spec.rb +39 -0
  166. data/spec/request/encoding_spec.rb +37 -0
  167. data/spec/request/error_handling_spec.rb +88 -0
  168. data/spec/request/headers_spec.rb +12 -0
  169. data/spec/request/ignore_errors_spec.rb +73 -0
  170. data/spec/request/option_dup_spec.rb +13 -0
  171. data/spec/request/parallel_requests_spec.rb +59 -0
  172. data/spec/request/params_encoding_spec.rb +26 -0
  173. data/spec/request/request_without_rails_spec.rb +15 -0
  174. data/spec/request/url_patterns_spec.rb +54 -0
  175. data/spec/request/user_agent_spec.rb +26 -0
  176. data/spec/request/user_agent_without_rails_spec.rb +27 -0
  177. data/spec/response/body_spec.rb +16 -0
  178. data/spec/response/code_spec.rb +16 -0
  179. data/spec/response/data_accessor_spec.rb +29 -0
  180. data/spec/response/data_spec.rb +61 -0
  181. data/spec/response/effective_url_spec.rb +16 -0
  182. data/spec/response/headers_spec.rb +18 -0
  183. data/spec/response/options_spec.rb +18 -0
  184. data/spec/response/success_spec.rb +13 -0
  185. data/spec/response/time_spec.rb +21 -0
  186. data/spec/spec_helper.rb +8 -0
  187. data/spec/support/fixtures/json/feedback.json +11 -0
  188. data/spec/support/fixtures/json/feedbacks.json +164 -0
  189. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  190. data/spec/support/load_json.rb +5 -0
  191. data/spec/support/reset_config.rb +7 -0
  192. data/spec/support/zipkin_mock.rb +113 -0
  193. data/spec/timeouts/no_signal_spec.rb +13 -0
  194. data/spec/timeouts/timings_spec.rb +55 -0
  195. 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