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,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Endpoint do
6
+ context 'compile' do
7
+ it 'uses parameters for interpolation' do
8
+ endpoint = LHC::Endpoint.new('{+datastore}/v2/{campaign_id}/feedbacks')
9
+ expect(
10
+ endpoint.compile(datastore: 'http://datastore', campaign_id: 'abc')
11
+ ).to eq "http://datastore/v2/abc/feedbacks"
12
+ end
13
+
14
+ it 'compiles when templates contain dots' do
15
+ endpoint = LHC::Endpoint.new('{+datastore}/entries/{id}.json')
16
+ expect(
17
+ endpoint.compile(datastore: 'http://datastore', id: 123)
18
+ ).to eq "http://datastore/entries/123.json"
19
+ end
20
+
21
+ it 'compiles complex urls containing all sort of characters' do
22
+ endpoint = LHC::Endpoint.new('{+ads}/?adrawdata/3.0/1108.1/2844859/0/0/header=yes;cookie=no;adct=204;alias={region_id}{lang}{product_type}{product};key=cat={category_id}')
23
+ expect(
24
+ endpoint.compile(ads: 'http://ads', region_id: 291, lang: 'de', product_type: 'ABC', product: 'xyz', category_id: 312)
25
+ ).to eq 'http://ads/?adrawdata/3.0/1108.1/2844859/0/0/header=yes;cookie=no;adct=204;alias=291deABCxyz;key=cat=312'
26
+ end
27
+
28
+ it 'compiles complex urls containing &' do
29
+ endpoint = LHC::Endpoint.new('http://{+weather_search_host}/forecast?format=json&period=hour&limit={limit}&areas={+zipcodes}&when={when}')
30
+ expect(
31
+ endpoint.compile(weather_search_host: 'weather', limit: 5, zipcodes: [8005, 8004].join(','), when: 'today')
32
+ ).to eq 'http://weather/forecast?format=json&period=hour&limit=5&areas=8005,8004&when=today'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Endpoint do
6
+ context 'match' do
7
+ context 'matching' do
8
+ {
9
+ '{+datastore}/v2/places' => 'http://local.ch:8082/v2/places',
10
+ '{+datastore}/v2/places/{id}' => 'http://local.ch:8082/v2/places/ZW9OJyrbt4OZE9ueu80w-A',
11
+ '{+datastore}/v2/places/{namespace}/{id}' => 'http://local.ch:8082/v2/places/switzerland/ZW9OJyrbt',
12
+ '{+datastore}/addresses/{id}' => 'http://local.ch/addresses/123',
13
+ 'http://local.ch/addresses/{id}' => 'http://local.ch/addresses/123',
14
+ '{+datastore}/customers/{id}/addresses' => 'http://local.ch:80/server/rest/v1/customers/123/addresses',
15
+ '{+datastore}/entries/{id}.json' => 'http://local.ch/entries/123.json',
16
+ '{+datastore}/places/{place_id}/feedbacks' => 'http://local.ch/places/1/feedbacks?limit=10&offset=0',
17
+ 'http://local.ch/places/1/feedbacks' => 'http://local.ch/places/1/feedbacks?lang=en',
18
+ 'http://local.ch/places/1/feedbacks.json' => 'http://local.ch/places/1/feedbacks.json?lang=en'
19
+ }.each do |template, url|
20
+ it "#{url} matches #{template}" do
21
+ expect(LHC::Endpoint.match?(url, template)).to be(true)
22
+ end
23
+ end
24
+ end
25
+
26
+ context 'not matching' do
27
+ {
28
+ '{+datastore}/v2/places' => 'http://local.ch:8082/v2/places/ZW9OJyrbt4OZE9ueu80w-A',
29
+ '{+datastore}/{campaign_id}/feedbacks' => 'http://datastore.local.ch/feedbacks',
30
+ '{+datastore}/customers/{id}' => 'http://local.ch:80/server/rest/v1/customers/123/addresses',
31
+ '{+datastore}/entries/{id}' => 'http://local.ch/entries/123.json'
32
+ }.each do |template, url|
33
+ it "#{url} should not match #{template}" do
34
+ expect(
35
+ LHC::Endpoint.match?(url, template)
36
+ ).to be(false)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Endpoint do
6
+ context 'placeholders' do
7
+ it 'returns all placeholders alphabetically sorted' do
8
+ endpoint = LHC::Endpoint.new('{+datastore}/v2/{campaign_id}/feedbacks')
9
+ expect(
10
+ endpoint.placeholders
11
+ ).to eq [:campaign_id, :datastore]
12
+ end
13
+
14
+ it 'allows basic auth token in url, like used on github' do
15
+ stub_request(:get, "https://d123token:@api.github.com/search")
16
+ .to_return(body: {}.to_json)
17
+ expect(-> {
18
+ LHC.get("https://d123token:@api.github.com/search")
19
+ }).not_to raise_error
20
+ end
21
+
22
+ it 'allows complete basic auth (username password) in url, like used for the gemserer' do
23
+ stub_request(:get, "https://name:password@gemserver.com")
24
+ .to_return(body: {}.to_json)
25
+ expect(-> {
26
+ LHC.get("https://name:password@gemserver.com")
27
+ }).not_to raise_error
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Endpoint do
6
+ it 'removes params used for interpolation' do
7
+ params = {
8
+ datastore: 'http://datastore',
9
+ campaign_id: 'abc',
10
+ has_reviews: true
11
+ }
12
+ endpoint = LHC::Endpoint.new('{+datastore}/v2/{campaign_id}/feedbacks')
13
+ removed = endpoint.remove_interpolated_params!(params)
14
+ expect(params).to eq(has_reviews: true)
15
+ expect(removed).to eq(datastore: 'http://datastore', campaign_id: 'abc')
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Endpoint do
6
+ context 'values_as_params' do
7
+ [
8
+ ['{+datastore}/v2/places', 'http://local.ch:8082/v2/places', {
9
+ datastore: 'http://local.ch:8082'
10
+ }],
11
+ ['{+datastore}/v2/places/{id}', 'http://local.ch:8082/v2/places/ZW9OJyrbt4OZE9ueu80w-A', {
12
+ datastore: 'http://local.ch:8082',
13
+ id: 'ZW9OJyrbt4OZE9ueu80w-A'
14
+ }],
15
+ ['{+datastore}/v2/places/{namespace}/{id}', 'http://local.ch:8082/v2/places/switzerland/ZW9OJyrbt', {
16
+ datastore: 'http://local.ch:8082',
17
+ namespace: 'switzerland',
18
+ id: 'ZW9OJyrbt'
19
+ }]
20
+ ].each do |example|
21
+ template = example[0]
22
+ url = example[1]
23
+ params = example[2]
24
+
25
+ it "for the template #{template} it extracts #{params.keys.join(', ')} from the url" do
26
+ extracted = LHC::Endpoint.values_as_params(template, url)
27
+ expect(extracted).to eq(params)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Error do
6
+ it 'does not dup' do
7
+ options = { errors: [described_class] }
8
+ expect(
9
+ options.deep_dup[:errors].include?(described_class)
10
+ ).to eq true
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Error do
6
+ def response(code, timedout = false)
7
+ LHC::Response.new(OpenStruct.new(code: code, 'timed_out?' => timedout), nil)
8
+ end
9
+
10
+ context 'find' do
11
+ it 'finds error class by status code' do
12
+ expect(LHC::Error.find(response('0', true))).to eq LHC::Timeout
13
+ expect(LHC::Error.find(response('400'))).to eq LHC::BadRequest
14
+ expect(LHC::Error.find(response('401'))).to eq LHC::Unauthorized
15
+ expect(LHC::Error.find(response('402'))).to eq LHC::PaymentRequired
16
+ expect(LHC::Error.find(response('403'))).to eq LHC::Forbidden
17
+ expect(LHC::Error.find(response('403'))).to eq LHC::Forbidden
18
+ expect(LHC::Error.find(response('404'))).to eq LHC::NotFound
19
+ expect(LHC::Error.find(response('405'))).to eq LHC::MethodNotAllowed
20
+ expect(LHC::Error.find(response('406'))).to eq LHC::NotAcceptable
21
+ expect(LHC::Error.find(response('407'))).to eq LHC::ProxyAuthenticationRequired
22
+ expect(LHC::Error.find(response('408'))).to eq LHC::RequestTimeout
23
+ expect(LHC::Error.find(response('409'))).to eq LHC::Conflict
24
+ expect(LHC::Error.find(response('410'))).to eq LHC::Gone
25
+ expect(LHC::Error.find(response('411'))).to eq LHC::LengthRequired
26
+ expect(LHC::Error.find(response('412'))).to eq LHC::PreconditionFailed
27
+ expect(LHC::Error.find(response('413'))).to eq LHC::RequestEntityTooLarge
28
+ expect(LHC::Error.find(response('414'))).to eq LHC::RequestUriToLong
29
+ expect(LHC::Error.find(response('415'))).to eq LHC::UnsupportedMediaType
30
+ expect(LHC::Error.find(response('416'))).to eq LHC::RequestedRangeNotSatisfiable
31
+ expect(LHC::Error.find(response('417'))).to eq LHC::ExpectationFailed
32
+ expect(LHC::Error.find(response('422'))).to eq LHC::UnprocessableEntity
33
+ expect(LHC::Error.find(response('423'))).to eq LHC::Locked
34
+ expect(LHC::Error.find(response('424'))).to eq LHC::FailedDependency
35
+ expect(LHC::Error.find(response('426'))).to eq LHC::UpgradeRequired
36
+ expect(LHC::Error.find(response('500'))).to eq LHC::InternalServerError
37
+ expect(LHC::Error.find(response('501'))).to eq LHC::NotImplemented
38
+ expect(LHC::Error.find(response('502'))).to eq LHC::BadGateway
39
+ expect(LHC::Error.find(response('503'))).to eq LHC::ServiceUnavailable
40
+ expect(LHC::Error.find(response('504'))).to eq LHC::GatewayTimeout
41
+ expect(LHC::Error.find(response('505'))).to eq LHC::HttpVersionNotSupported
42
+ expect(LHC::Error.find(response('507'))).to eq LHC::InsufficientStorage
43
+ expect(LHC::Error.find(response('510'))).to eq LHC::NotExtended
44
+ end
45
+
46
+ it 'finds error class also by extended status codes' do
47
+ expect(LHC::Error.find(response('40001'))).to eq LHC::BadRequest
48
+ expect(LHC::Error.find(response('50002'))).to eq LHC::InternalServerError
49
+ end
50
+
51
+ it 'returns UnknownError if no specific error was found' do
52
+ expect(LHC::Error.find(response('0'))).to eq LHC::UnknownError
53
+ expect(LHC::Error.find(response(''))).to eq LHC::UnknownError
54
+ expect(LHC::Error.find(response('600'))).to eq LHC::UnknownError
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Error do
6
+ context 'response' do
7
+ it 'throws timeout exception in case of a timeout' do
8
+ stub_request(:any, 'local.ch').to_return(status: 403)
9
+ begin
10
+ LHC.get('local.ch')
11
+ rescue => e
12
+ expect(e.response).to be_kind_of(LHC::Response)
13
+ expect(e.response.code).to eq 403
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Error do
6
+ context 'timeout' do
7
+ it 'throws timeout exception in case of a timeout' do
8
+ stub_request(:any, 'local.ch').to_timeout
9
+ expect(lambda {
10
+ LHC.get('local.ch')
11
+ }).to raise_error LHC::Timeout
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC::Error do
6
+ context 'to_s' do
7
+ let(:invalid) { (+"in\xc3lid").force_encoding('ASCII-8BIT') }
8
+ let(:valid) { "vælid" }
9
+
10
+ context 'check assumptions' do
11
+ it 'joining raises an error' do
12
+ expect { [valid, invalid].join }.to raise_error Encoding::CompatibilityError
13
+ end
14
+ it 'interpolation raises an error' do
15
+ expect { "#{valid} #{invalid}" }.to raise_error Encoding::CompatibilityError
16
+ end
17
+ it 'to_json on an array raises an error' do
18
+ expect { [valid, invalid].to_json }.to raise_error Encoding::UndefinedConversionError
19
+ end
20
+
21
+ it 'to_s on a hash does not raise an error' do
22
+ expect { { valid: valid, invalid: invalid }.to_s }.not_to raise_error
23
+ end
24
+
25
+ it 'to_json on a hash does raise an error' do
26
+ expect { { valid: valid, invalid: invalid }.to_json }.to raise_error Encoding::UndefinedConversionError
27
+ end
28
+ end
29
+
30
+ it 'invalid body, valid message' do
31
+ stub_request(:get, 'http://local.ch')
32
+ .to_return(status: 200, body: "{ text : '#{invalid}' }")
33
+ response = LHC.get('http://local.ch')
34
+ expect { LHC::Error.new(valid, response).to_s }.not_to raise_error # Encoding::CompatibilityError
35
+ end
36
+
37
+ it 'valid body, invalid message' do
38
+ stub_request(:get, 'http://local.ch')
39
+ .to_return(status: 200, body: "{ text : '#{valid}' }")
40
+ response = LHC.get('http://local.ch')
41
+ expect { LHC::Error.new(invalid, response).to_s }.not_to raise_error # Encoding::CompatibilityError
42
+ end
43
+ # the other cases cannot be tested (for example what happens if the headers contain invalid data)
44
+ # because the mocking framework triggers the encoding error already
45
+
46
+ context 'some mocked response' do
47
+ let(:request) do
48
+ double('request',
49
+ method: 'GET',
50
+ url: 'http://example.com/sessions',
51
+ headers: { 'Bearer Token' => "aaaaaaaa-bbbb-cccc-dddd-eeee" },
52
+ options: { followlocation: true,
53
+ auth: { bearer: "aaaaaaaa-bbbb-cccc-dddd-eeee" },
54
+ params: { limit: 20 }, url: "http://example.com/sessions" })
55
+ end
56
+
57
+ let(:response) do
58
+ double('response',
59
+ request: request,
60
+ code: 500,
61
+ options: { return_code: :internal_error, response_headers: "" },
62
+ body: '{"status":500,"message":"undefined"}')
63
+ end
64
+
65
+ subject { LHC::Error.new('The error message', response) }
66
+
67
+ it 'produces correct debug output' do
68
+ expect(subject.to_s.split("\n")).to eq(<<-MSG.strip_heredoc.split("\n"))
69
+ GET http://example.com/sessions
70
+ Options: {:followlocation=>true, :auth=>{:bearer=>"aaaaaaaa-bbbb-cccc-dddd-eeee"}, :params=>{:limit=>20}, :url=>"http://example.com/sessions"}
71
+ Headers: {"Bearer Token"=>"aaaaaaaa-bbbb-cccc-dddd-eeee"}
72
+ Response Code: 500 (internal_error)
73
+ Response Options: {:return_code=>:internal_error, :response_headers=>""}
74
+ {"status":500,"message":"undefined"}
75
+ The error message
76
+ MSG
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC do
6
+ include ActionDispatch::TestProcess
7
+
8
+ context 'form' do
9
+ it 'formats requests to be application/x-www-form-urlencoded' do
10
+ stub = stub_request(:post, 'http://local.ch/')
11
+ .with(body: 'client_id=1234&client_secret=4567&grant_type=client_credentials')
12
+ .with(headers: { 'Content-Type': 'application/x-www-form-urlencoded' })
13
+ .to_return(status: 200)
14
+
15
+ LHC.form.post(
16
+ 'http://local.ch',
17
+ body: {
18
+ client_id: '1234',
19
+ client_secret: '4567',
20
+ grant_type: 'client_credentials'
21
+ }
22
+ )
23
+
24
+ expect(stub).to have_been_requested
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC do
6
+ context 'formats' do
7
+ it 'adds Content-Type, Accept and Accept-Charset Headers to the request' do
8
+ stub_request(:get, "http://local.ch/")
9
+ .with(headers: {
10
+ 'Accept' => 'application/json,application/vnd.api+json',
11
+ 'Content-Type' => 'application/json; charset=utf-8',
12
+ 'Accept-Charset' => 'utf-8'
13
+ })
14
+ .to_return(body: {}.to_json)
15
+ LHC.json.get('http://local.ch')
16
+ end
17
+
18
+ context 'header key as symbol' do
19
+ it 'raises an error when trying to set content-type header even though the format is used' do
20
+ expect(lambda {
21
+ LHC.post(
22
+ 'http://local.ch',
23
+ headers: {
24
+ 'Content-Type': 'multipart/form-data'
25
+ }
26
+ )
27
+ }).to raise_error 'Content-Type header is not allowed for formatted requests!\nSee https://github.com/local-ch/lhc#formats for more information.'
28
+ end
29
+
30
+ it 'raises an error when trying to set accept header even though the format is used' do
31
+ expect(lambda {
32
+ LHC.post(
33
+ 'http://local.ch',
34
+ headers: {
35
+ 'Accept': 'multipart/form-data'
36
+ }
37
+ )
38
+ }).to raise_error 'Accept header is not allowed for formatted requests!\nSee https://github.com/local-ch/lhc#formats for more information.'
39
+ end
40
+ end
41
+
42
+ context 'header key as string' do
43
+ it 'raises an error when trying to set content-type header even though the format is used' do
44
+ expect(lambda {
45
+ LHC.post(
46
+ 'http://local.ch',
47
+ headers: {
48
+ 'Content-Type' => 'multipart/form-data'
49
+ }
50
+ )
51
+ }).to raise_error 'Content-Type header is not allowed for formatted requests!\nSee https://github.com/local-ch/lhc#formats for more information.'
52
+ end
53
+
54
+ it 'raises an error when trying to set accept header even though the format is used' do
55
+ expect(lambda {
56
+ LHC.post(
57
+ 'http://local.ch',
58
+ headers: {
59
+ 'Accept' => 'multipart/form-data'
60
+ }
61
+ )
62
+ }).to raise_error 'Accept header is not allowed for formatted requests!\nSee https://github.com/local-ch/lhc#formats for more information.'
63
+ end
64
+ end
65
+ end
66
+ end