lhc 9.2.0 → 9.3.0

Sign up to get free protection for your applications and to get access to all the features.
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