chassis 0.1.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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +362 -0
- data/Rakefile +33 -0
- data/chassis.gemspec +41 -0
- data/examples/repo.rb +40 -0
- data/lib/chassis.rb +81 -0
- data/lib/chassis/array_utils.rb +8 -0
- data/lib/chassis/circuit_panel.rb +22 -0
- data/lib/chassis/core_ext/array.rb +5 -0
- data/lib/chassis/core_ext/hash.rb +5 -0
- data/lib/chassis/core_ext/string.rb +13 -0
- data/lib/chassis/delegate.rb +29 -0
- data/lib/chassis/dirty_session.rb +105 -0
- data/lib/chassis/error.rb +7 -0
- data/lib/chassis/faraday.rb +226 -0
- data/lib/chassis/form.rb +56 -0
- data/lib/chassis/hash_utils.rb +16 -0
- data/lib/chassis/heroku.rb +5 -0
- data/lib/chassis/initializable.rb +11 -0
- data/lib/chassis/logger.rb +8 -0
- data/lib/chassis/observable.rb +19 -0
- data/lib/chassis/persistence.rb +49 -0
- data/lib/chassis/rack/bouncer.rb +33 -0
- data/lib/chassis/rack/builder_shim_patch.rb +7 -0
- data/lib/chassis/rack/health_check.rb +45 -0
- data/lib/chassis/rack/instrumentation.rb +20 -0
- data/lib/chassis/rack/json_body_parser.rb +20 -0
- data/lib/chassis/rack/no_robots.rb +24 -0
- data/lib/chassis/registry.rb +30 -0
- data/lib/chassis/repo.rb +73 -0
- data/lib/chassis/repo/base_repo.rb +99 -0
- data/lib/chassis/repo/delegation.rb +78 -0
- data/lib/chassis/repo/lazy_association.rb +57 -0
- data/lib/chassis/repo/memory_repo.rb +7 -0
- data/lib/chassis/repo/null_repo.rb +64 -0
- data/lib/chassis/repo/pstore_repo.rb +54 -0
- data/lib/chassis/repo/record_map.rb +44 -0
- data/lib/chassis/repo/redis_repo.rb +55 -0
- data/lib/chassis/serializable.rb +52 -0
- data/lib/chassis/string_utils.rb +50 -0
- data/lib/chassis/version.rb +3 -0
- data/lib/chassis/web_service.rb +61 -0
- data/test/array_utils_test.rb +23 -0
- data/test/chassis_test.rb +7 -0
- data/test/circuit_panel_test.rb +22 -0
- data/test/core_ext/array_test.rb +8 -0
- data/test/core_ext/hash_test.rb +8 -0
- data/test/core_ext/string_test.rb +16 -0
- data/test/delegate_test.rb +41 -0
- data/test/dirty_session_test.rb +138 -0
- data/test/error_test.rb +12 -0
- data/test/faraday_test.rb +749 -0
- data/test/form_test.rb +29 -0
- data/test/hash_utils_test.rb +17 -0
- data/test/initializable_test.rb +22 -0
- data/test/logger_test.rb +43 -0
- data/test/observable_test.rb +27 -0
- data/test/persistence_test.rb +112 -0
- data/test/prox_test.rb +7 -0
- data/test/rack/bouncer_test.rb +42 -0
- data/test/rack/builder_patch_test.rb +36 -0
- data/test/rack/health_check_test.rb +35 -0
- data/test/rack/instrumentation_test.rb +38 -0
- data/test/rack/json_body_parser_test.rb +38 -0
- data/test/rack/no_robots_test.rb +34 -0
- data/test/registry_test.rb +26 -0
- data/test/repo/delegation_test.rb +101 -0
- data/test/repo/lazy_association_test.rb +115 -0
- data/test/repo/memory_repo_test.rb +25 -0
- data/test/repo/null_repo_test.rb +48 -0
- data/test/repo/pstore_repo_test.rb +28 -0
- data/test/repo/redis_repo_test.rb +26 -0
- data/test/repo/repo_tests.rb +120 -0
- data/test/repo_test.rb +76 -0
- data/test/serializable_test.rb +77 -0
- data/test/string_utils_test.rb +21 -0
- data/test/test_helper.rb +10 -0
- data/test/web_service_test.rb +107 -0
- metadata +426 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/json'
|
3
|
+
require 'rack/contrib/bounce_favicon'
|
4
|
+
require 'rack/deflater'
|
5
|
+
|
6
|
+
module Chassis
|
7
|
+
class WebService < Sinatra::Base
|
8
|
+
ParameterMissingError = Chassis.error do |key|
|
9
|
+
%Q{Request did not provide "#{@key}"}
|
10
|
+
end
|
11
|
+
|
12
|
+
helpers do
|
13
|
+
def extract!(key)
|
14
|
+
value = params.fetch(key.to_s) do
|
15
|
+
raise ParameterMissingError, key
|
16
|
+
end
|
17
|
+
|
18
|
+
raise ParameterMissingError, key unless value.is_a?(Hash)
|
19
|
+
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
def halt_json_error(code, errors = {})
|
24
|
+
json_error env.fetch('sinatra.error'), code, errors
|
25
|
+
end
|
26
|
+
|
27
|
+
def json_error(ex, code, errors = {})
|
28
|
+
halt code, { 'Content-Type' => 'application/json' }, JSON.dump({
|
29
|
+
error: { message: ex.message }
|
30
|
+
}.merge(errors))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
error ParameterMissingError do
|
35
|
+
halt_json_error 400
|
36
|
+
end
|
37
|
+
|
38
|
+
error Chassis::UnknownFormFieldError do
|
39
|
+
halt_json_error 400
|
40
|
+
end
|
41
|
+
|
42
|
+
error Chassis::RecordNotFoundError do
|
43
|
+
halt_json_error 404
|
44
|
+
end
|
45
|
+
|
46
|
+
use Rack::NoRobots
|
47
|
+
use Rack::Bouncer
|
48
|
+
use ::Rack::BounceFavicon
|
49
|
+
use ::Rack::Deflater
|
50
|
+
use Rack::JsonBodyParser
|
51
|
+
|
52
|
+
set :cors, false
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def setup_default_middleware(builder)
|
56
|
+
super
|
57
|
+
builder.use Manifold::Middleware if settings.cors?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class ArrayUtilsTest < MiniTest::Unit::TestCase
|
4
|
+
def utils
|
5
|
+
Chassis::ArrayUtils
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_extract_options_removes_options_hash_if_present
|
9
|
+
args = ['foo', { bar: 'baz' }]
|
10
|
+
options = utils.extract_options! args
|
11
|
+
|
12
|
+
assert_equal({ bar: 'baz' }, options)
|
13
|
+
assert_equal(%w(foo), args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_extract_options_does_nothing_if_no_options
|
17
|
+
args = %w(foo)
|
18
|
+
options = utils.extract_options! args
|
19
|
+
|
20
|
+
assert_equal({}, options)
|
21
|
+
assert_equal(%w(foo), args)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class CircuitPanelTest < MiniTest::Unit::TestCase
|
4
|
+
def test_circuit_method_returns_the_given_circuit
|
5
|
+
panel = Chassis.circuit_panel do
|
6
|
+
circuit :test, timeout: 10
|
7
|
+
end.new
|
8
|
+
|
9
|
+
circuit = panel.test
|
10
|
+
assert_kind_of Breaker::Circuit, circuit
|
11
|
+
assert_equal :test, circuit.name
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_options_passed_to_circuit_are_set_on_the_circuit
|
15
|
+
panel = Chassis.circuit_panel do
|
16
|
+
circuit :test, timeout: 10
|
17
|
+
end.new
|
18
|
+
|
19
|
+
circuit = panel.test
|
20
|
+
assert_equal 10, circuit.timeout
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'chassis/core_ext/string'
|
3
|
+
|
4
|
+
class StringCoreExtTest < MiniTest::Unit::TestCase
|
5
|
+
def test_underscore
|
6
|
+
assert_equal('foo_bar', 'FooBar'.underscore)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_demodulize
|
10
|
+
assert_equal('Bar', 'Foo::Bar'.demodulize)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_constantize
|
14
|
+
assert_equal self.class, self.class.name.constantize
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class DelegateTest < MiniTest::Unit::TestCase
|
4
|
+
class Delegator
|
5
|
+
include Chassis.delegate(:add, to: :object)
|
6
|
+
|
7
|
+
attr_reader :object
|
8
|
+
|
9
|
+
def initialize(object)
|
10
|
+
@object = object
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_methods_are_delegated
|
15
|
+
delegate = Class.new do
|
16
|
+
def add(number)
|
17
|
+
number + 5
|
18
|
+
end
|
19
|
+
end.new
|
20
|
+
|
21
|
+
delegator = Delegator.new delegate
|
22
|
+
|
23
|
+
assert_equal 10, delegator.add(5)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_raises_an_error_if_no_object_to_delegate_to
|
27
|
+
delegator = Delegator.new nil
|
28
|
+
|
29
|
+
assert_raises Chassis::DelegationError do
|
30
|
+
delegator.add 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_fails_with_an_error_if_nothing_to_delegate_to
|
35
|
+
assert_raises ArgumentError do
|
36
|
+
Class.new do
|
37
|
+
include Chassis.delegate(:foo, :bar)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class DirtySessionTest < MiniTest::Unit::TestCase
|
4
|
+
class Person
|
5
|
+
include Chassis::Initializable
|
6
|
+
|
7
|
+
attr_accessor :name, :email, :id
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :person
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@person = Person.new do |person|
|
14
|
+
person.name = 'adam'
|
15
|
+
person.email = 'example@example.com'
|
16
|
+
person.id = 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_initialize_as_clean
|
21
|
+
session = Chassis::DirtySession.new person
|
22
|
+
assert session.clean?
|
23
|
+
refute session.dirty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_assigning_new_value_marks_the_session_dirty
|
27
|
+
session = Chassis::DirtySession.new person
|
28
|
+
session.name = 'foo'
|
29
|
+
|
30
|
+
refute session.clean?
|
31
|
+
assert session.dirty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_changes_can_be_tested_via_query_method
|
35
|
+
session = Chassis::DirtySession.new person
|
36
|
+
session.name = 'foo'
|
37
|
+
|
38
|
+
refute session.clean?
|
39
|
+
assert session.dirty?
|
40
|
+
|
41
|
+
assert_respond_to session, :name_changed?, "Session should respond to changed queries"
|
42
|
+
assert session.name_changed?
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_changes_include_all_new_assignments
|
46
|
+
session = Chassis::DirtySession.new person
|
47
|
+
session.name = 'foo'
|
48
|
+
|
49
|
+
refute session.clean?
|
50
|
+
assert session.dirty?
|
51
|
+
|
52
|
+
assert_equal(Set.new([:name]), session.changes)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_changes_are_accessible
|
56
|
+
session = Chassis::DirtySession.new person
|
57
|
+
session.name = 'foo'
|
58
|
+
|
59
|
+
refute session.clean?
|
60
|
+
assert session.dirty?
|
61
|
+
|
62
|
+
assert_equal({ name: 'foo' }, session.new_values)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_assigning_a_new_value_records_the_original_value
|
66
|
+
original_name = person.name
|
67
|
+
assert original_name, "Precondition: person must have a name"
|
68
|
+
|
69
|
+
session = Chassis::DirtySession.new person
|
70
|
+
session.name = 'foo'
|
71
|
+
|
72
|
+
refute session.clean?
|
73
|
+
assert session.dirty?
|
74
|
+
|
75
|
+
assert_equal({ name: original_name}, session.original_values)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_original_values_are_accessible_via_an_original_method
|
79
|
+
original_name = person.name
|
80
|
+
assert original_name, "Precondition: person must have a name"
|
81
|
+
|
82
|
+
session = Chassis::DirtySession.new person
|
83
|
+
session.name = 'foo'
|
84
|
+
|
85
|
+
refute session.clean?
|
86
|
+
assert session.dirty?
|
87
|
+
|
88
|
+
assert_respond_to session, :original_name, "Session should respond to original_XXX methods"
|
89
|
+
assert_equal original_name, session.original_name
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_assigning_the_same_value_does_not_count_as_a_change
|
93
|
+
original_name = person.name
|
94
|
+
assert original_name, "Precondition: person must have a name"
|
95
|
+
|
96
|
+
session = Chassis::DirtySession.new person
|
97
|
+
session.name = original_name
|
98
|
+
|
99
|
+
assert session.clean?, "Setting the same value should not count as a change"
|
100
|
+
refute session.dirty?
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_assigning_the_same_value_multiple_times_saves_the_initial_value
|
104
|
+
original_name = person.name
|
105
|
+
assert original_name, "Precondition: person must have a name"
|
106
|
+
|
107
|
+
session = Chassis::DirtySession.new person
|
108
|
+
session.name = 'matthew'
|
109
|
+
session.name = 'michael'
|
110
|
+
|
111
|
+
refute session.clean?
|
112
|
+
assert session.dirty?
|
113
|
+
|
114
|
+
assert_equal original_name, session.original_name
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_reset_moves_session_to_initial_state
|
118
|
+
original_name = person.name
|
119
|
+
assert original_name, "Precondition: person must have a name"
|
120
|
+
|
121
|
+
session = Chassis::DirtySession.new person
|
122
|
+
session.name = 'matthew'
|
123
|
+
|
124
|
+
refute session.clean?
|
125
|
+
assert session.dirty?
|
126
|
+
|
127
|
+
session.reset!
|
128
|
+
|
129
|
+
assert session.clean?
|
130
|
+
refute session.dirty?
|
131
|
+
|
132
|
+
assert_empty session.changes
|
133
|
+
assert_empty session.new_values
|
134
|
+
assert_empty session.original_values
|
135
|
+
|
136
|
+
refute session.name_changed?
|
137
|
+
end
|
138
|
+
end
|
data/test/error_test.rb
ADDED
@@ -0,0 +1,749 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
|
3
|
+
class FaradayTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Harness.config.queue = Harness::SyncQueue.new
|
6
|
+
Harness.config.collector = Harness::FakeCollector.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def stats
|
10
|
+
Harness.config.collector
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(url = nil, options = {}, &block)
|
14
|
+
Faraday.new url, options, &block
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_instruments_all_requests
|
18
|
+
faraday = build do |conn|
|
19
|
+
conn.request :instrumentation
|
20
|
+
|
21
|
+
conn.adapter :test do |stub|
|
22
|
+
stub.get 'test' do
|
23
|
+
[200, {'Content-Type' => 'application/json'}, JSON.dump(foo: 'bar')]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
faraday.get 'test'
|
29
|
+
|
30
|
+
refute_empty stats.timers
|
31
|
+
timer = stats.timers.first
|
32
|
+
|
33
|
+
assert_equal 'faraday.get', timer.name
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_instrumentation_namespace_can_be_customized
|
37
|
+
faraday = build 'http://example.com' do |conn|
|
38
|
+
conn.request :instrumentation, 'http'
|
39
|
+
|
40
|
+
conn.adapter :test do |stub|
|
41
|
+
stub.get 'test' do
|
42
|
+
[200, {'Content-Type' => 'application/json'}, JSON.dump(foo: 'bar')]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
faraday.get 'test'
|
48
|
+
|
49
|
+
refute_empty stats.timers
|
50
|
+
timer = stats.timers.first
|
51
|
+
|
52
|
+
assert_equal 'http.get', timer.name
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_sends_requests_in_json
|
56
|
+
faraday = build do |conn|
|
57
|
+
conn.request :encode_json
|
58
|
+
|
59
|
+
conn.adapter :test do |stub|
|
60
|
+
stub.post 'test' do |env|
|
61
|
+
json = JSON.load env.fetch(:body)
|
62
|
+
[200, {'Content-Type' => 'text/plain'}, json.fetch('foo')]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
response = faraday.post 'test', foo: 'bar'
|
68
|
+
|
69
|
+
assert_equal 'bar', response.body
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_parses_json_bodies
|
73
|
+
faraday = build do |conn|
|
74
|
+
conn.request :encode_json
|
75
|
+
conn.response :parse_json
|
76
|
+
|
77
|
+
conn.adapter :test do |stub|
|
78
|
+
stub.post 'test' do |env|
|
79
|
+
[ 200,
|
80
|
+
{'Requested-Type' => env.fetch(:request_headers).fetch('Content-Type')},
|
81
|
+
env.fetch(:body)
|
82
|
+
]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
response = faraday.post 'test', foo: 'bar'
|
88
|
+
|
89
|
+
assert_equal(JSON.dump({ 'foo' => 'bar' }), response.body)
|
90
|
+
assert_equal 'application/json', response.headers.fetch('Requested-Type')
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_does_not_parse_nil_bodies
|
94
|
+
faraday = build do |conn|
|
95
|
+
conn.response :parse_json
|
96
|
+
|
97
|
+
conn.adapter :test do |stub|
|
98
|
+
stub.get 'test' do
|
99
|
+
[200, {'Content-Type' => 'application/json'}, nil]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
response = faraday.get 'test'
|
105
|
+
|
106
|
+
assert_nil response[:body]
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_does_not_parse_empty_bodies
|
110
|
+
faraday = build do |conn|
|
111
|
+
conn.response :parse_json
|
112
|
+
|
113
|
+
conn.adapter :test do |stub|
|
114
|
+
stub.get 'test' do
|
115
|
+
[200, {'Content-Type' => 'application/json'}, '']
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
response = faraday.get 'test'
|
121
|
+
|
122
|
+
assert_nil response[:body]
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_does_not_parse_empty_strings
|
126
|
+
faraday = build do |conn|
|
127
|
+
conn.response :parse_json
|
128
|
+
|
129
|
+
conn.adapter :test do |stub|
|
130
|
+
stub.get 'test' do
|
131
|
+
[200, {'Content-Type' => 'application/json'}, ' ']
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
response = faraday.get 'test'
|
137
|
+
|
138
|
+
assert_nil response[:body]
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_does_not_parse_204s
|
142
|
+
faraday = build do |conn|
|
143
|
+
conn.response :parse_json
|
144
|
+
|
145
|
+
conn.adapter :test do |stub|
|
146
|
+
stub.get 'test' do
|
147
|
+
[204, {'Content-Type' => 'application/json'}, '']
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
response = faraday.get 'test'
|
153
|
+
|
154
|
+
assert_nil response[:body]
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_does_not_parse_304s
|
158
|
+
faraday = build do |conn|
|
159
|
+
conn.response :parse_json
|
160
|
+
|
161
|
+
conn.adapter :test do |stub|
|
162
|
+
stub.get 'test' do
|
163
|
+
[304, {'Content-Type' => 'application/json'}, '']
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
response = faraday.get 'test'
|
169
|
+
|
170
|
+
assert_nil response[:body]
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_logs_requests
|
174
|
+
stream = StringIO.new
|
175
|
+
logger = Logger.new stream
|
176
|
+
logger.level = :debug
|
177
|
+
|
178
|
+
faraday = build 'http://example.com' do |conn|
|
179
|
+
conn.response :logging, logger
|
180
|
+
|
181
|
+
conn.adapter :test do |stub|
|
182
|
+
stub.get 'test' do
|
183
|
+
[200, {}, 'dead']
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
faraday.get 'test', { foo: 'bar' }, { 'This-Header' => 'has_a_value' }
|
189
|
+
|
190
|
+
stream.rewind ; content = stream.read
|
191
|
+
|
192
|
+
assert_includes content, 'http://example.com/test'
|
193
|
+
assert_includes content, 'This-Header'
|
194
|
+
assert_includes content, 'has_a_value'
|
195
|
+
assert_includes content, 'foo'
|
196
|
+
assert_includes content, 'bar'
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_logs_responses
|
200
|
+
stream = StringIO.new
|
201
|
+
logger = Logger.new stream
|
202
|
+
logger.level = :debug
|
203
|
+
|
204
|
+
faraday = build 'http://example.com' do |conn|
|
205
|
+
conn.response :logging, logger
|
206
|
+
|
207
|
+
conn.adapter :test do |stub|
|
208
|
+
stub.get 'test' do
|
209
|
+
[200, {'This-Header' => 'has_a_value'}, 'the_body']
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
faraday.get 'test'
|
215
|
+
|
216
|
+
stream.rewind ; content = stream.read
|
217
|
+
|
218
|
+
assert_includes content, '200'
|
219
|
+
assert_includes content, 'This-Header'
|
220
|
+
assert_includes content, 'has_a_value'
|
221
|
+
assert_includes content, 'the_body'
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_raises_a_bad_request_error
|
225
|
+
faraday = build do |conn|
|
226
|
+
conn.response :server_error_handler
|
227
|
+
|
228
|
+
conn.adapter :test do |stub|
|
229
|
+
stub.get 'test' do
|
230
|
+
[400, {}, 'dead']
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
assert_raises Chassis::HttpBadRequestError do
|
236
|
+
response = faraday.get 'test'
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_raises_an_unauthorized_error
|
241
|
+
faraday = build do |conn|
|
242
|
+
conn.response :server_error_handler
|
243
|
+
|
244
|
+
conn.adapter :test do |stub|
|
245
|
+
stub.get 'test' do
|
246
|
+
[401, {}, 'dead']
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
assert_raises Chassis::HttpUnauthorizedError do
|
252
|
+
response = faraday.get 'test'
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_raises_a_payment_required_error
|
257
|
+
faraday = build do |conn|
|
258
|
+
conn.response :server_error_handler
|
259
|
+
conn.adapter :test do |stub|
|
260
|
+
stub.get 'test' do
|
261
|
+
[402, {}, 'dead']
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
assert_raises Chassis::HttpPaymentRequiredError do
|
267
|
+
response = faraday.get 'test'
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def test_raises_a_forbidden_error
|
272
|
+
faraday = build do |conn|
|
273
|
+
conn.response :server_error_handler
|
274
|
+
conn.adapter :test do |stub|
|
275
|
+
stub.get 'test' do
|
276
|
+
[403, {}, 'dead']
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
assert_raises Chassis::HttpForbiddenError do
|
282
|
+
response = faraday.get 'test'
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_raises_a_not_found_error
|
287
|
+
faraday = build do |conn|
|
288
|
+
conn.response :server_error_handler
|
289
|
+
conn.adapter :test do |stub|
|
290
|
+
stub.get 'test' do
|
291
|
+
[404, {}, 'dead']
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
assert_raises Chassis::HttpNotFoundError do
|
297
|
+
response = faraday.get 'test'
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_raises_a_method_not_allowed_error
|
302
|
+
faraday = build do |conn|
|
303
|
+
conn.response :server_error_handler
|
304
|
+
conn.adapter :test do |stub|
|
305
|
+
stub.get 'test' do
|
306
|
+
[405, {}, 'dead']
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
assert_raises Chassis::HttpMethodNotAllowedError do
|
312
|
+
response = faraday.get 'test'
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_raises_an_unacceptable_error
|
317
|
+
faraday = build do |conn|
|
318
|
+
conn.response :server_error_handler
|
319
|
+
conn.adapter :test do |stub|
|
320
|
+
stub.get 'test' do
|
321
|
+
[406, {}, 'dead']
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
assert_raises Chassis::HttpNotAcceptableError do
|
327
|
+
response = faraday.get 'test'
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_raises_a_proxy_auth_error
|
332
|
+
faraday = build do |conn|
|
333
|
+
conn.response :server_error_handler
|
334
|
+
conn.adapter :test do |stub|
|
335
|
+
stub.get 'test' do
|
336
|
+
[407, {}, 'dead']
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
assert_raises Chassis::HttpProxyAuthenticationRequiredError do
|
342
|
+
response = faraday.get 'test'
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_raises_a_timeout_error
|
347
|
+
faraday = build do |conn|
|
348
|
+
conn.response :server_error_handler
|
349
|
+
conn.adapter :test do |stub|
|
350
|
+
stub.get 'test' do
|
351
|
+
[408, {}, 'dead']
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
assert_raises Chassis::HttpRequestTimeoutError do
|
357
|
+
response = faraday.get 'test'
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def test_raises_a_conflict_error
|
362
|
+
faraday = build do |conn|
|
363
|
+
conn.response :server_error_handler
|
364
|
+
conn.adapter :test do |stub|
|
365
|
+
stub.get 'test' do
|
366
|
+
[409, {}, 'dead']
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
assert_raises Chassis::HttpConflictError do
|
372
|
+
response = faraday.get 'test'
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def test_raises_a_gone_error
|
377
|
+
faraday = build do |conn|
|
378
|
+
conn.response :server_error_handler
|
379
|
+
conn.adapter :test do |stub|
|
380
|
+
stub.get 'test' do
|
381
|
+
[410, {}, 'dead']
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
assert_raises Chassis::HttpGoneError do
|
387
|
+
response = faraday.get 'test'
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_raises_length_required
|
392
|
+
faraday = build do |conn|
|
393
|
+
conn.response :server_error_handler
|
394
|
+
conn.adapter :test do |stub|
|
395
|
+
stub.get 'test' do
|
396
|
+
[411, {}, 'dead']
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
assert_raises Chassis::HttpLengthRequiredError do
|
402
|
+
response = faraday.get 'test'
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_raises_precondition_failed
|
407
|
+
faraday = build do |conn|
|
408
|
+
conn.response :server_error_handler
|
409
|
+
conn.adapter :test do |stub|
|
410
|
+
stub.get 'test' do
|
411
|
+
[412, {}, 'dead']
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
assert_raises Chassis::HttpPreconditionFailedError do
|
417
|
+
response = faraday.get 'test'
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def test_raises_request_entity_too_large
|
422
|
+
faraday = build do |conn|
|
423
|
+
conn.response :server_error_handler
|
424
|
+
conn.adapter :test do |stub|
|
425
|
+
stub.get 'test' do
|
426
|
+
[413, {}, 'dead']
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
assert_raises Chassis::HttpRequestEntityTooLargeError do
|
432
|
+
response = faraday.get 'test'
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def test_raises_request_uri_too_long
|
437
|
+
faraday = build do |conn|
|
438
|
+
conn.response :server_error_handler
|
439
|
+
conn.adapter :test do |stub|
|
440
|
+
stub.get 'test' do
|
441
|
+
[414, {}, 'dead']
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
assert_raises Chassis::HttpRequestUriTooLongError do
|
447
|
+
response = faraday.get 'test'
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def test_raises_unsupported_media_type
|
452
|
+
faraday = build do |conn|
|
453
|
+
conn.response :server_error_handler
|
454
|
+
conn.adapter :test do |stub|
|
455
|
+
stub.get 'test' do
|
456
|
+
[415, {}, 'dead']
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
assert_raises Chassis::HttpUnsupportedMediaTypeError do
|
462
|
+
response = faraday.get 'test'
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_raises_range_not_satisfiable
|
467
|
+
faraday = build do |conn|
|
468
|
+
conn.response :server_error_handler
|
469
|
+
conn.adapter :test do |stub|
|
470
|
+
stub.get 'test' do
|
471
|
+
[416, {}, 'dead']
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
assert_raises Chassis::HttpRequestRangeNotSatisfiableError do
|
477
|
+
response = faraday.get 'test'
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_raises_expectation_failed
|
482
|
+
faraday = build do |conn|
|
483
|
+
conn.response :server_error_handler
|
484
|
+
conn.adapter :test do |stub|
|
485
|
+
stub.get 'test' do
|
486
|
+
[417, {}, 'dead']
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
assert_raises Chassis::HttpExpectationFailedError do
|
492
|
+
response = faraday.get 'test'
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def test_raises_unprocessable_entity
|
497
|
+
faraday = build do |conn|
|
498
|
+
conn.response :server_error_handler
|
499
|
+
conn.adapter :test do |stub|
|
500
|
+
stub.get 'test' do
|
501
|
+
[422, {}, 'dead']
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
assert_raises Chassis::HttpUnprocessableEntityError do
|
507
|
+
response = faraday.get 'test'
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
def test_raises_locked_error
|
512
|
+
faraday = build do |conn|
|
513
|
+
conn.response :server_error_handler
|
514
|
+
conn.adapter :test do |stub|
|
515
|
+
stub.get 'test' do
|
516
|
+
[423, {}, 'dead']
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
assert_raises Chassis::HttpLockedError do
|
522
|
+
response = faraday.get 'test'
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
def test_raises_failed_dependency_error
|
527
|
+
faraday = build do |conn|
|
528
|
+
conn.response :server_error_handler
|
529
|
+
conn.adapter :test do |stub|
|
530
|
+
stub.get 'test' do
|
531
|
+
[424, {}, 'dead']
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
assert_raises Chassis::HttpFailedDependencyError do
|
537
|
+
response = faraday.get 'test'
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
def test_raises_upgrade_require_error
|
542
|
+
faraday = build do |conn|
|
543
|
+
conn.response :server_error_handler
|
544
|
+
conn.adapter :test do |stub|
|
545
|
+
stub.get 'test' do
|
546
|
+
[426, {}, 'dead']
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
assert_raises Chassis::HttpUpgradeRequiredError do
|
552
|
+
response = faraday.get 'test'
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
def test_raises_internal_server_error
|
557
|
+
faraday = build do |conn|
|
558
|
+
conn.response :server_error_handler
|
559
|
+
conn.adapter :test do |stub|
|
560
|
+
stub.get 'test' do
|
561
|
+
[500, {}, 'dead']
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
assert_raises Chassis::HttpInternalServerError do
|
567
|
+
response = faraday.get 'test'
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def test_raises_not_implemented_error
|
572
|
+
faraday = build do |conn|
|
573
|
+
conn.response :server_error_handler
|
574
|
+
conn.adapter :test do |stub|
|
575
|
+
stub.get 'test' do
|
576
|
+
[501, {}, 'dead']
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
assert_raises Chassis::HttpNotImplementedError do
|
582
|
+
response = faraday.get 'test'
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
def test_raises_bad_gateway_error
|
587
|
+
faraday = build do |conn|
|
588
|
+
conn.response :server_error_handler
|
589
|
+
conn.adapter :test do |stub|
|
590
|
+
stub.get 'test' do
|
591
|
+
[502, {}, 'dead']
|
592
|
+
end
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
assert_raises Chassis::HttpBadGatewayError do
|
597
|
+
response = faraday.get 'test'
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
def test_raises_service_unavailable
|
602
|
+
faraday = build do |conn|
|
603
|
+
conn.response :server_error_handler
|
604
|
+
conn.adapter :test do |stub|
|
605
|
+
stub.get 'test' do
|
606
|
+
[503, {}, 'dead']
|
607
|
+
end
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
assert_raises Chassis::HttpServiceUnavailableError do
|
612
|
+
response = faraday.get 'test'
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
def test_raises_gateway_timeout
|
617
|
+
faraday = build do |conn|
|
618
|
+
conn.response :server_error_handler
|
619
|
+
conn.adapter :test do |stub|
|
620
|
+
stub.get 'test' do
|
621
|
+
[504, {}, 'dead']
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
assert_raises Chassis::HttpGatewayTimeoutError do
|
627
|
+
response = faraday.get 'test'
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
def test_raises_http_version_not_supported_error
|
632
|
+
faraday = build do |conn|
|
633
|
+
conn.response :server_error_handler
|
634
|
+
conn.adapter :test do |stub|
|
635
|
+
stub.get 'test' do
|
636
|
+
[505, {}, 'dead']
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
assert_raises Chassis::HttpVersionNotSupportedError do
|
642
|
+
response = faraday.get 'test'
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
def test_raises_insuffcient_storage
|
647
|
+
faraday = build do |conn|
|
648
|
+
conn.response :server_error_handler
|
649
|
+
conn.adapter :test do |stub|
|
650
|
+
stub.get 'test' do
|
651
|
+
[507, {}, 'dead']
|
652
|
+
end
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
assert_raises Chassis::HttpInsufficientStorageError do
|
657
|
+
response = faraday.get 'test'
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
def test_raises_not_extended_error
|
662
|
+
faraday = build do |conn|
|
663
|
+
conn.response :server_error_handler
|
664
|
+
conn.adapter :test do |stub|
|
665
|
+
stub.get 'test' do
|
666
|
+
[510, {}, 'dead']
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
assert_raises Chassis::HttpNotExtendedError do
|
672
|
+
response = faraday.get 'test'
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
def test_server_errors_contain_useful_information
|
677
|
+
faraday = build 'http://example.com' do |conn|
|
678
|
+
conn.response :server_error_handler
|
679
|
+
conn.adapter :test do |stub|
|
680
|
+
stub.get 'test.error' do
|
681
|
+
[500, {}, 'dead']
|
682
|
+
end
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
begin
|
687
|
+
faraday.get 'test.error'
|
688
|
+
rescue => ex
|
689
|
+
exception = ex
|
690
|
+
end
|
691
|
+
|
692
|
+
assert exception
|
693
|
+
msg = exception.to_s
|
694
|
+
assert_includes msg, "http://example.com/test.error"
|
695
|
+
end
|
696
|
+
|
697
|
+
def test_has_factory_for_faraday_connections
|
698
|
+
faraday = Chassis.faraday 'http://example.com'
|
699
|
+
|
700
|
+
stack = faraday.builder.handlers
|
701
|
+
|
702
|
+
assert_includes stack, Chassis::Instrumentation
|
703
|
+
assert_includes stack, Chassis::EncodeJson
|
704
|
+
assert_includes stack, Chassis::ParseJson
|
705
|
+
assert_includes stack, Chassis::ServerErrorHandler
|
706
|
+
assert_includes stack, Chassis::Logging
|
707
|
+
end
|
708
|
+
|
709
|
+
def test_factory_can_change_the_namespace
|
710
|
+
faraday = Chassis.faraday 'http://example.com', namespace: 'test' do |conn|
|
711
|
+
conn.adapter :test do |stub|
|
712
|
+
stub.get 'test' do
|
713
|
+
[200, {'Content-Type' => 'application/json'}, JSON.dump(foo: 'bar')]
|
714
|
+
end
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
faraday.get 'test'
|
719
|
+
|
720
|
+
refute_empty stats.timers
|
721
|
+
timer = stats.timers.first
|
722
|
+
|
723
|
+
assert_equal 'test.get', timer.name
|
724
|
+
end
|
725
|
+
|
726
|
+
def test_factory_can_change_the_logger
|
727
|
+
stream = StringIO.new
|
728
|
+
logger = Logger.new stream
|
729
|
+
logger.level = :debug
|
730
|
+
|
731
|
+
faraday = Chassis.faraday 'http://example.com', logger: logger do |conn|
|
732
|
+
conn.adapter :test do |stub|
|
733
|
+
stub.get 'test' do
|
734
|
+
[200, {}, 'dead']
|
735
|
+
end
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
faraday.get 'test', { foo: 'bar' }, { 'This-Header' => 'has_a_value' }
|
740
|
+
|
741
|
+
stream.rewind ; content = stream.read
|
742
|
+
|
743
|
+
assert_includes content, 'http://example.com/test'
|
744
|
+
assert_includes content, 'This-Header'
|
745
|
+
assert_includes content, 'has_a_value'
|
746
|
+
assert_includes content, 'foo'
|
747
|
+
assert_includes content, 'bar'
|
748
|
+
end
|
749
|
+
end
|