ruby_http_client 3.3.0 → 3.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.env_sample +1 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +32 -13
- data/CHANGELOG.md +89 -1
- data/CODE_OF_CONDUCT.md +57 -25
- data/CONTRIBUTING.md +21 -37
- data/FIRST_TIMERS.md +79 -0
- data/Gemfile +3 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/{LICENSE.txt → LICENSE} +8 -8
- data/Makefile +7 -0
- data/PULL_REQUEST_TEMPLATE.md +31 -0
- data/README.md +32 -23
- data/Rakefile +25 -2
- data/TROUBLESHOOTING.md +1 -1
- data/USAGE.md +108 -0
- data/examples/example.rb +29 -1
- data/lib/ruby_http_client.rb +134 -21
- data/ruby_http_client.gemspec +16 -13
- data/static/img/github-fork.png +0 -0
- data/static/img/github-sign-up.png +0 -0
- data/test/test_helper.rb +7 -0
- data/test/test_ruby_http_client.rb +242 -8
- data/twilio_sendgrid_logo.png +0 -0
- data/use_cases/README.md +3 -0
- metadata +77 -10
- data/.github/ISSUE_TEMPLATE +0 -17
- data/.github/PULL_REQUEST_TEMPLATE +0 -24
data/lib/ruby_http_client.rb
CHANGED
@@ -6,10 +6,54 @@ module SendGrid
|
|
6
6
|
|
7
7
|
# Holds the response from an API call.
|
8
8
|
class Response
|
9
|
+
# Provide useful functionality around API rate limiting.
|
10
|
+
class Ratelimit
|
11
|
+
attr_reader :limit, :remaining, :reset
|
12
|
+
|
13
|
+
# * *Args* :
|
14
|
+
# - +limit+ -> The total number of requests allowed within a rate limit window
|
15
|
+
# - +remaining+ -> The number of requests that have been processed within this current rate limit window
|
16
|
+
# - +reset+ -> The time (in seconds since Unix Epoch) when the rate limit will reset
|
17
|
+
def initialize(limit, remaining, reset)
|
18
|
+
@limit = limit.to_i
|
19
|
+
@remaining = remaining.to_i
|
20
|
+
@reset = Time.at reset.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def exceeded?
|
24
|
+
remaining <= 0
|
25
|
+
end
|
26
|
+
|
27
|
+
# * *Returns* :
|
28
|
+
# - The number of requests that have been used out of this
|
29
|
+
# rate limit window
|
30
|
+
def used
|
31
|
+
limit - remaining
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sleep until the reset time arrives. If given a block, it will
|
35
|
+
# be called after sleeping is finished.
|
36
|
+
#
|
37
|
+
# * *Returns* :
|
38
|
+
# - The amount of time (in seconds) that the rate limit slept
|
39
|
+
# for.
|
40
|
+
def wait!
|
41
|
+
now = Time.now.utc.to_i
|
42
|
+
duration = (reset.to_i - now) + 1
|
43
|
+
|
44
|
+
sleep duration if duration >= 0
|
45
|
+
|
46
|
+
yield if block_given?
|
47
|
+
|
48
|
+
duration
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
9
52
|
# * *Args* :
|
10
53
|
# - +response+ -> A NET::HTTP response object
|
11
54
|
#
|
12
55
|
attr_reader :status_code, :body, :headers
|
56
|
+
|
13
57
|
def initialize(response)
|
14
58
|
@status_code = response.code
|
15
59
|
@body = response.body
|
@@ -21,6 +65,20 @@ module SendGrid
|
|
21
65
|
def parsed_body
|
22
66
|
@parsed_body ||= JSON.parse(@body, symbolize_names: true)
|
23
67
|
end
|
68
|
+
|
69
|
+
def ratelimit
|
70
|
+
return @ratelimit unless @ratelimit.nil?
|
71
|
+
|
72
|
+
limit = headers['X-RateLimit-Limit']
|
73
|
+
remaining = headers['X-RateLimit-Remaining']
|
74
|
+
reset = headers['X-RateLimit-Reset']
|
75
|
+
|
76
|
+
# Guard against possibility that one (or probably, all) of the
|
77
|
+
# needed headers were not returned.
|
78
|
+
@ratelimit = Ratelimit.new(limit, remaining, reset) if limit && remaining && reset
|
79
|
+
|
80
|
+
@ratelimit
|
81
|
+
end
|
24
82
|
end
|
25
83
|
|
26
84
|
# A simple REST client.
|
@@ -35,15 +93,19 @@ module SendGrid
|
|
35
93
|
# Or just pass the version as part of the URL
|
36
94
|
# (e.g. client._("/v3"))
|
37
95
|
# - +url_path+ -> A list of the url path segments
|
96
|
+
# - +proxy_options+ -> A hash of proxy settings.
|
97
|
+
# (e.g. { host: '127.0.0.1', port: 8080 })
|
38
98
|
#
|
39
|
-
def initialize(host: nil, request_headers: nil, version: nil, url_path: nil)
|
99
|
+
def initialize(host: nil, request_headers: nil, version: nil, url_path: nil, http_options: {}, proxy_options: {}) # rubocop:disable Metrics/ParameterLists
|
40
100
|
@host = host
|
41
101
|
@request_headers = request_headers || {}
|
42
102
|
@version = version
|
43
103
|
@url_path = url_path || []
|
44
|
-
@methods = %w
|
104
|
+
@methods = %w[delete get patch post put]
|
45
105
|
@query_params = nil
|
46
106
|
@request_body = nil
|
107
|
+
@http_options = http_options
|
108
|
+
@proxy_options = proxy_options
|
47
109
|
end
|
48
110
|
|
49
111
|
# Update the headers for the request
|
@@ -137,21 +199,10 @@ module SendGrid
|
|
137
199
|
#
|
138
200
|
def build_request(name, args)
|
139
201
|
build_args(args) if args
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
if (@request_body &&
|
145
|
-
(!@request_headers.has_key?('Content-Type') ||
|
146
|
-
@request_headers['Content-Type'] == 'application/json')
|
147
|
-
)
|
148
|
-
@request.body = @request_body.to_json
|
149
|
-
@request['Content-Type'] = 'application/json'
|
150
|
-
elsif !@request_body and (name.to_s == "post")
|
151
|
-
@request['Content-Type'] = ''
|
152
|
-
else
|
153
|
-
@request.body = @request_body
|
154
|
-
end
|
202
|
+
# build the request & http object
|
203
|
+
build_http_request(name)
|
204
|
+
# set the content type & request body
|
205
|
+
update_content_type(name)
|
155
206
|
make_request(@http, @request)
|
156
207
|
end
|
157
208
|
|
@@ -169,6 +220,18 @@ module SendGrid
|
|
169
220
|
Response.new(response)
|
170
221
|
end
|
171
222
|
|
223
|
+
# Build HTTP request object
|
224
|
+
#
|
225
|
+
# * *Returns* :
|
226
|
+
# - Request object
|
227
|
+
def build_http(host, port)
|
228
|
+
params = [host, port]
|
229
|
+
params += @proxy_options.values_at(:host, :port, :user, :pass) unless @proxy_options.empty?
|
230
|
+
http = add_ssl(Net::HTTP.new(*params))
|
231
|
+
http = add_http_options(http) unless @http_options.empty?
|
232
|
+
http
|
233
|
+
end
|
234
|
+
|
172
235
|
# Allow for https calls
|
173
236
|
#
|
174
237
|
# * *Args* :
|
@@ -184,6 +247,20 @@ module SendGrid
|
|
184
247
|
http
|
185
248
|
end
|
186
249
|
|
250
|
+
# Add others http options to http object
|
251
|
+
#
|
252
|
+
# * *Args* :
|
253
|
+
# - +http+ -> HTTP::NET object
|
254
|
+
# * *Returns* :
|
255
|
+
# - HTTP::NET object
|
256
|
+
#
|
257
|
+
def add_http_options(http)
|
258
|
+
@http_options.each do |attribute, value|
|
259
|
+
http.send("#{attribute}=", value)
|
260
|
+
end
|
261
|
+
http
|
262
|
+
end
|
263
|
+
|
187
264
|
# Add variable values to the url.
|
188
265
|
# (e.g. /your/api/{variable_value}/call)
|
189
266
|
# Another example: if you have a ruby reserved word, such as true,
|
@@ -195,20 +272,22 @@ module SendGrid
|
|
195
272
|
# - Client object
|
196
273
|
#
|
197
274
|
def _(name = nil)
|
198
|
-
url_path = name ? @url_path
|
199
|
-
@url_path = []
|
275
|
+
url_path = name ? @url_path + [name] : @url_path
|
200
276
|
Client.new(host: @host, request_headers: @request_headers,
|
201
|
-
version: @version, url_path: url_path
|
277
|
+
version: @version, url_path: url_path,
|
278
|
+
http_options: @http_options)
|
202
279
|
end
|
203
280
|
|
204
281
|
# Dynamically add segments to the url, then call a method.
|
205
282
|
# (e.g. client.name.name.get())
|
206
283
|
#
|
207
284
|
# * *Args* :
|
208
|
-
# - The args are
|
285
|
+
# - The args are automatically passed in
|
209
286
|
# * *Returns* :
|
210
287
|
# - Client object or Response object
|
211
288
|
#
|
289
|
+
# rubocop:disable Style/MethodMissingSuper
|
290
|
+
# rubocop:disable Style/MissingRespondToMissing
|
212
291
|
def method_missing(name, *args, &_block)
|
213
292
|
# Capture the version
|
214
293
|
if name.to_s == 'version'
|
@@ -217,8 +296,42 @@ module SendGrid
|
|
217
296
|
end
|
218
297
|
# We have reached the end of the method chain, make the API call
|
219
298
|
return build_request(name, args) if @methods.include?(name.to_s)
|
299
|
+
|
220
300
|
# Add a segment to the URL
|
221
301
|
_(name)
|
222
302
|
end
|
303
|
+
|
304
|
+
private
|
305
|
+
|
306
|
+
def build_http_request(http_method)
|
307
|
+
uri = build_url(query_params: @query_params)
|
308
|
+
net_http = Kernel.const_get('Net::HTTP::' + http_method.to_s.capitalize)
|
309
|
+
|
310
|
+
@http = build_http(uri.host, uri.port)
|
311
|
+
@request = build_request_headers(net_http.new(uri.request_uri))
|
312
|
+
end
|
313
|
+
|
314
|
+
def update_content_type(http_method)
|
315
|
+
if @request_body && content_type_json?
|
316
|
+
# If body is a hash or array, encode it; else leave it alone
|
317
|
+
@request.body = if [Hash, Array].include?(@request_body.class)
|
318
|
+
@request_body.to_json
|
319
|
+
else
|
320
|
+
@request_body
|
321
|
+
end
|
322
|
+
@request['Content-Type'] = 'application/json'
|
323
|
+
elsif !@request_body && http_method.to_s == 'post'
|
324
|
+
@request['Content-Type'] = ''
|
325
|
+
else
|
326
|
+
@request.body = @request_body
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def content_type_json?
|
331
|
+
!@request_headers.key?('Content-Type') ||
|
332
|
+
@request_headers['Content-Type'] == 'application/json'
|
333
|
+
end
|
334
|
+
# rubocop:enable Style/MethodMissingSuper
|
335
|
+
# rubocop:enable Style/MissingRespondToMissing
|
223
336
|
end
|
224
337
|
end
|
data/ruby_http_client.gemspec
CHANGED
@@ -1,20 +1,23 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
|
5
4
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name
|
7
|
-
spec.version
|
8
|
-
spec.authors
|
9
|
-
spec.email
|
10
|
-
spec.summary
|
5
|
+
spec.name = 'ruby_http_client'
|
6
|
+
spec.version = '3.5.2'
|
7
|
+
spec.authors = ['Elmer Thomas']
|
8
|
+
spec.email = 'help@twilio.com'
|
9
|
+
spec.summary = 'A simple REST client'
|
11
10
|
spec.description = 'Quickly and easily access any REST or REST-like API.'
|
12
|
-
spec.homepage
|
13
|
-
spec.license
|
14
|
-
spec.files
|
15
|
-
spec.executables
|
16
|
-
spec.test_files
|
11
|
+
spec.homepage = 'http://github.com/sendgrid/ruby-http-client'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.files = `git ls-files -z`.split("\x0")
|
14
|
+
spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
|
15
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)/)
|
17
16
|
spec.require_paths = ['lib']
|
18
17
|
|
19
|
-
spec.add_development_dependency '
|
18
|
+
spec.add_development_dependency 'codecov'
|
19
|
+
spec.add_development_dependency 'minitest'
|
20
|
+
spec.add_development_dependency 'rake'
|
21
|
+
spec.add_development_dependency 'rubocop', '~> 0.88.0'
|
22
|
+
spec.add_development_dependency 'simplecov', '~> 0.18.5'
|
20
23
|
end
|
Binary file
|
Binary file
|
data/test/test_helper.rb
ADDED
@@ -1,3 +1,4 @@
|
|
1
|
+
require './test/test_helper'
|
1
2
|
require 'ruby_http_client'
|
2
3
|
require 'minitest/autorun'
|
3
4
|
|
@@ -11,6 +12,26 @@ class MockResponse
|
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
15
|
+
class MockHttpResponse
|
16
|
+
attr_reader :code, :body, :headers
|
17
|
+
|
18
|
+
def initialize(code, body, headers)
|
19
|
+
@code = code
|
20
|
+
@body = body
|
21
|
+
@headers = headers
|
22
|
+
end
|
23
|
+
|
24
|
+
alias to_hash headers
|
25
|
+
end
|
26
|
+
|
27
|
+
class MockResponseWithRequestBody < MockResponse
|
28
|
+
attr_reader :request_body
|
29
|
+
|
30
|
+
def initialize(response)
|
31
|
+
@request_body = response['request_body']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
14
35
|
class MockRequest < SendGrid::Client
|
15
36
|
def make_request(_http, _request)
|
16
37
|
response = {}
|
@@ -21,6 +42,17 @@ class MockRequest < SendGrid::Client
|
|
21
42
|
end
|
22
43
|
end
|
23
44
|
|
45
|
+
class MockRequestWithRequestBody < SendGrid::Client
|
46
|
+
def make_request(_http, request)
|
47
|
+
response = {}
|
48
|
+
response['code'] = 200
|
49
|
+
response['body'] = { 'message' => 'success' }
|
50
|
+
response['headers'] = { 'headers' => 'test' }
|
51
|
+
response['request_body'] = request.body
|
52
|
+
MockResponseWithRequestBody.new(response)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
24
56
|
class TestClient < Minitest::Test
|
25
57
|
def setup
|
26
58
|
@headers = JSON.parse('
|
@@ -31,9 +63,14 @@ class TestClient < Minitest::Test
|
|
31
63
|
')
|
32
64
|
@host = 'http://localhost:4010'
|
33
65
|
@version = 'v3'
|
66
|
+
@http_options = { open_timeout: 60, read_timeout: 60 }
|
34
67
|
@client = MockRequest.new(host: @host,
|
35
68
|
request_headers: @headers,
|
36
69
|
version: @version)
|
70
|
+
@client_with_options = MockRequest.new(host: @host,
|
71
|
+
request_headers: @headers,
|
72
|
+
version: @version,
|
73
|
+
http_options: @http_options)
|
37
74
|
end
|
38
75
|
|
39
76
|
def test_init
|
@@ -61,7 +98,7 @@ class TestClient < Minitest::Test
|
|
61
98
|
|
62
99
|
def test_build_query_params
|
63
100
|
url = ''
|
64
|
-
query_params = { 'limit' => 100, 'offset' => 0, 'categories' => [
|
101
|
+
query_params = { 'limit' => 100, 'offset' => 0, 'categories' => %w[category1 category2] }
|
65
102
|
url = @client.build_query_params(url, query_params)
|
66
103
|
assert_equal('?limit=100&offset=0&categories=category1&categories=category2', url)
|
67
104
|
end
|
@@ -91,8 +128,8 @@ class TestClient < Minitest::Test
|
|
91
128
|
args = nil
|
92
129
|
response = @client.build_request(name, args)
|
93
130
|
assert_equal(200, response.status_code)
|
94
|
-
assert_equal({'message' => 'success'}, response.body)
|
95
|
-
assert_equal({'headers' => 'test'}, response.headers)
|
131
|
+
assert_equal({ 'message' => 'success' }, response.body)
|
132
|
+
assert_equal({ 'headers' => 'test' }, response.headers)
|
96
133
|
end
|
97
134
|
|
98
135
|
def test_build_request_post_empty_content_type
|
@@ -103,7 +140,7 @@ class TestClient < Minitest::Test
|
|
103
140
|
request_headers: headers,
|
104
141
|
version: 'v3'
|
105
142
|
)
|
106
|
-
args = [{'request_body' => {
|
143
|
+
args = [{ 'request_body' => { 'hogekey' => 'hogevalue' } }]
|
107
144
|
client.build_request('post', args)
|
108
145
|
assert_equal('application/json', client.request['Content-Type'])
|
109
146
|
assert_equal('{"hogekey":"hogevalue"}', client.request.body)
|
@@ -143,15 +180,71 @@ class TestClient < Minitest::Test
|
|
143
180
|
}
|
144
181
|
client = MockRequest.new(
|
145
182
|
host: 'https://localhost',
|
146
|
-
request_headers: headers
|
183
|
+
request_headers: headers
|
147
184
|
)
|
148
185
|
name = 'post'
|
149
|
-
args = [{'request_body' => 'hogebody'}]
|
186
|
+
args = [{ 'request_body' => 'hogebody' }]
|
150
187
|
client.build_request(name, args)
|
151
188
|
assert_equal('multipart/form-data; boundary=xYzZY', client.request['Content-Type'])
|
152
189
|
assert_equal('hogebody', client.request.body)
|
153
190
|
end
|
154
191
|
|
192
|
+
def test_json_body_encode_hash
|
193
|
+
headers = {
|
194
|
+
'Content-Type' => 'application/json'
|
195
|
+
}
|
196
|
+
client = MockRequestWithRequestBody.new(
|
197
|
+
host: 'https://localhost',
|
198
|
+
request_headers: headers
|
199
|
+
)
|
200
|
+
name = 'post'
|
201
|
+
args = [{ 'request_body' => { 'this_is' => 'json' } }]
|
202
|
+
response = client.build_request(name, args)
|
203
|
+
assert_equal('{"this_is":"json"}', response.request_body)
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_json_body_encode_array
|
207
|
+
headers = {
|
208
|
+
'Content-Type' => 'application/json'
|
209
|
+
}
|
210
|
+
client = MockRequestWithRequestBody.new(
|
211
|
+
host: 'https://localhost',
|
212
|
+
request_headers: headers
|
213
|
+
)
|
214
|
+
name = 'post'
|
215
|
+
args = [{ 'request_body' => [{ 'this_is' => 'json' }] }]
|
216
|
+
response = client.build_request(name, args)
|
217
|
+
assert_equal('[{"this_is":"json"}]', response.request_body)
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_json_body_do_not_reencode
|
221
|
+
headers = {
|
222
|
+
'Content-Type' => 'application/json'
|
223
|
+
}
|
224
|
+
client = MockRequestWithRequestBody.new(
|
225
|
+
host: 'https://localhost',
|
226
|
+
request_headers: headers
|
227
|
+
)
|
228
|
+
name = 'post'
|
229
|
+
args = [{ 'request_body' => '{"this_is":"json"}' }]
|
230
|
+
response = client.build_request(name, args)
|
231
|
+
assert_equal('{"this_is":"json"}', response.request_body)
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_json_body_do_not_reencode_simplejson
|
235
|
+
headers = {
|
236
|
+
'Content-Type' => 'application/json'
|
237
|
+
}
|
238
|
+
client = MockRequestWithRequestBody.new(
|
239
|
+
host: 'https://localhost',
|
240
|
+
request_headers: headers
|
241
|
+
)
|
242
|
+
name = 'post'
|
243
|
+
args = [{ 'request_body' => 'true' }]
|
244
|
+
response = client.build_request(name, args)
|
245
|
+
assert_equal('true', response.request_body)
|
246
|
+
end
|
247
|
+
|
155
248
|
def add_ssl
|
156
249
|
uri = URI.parse('https://localhost:4010')
|
157
250
|
http = Net::HTTP.new(uri.host, uri.port)
|
@@ -160,15 +253,156 @@ class TestClient < Minitest::Test
|
|
160
253
|
assert_equal(http.verify_mode, OpenSSL::SSL::VERIFY_PEER)
|
161
254
|
end
|
162
255
|
|
256
|
+
def test_add_http_options
|
257
|
+
uri = URI.parse('https://localhost:4010')
|
258
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
259
|
+
http = @client_with_options.add_http_options(http)
|
260
|
+
assert_equal(http.open_timeout, 60)
|
261
|
+
assert_equal(http.read_timeout, 60)
|
262
|
+
end
|
263
|
+
|
163
264
|
def test__
|
164
265
|
url1 = @client._('test')
|
165
266
|
assert_equal(['test'], url1.url_path)
|
166
267
|
end
|
167
268
|
|
269
|
+
def test_ratelimit_core
|
270
|
+
expiry = Time.now.to_i + 1
|
271
|
+
rl = SendGrid::Response::Ratelimit.new(500, 100, expiry)
|
272
|
+
rl2 = SendGrid::Response::Ratelimit.new(500, 0, expiry)
|
273
|
+
|
274
|
+
refute rl.exceeded?
|
275
|
+
assert rl2.exceeded?
|
276
|
+
|
277
|
+
assert_equal(rl.used, 400)
|
278
|
+
assert_equal(rl2.used, 500)
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_response_ratelimit_parsing
|
282
|
+
headers = {
|
283
|
+
'X-RateLimit-Limit' => '500',
|
284
|
+
'X-RateLimit-Remaining' => '300',
|
285
|
+
'X-RateLimit-Reset' => Time.now.to_i.to_s
|
286
|
+
}
|
287
|
+
|
288
|
+
body = ''
|
289
|
+
code = 204
|
290
|
+
http_response = MockHttpResponse.new(code, body, headers)
|
291
|
+
response = SendGrid::Response.new(http_response)
|
292
|
+
|
293
|
+
refute_nil response.ratelimit
|
294
|
+
refute response.ratelimit.exceeded?
|
295
|
+
end
|
296
|
+
|
168
297
|
def test_method_missing
|
169
298
|
response = @client.get
|
170
299
|
assert_equal(200, response.status_code)
|
171
|
-
assert_equal({'message' => 'success'}, response.body)
|
172
|
-
assert_equal({'headers' => 'test'}, response.headers)
|
300
|
+
assert_equal({ 'message' => 'success' }, response.body)
|
301
|
+
assert_equal({ 'headers' => 'test' }, response.headers)
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_http_options
|
305
|
+
url1 = @client_with_options._('test')
|
306
|
+
assert_equal(@host, @client_with_options.host)
|
307
|
+
assert_equal(@headers, @client_with_options.request_headers)
|
308
|
+
assert_equal(['test'], url1.url_path)
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_proxy_options
|
312
|
+
proxy_options = {
|
313
|
+
host: '127.0.0.1', port: 8080, user: 'anonymous', pass: 'secret'
|
314
|
+
}
|
315
|
+
client = MockRequest.new(
|
316
|
+
host: 'https://api.sendgrid.com',
|
317
|
+
request_headers: { 'Authorization' => 'Bearer xxx' },
|
318
|
+
proxy_options: proxy_options
|
319
|
+
).version('v3').api_keys
|
320
|
+
|
321
|
+
assert(client.proxy_address, '127.0.0.1')
|
322
|
+
assert(client.proxy_pass, 'secret')
|
323
|
+
assert(client.proxy_port, 8080)
|
324
|
+
assert(client.proxy_user, 'anonymous')
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_proxy_from_http_proxy_environment_variable
|
328
|
+
ENV['http_proxy'] = 'anonymous:secret@127.0.0.1:8080'
|
329
|
+
|
330
|
+
client = MockRequest.new(
|
331
|
+
host: 'https://api.sendgrid.com',
|
332
|
+
request_headers: { 'Authorization' => 'Bearer xxx' }
|
333
|
+
).version('v3').api_keys
|
334
|
+
|
335
|
+
assert(client.proxy_address, '127.0.0.1')
|
336
|
+
assert(client.proxy_pass, 'secret')
|
337
|
+
assert(client.proxy_port, 8080)
|
338
|
+
assert(client.proxy_user, 'anonymous')
|
339
|
+
ensure
|
340
|
+
ENV.delete('http_proxy')
|
341
|
+
end
|
342
|
+
|
343
|
+
# def test_docker_exists
|
344
|
+
# assert(File.file?('./Dockerfile') || File.file?('./docker/Dockerfile'))
|
345
|
+
# end
|
346
|
+
|
347
|
+
# def test_docker_compose_exists
|
348
|
+
# assert(File.file?('./docker-compose.yml') || File.file?('./docker/docker-compose.yml'))
|
349
|
+
# end
|
350
|
+
|
351
|
+
def test_env_sample_exists
|
352
|
+
assert(File.file?('./.env_sample'))
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_gitignore_exists
|
356
|
+
assert(File.file?('./.gitignore'))
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_travis_exists
|
360
|
+
assert(File.file?('./.travis.yml'))
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_codeclimate_exists
|
364
|
+
assert(File.file?('./.codeclimate.yml'))
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_changelog_exists
|
368
|
+
assert(File.file?('./CHANGELOG.md'))
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_code_of_conduct_exists
|
372
|
+
assert(File.file?('./CODE_OF_CONDUCT.md'))
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_contributing_exists
|
376
|
+
assert(File.file?('./CONTRIBUTING.md'))
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_issue_template_exists
|
380
|
+
assert(File.file?('./ISSUE_TEMPLATE.md'))
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_license_exists
|
384
|
+
assert(File.file?('./LICENSE'))
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_pull_request_template_exists
|
388
|
+
assert(File.file?('./PULL_REQUEST_TEMPLATE.md'))
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_readme_exists
|
392
|
+
assert(File.file?('./README.md'))
|
393
|
+
end
|
394
|
+
|
395
|
+
def test_troubleshooting_exists
|
396
|
+
assert(File.file?('./TROUBLESHOOTING.md'))
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_use_cases_exists
|
400
|
+
assert(File.file?('use_cases/README.md'))
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_license_date_is_updated
|
404
|
+
license_end_year = IO.read('LICENSE').match(/Copyright \(C\) (\d{4}), Twilio SendGrid/)[1].to_i
|
405
|
+
current_year = Time.new.year
|
406
|
+
assert_equal(current_year, license_end_year)
|
173
407
|
end
|
174
408
|
end
|