opinionated_http 0.0.4 → 0.0.5
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 +4 -4
- data/Rakefile +7 -7
- data/lib/opinionated_http.rb +3 -3
- data/lib/opinionated_http/client.rb +112 -51
- data/lib/opinionated_http/version.rb +1 -1
- data/test/client_test.rb +75 -48
- data/test/test_helper.rb +10 -10
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e42aeb5b1a1b2647f48288e3b34b54064b327f72b0cce291ea75a1c0a563eb79
|
|
4
|
+
data.tar.gz: 533c7d1bf33a594ebb5b910e25a4ebf0b8420d9e5a24d0aac5f99e83e779fbe4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2555937900d00a7b139a1bee2b76de642065b8b0469aeebb7783934c588bd032dc9b72b211e7ba5b04f06d01f55ece6f7a45d44439f14303c051e71cb4207bc
|
|
7
|
+
data.tar.gz: c78cfe4681bfe65cba9d570878dcf78328059d5835e9de0cbff7d416d7ee5954cc4d4fd831f459373027bff9cf37f096ad12f5108ae40fd32db5502fd02ebd12
|
data/Rakefile
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# Setup bundler to avoid having to run bundle exec all the time.
|
|
2
|
-
require
|
|
3
|
-
require
|
|
2
|
+
require "rubygems"
|
|
3
|
+
require "bundler/setup"
|
|
4
4
|
|
|
5
|
-
require
|
|
6
|
-
require_relative
|
|
5
|
+
require "rake/testtask"
|
|
6
|
+
require_relative "lib/opinionated_http/version"
|
|
7
7
|
|
|
8
8
|
task :gem do
|
|
9
|
-
system
|
|
9
|
+
system "gem build opinionated_http.gemspec"
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
task publish: :gem do
|
|
13
13
|
system "git tag -a v#{OpinionatedHTTP::VERSION} -m 'Tagging #{OpinionatedHTTP::VERSION}'"
|
|
14
|
-
system
|
|
14
|
+
system "git push --tags"
|
|
15
15
|
system "gem push opinionated_http-#{OpinionatedHTTP::VERSION}.gem"
|
|
16
16
|
system "rm opinionated_http-#{OpinionatedHTTP::VERSION}.gem"
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
Rake::TestTask.new(:test) do |t|
|
|
20
|
-
t.pattern =
|
|
20
|
+
t.pattern = "test/**/*_test.rb"
|
|
21
21
|
t.verbose = true
|
|
22
22
|
t.warning = false
|
|
23
23
|
end
|
data/lib/opinionated_http.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "opinionated_http/version"
|
|
2
2
|
#
|
|
3
3
|
# Opinionated HTTP
|
|
4
4
|
#
|
|
5
5
|
# An opinionated HTTP Client library using convention over configuration.
|
|
6
6
|
#
|
|
7
7
|
module OpinionatedHTTP
|
|
8
|
-
autoload :Client,
|
|
9
|
-
autoload :Logger,
|
|
8
|
+
autoload :Client, "opinionated_http/client"
|
|
9
|
+
autoload :Logger, "opinionated_http/logger"
|
|
10
10
|
|
|
11
11
|
#
|
|
12
12
|
# Create a new Opinionated HTTP instance.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
1
|
+
require "persistent_http"
|
|
2
|
+
require "secret_config"
|
|
3
|
+
require "semantic_logger"
|
|
4
4
|
#
|
|
5
5
|
# Client http implementation
|
|
6
6
|
#
|
|
@@ -8,35 +8,73 @@ require 'semantic_logger'
|
|
|
8
8
|
module OpinionatedHTTP
|
|
9
9
|
class Client
|
|
10
10
|
# 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout
|
|
11
|
-
HTTP_RETRY_CODES = %w[502 503 504]
|
|
11
|
+
HTTP_RETRY_CODES = %w[502 503 504].freeze
|
|
12
12
|
|
|
13
13
|
attr_reader :secret_config_prefix, :logger, :metric_prefix, :error_class, :driver,
|
|
14
|
-
:retry_count, :retry_interval, :retry_multiplier, :http_retry_codes
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
:retry_count, :retry_interval, :retry_multiplier, :http_retry_codes,
|
|
15
|
+
:url, :pool_size, :keep_alive, :proxy, :force_retry, :max_redirects,
|
|
16
|
+
:open_timeout, :read_timeout, :idle_timeout, :pool_timeout, :warn_timeout
|
|
17
|
+
|
|
18
|
+
# Any option supplied here can be overridden if that corresponding value is set in Secret Config.
|
|
19
|
+
# Except for any values passed directly to Persistent HTTP under `**options`.
|
|
20
|
+
def initialize(
|
|
21
|
+
secret_config_prefix:,
|
|
22
|
+
metric_prefix:,
|
|
23
|
+
error_class:,
|
|
24
|
+
logger: nil,
|
|
25
|
+
retry_count: 11,
|
|
26
|
+
retry_interval: 0.01,
|
|
27
|
+
retry_multiplier: 1.8,
|
|
28
|
+
http_retry_codes: HTTP_RETRY_CODES.join(","),
|
|
29
|
+
url: nil,
|
|
30
|
+
pool_size: 100,
|
|
31
|
+
open_timeout: 10,
|
|
32
|
+
read_timeout: 10,
|
|
33
|
+
idle_timeout: 300,
|
|
34
|
+
keep_alive: 300,
|
|
35
|
+
pool_timeout: 5,
|
|
36
|
+
warn_timeout: 0.25,
|
|
37
|
+
proxy: :ENV,
|
|
38
|
+
force_retry: true,
|
|
39
|
+
max_redirects: 10,
|
|
40
|
+
**options
|
|
41
|
+
)
|
|
17
42
|
@metric_prefix = metric_prefix
|
|
18
43
|
@logger = logger || SemanticLogger[self]
|
|
19
44
|
@error_class = error_class
|
|
20
|
-
@retry_count = SecretConfig.fetch("#{secret_config_prefix}/retry_count", type: :integer, default:
|
|
21
|
-
@retry_interval = SecretConfig.fetch("#{secret_config_prefix}/retry_interval", type: :float, default:
|
|
22
|
-
@retry_multiplier = SecretConfig.fetch("#{secret_config_prefix}/retry_multiplier", type: :float, default:
|
|
23
|
-
|
|
24
|
-
|
|
45
|
+
@retry_count = SecretConfig.fetch("#{secret_config_prefix}/retry_count", type: :integer, default: retry_count)
|
|
46
|
+
@retry_interval = SecretConfig.fetch("#{secret_config_prefix}/retry_interval", type: :float, default: retry_interval)
|
|
47
|
+
@retry_multiplier = SecretConfig.fetch("#{secret_config_prefix}/retry_multiplier", type: :float, default: retry_multiplier)
|
|
48
|
+
@max_redirects = SecretConfig.fetch("#{secret_config_prefix}/max_redirects", type: :integer, default: max_redirects)
|
|
49
|
+
http_retry_codes = SecretConfig.fetch("#{secret_config_prefix}/http_retry_codes", type: :string, default: http_retry_codes)
|
|
50
|
+
@http_retry_codes = http_retry_codes.split(",").collect(&:strip)
|
|
51
|
+
|
|
52
|
+
@url = url.nil? ? SecretConfig["#{secret_config_prefix}/url"] : SecretConfig.fetch("#{secret_config_prefix}/url", default: url)
|
|
53
|
+
|
|
54
|
+
@pool_size = SecretConfig.fetch("#{secret_config_prefix}/pool_size", type: :integer, default: pool_size)
|
|
55
|
+
@open_timeout = SecretConfig.fetch("#{secret_config_prefix}/open_timeout", type: :float, default: open_timeout)
|
|
56
|
+
@read_timeout = SecretConfig.fetch("#{secret_config_prefix}/read_timeout", type: :float, default: read_timeout)
|
|
57
|
+
@idle_timeout = SecretConfig.fetch("#{secret_config_prefix}/idle_timeout", type: :float, default: idle_timeout)
|
|
58
|
+
@keep_alive = SecretConfig.fetch("#{secret_config_prefix}/keep_alive", type: :float, default: keep_alive)
|
|
59
|
+
@pool_timeout = SecretConfig.fetch("#{secret_config_prefix}/pool_timeout", type: :float, default: pool_timeout)
|
|
60
|
+
@warn_timeout = SecretConfig.fetch("#{secret_config_prefix}/warn_timeout", type: :float, default: warn_timeout)
|
|
61
|
+
@proxy = SecretConfig.fetch("#{secret_config_prefix}/proxy", type: :symbol, default: proxy)
|
|
62
|
+
@force_retry = SecretConfig.fetch("#{secret_config_prefix}/force_retry", type: :boolean, default: force_retry)
|
|
25
63
|
|
|
26
64
|
internal_logger = OpinionatedHTTP::Logger.new(@logger)
|
|
27
65
|
new_options = {
|
|
28
66
|
logger: internal_logger,
|
|
29
67
|
debug_output: internal_logger,
|
|
30
68
|
name: "",
|
|
31
|
-
pool_size:
|
|
32
|
-
open_timeout:
|
|
33
|
-
read_timeout:
|
|
34
|
-
idle_timeout:
|
|
35
|
-
keep_alive:
|
|
36
|
-
pool_timeout:
|
|
37
|
-
warn_timeout:
|
|
38
|
-
proxy:
|
|
39
|
-
force_retry:
|
|
69
|
+
pool_size: @pool_size,
|
|
70
|
+
open_timeout: @open_timeout,
|
|
71
|
+
read_timeout: @read_timeout,
|
|
72
|
+
idle_timeout: @idle_timeout,
|
|
73
|
+
keep_alive: @keep_alive,
|
|
74
|
+
pool_timeout: @pool_timeout,
|
|
75
|
+
warn_timeout: @warn_timeout,
|
|
76
|
+
proxy: @proxy,
|
|
77
|
+
force_retry: @force_retry
|
|
40
78
|
}
|
|
41
79
|
|
|
42
80
|
url = SecretConfig["#{secret_config_prefix}/url"]
|
|
@@ -45,88 +83,111 @@ module OpinionatedHTTP
|
|
|
45
83
|
end
|
|
46
84
|
|
|
47
85
|
# Perform an HTTP Get against the supplied path
|
|
48
|
-
def get(action:, path: "/#{action}",
|
|
49
|
-
|
|
50
|
-
|
|
86
|
+
def get(action:, path: "/#{action}", **args)
|
|
87
|
+
request = build_request(path: path, verb: "Get", **args)
|
|
88
|
+
response = request(action: action, request: request)
|
|
89
|
+
extract_body(response)
|
|
90
|
+
end
|
|
51
91
|
|
|
52
|
-
|
|
53
|
-
|
|
92
|
+
def post(action:, path: "/#{action}", **args)
|
|
93
|
+
request = build_request(path: path, verb: "Post", **args)
|
|
54
94
|
|
|
55
|
-
response
|
|
95
|
+
response = request(action: action, request: request)
|
|
96
|
+
extract_body(response)
|
|
56
97
|
end
|
|
57
98
|
|
|
58
|
-
def
|
|
59
|
-
|
|
60
|
-
|
|
99
|
+
def build_request(verb:, path:, headers: nil, body: nil, form_data: nil, username: nil, password: nil, parameters: nil)
|
|
100
|
+
unless headers_and_form_data_compatible?(headers, form_data)
|
|
101
|
+
raise(ArgumentError, "Setting form data will overwrite supplied content-type")
|
|
102
|
+
end
|
|
103
|
+
raise(ArgumentError, "Cannot supply both form_data and a body") if body && form_data
|
|
61
104
|
|
|
62
|
-
|
|
105
|
+
path = "/#{path}" unless path.start_with?("/")
|
|
106
|
+
path = "#{path}?#{URI.encode_www_form(parameters)}" if parameters
|
|
63
107
|
|
|
64
|
-
|
|
65
|
-
end
|
|
108
|
+
request = Net::HTTP.const_get(verb).new(path, headers)
|
|
66
109
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
110
|
+
raise(ArgumentError, "#{request.class.name} does not support a request body") if body && !request.request_body_permitted?
|
|
111
|
+
if parameters && !request.response_body_permitted?
|
|
112
|
+
raise(ArgumentError, ":parameters cannot be supplied for #{request.class.name}")
|
|
113
|
+
end
|
|
70
114
|
|
|
71
|
-
request = Net::HTTP.const_get(verb).new(path, headers)
|
|
72
115
|
request.body = body if body
|
|
73
116
|
request.set_form_data form_data if form_data
|
|
74
117
|
request.basic_auth(username, password) if username && password
|
|
75
118
|
request
|
|
76
119
|
end
|
|
77
120
|
|
|
121
|
+
# Returns [HTTP Response] after submitting the request
|
|
122
|
+
#
|
|
123
|
+
# Notes:
|
|
124
|
+
# - Does not raise an exception when the http response is not an HTTP OK (200.
|
|
125
|
+
def request(action:, request:)
|
|
126
|
+
request_with_retry(action: action, request: request)
|
|
127
|
+
end
|
|
128
|
+
|
|
78
129
|
private
|
|
79
130
|
|
|
80
|
-
def request_with_retry(action:,
|
|
131
|
+
def request_with_retry(action:, request:, try_count: 0)
|
|
81
132
|
http_method = request.method.upcase
|
|
82
133
|
response =
|
|
83
134
|
begin
|
|
84
135
|
payload = {}
|
|
85
136
|
if logger.trace?
|
|
86
137
|
payload[:parameters] = parameters
|
|
87
|
-
payload[:path] = path
|
|
138
|
+
payload[:path] = request.path
|
|
88
139
|
end
|
|
89
140
|
message = "HTTP #{http_method}: #{action}" if logger.debug?
|
|
90
141
|
|
|
91
142
|
logger.benchmark_info(message: message, metric: "#{metric_prefix}/#{action}", payload: payload) { driver.request(request) }
|
|
92
|
-
rescue StandardError =>
|
|
93
|
-
message = "HTTP #{http_method}: #{action} Failure: #{
|
|
94
|
-
logger.error(message: message, metric: "#{metric_prefix}/exception", exception:
|
|
143
|
+
rescue StandardError => e
|
|
144
|
+
message = "HTTP #{http_method}: #{action} Failure: #{e.class.name}: #{e.message}"
|
|
145
|
+
logger.error(message: message, metric: "#{metric_prefix}/exception", exception: e)
|
|
95
146
|
raise(error_class, message)
|
|
96
147
|
end
|
|
97
148
|
|
|
98
149
|
# Retry on http 5xx errors except 500 which means internal server error.
|
|
99
150
|
if http_retry_codes.include?(response.code)
|
|
100
151
|
if try_count < retry_count
|
|
101
|
-
try_count
|
|
102
|
-
duration
|
|
152
|
+
try_count += 1
|
|
153
|
+
duration = retry_sleep_interval(try_count)
|
|
103
154
|
logger.warn(message: "HTTP #{http_method}: #{action} Failure: (#{response.code}) #{response.message}. Retry: #{try_count}", metric: "#{metric_prefix}/retry", duration: duration * 1_000)
|
|
104
155
|
sleep(duration)
|
|
105
|
-
response = request_with_retry(action: action,
|
|
156
|
+
response = request_with_retry(action: action, request: request, try_count: try_count)
|
|
106
157
|
else
|
|
107
158
|
message = "HTTP #{http_method}: #{action} Failure: (#{response.code}) #{response.message}. Retries Exhausted"
|
|
108
159
|
logger.error(message: message, metric: "#{metric_prefix}/exception")
|
|
109
160
|
raise(error_class, message)
|
|
110
161
|
end
|
|
111
|
-
elsif !response.is_a?(Net::HTTPSuccess)
|
|
112
|
-
message = "HTTP #{http_method}: #{action} Failure: (#{response.code}) #{response.message}"
|
|
113
|
-
logger.error(message: message, metric: "#{metric_prefix}/exception")
|
|
114
|
-
raise(error_class, message)
|
|
115
162
|
end
|
|
116
163
|
|
|
117
164
|
response
|
|
118
165
|
end
|
|
119
166
|
|
|
167
|
+
def extract_body(response)
|
|
168
|
+
return response.body if response.is_a?(Net::HTTPSuccess)
|
|
169
|
+
|
|
170
|
+
message = "HTTP #{http_method}: #{action} Failure: (#{response.code}) #{response.message}"
|
|
171
|
+
logger.error(message: message, metric: "#{metric_prefix}/exception")
|
|
172
|
+
raise(error_class, message)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def prefix_path(path)
|
|
176
|
+
path.start_with?("/") ? path : "/#{path}"
|
|
177
|
+
end
|
|
178
|
+
|
|
120
179
|
# First retry is immediate, next retry is after `retry_interval`,
|
|
121
180
|
# each subsequent retry interval is 100% longer than the prior interval.
|
|
122
181
|
def retry_sleep_interval(retry_count)
|
|
123
182
|
return 0 if retry_count <= 1
|
|
124
|
-
|
|
183
|
+
|
|
184
|
+
(retry_multiplier**(retry_count - 1)) * retry_interval
|
|
125
185
|
end
|
|
126
186
|
|
|
127
187
|
def headers_and_form_data_compatible?(headers, form_data)
|
|
128
188
|
return true if headers.nil? || form_data.nil?
|
|
129
|
-
|
|
189
|
+
|
|
190
|
+
!headers.keys.map(&:downcase).include?("content-type")
|
|
130
191
|
end
|
|
131
192
|
end
|
|
132
193
|
end
|
data/test/client_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require_relative
|
|
1
|
+
require "net/http"
|
|
2
|
+
require "json"
|
|
3
|
+
require_relative "test_helper"
|
|
4
4
|
|
|
5
5
|
module OpinionatedHTTP
|
|
6
6
|
class ClientTest < Minitest::Test
|
|
@@ -10,99 +10,126 @@ module OpinionatedHTTP
|
|
|
10
10
|
|
|
11
11
|
let :http do
|
|
12
12
|
OpinionatedHTTP.new(
|
|
13
|
-
secret_config_prefix:
|
|
14
|
-
metric_prefix:
|
|
13
|
+
secret_config_prefix: "fake_service",
|
|
14
|
+
metric_prefix: "FakeService",
|
|
15
15
|
logger: SemanticLogger["FakeService"],
|
|
16
16
|
error_class: ServiceError,
|
|
17
|
-
header: {
|
|
17
|
+
header: {"Content-Type" => "application/json"}
|
|
18
18
|
)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
describe "get" do
|
|
22
|
-
it
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
it "succeeds" do
|
|
23
|
+
output = {zip: "12345", population: 54_321}
|
|
24
|
+
body = output.to_json
|
|
25
|
+
response = stub_request(Net::HTTPSuccess, 200, "OK", body) do
|
|
26
|
+
http.get(action: "lookup", parameters: {zip: "12345"})
|
|
27
|
+
end
|
|
28
|
+
assert_equal body, response
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
describe "
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
describe "post" do
|
|
33
|
+
it "succeeds with body" do
|
|
34
|
+
output = {zip: "12345", population: 54_321}
|
|
35
|
+
body = output.to_json
|
|
36
|
+
response = stub_request(Net::HTTPSuccess, 200, "OK", body) do
|
|
37
|
+
http.post(action: "lookup", body: body)
|
|
38
|
+
end
|
|
39
|
+
assert_equal body, response
|
|
40
|
+
end
|
|
36
41
|
|
|
37
|
-
it
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
it "with form data" do
|
|
43
|
+
output = {zip: "12345", population: 54_321}
|
|
44
|
+
body = output.to_json
|
|
45
|
+
response = stub_request(Net::HTTPSuccess, 200, "OK", body) do
|
|
46
|
+
http.post(action: "lookup", form_data: output)
|
|
47
|
+
end
|
|
48
|
+
assert_equal body, response
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "build_request" do
|
|
53
|
+
let(:path) { "/fake_action" }
|
|
54
|
+
let(:post_verb) { "Post" }
|
|
55
|
+
let(:get_verb) { "Get" }
|
|
56
|
+
|
|
57
|
+
it "creates a request corresponding to the supplied verb" do
|
|
58
|
+
req = http.build_request(path: path, verb: post_verb)
|
|
59
|
+
req2 = http.build_request(path: path, verb: get_verb)
|
|
40
60
|
|
|
41
61
|
assert_kind_of Net::HTTP::Post, req
|
|
42
62
|
assert_kind_of Net::HTTP::Get, req2
|
|
43
63
|
end
|
|
44
64
|
|
|
45
|
-
it
|
|
46
|
-
test_headers = {
|
|
47
|
-
req = http.
|
|
65
|
+
it "returns a request with supplied headers" do
|
|
66
|
+
test_headers = {"test1" => "yes_test_1", "test2" => "yes_test_2"}
|
|
67
|
+
req = http.build_request(path: path, verb: get_verb, headers: test_headers)
|
|
48
68
|
|
|
49
|
-
assert_equal test_headers[
|
|
50
|
-
assert_equal test_headers[
|
|
69
|
+
assert_equal test_headers["test1"], req["test1"]
|
|
70
|
+
assert_equal test_headers["test2"], req["test2"]
|
|
51
71
|
end
|
|
52
72
|
|
|
53
|
-
it
|
|
73
|
+
it "returns a request with supplied body" do
|
|
54
74
|
test_body = "nice bod"
|
|
55
|
-
req = http.
|
|
75
|
+
req = http.build_request(path: path, verb: post_verb, body: test_body)
|
|
56
76
|
|
|
57
77
|
assert_equal test_body, req.body
|
|
58
78
|
end
|
|
59
79
|
|
|
60
|
-
it
|
|
61
|
-
test_data
|
|
80
|
+
it "returns a request with supplied form data in x-www-form-urlencoded Content-Type" do
|
|
81
|
+
test_data = {test1: "yes", test2: "no"}
|
|
62
82
|
expected_string = "test1=yes&test2=no"
|
|
63
|
-
req
|
|
83
|
+
req = http.build_request(path: path, verb: post_verb, form_data: test_data)
|
|
64
84
|
|
|
65
85
|
assert_equal expected_string, req.body
|
|
66
|
-
assert_equal
|
|
86
|
+
assert_equal "application/x-www-form-urlencoded", req["Content-Type"]
|
|
67
87
|
end
|
|
68
88
|
|
|
69
|
-
it
|
|
70
|
-
test_un =
|
|
71
|
-
test_pw =
|
|
72
|
-
req
|
|
73
|
-
req2
|
|
89
|
+
it "add supplied authentication to the request" do
|
|
90
|
+
test_un = "admin"
|
|
91
|
+
test_pw = "hunter2"
|
|
92
|
+
req = http.build_request(path: path, verb: get_verb, username: test_un, password: test_pw)
|
|
93
|
+
req2 = Net::HTTP::Get.new(path)
|
|
74
94
|
req2.basic_auth test_un, test_pw
|
|
75
95
|
|
|
76
|
-
assert_equal req2[
|
|
96
|
+
assert_equal req2["authorization"], req["authorization"]
|
|
77
97
|
end
|
|
78
98
|
|
|
79
|
-
it
|
|
80
|
-
downcase_headers = {
|
|
81
|
-
capitalized_headers = {
|
|
82
|
-
no_conflict_headers = {
|
|
99
|
+
it "raise an error if supplied content-type header would be overwritten by setting form_data" do
|
|
100
|
+
downcase_headers = {"unimportant" => "blank", "content-type" => "application/json"}
|
|
101
|
+
capitalized_headers = {"Unimportant" => "blank", "Content-Type" => "application/json"}
|
|
102
|
+
no_conflict_headers = {"whatever" => "blank", "irrelevant" => "test"}
|
|
83
103
|
form_data = {thing1: 1, thing2: 2}
|
|
84
104
|
|
|
85
105
|
assert_raises ArgumentError do
|
|
86
|
-
http.
|
|
106
|
+
http.build_request(path: path, verb: post_verb, headers: downcase_headers, form_data: form_data)
|
|
87
107
|
end
|
|
88
108
|
|
|
89
109
|
assert_raises ArgumentError do
|
|
90
|
-
http.
|
|
110
|
+
http.build_request(path: path, verb: post_verb, headers: capitalized_headers, form_data: form_data)
|
|
91
111
|
end
|
|
92
112
|
|
|
93
|
-
assert http.
|
|
113
|
+
assert http.build_request(path: path, verb: post_verb, headers: no_conflict_headers, form_data: form_data)
|
|
94
114
|
end
|
|
95
115
|
|
|
96
|
-
it
|
|
116
|
+
it "raise an error if there is a collision between supplied body and form_data" do
|
|
97
117
|
form_data = {thing1: 1, thing2: 2}
|
|
98
118
|
body = "not form data"
|
|
99
119
|
|
|
100
120
|
assert_raises ArgumentError do
|
|
101
|
-
http.
|
|
121
|
+
http.build_request(path: path, verb: post_verb, body: body, form_data: form_data)
|
|
102
122
|
end
|
|
103
123
|
|
|
104
|
-
assert http.
|
|
105
|
-
assert http.
|
|
124
|
+
assert http.build_request(path: path, verb: post_verb, body: body)
|
|
125
|
+
assert http.build_request(path: path, verb: post_verb, form_data: form_data)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def stub_request(klass, code, msg, body, &block)
|
|
130
|
+
response = klass.new("1.1", code, msg)
|
|
131
|
+
response.stub(:body, body) do
|
|
132
|
+
http.driver.stub(:request, response, &block)
|
|
106
133
|
end
|
|
107
134
|
end
|
|
108
135
|
end
|
data/test/test_helper.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
$LOAD_PATH.unshift File.dirname(__FILE__) +
|
|
2
|
-
ENV[
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
|
2
|
+
ENV["TZ"] = "America/New_York"
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
4
|
+
require "yaml"
|
|
5
|
+
require "minitest/autorun"
|
|
6
|
+
require "awesome_print"
|
|
7
|
+
require "secret_config"
|
|
8
|
+
require "semantic_logger"
|
|
9
|
+
require "opinionated_http"
|
|
10
10
|
|
|
11
|
-
SemanticLogger.add_appender(file_name:
|
|
11
|
+
SemanticLogger.add_appender(file_name: "test.log", formatter: :color)
|
|
12
12
|
SemanticLogger.default_level = :debug
|
|
13
13
|
|
|
14
|
-
SecretConfig.use :file, path:
|
|
14
|
+
SecretConfig.use :file, path: "test", file_name: File.expand_path("config/application.yml", __dir__)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: opinionated_http
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Reid Morrison
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-04-
|
|
11
|
+
date: 2020-04-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: persistent_http
|