lhs 19.8.2 → 20.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +89 -5
- data/lhs.gemspec +2 -0
- data/lib/lhs.rb +18 -0
- data/lib/lhs/concerns/option_blocks.rb +2 -1
- data/lib/lhs/concerns/record/href_for.rb +19 -0
- data/lib/lhs/concerns/record/request.rb +4 -4
- data/lib/lhs/interceptors/extended_rollbar/handler.rb +40 -0
- data/lib/lhs/interceptors/extended_rollbar/interceptor.rb +20 -0
- data/lib/lhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
- data/lib/lhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
- data/lib/lhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
- data/lib/lhs/railtie.rb +8 -1
- data/lib/lhs/record.rb +3 -8
- data/lib/lhs/rspec.rb +19 -0
- data/lib/lhs/test/stub.rb +29 -0
- data/lib/lhs/version.rb +1 -1
- data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
- data/spec/dummy/config/initializers/rollbar.rb +9 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/extended_rollbar_spec.rb +67 -0
- data/spec/rails_helper.rb +2 -0
- data/spec/record/href_for_spec.rb +25 -0
- data/spec/request_cycle_cache_spec.rb +4 -4
- data/spec/stubs/all_spec.rb +28 -0
- metadata +49 -7
- data/lib/lhs/concerns/record/request_cycle_cache/interceptor.rb +0 -40
- data/lib/lhs/concerns/record/request_cycle_cache/request_cycle_thread_registry.rb +0 -15
- data/lib/lhs/test/request_cycle_cache_helper.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6222738010dc108833f001419f0fe23f97c1fbe6bb3211347724455bd6d1fab6
|
4
|
+
data.tar.gz: ec1856d1a8ce39396dedf8251058f59604f3e84111a2dffea05a7b0d97b07cab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22dde92abf63322ceab6d51962462c5dac3a34c12c46438a761fdce584066e50c1202babbc31762326cd96d073edd7d83aa8b8a231948a3d404adb93ea8a8ea2
|
7
|
+
data.tar.gz: eaafb72d93e036a0e8af226877fea17d5489e722bbd0d403946bc4828e3429f2a37cf85dc46818116fe751fb937dc3c1851e4cc9ac55f0d7fbbb0482611abe38
|
data/README.md
CHANGED
@@ -119,6 +119,7 @@ record.review # "Lunch was great
|
|
119
119
|
* [Record setters](#record-setters)
|
120
120
|
* [Record getters](#record-getters)
|
121
121
|
* [Include linked resources (hyperlinks and hypermedia)](#include-linked-resources-hyperlinks-and-hypermedia)
|
122
|
+
* [Generate links from parameters](#generate-links-from-parameters)
|
122
123
|
* [Ensure the whole linked collection is included: includes_all](#ensure-the-whole-linked-collection-is-included-includes_all)
|
123
124
|
* [Include the first linked page or single item is included: include](#include-the-first-linked-page-or-single-item-is-included-include)
|
124
125
|
* [Include various levels of linked data](#include-various-levels-of-linked-data)
|
@@ -136,8 +137,11 @@ record.review # "Lunch was great
|
|
136
137
|
* [Disable request cycle cache](#disable-request-cycle-cache)
|
137
138
|
* [Option Blocks](#option-blocks)
|
138
139
|
* [Request tracing](#request-tracing)
|
140
|
+
* [Extended Rollbar Logging](#extended-rollbar-logging)
|
139
141
|
* [Testing with LHS](#testing-with-lhs)
|
140
|
-
* [Test helper
|
142
|
+
* [Test helper](#test-helper)
|
143
|
+
* [Stub](#stub)
|
144
|
+
* [Stub All](#stub-all)
|
141
145
|
* [Test query chains](#test-query-chains)
|
142
146
|
* [By explicitly resolving the chain: fetch](#by-explicitly-resolving-the-chain-fetch)
|
143
147
|
* [Without resolving the chain: where_values_hash](#without-resolving-the-chain-where_values_hash)
|
@@ -1627,6 +1631,15 @@ POST https://service.example.com/records/1z-5r1fkaj { body: "{ 'name': 'Starbuck
|
|
1627
1631
|
|
1628
1632
|
-> See [record validation](#record-validation) for how to handle validation errors when updating records.
|
1629
1633
|
|
1634
|
+
You can also pass explicit request options to `update`, by passing two explicit hashes:
|
1635
|
+
|
1636
|
+
```ruby
|
1637
|
+
# app/controllers/some_controller.rb
|
1638
|
+
|
1639
|
+
record.update({ recommended: true }, { method: 'put' })
|
1640
|
+
|
1641
|
+
```
|
1642
|
+
|
1630
1643
|
##### partial_update
|
1631
1644
|
|
1632
1645
|
`partial_update` updates just the provided parameters.
|
@@ -1658,6 +1671,15 @@ POST https://service.example.com/records/1z-5r1fkaj { body: "{ 'name': 'Starbuck
|
|
1658
1671
|
|
1659
1672
|
-> See [record validation](#record-validation) for how to handle validation errors when updating records.
|
1660
1673
|
|
1674
|
+
You can also pass explicit request options to `partial_update`, by passing two explicit hashes:
|
1675
|
+
|
1676
|
+
```ruby
|
1677
|
+
# app/controllers/some_controller.rb
|
1678
|
+
|
1679
|
+
record.partial_update({ recommended: true }, { method: 'put' })
|
1680
|
+
|
1681
|
+
```
|
1682
|
+
|
1661
1683
|
#### Endpoint url parameter injection during record creation/change
|
1662
1684
|
|
1663
1685
|
LHS injects parameters provided to `create`, `update`, `partial_update`, `save` etc. into an endpoint's URL when matching:
|
@@ -2020,6 +2042,21 @@ With `includes` or `includes_all` (to enforce fetching all remote objects for pa
|
|
2020
2042
|
|
2021
2043
|
Including linked resources/records is heavily influenced by [https://guides.rubyonrails.org/active_record_querying.html](https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) and you should read it to understand this feature in all it's glory.
|
2022
2044
|
|
2045
|
+
#### Generate links from parameters
|
2046
|
+
|
2047
|
+
Sometimes you need to generate full hrefs/urls for records but you just have parameters that describe that record, like the ID.
|
2048
|
+
|
2049
|
+
For those usecases you can use `href_for(params)`:
|
2050
|
+
|
2051
|
+
```ruby
|
2052
|
+
# app/controllers/some_controller.rb
|
2053
|
+
|
2054
|
+
Presence.create(place: { href: Place.href_for(123) })
|
2055
|
+
```
|
2056
|
+
```
|
2057
|
+
POST '/presences' { place: { href: "http://datastore/places/123" } }
|
2058
|
+
```
|
2059
|
+
|
2023
2060
|
#### Ensure the whole linked collection is included: includes_all
|
2024
2061
|
|
2025
2062
|
In case endpoints are paginated and you are certain that you'll need all objects of a set and not only the first page/batch, use `includes_all`.
|
@@ -2428,6 +2465,26 @@ code.places
|
|
2428
2465
|
}
|
2429
2466
|
```
|
2430
2467
|
|
2468
|
+
## Extended Rollbar Logging
|
2469
|
+
|
2470
|
+
In order to log all requests/responses prior to an exception reported by Rollbar in addition to the exception itself, use the `LHS::ExtendedRollbar` interceptor in combination with the rollbar processor/handler:
|
2471
|
+
|
2472
|
+
```ruby
|
2473
|
+
# config/initializers/lhc.rb
|
2474
|
+
|
2475
|
+
LHC.configure do |config|
|
2476
|
+
config.interceptors = [LHS::ExtendedRollbar]
|
2477
|
+
end
|
2478
|
+
```
|
2479
|
+
|
2480
|
+
```ruby
|
2481
|
+
# config/initializers/rollbar.rb
|
2482
|
+
|
2483
|
+
Rollbar.configure do |config|
|
2484
|
+
config.before_process << LHS::Interceptors::ExtendedRollbar::Handler.init
|
2485
|
+
end
|
2486
|
+
```
|
2487
|
+
|
2431
2488
|
## Testing with LHS
|
2432
2489
|
|
2433
2490
|
**Best practice in regards of testing applications using LHS, is to let LHS fetch your records, actually perform HTTP requests and [WebMock](https://github.com/bblimke/webmock) to stub/mock those http requests/responses.**
|
@@ -2465,17 +2522,44 @@ it 'displays contracts' do
|
|
2465
2522
|
end
|
2466
2523
|
```
|
2467
2524
|
|
2468
|
-
### Test helper
|
2525
|
+
### Test helper
|
2469
2526
|
|
2470
|
-
In order to
|
2527
|
+
In order to load LHS test helpers into your tests, add the following to your spec helper:
|
2471
2528
|
|
2472
2529
|
```ruby
|
2473
2530
|
# spec/spec_helper.rb
|
2474
2531
|
|
2475
|
-
require 'lhs/
|
2532
|
+
require 'lhs/rspec'
|
2476
2533
|
```
|
2477
2534
|
|
2478
|
-
This will
|
2535
|
+
This e.g. will prevent running into caching issues during your tests, when (request cycle cache)[#request-cycle-cache] is enabled.
|
2536
|
+
It will initialize a MemoryStore cache for LHC::Caching interceptor and resets the cache before every test.
|
2537
|
+
|
2538
|
+
#### Stub
|
2539
|
+
|
2540
|
+
LHS offers stub helpers that simplify stubbing https request to your apis.
|
2541
|
+
|
2542
|
+
##### Stub All
|
2543
|
+
|
2544
|
+
`LHS.stub.all(url, items, additional_options)`
|
2545
|
+
|
2546
|
+
```ruby
|
2547
|
+
# your_spec.rb
|
2548
|
+
|
2549
|
+
before do
|
2550
|
+
LHS.stub.all(
|
2551
|
+
'https://records',
|
2552
|
+
200.times.map{ |index| { name: "Item #{index}" } },
|
2553
|
+
headers: {
|
2554
|
+
'Authorization' => 'Bearer 123'
|
2555
|
+
}
|
2556
|
+
)
|
2557
|
+
end
|
2558
|
+
```
|
2559
|
+
```
|
2560
|
+
GET https://records?limit=100
|
2561
|
+
GET https://records?limit=100&offset=100
|
2562
|
+
```
|
2479
2563
|
|
2480
2564
|
### Test query chains
|
2481
2565
|
|
data/lhs.gemspec
CHANGED
@@ -28,9 +28,11 @@ Gem::Specification.new do |s|
|
|
28
28
|
|
29
29
|
s.add_development_dependency 'capybara'
|
30
30
|
s.add_development_dependency 'json', '>= 1.8.2'
|
31
|
+
s.add_development_dependency 'local_uri'
|
31
32
|
s.add_development_dependency 'pry'
|
32
33
|
s.add_development_dependency 'pry-byebug'
|
33
34
|
s.add_development_dependency 'rails', '>= 4.2.11'
|
35
|
+
s.add_development_dependency 'rollbar'
|
34
36
|
s.add_development_dependency 'rspec-rails', '>= 3.7.0'
|
35
37
|
s.add_development_dependency 'rubocop', '~> 0.57.1'
|
36
38
|
s.add_development_dependency 'rubocop-rspec', '~> 1.26.0'
|
data/lib/lhs.rb
CHANGED
@@ -15,10 +15,28 @@ module LHS
|
|
15
15
|
'lhs/config'
|
16
16
|
autoload :Data,
|
17
17
|
'lhs/data'
|
18
|
+
autoload :ExtendedRollbar,
|
19
|
+
'lhs/interceptors/extended_rollbar/interceptor'
|
18
20
|
autoload :Endpoint,
|
19
21
|
'lhs/endpoint'
|
20
22
|
autoload :Inspect,
|
21
23
|
'lhs/concerns/inspect'
|
24
|
+
module Interceptors
|
25
|
+
module RequestCycleCache
|
26
|
+
autoload :ThreadRegistry,
|
27
|
+
'lhs/interceptors/request_cycle_cache/thread_registry'
|
28
|
+
autoload :Interceptor,
|
29
|
+
'lhs/interceptors/request_cycle_cache/interceptor'
|
30
|
+
end
|
31
|
+
module ExtendedRollbar
|
32
|
+
autoload :ThreadRegistry,
|
33
|
+
'lhs/interceptors/extended_rollbar/thread_registry'
|
34
|
+
autoload :Interceptor,
|
35
|
+
'lhs/interceptors/extended_rollbar/interceptor'
|
36
|
+
autoload :Handler,
|
37
|
+
'lhs/interceptors/extended_rollbar/handler'
|
38
|
+
end
|
39
|
+
end
|
22
40
|
autoload :IsHref,
|
23
41
|
'lhs/concerns/is_href'
|
24
42
|
autoload :Item,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_support'
|
4
|
+
require 'active_support/per_thread_registry'
|
4
5
|
|
5
6
|
module LHS
|
6
7
|
module OptionBlocks
|
@@ -8,7 +9,7 @@ module LHS
|
|
8
9
|
|
9
10
|
class CurrentOptionBlock
|
10
11
|
# Using ActiveSupports PerThreadRegistry to be able to support Active Support v4.
|
11
|
-
# Will switch to thread_mattr_accessor (which comes with Activesupport) when we dropping support for Active Support
|
12
|
+
# Will switch to thread_mattr_accessor (which comes with Activesupport) when we dropping support for Active Support v4.
|
12
13
|
extend ActiveSupport::PerThreadRegistry
|
13
14
|
attr_accessor :options
|
14
15
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
class LHS::Record
|
6
|
+
|
7
|
+
module HrefFor
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def href_for(args = nil)
|
12
|
+
return unless [Integer, String].include?(args.class)
|
13
|
+
params = { id: args }
|
14
|
+
find_endpoint(params).compile(params)
|
15
|
+
end
|
16
|
+
alias url_for href_for
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -509,16 +509,16 @@ class LHS::Record
|
|
509
509
|
options
|
510
510
|
end
|
511
511
|
|
512
|
-
# Injects options into request, that enable the
|
512
|
+
# Injects options into request, that enable the request cycle cache interceptor
|
513
513
|
def inject_request_cycle_cache!(options)
|
514
514
|
return unless LHS.config.request_cycle_cache_enabled
|
515
515
|
interceptors = options[:interceptors] || LHC.config.interceptors
|
516
516
|
if interceptors.include?(LHC::Caching)
|
517
|
-
# Ensure
|
518
|
-
interceptors = interceptors.unshift(LHS::
|
517
|
+
# Ensure interceptor is prepend
|
518
|
+
interceptors = interceptors.unshift(LHS::Interceptors::RequestCycleCache::Interceptor)
|
519
519
|
options[:interceptors] = interceptors
|
520
520
|
else
|
521
|
-
warn("[WARNING] Can't enable
|
521
|
+
warn("[WARNING] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured (see https://github.com/local-ch/lhc/blob/master/docs/interceptors/caching.md#caching-interceptor)!")
|
522
522
|
end
|
523
523
|
end
|
524
524
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LHS
|
4
|
+
module Interceptors
|
5
|
+
module ExtendedRollbar
|
6
|
+
class Handler
|
7
|
+
|
8
|
+
def self.init
|
9
|
+
proc do |options|
|
10
|
+
# as handlers cant influence what actually is reported to rollbar
|
11
|
+
# this just makes sure that Rollbar is already loaded when this class is loaded,
|
12
|
+
# so that we can extend rollbar loging
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ExtendedLogging
|
17
|
+
def log(level, *args)
|
18
|
+
args[2] = {} if args[2].nil?
|
19
|
+
args[2][:lhs] = LHS::Interceptors::ExtendedRollbar::ThreadRegistry.log.map do |entry|
|
20
|
+
{
|
21
|
+
request: entry[:request].options,
|
22
|
+
response: {
|
23
|
+
code: entry[:response].code,
|
24
|
+
body: entry[:response].body
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end.to_json
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ::Rollbar
|
33
|
+
class Notifier
|
34
|
+
prepend LHS::Interceptors::ExtendedRollbar::Handler::ExtendedLogging
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
module LHS
|
6
|
+
module Interceptors
|
7
|
+
module ExtendedRollbar
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
class Interceptor < LHC::Interceptor
|
11
|
+
def after_response
|
12
|
+
return unless LHS::Interceptors::ExtendedRollbar::ThreadRegistry.log
|
13
|
+
LHS::Interceptors::ExtendedRollbar::ThreadRegistry.log.push(request: request, response: response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
const_set('ExtendedRollbar', LHS::Interceptors::ExtendedRollbar::Interceptor)
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/per_thread_registry'
|
5
|
+
|
6
|
+
module LHS
|
7
|
+
module Interceptors
|
8
|
+
module ExtendedRollbar
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class ThreadRegistry
|
12
|
+
# Using ActiveSupports PerThreadRegistry to be able to support Active Support v4.
|
13
|
+
# Will switch to thread_mattr_accessor (which comes with Activesupport) when we dropping support for Active Support v4.
|
14
|
+
extend ActiveSupport::PerThreadRegistry
|
15
|
+
attr_accessor :log
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
module LHS
|
6
|
+
module Interceptors
|
7
|
+
module RequestCycleCache
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
class Interceptor < LHC::Interceptor
|
11
|
+
|
12
|
+
VERSION = 1
|
13
|
+
CACHED_METHODS = [:get].freeze
|
14
|
+
|
15
|
+
def before_request
|
16
|
+
request.options = {
|
17
|
+
cache: {
|
18
|
+
expires_in: 5.minutes,
|
19
|
+
race_condition_ttl: 5.seconds,
|
20
|
+
key: cache_key_for(request),
|
21
|
+
methods: CACHED_METHODS,
|
22
|
+
use: LHS.config.request_cycle_cache
|
23
|
+
}
|
24
|
+
}.merge(request.options)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def cache_key_for(request)
|
30
|
+
[
|
31
|
+
"LHS_REQUEST_CYCLE_CACHE(v#{VERSION})",
|
32
|
+
request.method.upcase,
|
33
|
+
[request.url, request.params.presence].compact.join('?'),
|
34
|
+
"REQUEST=#{LHS::Interceptors::RequestCycleCache::ThreadRegistry.request_id}",
|
35
|
+
"HEADERS=#{request.headers.hash}"
|
36
|
+
].join(' ')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/per_thread_registry'
|
5
|
+
|
6
|
+
module LHS
|
7
|
+
module Interceptors
|
8
|
+
module RequestCycleCache
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
class ThreadRegistry
|
11
|
+
# Using ActiveSupports PerThreadRegistry to be able to support Active Support v4.
|
12
|
+
# Will switch to thread_mattr_accessor (which comes with Activesupport) when we dropping support for Active Support v4.
|
13
|
+
extend ActiveSupport::PerThreadRegistry
|
14
|
+
attr_accessor :request_id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/lhs/railtie.rb
CHANGED
@@ -8,6 +8,7 @@ module LHS
|
|
8
8
|
def initialize
|
9
9
|
prepare_lhs_request_cycle_cache
|
10
10
|
reset_option_blocks
|
11
|
+
reset_extended_rollbar_request_logs
|
11
12
|
super
|
12
13
|
end
|
13
14
|
|
@@ -15,12 +16,18 @@ module LHS
|
|
15
16
|
|
16
17
|
def prepare_lhs_request_cycle_cache
|
17
18
|
return unless LHS.config.request_cycle_cache_enabled
|
18
|
-
LHS::
|
19
|
+
LHS::Interceptors::RequestCycleCache::ThreadRegistry.request_id = [Time.now.to_f, request.object_id].join('#')
|
19
20
|
end
|
20
21
|
|
21
22
|
def reset_option_blocks
|
22
23
|
LHS::OptionBlocks::CurrentOptionBlock.options = nil
|
23
24
|
end
|
25
|
+
|
26
|
+
def reset_extended_rollbar_request_logs
|
27
|
+
return unless defined?(::Rollbar)
|
28
|
+
return unless LHC.config.interceptors.include?(LHS::Interceptors::ExtendedRollbar::Interceptor)
|
29
|
+
LHS::Interceptors::ExtendedRollbar::ThreadRegistry.log = []
|
30
|
+
end
|
24
31
|
end
|
25
32
|
end
|
26
33
|
end
|
data/lib/lhs/record.rb
CHANGED
@@ -23,6 +23,8 @@ class LHS::Record
|
|
23
23
|
'lhs/concerns/record/find_by'
|
24
24
|
autoload :First,
|
25
25
|
'lhs/concerns/record/first'
|
26
|
+
autoload :HrefFor,
|
27
|
+
'lhs/concerns/record/href_for'
|
26
28
|
autoload :Last,
|
27
29
|
'lhs/concerns/record/last'
|
28
30
|
autoload :Mapping,
|
@@ -46,13 +48,6 @@ class LHS::Record
|
|
46
48
|
autoload :AttributeAssignment,
|
47
49
|
'lhs/concerns/record/attribute_assignment'
|
48
50
|
|
49
|
-
module RequestCycleCache
|
50
|
-
autoload :RequestCycleThreadRegistry,
|
51
|
-
'lhs/concerns/record/request_cycle_cache/request_cycle_thread_registry'
|
52
|
-
autoload :Interceptor,
|
53
|
-
'lhs/concerns/record/request_cycle_cache/interceptor'
|
54
|
-
end
|
55
|
-
|
56
51
|
include Batch
|
57
52
|
include Chainable
|
58
53
|
include Configuration
|
@@ -64,6 +59,7 @@ class LHS::Record
|
|
64
59
|
include Find
|
65
60
|
include FindBy
|
66
61
|
include First
|
62
|
+
include HrefFor
|
67
63
|
include LHS::IsHref
|
68
64
|
include Last
|
69
65
|
include LHS::Inspect
|
@@ -74,7 +70,6 @@ class LHS::Record
|
|
74
70
|
include Provider
|
75
71
|
include Request
|
76
72
|
include Relations
|
77
|
-
include RequestCycleCache
|
78
73
|
include Scope
|
79
74
|
include Tracing
|
80
75
|
include AttributeAssignment
|
data/lib/lhs/rspec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lhs'
|
4
|
+
require 'lhs/test/stub'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.before(:each) do
|
8
|
+
LHS.config.request_cycle_cache.clear
|
9
|
+
end
|
10
|
+
|
11
|
+
config.before(:all) do
|
12
|
+
|
13
|
+
module LHS
|
14
|
+
def self.stub
|
15
|
+
LHS::Test::Stub
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'local_uri'
|
4
|
+
require 'webmock'
|
5
|
+
module LHS
|
6
|
+
module Test
|
7
|
+
class Stub
|
8
|
+
extend WebMock::API
|
9
|
+
DEFAULT_LIMIT = LHS::Pagination::Base::DEFAULT_LIMIT
|
10
|
+
|
11
|
+
def self.all(url, items, options = {})
|
12
|
+
items.each_slice(DEFAULT_LIMIT).with_index do |(*batch), index|
|
13
|
+
uri = LocalUri::URI.new(url)
|
14
|
+
uri.query.merge!(limit: DEFAULT_LIMIT)
|
15
|
+
uri.query.merge!(offset: DEFAULT_LIMIT * index) unless index.zero?
|
16
|
+
stub_request(:get, uri.to_s)
|
17
|
+
.with(options)
|
18
|
+
.to_return(
|
19
|
+
body: {
|
20
|
+
items: batch,
|
21
|
+
offset: index * DEFAULT_LIMIT,
|
22
|
+
total: items.length
|
23
|
+
}.to_json
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/lhs/version.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ExtendedRollbarController < ApplicationController
|
4
|
+
|
5
|
+
def extended_rollbar
|
6
|
+
Record.where(color: 'blue').fetch
|
7
|
+
Record.where(color: 'red').fetch
|
8
|
+
raise "Let's see if rollbar logs information about what kind of requests where made around here!"
|
9
|
+
end
|
10
|
+
end
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe 'Extended Rollbar', type: :request do
|
6
|
+
let!(:records_request_1) do
|
7
|
+
stub_request(:get, "http://datastore/v2/records?color=blue").to_return(body: ['blue'].to_json)
|
8
|
+
end
|
9
|
+
|
10
|
+
let!(:records_request_2) do
|
11
|
+
stub_request(:get, "http://datastore/v2/records?color=red").to_return(body: ['red'].to_json)
|
12
|
+
end
|
13
|
+
|
14
|
+
let!(:rollbar_request) do
|
15
|
+
stub_request(:post, "https://api.rollbar.com/api/1/item/")
|
16
|
+
.with do |request|
|
17
|
+
json = JSON.parse request.body
|
18
|
+
message = "Let's see if rollbar logs information about what kind of requests where made around here!"
|
19
|
+
extra = {
|
20
|
+
lhs: [
|
21
|
+
{
|
22
|
+
request: {
|
23
|
+
params: { color: 'blue' },
|
24
|
+
url: 'http://datastore/v2/records',
|
25
|
+
headers: {
|
26
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
27
|
+
'Accept' => 'application/json,application/vnd.api+json',
|
28
|
+
'Accept-Charset' => 'utf-8'
|
29
|
+
}
|
30
|
+
},
|
31
|
+
response: { code: 200, body: '["blue"]' }
|
32
|
+
}, {
|
33
|
+
request: {
|
34
|
+
params: { color: 'red' },
|
35
|
+
url: 'http://datastore/v2/records',
|
36
|
+
headers: {
|
37
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
38
|
+
'Accept' => 'application/json,application/vnd.api+json',
|
39
|
+
'Accept-Charset' => 'utf-8'
|
40
|
+
}
|
41
|
+
},
|
42
|
+
response: { code: 200, body: '["red"]' }
|
43
|
+
}
|
44
|
+
].to_json
|
45
|
+
}
|
46
|
+
json['access_token'] == '12345' &&
|
47
|
+
json['data']['level'] == 'error' &&
|
48
|
+
json['data']['body']['trace']['exception']['message'] == message &&
|
49
|
+
json['data']['body']['trace']['extra'].to_json == extra.to_json
|
50
|
+
end
|
51
|
+
.to_return(status: 200)
|
52
|
+
end
|
53
|
+
|
54
|
+
before do
|
55
|
+
LHC.configure do |config|
|
56
|
+
config.interceptors = [LHS::ExtendedRollbar]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'extends default rollbar logging by adding information about the requests made during a request/response cycle',
|
61
|
+
dummy_models: true, extended_rollbar: true do
|
62
|
+
get '/extended_rollbar'
|
63
|
+
expect(records_request_1).to have_been_requested
|
64
|
+
expect(records_request_2).to have_been_requested
|
65
|
+
expect(rollbar_request).to have_been_requested
|
66
|
+
end
|
67
|
+
end
|
data/spec/rails_helper.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHS::Record do
|
6
|
+
before do
|
7
|
+
class Record < LHS::Record
|
8
|
+
endpoint 'http://datastore/records/'
|
9
|
+
endpoint 'http://datastore/records/{id}'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'href_for' do
|
14
|
+
|
15
|
+
it 'injects variables and returns href' do
|
16
|
+
expect(Record.href_for(1)).to eq 'http://datastore/records/1'
|
17
|
+
expect(Record.href_for('vmasd241')).to eq 'http://datastore/records/vmasd241'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'also works with url_for (alias)' do
|
21
|
+
expect(Record.url_for(1)).to eq 'http://datastore/records/1'
|
22
|
+
expect(Record.url_for('vmasd241')).to eq 'http://datastore/records/vmasd241'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -37,7 +37,7 @@ describe 'Request Cycle Cache', type: :request do
|
|
37
37
|
expect(lambda do
|
38
38
|
get '/request_cycle_cache/no_caching_interceptor'
|
39
39
|
end).to output(
|
40
|
-
%r{\[WARNING\] Can't enable
|
40
|
+
%r{\[WARNING\] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured \(see https://github.com/local-ch/lhc/blob/master/docs/interceptors/caching.md#caching-interceptor\)!}
|
41
41
|
).to_stderr
|
42
42
|
expect(request).to have_been_made.times(2)
|
43
43
|
end
|
@@ -52,11 +52,11 @@ describe 'Request Cycle Cache', type: :request do
|
|
52
52
|
it 'sets different uniq request ids as base for request cycle caching for different requests',
|
53
53
|
dummy_models: true, request_cycle_cache: true do
|
54
54
|
get '/request_cycle_cache/simple'
|
55
|
-
first_request_id = LHS::
|
55
|
+
first_request_id = LHS::Interceptors::RequestCycleCache::ThreadRegistry.request_id
|
56
56
|
second_request_id = nil
|
57
57
|
thread = Thread.new do
|
58
58
|
get '/request_cycle_cache/simple'
|
59
|
-
second_request_id = LHS::
|
59
|
+
second_request_id = LHS::Interceptors::RequestCycleCache::ThreadRegistry.request_id
|
60
60
|
end
|
61
61
|
thread.join
|
62
62
|
expect(first_request_id).not_to be_nil
|
@@ -70,7 +70,7 @@ describe 'Request Cycle Cache', type: :request do
|
|
70
70
|
expect(lambda do
|
71
71
|
get '/request_cycle_cache/no_caching_interceptor'
|
72
72
|
end).not_to output(
|
73
|
-
%r{\[WARNING\] Can't enable
|
73
|
+
%r{\[WARNING\] Can't enable request cycle cache as LHC::Caching interceptor is not enabled/configured \(see https://github.com/local-ch/lhc/blob/master/docs/interceptors/caching.md#caching-interceptor\)!}
|
74
74
|
).to_stderr
|
75
75
|
expect(request).to have_been_made.times(2)
|
76
76
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
require 'lhs/rspec'
|
5
|
+
|
6
|
+
describe LHS do
|
7
|
+
|
8
|
+
before do
|
9
|
+
class Record < LHS::Record
|
10
|
+
endpoint 'https://records'
|
11
|
+
end
|
12
|
+
|
13
|
+
LHS.stub.all(
|
14
|
+
'https://records',
|
15
|
+
200.times.map { |index| { name: "Item #{index}" } },
|
16
|
+
headers: {
|
17
|
+
'Authorization' => 'Bearer 123'
|
18
|
+
}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'stubs all requests' do
|
23
|
+
records = Record.options(headers: { 'Authorization' => 'Bearer 123' }).all.fetch
|
24
|
+
expect(records.count).to eq 200
|
25
|
+
expect(records.length).to eq 200
|
26
|
+
expect(records.first.name).to eq 'Item 0'
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 20.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhs/graphs/contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.8.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: local_uri
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: pry
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +136,20 @@ dependencies:
|
|
122
136
|
- - ">="
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: 4.2.11
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rollbar
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
125
153
|
- !ruby/object:Gem::Dependency
|
126
154
|
name: rspec-rails
|
127
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -252,6 +280,7 @@ files:
|
|
252
280
|
- lib/lhs/concerns/record/find.rb
|
253
281
|
- lib/lhs/concerns/record/find_by.rb
|
254
282
|
- lib/lhs/concerns/record/first.rb
|
283
|
+
- lib/lhs/concerns/record/href_for.rb
|
255
284
|
- lib/lhs/concerns/record/last.rb
|
256
285
|
- lib/lhs/concerns/record/mapping.rb
|
257
286
|
- lib/lhs/concerns/record/merge.rb
|
@@ -260,13 +289,16 @@ files:
|
|
260
289
|
- lib/lhs/concerns/record/provider.rb
|
261
290
|
- lib/lhs/concerns/record/relations.rb
|
262
291
|
- lib/lhs/concerns/record/request.rb
|
263
|
-
- lib/lhs/concerns/record/request_cycle_cache/interceptor.rb
|
264
|
-
- lib/lhs/concerns/record/request_cycle_cache/request_cycle_thread_registry.rb
|
265
292
|
- lib/lhs/concerns/record/scope.rb
|
266
293
|
- lib/lhs/concerns/record/tracing.rb
|
267
294
|
- lib/lhs/config.rb
|
268
295
|
- lib/lhs/data.rb
|
269
296
|
- lib/lhs/endpoint.rb
|
297
|
+
- lib/lhs/interceptors/extended_rollbar/handler.rb
|
298
|
+
- lib/lhs/interceptors/extended_rollbar/interceptor.rb
|
299
|
+
- lib/lhs/interceptors/extended_rollbar/thread_registry.rb
|
300
|
+
- lib/lhs/interceptors/request_cycle_cache/interceptor.rb
|
301
|
+
- lib/lhs/interceptors/request_cycle_cache/thread_registry.rb
|
270
302
|
- lib/lhs/item.rb
|
271
303
|
- lib/lhs/pagination/base.rb
|
272
304
|
- lib/lhs/pagination/link.rb
|
@@ -282,7 +314,8 @@ files:
|
|
282
314
|
- lib/lhs/proxy.rb
|
283
315
|
- lib/lhs/railtie.rb
|
284
316
|
- lib/lhs/record.rb
|
285
|
-
- lib/lhs/
|
317
|
+
- lib/lhs/rspec.rb
|
318
|
+
- lib/lhs/test/stub.rb
|
286
319
|
- lib/lhs/unprocessable.rb
|
287
320
|
- lib/lhs/version.rb
|
288
321
|
- script/ci/build.sh
|
@@ -321,6 +354,7 @@ files:
|
|
321
354
|
- spec/dummy/app/controllers/application_controller.rb
|
322
355
|
- spec/dummy/app/controllers/concerns/.keep
|
323
356
|
- spec/dummy/app/controllers/error_handling_with_chains_controller.rb
|
357
|
+
- spec/dummy/app/controllers/extended_rollbar_controller.rb
|
324
358
|
- spec/dummy/app/controllers/option_blocks_controller.rb
|
325
359
|
- spec/dummy/app/controllers/request_cycle_cache_controller.rb
|
326
360
|
- spec/dummy/app/helpers/application_helper.rb
|
@@ -349,6 +383,7 @@ files:
|
|
349
383
|
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
350
384
|
- spec/dummy/config/initializers/inflections.rb
|
351
385
|
- spec/dummy/config/initializers/mime_types.rb
|
386
|
+
- spec/dummy/config/initializers/rollbar.rb
|
352
387
|
- spec/dummy/config/initializers/session_store.rb
|
353
388
|
- spec/dummy/config/initializers/wrap_parameters.rb
|
354
389
|
- spec/dummy/config/locales/en.yml
|
@@ -361,6 +396,7 @@ files:
|
|
361
396
|
- spec/dummy/public/500.html
|
362
397
|
- spec/dummy/public/favicon.ico
|
363
398
|
- spec/endpoint/for_url_spec.rb
|
399
|
+
- spec/extended_rollbar_spec.rb
|
364
400
|
- spec/item/access_errors_spec.rb
|
365
401
|
- spec/item/accessors_spec.rb
|
366
402
|
- spec/item/add_error_spec.rb
|
@@ -427,6 +463,7 @@ files:
|
|
427
463
|
- spec/record/handle_includes_errors_spec.rb
|
428
464
|
- spec/record/has_many_spec.rb
|
429
465
|
- spec/record/has_one_spec.rb
|
466
|
+
- spec/record/href_for_spec.rb
|
430
467
|
- spec/record/ignore_errors_spec.rb
|
431
468
|
- spec/record/immutable_chains_spec.rb
|
432
469
|
- spec/record/includes_all_spec.rb
|
@@ -465,6 +502,7 @@ files:
|
|
465
502
|
- spec/request_cycle_cache_spec.rb
|
466
503
|
- spec/require_lhs_spec.rb
|
467
504
|
- spec/spec_helper.rb
|
505
|
+
- spec/stubs/all_spec.rb
|
468
506
|
- spec/support/fixtures/json/feedback.json
|
469
507
|
- spec/support/fixtures/json/feedbacks.json
|
470
508
|
- spec/support/fixtures/json/localina_content_ad.json
|
@@ -492,8 +530,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
492
530
|
version: '0'
|
493
531
|
requirements:
|
494
532
|
- Ruby >= 2.3.0
|
495
|
-
|
496
|
-
rubygems_version: 2.7.8
|
533
|
+
rubygems_version: 3.0.3
|
497
534
|
signing_key:
|
498
535
|
specification_version: 4
|
499
536
|
summary: 'REST services accelerator: Rails gem providing an easy, active-record-like
|
@@ -533,6 +570,7 @@ test_files:
|
|
533
570
|
- spec/dummy/app/controllers/application_controller.rb
|
534
571
|
- spec/dummy/app/controllers/concerns/.keep
|
535
572
|
- spec/dummy/app/controllers/error_handling_with_chains_controller.rb
|
573
|
+
- spec/dummy/app/controllers/extended_rollbar_controller.rb
|
536
574
|
- spec/dummy/app/controllers/option_blocks_controller.rb
|
537
575
|
- spec/dummy/app/controllers/request_cycle_cache_controller.rb
|
538
576
|
- spec/dummy/app/helpers/application_helper.rb
|
@@ -561,6 +599,7 @@ test_files:
|
|
561
599
|
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
562
600
|
- spec/dummy/config/initializers/inflections.rb
|
563
601
|
- spec/dummy/config/initializers/mime_types.rb
|
602
|
+
- spec/dummy/config/initializers/rollbar.rb
|
564
603
|
- spec/dummy/config/initializers/session_store.rb
|
565
604
|
- spec/dummy/config/initializers/wrap_parameters.rb
|
566
605
|
- spec/dummy/config/locales/en.yml
|
@@ -573,6 +612,7 @@ test_files:
|
|
573
612
|
- spec/dummy/public/500.html
|
574
613
|
- spec/dummy/public/favicon.ico
|
575
614
|
- spec/endpoint/for_url_spec.rb
|
615
|
+
- spec/extended_rollbar_spec.rb
|
576
616
|
- spec/item/access_errors_spec.rb
|
577
617
|
- spec/item/accessors_spec.rb
|
578
618
|
- spec/item/add_error_spec.rb
|
@@ -639,6 +679,7 @@ test_files:
|
|
639
679
|
- spec/record/handle_includes_errors_spec.rb
|
640
680
|
- spec/record/has_many_spec.rb
|
641
681
|
- spec/record/has_one_spec.rb
|
682
|
+
- spec/record/href_for_spec.rb
|
642
683
|
- spec/record/ignore_errors_spec.rb
|
643
684
|
- spec/record/immutable_chains_spec.rb
|
644
685
|
- spec/record/includes_all_spec.rb
|
@@ -677,6 +718,7 @@ test_files:
|
|
677
718
|
- spec/request_cycle_cache_spec.rb
|
678
719
|
- spec/require_lhs_spec.rb
|
679
720
|
- spec/spec_helper.rb
|
721
|
+
- spec/stubs/all_spec.rb
|
680
722
|
- spec/support/fixtures/json/feedback.json
|
681
723
|
- spec/support/fixtures/json/feedbacks.json
|
682
724
|
- spec/support/fixtures/json/localina_content_ad.json
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support'
|
4
|
-
|
5
|
-
class LHS::Record
|
6
|
-
|
7
|
-
module RequestCycleCache
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
class Interceptor < LHC::Interceptor
|
11
|
-
|
12
|
-
VERSION = 1
|
13
|
-
CACHED_METHODS = [:get].freeze
|
14
|
-
|
15
|
-
def before_request
|
16
|
-
request.options = request.options.merge({
|
17
|
-
cache: {
|
18
|
-
expires_in: 5.minutes,
|
19
|
-
race_condition_ttl: 5.seconds,
|
20
|
-
key: cache_key_for(request),
|
21
|
-
methods: CACHED_METHODS,
|
22
|
-
use: LHS.config.request_cycle_cache
|
23
|
-
}
|
24
|
-
}.merge(request.options))
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def cache_key_for(request)
|
30
|
-
[
|
31
|
-
"LHS_REQUEST_CYCLE_CACHE(v#{VERSION})",
|
32
|
-
request.method.upcase,
|
33
|
-
[request.url, request.params.presence].compact.join('?'),
|
34
|
-
"REQUEST=#{LHS::Record::RequestCycleCache::RequestCycleThreadRegistry.request_id}",
|
35
|
-
"HEADERS=#{request.headers.hash}"
|
36
|
-
].join(' ')
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support'
|
4
|
-
|
5
|
-
class LHS::Record
|
6
|
-
|
7
|
-
module RequestCycleCache
|
8
|
-
class RequestCycleThreadRegistry
|
9
|
-
# Using ActiveSupports PerThreadRegistry to be able to support Active Support v4.
|
10
|
-
# Will switch to thread_mattr_accessor (which comes with Activesupport) when we dropping support for Active Support v5.
|
11
|
-
extend ActiveSupport::PerThreadRegistry
|
12
|
-
attr_accessor :request_id
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|