Skip to content

Commit

Permalink
Chain error handling integration tests (#307)
Browse files Browse the repository at this point in the history
* + chain error handling integration tests

* ! rubocop ~ feedback: private method

* ! spec

* ! spec

* ! spec naming

* ! specs;

* ! spec

* ~ docs

* ! Gemfile

* ~ wording

* ~ doc

* ! rubocop
  • Loading branch information
spape committed Aug 13, 2018
1 parent 50f9a17 commit 392abbf
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ Gemfile.*.lock
bower.json

spec/dummy/log/test.log
spec/dummy/tmp
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -800,18 +800,28 @@ end

To simplify error handling with chains, you can also chain error handlers to be resolved, as part of the chain.

In case no matching error handler is found the error gets re-raised.
If you need to render some different view in Rails based on an LHS error raised during rendering the view, please proceed as following:

```ruby
# app/controllers/some_controller.rb

record = Record.where(color: 'blue')
.handle(LHC::BadRequest, ->(error){ handle_error(error) })
def show
@records = Record
.handle(LHC::Error, ->(error){ handle_error(error) })
.where(color: 'blue')
render 'show'
render_error if @error
end

private

def handle_error(error)
@error = error
nil
end

def render_error
self.response_body = nil # required to not raise AbstractController::DoubleRenderError
render 'error'
end
```
Expand All @@ -820,6 +830,8 @@ end
< 406
```

In case no matching error handler is found the error gets re-raised.

-> Read more about [LHC error types/classes](https://github.com/local-ch/lhc#exceptions)

If you want to inject values for the failing records, that might not have been found, you can inject values for them with error handlers:
Expand Down
2 changes: 1 addition & 1 deletion spec/autoloading_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
context 'autoloading' do
it "pre/re-loads all LHS classes initialy,|
because it's necessary for endpoint-to-record-class-discovery",
cleanup_before: false do
reset_before: false do
all_endpoints = LHS::Record::Endpoints.all
expect(all_endpoints['http://datastore/v2/users']).to be_present
expect(all_endpoints['http://datastore/v2/users/{id}']).to be_present
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class ErrorHandlingWithChainsController < ApplicationController

# Example where the query chain is resolved
# in the view (during render 'show')
def fetch_in_view
@records = Record
.handle(LHC::Error, ->(error) { handle_error(error) })
.where(color: 'blue')
render 'show'
render_error if @error
end

# Example where the query chain is resolved
# before the view is rendered
def fetch_in_controller
@records = Record
.handle(LHC::Error, ->(error) { handle_error(error) })
.where(color: 'blue').fetch
render 'show'
render_error if @error
end

private

def handle_error(error)
@error = error
nil
end

def render_error
self.response_body = nil
render 'error'
end
end
4 changes: 4 additions & 0 deletions spec/dummy/app/models/record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Record < LHS::Record
endpoint 'http://datastore/v2/records'
endpoint 'http://datastore/v2/records/{id}'
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sorry there was an error.
3 changes: 3 additions & 0 deletions spec/dummy/app/views/error_handling_with_chains/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<% @records.each do |record| %>
Name: <%= record.name %>
<% end %>
6 changes: 6 additions & 0 deletions spec/dummy/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
Rails.application.routes.draw do
root 'application#root'

# Request Cycle Cache
get 'request_cycle_cache/simple' => 'request_cycle_cache#simple'
get 'request_cycle_cache/no_caching_interceptor' => 'request_cycle_cache#no_caching_interceptor'
get 'request_cycle_cache/parallel' => 'request_cycle_cache#parallel'
get 'request_cycle_cache/headers' => 'request_cycle_cache#headers'

# Error handling with chains
get 'error_handling_with_chains/fetch_in_controller' => 'error_handling_with_chains#fetch_in_controller'
get 'error_handling_with_chains/fetch_in_view' => 'error_handling_with_chains#fetch_in_view'
end
23 changes: 23 additions & 0 deletions spec/record/error_handling_integration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'rails_helper'
require 'lhc/test/cache_helper.rb'

describe 'Error handling with chains', type: :request do
let!(:request) do
stub_request(:get, "http://datastore/v2/records?color=blue")
.to_return(status: 404)
end

it 'handles errors in rails controllers when query resolved in controller',
dummy_models: true do
get '/error_handling_with_chains/fetch_in_controller'
expect(request).to have_been_made.once
expect(response.body).to include('Sorry there was an error.')
end

it 'handles errors in rails controllers when query resolved in view',
dummy_models: true do
get '/error_handling_with_chains/fetch_in_view'
expect(request).to have_been_made.once
expect(response.body).to include('Sorry there was an error.')
end
end
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class User < LHS::Record
end

it 'serves requests that are exactly the same during one request cycle from the cache',
cleanup_before: false, request_cycle_cache: true do
dummy_models: true, request_cycle_cache: true do
get '/request_cycle_cache/simple'
expect(request).to have_been_made.once

Expand All @@ -31,7 +31,7 @@ class User < LHS::Record
end

it 'does not serve from request cycle cache when cache interceptor is not hooked in, but logs a warning',
cleanup_before: false, request_cycle_cache: true do
dummy_models: true, request_cycle_cache: true do
expect(lambda do
get '/request_cycle_cache/no_caching_interceptor'
end).to output(
Expand All @@ -41,14 +41,14 @@ class User < LHS::Record
end

it 'serves requests also from cache when LHS/LHC makes requests in parallel',
cleanup_before: false, request_cycle_cache: true do
dummy_models: true, request_cycle_cache: true do
get '/request_cycle_cache/parallel'
expect(request).to have_been_made.once
expect(second_request).to have_been_made.once
end

it 'sets different uniq request ids as base for request cycle caching for different requests',
cleanup_before: false, request_cycle_cache: true do
dummy_models: true, request_cycle_cache: true do
get '/request_cycle_cache/simple'
first_request_id = LHS::Record::RequestCycleCache::RequestCycleThreadRegistry.request_id
second_request_id = nil
Expand All @@ -64,7 +64,7 @@ class User < LHS::Record

context 'disabled request cycle cache' do
it 'does not serve from request cycle cache when cache interceptor is not hooked in, and does not warn if request cycle cache is explicitly disabled',
cleanup_before: false do
dummy_models: true do
expect(lambda do
get '/request_cycle_cache/no_caching_interceptor'
end).not_to output(
Expand All @@ -74,15 +74,15 @@ class User < LHS::Record
end

it 'DOES NOT serve requests that are exactly the same during one request cycle from the cache, when request cycle cache is disabled',
cleanup_before: false do
dummy_models: true do
get '/request_cycle_cache/simple'
expect(request).to have_been_made.times(2)
end
end

context 'headers' do
it 'considers the request headers when setting the cache key',
cleanup_before: false, request_cycle_cache: true do
dummy_models: true, request_cycle_cache: true do
get '/request_cycle_cache/headers'
expect(request).to have_been_made.times(2)
end
Expand All @@ -95,7 +95,7 @@ class User < LHS::Record
after { LHS.config.request_cycle_cache = old_cache }

it 'uses the cache passed in',
cleanup_before: true, request_cycle_cache: true do
dummy_models: true, request_cycle_cache: true do
expect(LHS.config.request_cycle_cache).to receive(:fetch).at_least(:once)
expect(LHS.config.request_cycle_cache).to receive(:write).at_least(:once)
get '/request_cycle_cache/simple'
Expand Down
32 changes: 0 additions & 32 deletions spec/support/cleanup.rb

This file was deleted.

43 changes: 43 additions & 0 deletions spec/support/reset.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require 'lhc'
class LHC::Config

def _cleanup
@endpoints = {}
@placeholders = {}
@interceptors = nil
end
end

class LHS::Record

CHILDREN = []

def self.inherited(child)
CHILDREN.push(child)
super
end

end

def reset_lhc
LHC::Config.instance._cleanup
end

def reset_lhs
LHS::Record::Endpoints.all = {}
LHS::Record::CHILDREN.each do |child|
child.endpoints = [] if !child.name['LHS'] && defined?(child.endpoints)
child.configuration({}) if !child.name['LHS']
end
end

RSpec.configure do |config|
config.before do |spec|
reset_lhc unless spec.metadata.key?(:reset_before) && spec.metadata[:reset_before] == false
reset_lhs unless spec.metadata.key?(:reset_before) && spec.metadata[:reset_before] == false
next unless spec.metadata.key?(:dummy_models) && spec.metadata[:dummy_models] == true
Dir.glob(Rails.root.join('app', 'models', '**', '*.rb')).each do |file|
load file if File.read(file).match('LHS::Record')
end
end
end

0 comments on commit 392abbf

Please sign in to comment.