lhc 9.2.0 → 9.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e82411889a538078642c154032b132cec72cf53b
4
- data.tar.gz: 12f685a1fb5cb8e9452ecd3c2f8ffaf2621a7122
3
+ metadata.gz: 4c7d1ebc28ca92627c9828b98adffdf9e57cd41e
4
+ data.tar.gz: f69dcd78f74648df6cf81189743fce7e9b78e2ee
5
5
  SHA512:
6
- metadata.gz: efa93d6795be75faa9151a9b4fb273338e6fe7ff4d9772302b3f6a04b08364c3111b71e7b0d3529d2af8a8f965d9e23c5d71df5141a83677dfa21bafd2a26738
7
- data.tar.gz: 8d88b401cfe5122a19cb6ac5c2f5b2478a0bf231858e7430edd133f4f6c592e165f9ca2c6bf1cbf8e433a93027f7892bbcc890bd638c1cec4d8419b158331b8e
6
+ metadata.gz: beb8f74e3901b68de00d2d2c3ebc9874666aee0dac0eaef6d49a16482f1d82a45cf6f47e9aad98ae0ffc60cc5784a7c04d7865acc95a90e68a3e681d31fe52fd
7
+ data.tar.gz: 1df77507930a88568ef63e9fab8f62ee9a09440b7d8d1b2502f703652d22d7cfe15b423612bc7a11233cd6731bb0c18c64d87809a4bc59e7452e94afae1ad8bb
@@ -1,22 +1,21 @@
1
1
  # This is master rubocop configuration.
2
2
  # DO NOT EDIT THIS FILE - it WILL be overwriten on every config update
3
3
  AllCops:
4
- TargetRubyVersion: 2.1
4
+ TargetRubyVersion: 2.3
5
5
  DisplayCopNames: true
6
6
  DisplayStyleGuide: true
7
- Include:
8
- - '**/Rakefile'
9
- - '**/config.ru'
10
- - '**/Capfile'
11
7
  Exclude:
12
8
  - 'db/**/*'
13
9
  - 'script/**/*'
14
10
  - 'vendor/bundle/**/*'
11
+ - 'vendor/assets/**/*'
15
12
  - 'bin/**/*'
16
13
  - 'config/unicorn.rb'
17
14
  - 'config/compass.rb'
18
15
  - 'Rakefile'
19
- - 'spec/error/to_s_spec.rb' # this file contains invalid UTF8 character on purpose!
16
+ - 'app/controllers/error_trap_controller.rb'
17
+ - 'app/controllers/hsts_controller.rb'
18
+ - 'spec/lib/util_spec.rb'
20
19
 
21
20
  Rails:
22
21
  Enabled: true
@@ -24,10 +23,19 @@ Rails:
24
23
  require:
25
24
  - rubocop-rspec
26
25
 
26
+ Bundler/OrderedGems:
27
+ Enabled: false
28
+
27
29
  Lint/HandleExceptions:
28
30
  Exclude:
29
31
  - spec/**/*
30
32
 
33
+ Lint/UriEscapeUnescape:
34
+ Enabled: false
35
+
36
+ Style/RescueStandardError:
37
+ Enabled: false
38
+
31
39
  Metrics/LineLength:
32
40
  Enabled: false
33
41
 
@@ -49,6 +57,9 @@ Metrics/ClassLength:
49
57
  Metrics/ModuleLength:
50
58
  Enabled: false
51
59
 
60
+ Metrics/BlockLength:
61
+ Enabled: false
62
+
52
63
  Metrics/ParameterLists:
53
64
  Enabled: false
54
65
 
@@ -73,9 +84,39 @@ Performance/RedundantMerge:
73
84
  Performance/Casecmp:
74
85
  Enabled: false
75
86
 
76
- Style/MultilineOperationIndentation:
87
+ Layout/MultilineOperationIndentation:
88
+ EnforcedStyle: indented
89
+
90
+ Layout/DotPosition:
91
+ EnforcedStyle: leading
92
+
93
+ Layout/AlignParameters:
94
+ Enabled: false
95
+
96
+ Layout/EmptyLinesAroundClassBody:
97
+ Enabled: false
98
+
99
+ Layout/IndentArray:
100
+ EnforcedStyle: consistent
101
+
102
+ Layout/MultilineMethodCallIndentation:
77
103
  EnforcedStyle: indented
78
104
 
105
+ Layout/MultilineMethodCallBraceLayout:
106
+ EnforcedStyle: symmetrical
107
+
108
+ Layout/EmptyLinesAroundBlockBody:
109
+ EnforcedStyle: no_empty_lines
110
+
111
+ Layout/IndentHeredoc:
112
+ Enabled: false
113
+
114
+ Layout/MultilineArrayBraceLayout:
115
+ EnforcedStyle: symmetrical
116
+
117
+ Layout/MultilineHashBraceLayout:
118
+ EnforcedStyle: symmetrical
119
+
79
120
  Style/StringLiterals:
80
121
  Enabled: false
81
122
 
@@ -83,21 +124,12 @@ Style/RegexpLiteral:
83
124
  Exclude:
84
125
  - spec/**/*
85
126
 
86
- Style/DotPosition:
87
- EnforcedStyle: leading
88
-
89
- Style/AlignParameters:
90
- Enabled: false
91
-
92
127
  Style/NumericLiterals:
93
128
  Enabled: false
94
129
 
95
130
  Style/WordArray:
96
131
  Enabled: false
97
132
 
98
- Style/EmptyLinesAroundClassBody:
99
- Enabled: false
100
-
101
133
  Style/Next:
102
134
  Enabled: false
103
135
 
@@ -156,7 +188,7 @@ Style/Documentation:
156
188
  Style/GuardClause:
157
189
  Enabled: false
158
190
 
159
- Style/AccessorMethodName:
191
+ Naming/AccessorMethodName:
160
192
  Exclude:
161
193
  - spec/support/pages/**/*
162
194
 
@@ -169,11 +201,50 @@ Style/MutableConstant:
169
201
  Style/ConditionalAssignment:
170
202
  Enabled: false
171
203
 
172
- Style/IndentArray:
173
- EnforcedStyle: consistent
204
+ Style/Lambda:
205
+ Enabled: false
174
206
 
175
- Style/MultilineMethodCallIndentation:
176
- EnforcedStyle: indented
207
+ Style/FrozenStringLiteralComment:
208
+ Enabled: false
209
+
210
+ Style/SymbolArray:
211
+ Enabled: false
212
+
213
+ Style/HashSyntax:
214
+ EnforcedStyle: ruby19
215
+
216
+ Style/FormatStringToken:
217
+ Enabled: false
218
+
219
+ Style/EmptyMethod:
220
+ EnforcedStyle: expanded
221
+
222
+ Style/TernaryParentheses:
223
+ EnforcedStyle: require_parentheses_when_complex
224
+
225
+ Naming/VariableNumber:
226
+ Enabled: false
227
+
228
+ Style/PerlBackrefs:
229
+ Enabled: false
230
+
231
+ Style/RegexpLiteral:
232
+ AllowInnerSlashes: false
233
+
234
+ Style/BlockComments:
235
+ Enabled: false
236
+
237
+ Style/RedundantParentheses:
238
+ Enabled: false
239
+
240
+ Naming/FileName:
241
+ Exclude:
242
+ - Gemfile
243
+ - Brewfile
244
+ - Guardfile
245
+
246
+ Style/NumericPredicate:
247
+ Enabled: false
177
248
 
178
249
  RSpec/DescribeClass:
179
250
  Exclude:
@@ -185,7 +256,70 @@ RSpec/DescribeClass:
185
256
  RSpec/FilePath:
186
257
  Enabled: false
187
258
 
259
+ RSpec/NamedSubject:
260
+ Enabled: false
261
+
262
+ RSpec/MultipleExpectations:
263
+ Enabled: false
264
+
265
+ RSpec/ExampleLength:
266
+ Enabled: false
267
+
268
+ RSpec/HookArgument:
269
+ EnforcedStyle: implicit
270
+
271
+ RSpec/MessageSpies:
272
+ EnforcedStyle: receive
273
+
274
+ RSpec/NestedGroups:
275
+ Enabled: false
276
+
277
+ RSpec/VerifiedDoubles:
278
+ Enabled: false
279
+
280
+ RSpec/LeadingSubject:
281
+ Enabled: false
282
+
283
+ RSpec/ExpectInHook:
284
+ Enabled: false
285
+
286
+ RSpec/ReturnFromStub:
287
+ Enabled: false
288
+
289
+ RSpec/SubjectStub:
290
+ Enabled: false
291
+
292
+ RSpec/EmptyLineAfterSubject:
293
+ Enabled: false
294
+
295
+ RSpec/LetSetup:
296
+ Enabled: false
297
+
298
+ RSpec/ImplicitExpect:
299
+ EnforcedStyle: is_expected
300
+
301
+ RSpec/ScatteredLet:
302
+ Enabled: false
303
+
304
+ RSpec/ContextWording:
305
+ Enabled: false
306
+
188
307
  Rails/Output:
189
308
  Exclude:
190
309
  - 'config/application.rb'
191
310
  - 'config/initializers/asset_manifest_warning.rb'
311
+
312
+ Rails/DynamicFindBy:
313
+ Enabled: false
314
+
315
+ Rails/Presence:
316
+ Enabled: false
317
+
318
+ Capybara/CurrentPathExpectation:
319
+ Enabled: false
320
+
321
+ Naming/UncommunicativeMethodParamName:
322
+ Enabled: false
323
+
324
+ Style/ExpandPathArguments:
325
+ Enabled: false
@@ -44,3 +44,15 @@ RSpec/InstanceVariable:
44
44
 
45
45
  Style/FrozenStringLiteralComment:
46
46
  Enabled: false
47
+
48
+ Naming/MemoizedInstanceVariableName:
49
+ Enabled: false
50
+
51
+ RSpec/MessageSpies:
52
+ Enabled: false
53
+
54
+ RSpec/BeforeAfterAll:
55
+ Enabled: false
56
+
57
+ Style/EmptyMethod:
58
+ EnforcedStyle: compact
@@ -31,3 +31,24 @@ Adds the following header to the request:
31
31
  ```
32
32
 
33
33
  Which is the base64 encoded credentials "username:password".
34
+
35
+ # Reauthenticate
36
+
37
+ The current implementation can only offer reauthenticate for _client access tokens_. For this to work the following has to be given:
38
+
39
+ * You have configured and implemented `LHC::Auth.refresh_client_token = -> { TokenRefreshUtil.client_access_token(true) }` which when called will force a refresh of the token and return the new value. It is also expected that this implementation will handle invalidating caches if necessary.
40
+ * Your interceptors contain `LHC::Auth` and `LHC::Retry`, whereas `LHC::Retry` comes _after_ `LHC::Auth` in the chain.
41
+
42
+ ## Bearer Authentication with client access token
43
+
44
+ Reauthentication will be initiated if:
45
+
46
+ * setup is correct
47
+ * `response.success?` is false and an `LHC::Unauthorized` was observed
48
+ * reauthentication wasn't already attempted once
49
+
50
+ If this is the case, this happens:
51
+
52
+ * refresh the client token, by calling `refresh_client_token`
53
+ * the authentication header will be updated with the new token
54
+ * `LHC::Retry` will be triggered by adding `retry: { max: 1 }` to the request options
@@ -1,4 +1,4 @@
1
- $:.push File.expand_path("../lib", __FILE__)
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
2
 
3
3
  # Maintain your gem's version:
4
4
  require "lhc/version"
@@ -18,20 +18,20 @@ Gem::Specification.new do |s|
18
18
  s.require_paths = ['lib']
19
19
 
20
20
  s.requirements << 'Ruby >= 2.0.0'
21
- s.required_ruby_version = '>= 2.0.0'
21
+ s.required_ruby_version = '>= 2.3.0'
22
22
 
23
- s.add_dependency 'typhoeus', '>= 0.11'
24
23
  s.add_dependency 'activesupport', '>= 4.2'
25
24
  s.add_dependency 'addressable'
25
+ s.add_dependency 'typhoeus', '>= 0.11'
26
26
 
27
- s.add_development_dependency 'rspec-rails', '>= 3.0.0'
28
- s.add_development_dependency 'rails', '~> 4.2'
29
- s.add_development_dependency 'webmock'
30
27
  s.add_development_dependency 'geminabox'
31
- s.add_development_dependency 'pry'
32
- s.add_development_dependency 'rubocop', '~> 0.36.0'
33
- s.add_development_dependency 'rubocop-rspec'
34
28
  s.add_development_dependency 'prometheus-client', '~> 0.7.1'
29
+ s.add_development_dependency 'pry'
30
+ s.add_development_dependency 'rails', '~> 4.2'
31
+ s.add_development_dependency 'rspec-rails', '>= 3.0.0'
32
+ s.add_development_dependency 'rubocop', '~> 0.57.1'
33
+ s.add_development_dependency 'rubocop-rspec', '~> 1.26.0'
34
+ s.add_development_dependency 'webmock'
35
35
 
36
36
  s.license = 'GPL-3'
37
37
  end
@@ -18,7 +18,7 @@ module LHC
18
18
  request(options.merge(
19
19
  url: url,
20
20
  method: http_method
21
- ))
21
+ ))
22
22
  end
23
23
  end
24
24
 
@@ -10,7 +10,7 @@ class LHC::Config
10
10
 
11
11
  def endpoint(name, url, options = {})
12
12
  name = name.to_sym
13
- fail 'Endpoint already exists for that name' if @endpoints[name]
13
+ raise 'Endpoint already exists for that name' if @endpoints[name]
14
14
  @endpoints[name] = LHC::Endpoint.new(url, options)
15
15
  end
16
16
 
@@ -20,7 +20,7 @@ class LHC::Config
20
20
 
21
21
  def placeholder(name, value)
22
22
  name = name.to_sym
23
- fail 'Placeholder already exists for that name' if @placeholders[name]
23
+ raise 'Placeholder already exists for that name' if @placeholders[name]
24
24
  @placeholders[name] = value
25
25
  end
26
26
 
@@ -33,7 +33,7 @@ class LHC::Config
33
33
  end
34
34
 
35
35
  def interceptors=(interceptors)
36
- fail 'Default interceptors already set and can only be set once' if @interceptors
36
+ raise 'Default interceptors already set and can only be set once' if @interceptors
37
37
  @interceptors = interceptors
38
38
  end
39
39
 
@@ -3,7 +3,8 @@ require 'addressable/template'
3
3
  # An endpoint is an url that leads to a backend resource.
4
4
  # The url can also be an url-template (https://tools.ietf.org/html/rfc6570).
5
5
  class LHC::Endpoint
6
- attr_accessor :url, :options
6
+ attr_accessor :url
7
+ attr_writer :options
7
8
 
8
9
  def initialize(url, options = nil)
9
10
  self.url = url
@@ -22,7 +23,7 @@ class LHC::Endpoint
22
23
  if expanded.variables.empty?
23
24
  expanded.pattern
24
25
  else
25
- fail("Compilation incomplete. Unable to find value for #{expanded.variables.join(', ')}.")
26
+ raise("Compilation incomplete. Unable to find value for #{expanded.variables.join(', ')}.")
26
27
  end
27
28
  end
28
29
 
@@ -99,7 +100,7 @@ class LHC::Endpoint
99
100
  # Extracts the values from url and
100
101
  # creates params according to template
101
102
  def self.values_as_params(template, url)
102
- fail("#{url} does not match the template: #{template}") if !match?(url, template)
103
+ raise("#{url} does not match the template: #{template}") if !match?(url, template)
103
104
  new(template).values_as_params(url)
104
105
  end
105
106
 
@@ -16,7 +16,7 @@ class LHC::Interceptors
16
16
  all.each do |interceptor|
17
17
  result = interceptor.send(name)
18
18
  if result.is_a? LHC::Response
19
- fail 'Response already set from another interceptor' if @response
19
+ raise 'Response already set from another interceptor' if @response
20
20
  @response = interceptor.request.response = result
21
21
  end
22
22
  end
@@ -1,33 +1,96 @@
1
1
  class LHC::Auth < LHC::Interceptor
2
+ include ActiveSupport::Configurable
3
+ config_accessor :refresh_client_token
2
4
 
3
5
  def before_request
4
- options = request.options[:auth] || {}
5
- authenticate!(request, options)
6
+ authenticate!
7
+ end
8
+
9
+ def after_response
10
+ return unless configuration_correct?
11
+ return unless reauthenticate?
12
+ reauthenticate!
6
13
  end
7
14
 
8
15
  private
9
16
 
10
- def authenticate!(request, options)
11
- if options[:bearer]
12
- bearer_authentication!(request, options)
13
- elsif options[:basic]
14
- basic_authentication!(request, options)
17
+ def authenticate!
18
+ if auth_options[:bearer]
19
+ bearer_authentication!
20
+ elsif auth_options[:basic]
21
+ basic_authentication!
15
22
  end
16
23
  end
17
24
 
18
- def basic_authentication!(request, options)
19
- auth = options[:basic]
25
+ def basic_authentication!
26
+ auth = auth_options[:basic]
20
27
  credentials = "#{auth[:username]}:#{auth[:password]}"
21
- set_authorization_header request, "Basic #{Base64.encode64(credentials).chomp}"
28
+ set_authorization_header("Basic #{Base64.encode64(credentials).chomp}")
22
29
  end
23
30
 
24
- def bearer_authentication!(request, options)
25
- token = options[:bearer]
31
+ def bearer_authentication!
32
+ token = auth_options[:bearer]
26
33
  token = token.call if token.is_a?(Proc)
27
- set_authorization_header request, "Bearer #{token}"
34
+ set_bearer_authorization_header(token)
28
35
  end
29
36
 
30
- def set_authorization_header(request, value)
37
+ # rubocop:disable Style/AccessorMethodName
38
+ def set_authorization_header(value)
31
39
  request.headers['Authorization'] = value
32
40
  end
41
+
42
+ def set_bearer_authorization_header(token)
43
+ set_authorization_header("Bearer #{token}")
44
+ end
45
+ # rubocop:enable Style/AccessorMethodName
46
+
47
+ def reauthenticate!
48
+ # refresh token and update header
49
+ token = refresh_client_token_option.call
50
+ set_bearer_authorization_header(token)
51
+ # trigger LHC::Retry and ensure we do not trigger reauthenticate!
52
+ # again should it fail another time
53
+ new_options = request.options.dup
54
+ new_options = new_options.merge(retry: { max: 1 })
55
+ new_options = new_options.merge(auth: { reauthenticated: true })
56
+ request.options = new_options
57
+ end
58
+
59
+ def reauthenticate?
60
+ !response.success? &&
61
+ !auth_options[:reauthenticated] &&
62
+ bearer_header_present? &&
63
+ LHC::Error.find(response) == LHC::Unauthorized
64
+ end
65
+
66
+ def bearer_header_present?
67
+ @has_bearer_header ||= request.headers['Authorization'] =~ /^Bearer [0-9a-f-]+$/i
68
+ end
69
+
70
+ def refresh_client_token_option
71
+ @refresh_client_token_option ||= auth_options[:refresh_client_token] || refresh_client_token
72
+ end
73
+
74
+ def all_interceptor_classes
75
+ @all_interceptors ||= LHC::Interceptors.new(request).all.map(&:class)
76
+ end
77
+
78
+ def auth_options
79
+ @auth_options ||= request.options[:auth].dup || {}
80
+ end
81
+
82
+ def configuration_correct?
83
+ # warn user about configs, only if refresh_client_token_option is set at all
84
+ refresh_client_token_option && refresh_client_token? && retry_interceptor?
85
+ end
86
+
87
+ def refresh_client_token?
88
+ return true if refresh_client_token_option.is_a?(Proc)
89
+ warn("[WARNING] The given refresh_client_token must be a Proc for reauthentication.")
90
+ end
91
+
92
+ def retry_interceptor?
93
+ return true if all_interceptor_classes.include?(LHC::Retry) && all_interceptor_classes.index(LHC::Retry) > all_interceptor_classes.index(self.class)
94
+ warn("[WARNING] Your interceptors must include LHC::Retry after LHC::Auth.")
95
+ end
33
96
  end
@@ -15,7 +15,7 @@ class LHC::Caching < LHC::Interceptor
15
15
  key = key(request, options[:key])
16
16
  response_data = cache_for(options).fetch(key)
17
17
  return unless response_data
18
- logger.info "Served from cache: #{key}" if logger
18
+ logger&.info "Served from cache: #{key}"
19
19
  from_cache(request, response_data)
20
20
  end
21
21
 
@@ -51,7 +51,7 @@ class LHC::Caching < LHC::Interceptor
51
51
  # returns the request_options
52
52
  # will map deprecated options to the new format
53
53
  def options(request_options)
54
- options = request_options[:cache] == true ? {} : request_options[:cache].dup
54
+ options = (request_options[:cache] == true) ? {} : request_options[:cache].dup
55
55
  map_deprecated_options!(request_options, options)
56
56
  options
57
57
  end
@@ -6,14 +6,14 @@ class LHC::Logging < LHC::Interceptor
6
6
  def before_request
7
7
  return unless logger
8
8
  logger.info(
9
- "Before LHC request<#{request.object_id}> #{request.method.upcase} #{request.url} at #{DateTime.now} Params=#{request.params} Headers=#{request.headers}"
9
+ "Before LHC request<#{request.object_id}> #{request.method.upcase} #{request.url} at #{Time.now.iso8601} Params=#{request.params} Headers=#{request.headers}"
10
10
  )
11
11
  end
12
12
 
13
13
  def after_response
14
14
  return unless logger
15
15
  logger.info(
16
- "After LHC response for request<#{request.object_id}> #{request.method.upcase} #{request.url} at #{DateTime.now} Time=#{response.time_ms}ms URL=#{response.effective_url}"
16
+ "After LHC response for request<#{request.object_id}> #{request.method.upcase} #{request.url} at #{Time.now.iso8601} Time=#{response.time_ms}ms URL=#{response.effective_url}"
17
17
  )
18
18
  end
19
19
  end
@@ -143,6 +143,6 @@ class LHC::Request
143
143
  end
144
144
 
145
145
  def throw_error(response)
146
- fail error.new(error, response)
146
+ raise error.new(error, response)
147
147
  end
148
148
  end
@@ -16,7 +16,7 @@ class LHC::Response::Data
16
16
  end
17
17
  end
18
18
 
19
- def method_missing(method, *args, &block)
19
+ def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissingSuper
20
20
  @base.send(method, *args, &block)
21
21
  end
22
22
 
@@ -1,3 +1,3 @@
1
1
  module LHC
2
- VERSION ||= '9.2.0'
2
+ VERSION ||= '9.3.0'
3
3
  end
@@ -19,14 +19,14 @@ describe LHC do
19
19
  LHC.delete('http://datastore/v2/feedbacks/12121')
20
20
  end
21
21
 
22
- it 'it makes response data available in a rails way' do
22
+ it 'makes response data available in a rails way' do
23
23
  response = LHC.delete('http://datastore/v2/feedbacks/12121')
24
24
  expect(response.data.recommended).to eq true
25
25
  end
26
26
 
27
27
  it 'provides response headers' do
28
28
  response = LHC.delete('http://datastore/v2/feedbacks/12121')
29
- expect(response.headers).to be
29
+ expect(response.headers).to be_present
30
30
  end
31
31
  end
32
32
  end
@@ -22,14 +22,14 @@ describe LHC do
22
22
  LHC.get(:feedbacks, params: parameters)
23
23
  end
24
24
 
25
- it 'it makes response data available in a rails way' do
25
+ it 'makes response data available in a rails way' do
26
26
  response = LHC.get('http://datastore/v2/feedbacks', params: parameters)
27
27
  expect(response.data.total).to eq 99
28
28
  end
29
29
 
30
30
  it 'provides response headers' do
31
31
  response = LHC.get('http://datastore/v2/feedbacks', params: parameters)
32
- expect(response.headers).to be
32
+ expect(response.headers).to be_present
33
33
  end
34
34
  end
35
35
 
@@ -27,14 +27,14 @@ describe LHC do
27
27
  LHC.post(:feedbacks, body: feedback)
28
28
  end
29
29
 
30
- it 'it makes response data available in a rails way' do
30
+ it 'makes response data available in a rails way' do
31
31
  response = LHC.post('http://datastore/v2/feedbacks', body: feedback)
32
32
  expect(response.data.source_id).to eq 'aaa'
33
33
  end
34
34
 
35
35
  it 'provides response headers' do
36
36
  response = LHC.post('http://datastore/v2/feedbacks', body: feedback)
37
- expect(response.headers).to be
37
+ expect(response.headers).to be_present
38
38
  end
39
39
  end
40
40
  end
@@ -33,14 +33,14 @@ describe LHC do
33
33
  LHC.put(:feedbacks, body: change)
34
34
  end
35
35
 
36
- it 'it makes response data available in a rails way' do
36
+ it 'makes response data available in a rails way' do
37
37
  response = LHC.put('http://datastore/v2/feedbacks', body: change)
38
38
  expect(response.data.recommended).to eq false
39
39
  end
40
40
 
41
41
  it 'provides response headers' do
42
42
  response = LHC.put('http://datastore/v2/feedbacks', body: change)
43
- expect(response.headers).to be
43
+ expect(response.headers).to be_present
44
44
  end
45
45
  end
46
46
  end
@@ -16,7 +16,7 @@ describe LHC::Endpoint do
16
16
  'http://local.ch/places/1/feedbacks.json' => 'http://local.ch/places/1/feedbacks.json?lang=en'
17
17
  }.each do |template, url|
18
18
  it "#{url} matches #{template}" do
19
- expect(LHC::Endpoint.match?(url, template)).to be
19
+ expect(LHC::Endpoint.match?(url, template)).to be(true)
20
20
  end
21
21
  end
22
22
  end
@@ -31,7 +31,7 @@ describe LHC::Endpoint do
31
31
  it "#{url} should not match #{template}" do
32
32
  expect(
33
33
  LHC::Endpoint.match?(url, template)
34
- ).not_to be
34
+ ).to be(false)
35
35
  end
36
36
  end
37
37
  end
@@ -12,7 +12,7 @@ describe LHC::Endpoint do
12
12
  it 'allows basic auth token in url, like used on github' do
13
13
  stub_request(:get, "https://d123token:@api.github.com/search")
14
14
  .to_return(body: {}.to_json)
15
- expect(->{
15
+ expect(-> {
16
16
  LHC.get("https://d123token:@api.github.com/search")
17
17
  }).not_to raise_error
18
18
  end
@@ -20,7 +20,7 @@ describe LHC::Endpoint do
20
20
  it 'allows complete basic auth (username password) in url, like used for the gemserer' do
21
21
  stub_request(:get, "https://name:password@gemserver.com")
22
22
  .to_return(body: {}.to_json)
23
- expect(->{
23
+ expect(-> {
24
24
  LHC.get("https://name:password@gemserver.com")
25
25
  }).not_to raise_error
26
26
  end
@@ -46,10 +46,10 @@ describe LHC::Error do
46
46
  double('request',
47
47
  method: 'GET',
48
48
  url: 'http://example.com/sessions',
49
- headers: { 'Bearer Token' => "aaaaaaaa-bbbb-cccc-dddd-eeee"},
49
+ headers: { 'Bearer Token' => "aaaaaaaa-bbbb-cccc-dddd-eeee" },
50
50
  options: { followlocation: true,
51
- auth: { bearer: "aaaaaaaa-bbbb-cccc-dddd-eeee"},
52
- params: { limit: 20}, url: "http://example.com/sessions" })
51
+ auth: { bearer: "aaaaaaaa-bbbb-cccc-dddd-eeee" },
52
+ params: { limit: 20 }, url: "http://example.com/sessions" })
53
53
  end
54
54
 
55
55
  let(:response) do
@@ -4,12 +4,9 @@ describe LHC do
4
4
  context 'interceptor' do
5
5
  before(:each) do
6
6
  class Services
7
- def self.timing(_path, _time)
8
- end
7
+ def self.timing(_path, _time); end
9
8
  end
10
- end
11
9
 
12
- before(:each) do
13
10
  class StatsTimingInterceptor < LHC::Interceptor
14
11
  def after_response
15
12
  uri = URI.parse(response.request.url)
@@ -0,0 +1,59 @@
1
+ require 'rails_helper'
2
+
3
+ describe LHC::Auth do
4
+ let(:bearer_token) { '123456' }
5
+
6
+ before(:each) do
7
+ stub_request(:get, 'http://local.ch').with(headers: { 'Authorization' => "Bearer #{bearer_token}" })
8
+ end
9
+
10
+ context "configuration check not happening" do
11
+ let(:options) { { bearer: bearer_token } }
12
+
13
+ before(:each) { LHC.config.interceptors = [LHC::Auth, LHC::Retry] }
14
+
15
+ it "max_recovery_attempts is zero" do
16
+ expect_any_instance_of(described_class).not_to receive(:warn)
17
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options.merge(max_recovery_attempts: 0))
18
+ LHC.get(:local)
19
+ end
20
+
21
+ it "max_recovery_attempts is missing" do
22
+ expect_any_instance_of(described_class).not_to receive(:warn)
23
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options)
24
+ LHC.get(:local)
25
+ end
26
+ end
27
+
28
+ context "configuration check happening" do
29
+ let(:options) { { bearer: bearer_token, max_recovery_attempts: 1, refresh_client_token: -> { "here comes your refresh code" } } }
30
+
31
+ it "no warning with proper options" do
32
+ LHC.config.interceptors = [LHC::Auth, LHC::Retry]
33
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options)
34
+ expect_any_instance_of(described_class).not_to receive(:warn)
35
+ LHC.get(:local)
36
+ end
37
+
38
+ it "warn refresh_client_token is a string" do
39
+ LHC.config.interceptors = [LHC::Auth, LHC::Retry]
40
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options.merge(refresh_client_token: bearer_token))
41
+ expect_any_instance_of(described_class).to receive(:warn).with("[WARNING] The given refresh_client_token must be a Proc for reauthentication.")
42
+ LHC.get(:local)
43
+ end
44
+
45
+ it "warn interceptors miss LHC::Retry" do
46
+ LHC.config.interceptors = [LHC::Auth]
47
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options)
48
+ expect_any_instance_of(described_class).to receive(:warn).with("[WARNING] Your interceptors must include LHC::Retry after LHC::Auth.")
49
+ LHC.get(:local)
50
+ end
51
+
52
+ it "warn interceptors LHC::Retry before LHC::Auth" do
53
+ LHC.config.interceptors = [LHC::Retry, LHC::Auth]
54
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options)
55
+ expect_any_instance_of(described_class).to receive(:warn).with("[WARNING] Your interceptors must include LHC::Retry after LHC::Auth.")
56
+ LHC.get(:local)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,32 @@
1
+ require 'rails_helper'
2
+
3
+ describe LHC::Auth do
4
+ let(:initial_token) { '123456' }
5
+ let(:refresh_token) { 'abcdef' }
6
+ let(:options) { { bearer: initial_token, refresh_client_token: -> { refresh_token } } }
7
+ let!(:auth_failing) do
8
+ stub_request(:get, 'http://local.ch')
9
+ .with(headers: { 'Authorization' => "Bearer #{initial_token}" })
10
+ .to_return(status: 401, body: "{}") # LHC::Unauthorized
11
+ end
12
+ let!(:auth_suceeding_after_recovery) do
13
+ stub_request(:get, 'http://local.ch')
14
+ .with(headers: { 'Authorization' => "Bearer #{refresh_token}" })
15
+ end
16
+
17
+ before(:each) do
18
+ LHC.config.interceptors = [LHC::Auth, LHC::Retry]
19
+ end
20
+
21
+ it "recovery is attempted" do
22
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options)
23
+ # the retried request (with updated Bearer), that should work
24
+ LHC.get(:local)
25
+ expect(auth_suceeding_after_recovery).to have_been_made.once
26
+ end
27
+
28
+ it "recovery is not attempted again when the request has reauthenticated: true " do
29
+ LHC.config.endpoint(:local, 'http://local.ch', auth: options.merge(reauthenticated: true))
30
+ expect { LHC.get(:local) }.to raise_error(LHC::Unauthorized)
31
+ end
32
+ end
@@ -5,14 +5,12 @@ describe LHC::Caching do
5
5
  LHC.config.interceptors = [LHC::Caching]
6
6
  LHC::Caching.cache = Rails.cache
7
7
  Rails.cache.clear
8
- end
9
-
10
- let!(:stub) { stub_request(:post, 'http://local.ch').to_return(status: 200, body: 'The Website') }
11
8
 
12
- before(:each) do
13
9
  LHC.config.endpoint(:local, 'http://local.ch', cache: { expires_in: 5.minutes })
14
10
  end
15
11
 
12
+ let!(:stub) { stub_request(:post, 'http://local.ch').to_return(status: 200, body: 'The Website') }
13
+
16
14
  it 'only caches GET requests by default' do
17
15
  expect(Rails.cache).not_to receive(:write)
18
16
  LHC.post(:local)
@@ -4,15 +4,14 @@ require 'rails_helper'
4
4
  # we need a class where we can setup method expectations
5
5
  # with `expect_any_instance`
6
6
  class CacheMock
7
- def fetch(*_)
8
- end
7
+ def fetch(*_); end
9
8
 
10
- def write(*_)
11
- end
9
+ def write(*_); end
12
10
  end
13
11
 
14
12
  describe LHC::Caching do
15
13
  let(:default_cache) { LHC::Caching.cache }
14
+
16
15
  before(:each) do
17
16
  stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website')
18
17
  LHC.config.interceptors = [LHC::Caching]
@@ -26,7 +25,7 @@ describe LHC::Caching do
26
25
  expect(lambda {
27
26
  LHC.get('http://local.ch', cache: true, cache_expires_in: 5.minutes, cache_key: 'key', cache_race_condition_ttl: 15.seconds)
28
27
  }).to output(
29
- %r{Cache options have changed! cache_expires_in, cache_key, cache_race_condition_ttl are deprecated and will be removed in future versions.}
28
+ /Cache options have changed! cache_expires_in, cache_key, cache_race_condition_ttl are deprecated and will be removed in future versions./
30
29
  ).to_stderr
31
30
  end
32
31
 
@@ -5,11 +5,9 @@ describe LHC::Monitoring do
5
5
  let(:endpoint_configuration) { LHC.config.endpoint(:local, 'http://local.ch') }
6
6
 
7
7
  module Statsd
8
- def self.count(_path, _value)
9
- end
8
+ def self.count(_path, _value); end
10
9
 
11
- def self.timing(_path, _value)
12
- end
10
+ def self.timing(_path, _value); end
13
11
  end
14
12
 
15
13
  before(:each) do
@@ -100,7 +100,7 @@ describe LHC::Zipkin do
100
100
 
101
101
  it 'does register a new span' do
102
102
  # ensure a span was registered, by checking call on span
103
- expect_any_instance_of(described_class).to receive(:span).at_least(1).times.and_call_original
103
+ expect_any_instance_of(described_class).to receive(:span).at_least(:once).and_call_original
104
104
  LHC.get(:local)
105
105
  end
106
106
  end
@@ -3,6 +3,7 @@ require 'rails_helper'
3
3
  describe LHC::Request do
4
4
  context 'ignoring LHC::NotFound' do
5
5
  let(:response) { LHC.get('http://local.ch', ignored_errors: [LHC::NotFound]) }
6
+
6
7
  before { stub_request(:get, 'http://local.ch').to_return(status: 404) }
7
8
 
8
9
  it 'does not raise an error' do
@@ -5,7 +5,7 @@ describe LHC::Response do
5
5
  let(:response_success) { LHC::Response.new(Typhoeus::Response.new(response_code: 200, mock: true), nil) }
6
6
  let(:response_error) { LHC::Response.new(Typhoeus::Response.new(response_code: 404, mock: true), nil) }
7
7
 
8
- it { expect(response_success.success?).to be_truthy }
9
- it { expect(response_error.success?).to be_falsy }
8
+ it { expect(response_success).to be_success }
9
+ it { expect(response_error).not_to be_success }
10
10
  end
11
11
  end
@@ -11,7 +11,7 @@ describe LHC::Response do
11
11
  expect(response.time).to eq time * 1000
12
12
  end
13
13
 
14
- it 'provides response time in seconds' do
14
+ it 'provides response time in miliseconds' do
15
15
  response = LHC::Response.new(raw_response, nil)
16
16
  expect(response.time_ms).to eq time
17
17
  end
@@ -55,11 +55,9 @@ module ZipkinTracer
55
55
  end
56
56
 
57
57
  class Span
58
- def record_tag(*)
59
- end
58
+ def record_tag(*); end
60
59
 
61
- def record(*)
62
- end
60
+ def record(*); end
63
61
  end
64
62
  end
65
63
 
metadata CHANGED
@@ -1,87 +1,87 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lhc
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.2.0
4
+ version: 9.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/local-ch/lhc/contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-23 00:00:00.000000000 Z
11
+ date: 2018-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: typhoeus
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0.11'
19
+ version: '4.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0.11'
26
+ version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: addressable
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '4.2'
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '4.2'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: addressable
42
+ name: typhoeus
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '0.11'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '0.11'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec-rails
56
+ name: geminabox
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 3.0.0
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.0.0
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rails
70
+ name: prometheus-client
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '4.2'
75
+ version: 0.7.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '4.2'
82
+ version: 0.7.1
83
83
  - !ruby/object:Gem::Dependency
84
- name: webmock
84
+ name: pry
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,75 +95,75 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: geminabox
98
+ name: rails
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '4.2'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '4.2'
111
111
  - !ruby/object:Gem::Dependency
112
- name: pry
112
+ name: rspec-rails
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: 3.0.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: 3.0.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.36.0
131
+ version: 0.57.1
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.36.0
138
+ version: 0.57.1
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rubocop-rspec
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ">="
143
+ - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: 1.26.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ">="
150
+ - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: 1.26.0
153
153
  - !ruby/object:Gem::Dependency
154
- name: prometheus-client
154
+ name: webmock
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - "~>"
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
- version: 0.7.1
159
+ version: '0'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - "~>"
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
- version: 0.7.1
166
+ version: '0'
167
167
  description: 'Rails gem for HTTP: Wraps typhoeus and provides additional features
168
168
  (like interceptors)'
169
169
  email:
@@ -302,6 +302,8 @@ files:
302
302
  - spec/interceptors/after_response_spec.rb
303
303
  - spec/interceptors/auth/basic_auth_spec.rb
304
304
  - spec/interceptors/auth/bearer_spec.rb
305
+ - spec/interceptors/auth/reauthentication_configuration_spec.rb
306
+ - spec/interceptors/auth/reauthentication_spec.rb
305
307
  - spec/interceptors/before_request_spec.rb
306
308
  - spec/interceptors/before_response_spec.rb
307
309
  - spec/interceptors/caching/hydra_spec.rb
@@ -363,7 +365,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
363
365
  requirements:
364
366
  - - ">="
365
367
  - !ruby/object:Gem::Version
366
- version: 2.0.0
368
+ version: 2.3.0
367
369
  required_rubygems_version: !ruby/object:Gem::Requirement
368
370
  requirements:
369
371
  - - ">="
@@ -372,7 +374,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
372
374
  requirements:
373
375
  - Ruby >= 2.0.0
374
376
  rubyforge_project:
375
- rubygems_version: 2.6.12
377
+ rubygems_version: 2.6.14
376
378
  signing_key:
377
379
  specification_version: 4
378
380
  summary: LocalHttpClient
@@ -440,6 +442,8 @@ test_files:
440
442
  - spec/interceptors/after_response_spec.rb
441
443
  - spec/interceptors/auth/basic_auth_spec.rb
442
444
  - spec/interceptors/auth/bearer_spec.rb
445
+ - spec/interceptors/auth/reauthentication_configuration_spec.rb
446
+ - spec/interceptors/auth/reauthentication_spec.rb
443
447
  - spec/interceptors/before_request_spec.rb
444
448
  - spec/interceptors/before_response_spec.rb
445
449
  - spec/interceptors/caching/hydra_spec.rb