ruby_http_client 3.2.0 → 3.5.1
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 +5 -5
- data/.codeclimate.yml +16 -0
- data/.env_sample +1 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +34 -13
- data/CHANGELOG.md +87 -0
- data/CODE_OF_CONDUCT.md +73 -0
- data/CONTRIBUTING.md +36 -50
- data/FIRST_TIMERS.md +79 -0
- data/Gemfile +3 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/{LICENSE.txt → LICENSE.md} +8 -8
- data/Makefile +7 -0
- data/PULL_REQUEST_TEMPLATE.md +31 -0
- data/README.md +54 -18
- data/Rakefile +25 -2
- data/TROUBLESHOOTING.md +17 -0
- data/USAGE.md +108 -0
- data/examples/example.rb +29 -1
- data/lib/ruby_http_client.rb +119 -22
- 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 +237 -11
- data/twilio_sendgrid_logo.png +0 -0
- data/use_cases/README.md +3 -0
- metadata +80 -9
- data/.github/ISSUE_TEMPLATE +0 -17
data/examples/example.rb
CHANGED
@@ -6,9 +6,28 @@ headers = JSON.parse('
|
|
6
6
|
"Authorization": "Bearer ' + ENV['SENDGRID_API_KEY'] + '"
|
7
7
|
}
|
8
8
|
')
|
9
|
-
host =
|
9
|
+
host = 'https://api.sendgrid.com'
|
10
10
|
client = SendGrid::Client.new(host: host, request_headers: headers)
|
11
11
|
|
12
|
+
# You can pass in an http_options hash to set values for NET::HTTP attributes
|
13
|
+
# https://ruby-doc.org/stdlib-2.4.1/libdoc/net/http/rdoc/Net/HTTP.html
|
14
|
+
# client = SendGrid::Client.new(host: host,
|
15
|
+
# request_headers: headers,
|
16
|
+
# http_options: {open_timeout: 15, read_timeout: 30})
|
17
|
+
|
18
|
+
# If you want to make request via proxy, you can set your proxy server in two ways.
|
19
|
+
#
|
20
|
+
# (1) Pass proxy_options hash
|
21
|
+
#
|
22
|
+
# client = SendGrid::Client.new(host: host,
|
23
|
+
# request_headers: headers,
|
24
|
+
# proxy_options: { host: '127.0.0.1', port: 8080 })
|
25
|
+
#
|
26
|
+
# (2) Set 'http_proxy' environment variable
|
27
|
+
#
|
28
|
+
# ENV['http_proxy'] = 'user:pass@127.0.0.1:8080'
|
29
|
+
# client = SendGrid::Client.new(host: host, request_headers: headers)
|
30
|
+
|
12
31
|
# GET Collection
|
13
32
|
query_params = { 'limit' => 100, 'offset' => 0 }
|
14
33
|
response = client.version('v3').api_keys.get(query_params: query_params)
|
@@ -69,3 +88,12 @@ puts response.headers
|
|
69
88
|
response = client.api_keys._(api_key_id).delete
|
70
89
|
puts response.status_code
|
71
90
|
puts response.headers
|
91
|
+
|
92
|
+
# Rate limit information
|
93
|
+
response = client.version('v3').api_keys._(api_key_id).get
|
94
|
+
puts response.ratelimit.limit
|
95
|
+
puts response.ratelimit.remaining
|
96
|
+
puts response.ratelimit.reset
|
97
|
+
puts response.ratelimit.exceeded?
|
98
|
+
# Sleep the current thread until the reset has happened
|
99
|
+
response.ratelimit.wait!
|
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
|
@@ -90,7 +152,7 @@ module SendGrid
|
|
90
152
|
# - The url string with the query parameters appended
|
91
153
|
#
|
92
154
|
def build_query_params(url, query_params)
|
93
|
-
params =
|
155
|
+
params = URI.encode_www_form(query_params)
|
94
156
|
url.concat("?#{params}")
|
95
157
|
end
|
96
158
|
|
@@ -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,16 @@ 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
|
+
add_ssl(Net::HTTP.new(*params))
|
231
|
+
end
|
232
|
+
|
172
233
|
# Allow for https calls
|
173
234
|
#
|
174
235
|
# * *Args* :
|
@@ -195,20 +256,22 @@ module SendGrid
|
|
195
256
|
# - Client object
|
196
257
|
#
|
197
258
|
def _(name = nil)
|
198
|
-
url_path = name ? @url_path
|
199
|
-
@url_path = []
|
259
|
+
url_path = name ? @url_path + [name] : @url_path
|
200
260
|
Client.new(host: @host, request_headers: @request_headers,
|
201
|
-
version: @version, url_path: url_path
|
261
|
+
version: @version, url_path: url_path,
|
262
|
+
http_options: @http_options)
|
202
263
|
end
|
203
264
|
|
204
265
|
# Dynamically add segments to the url, then call a method.
|
205
266
|
# (e.g. client.name.name.get())
|
206
267
|
#
|
207
268
|
# * *Args* :
|
208
|
-
# - The args are
|
269
|
+
# - The args are automatically passed in
|
209
270
|
# * *Returns* :
|
210
271
|
# - Client object or Response object
|
211
272
|
#
|
273
|
+
# rubocop:disable Style/MethodMissingSuper
|
274
|
+
# rubocop:disable Style/MissingRespondToMissing
|
212
275
|
def method_missing(name, *args, &_block)
|
213
276
|
# Capture the version
|
214
277
|
if name.to_s == 'version'
|
@@ -217,8 +280,42 @@ module SendGrid
|
|
217
280
|
end
|
218
281
|
# We have reached the end of the method chain, make the API call
|
219
282
|
return build_request(name, args) if @methods.include?(name.to_s)
|
283
|
+
|
220
284
|
# Add a segment to the URL
|
221
285
|
_(name)
|
222
286
|
end
|
287
|
+
|
288
|
+
private
|
289
|
+
|
290
|
+
def build_http_request(http_method)
|
291
|
+
uri = build_url(query_params: @query_params)
|
292
|
+
net_http = Kernel.const_get('Net::HTTP::' + http_method.to_s.capitalize)
|
293
|
+
|
294
|
+
@http = build_http(uri.host, uri.port)
|
295
|
+
@request = build_request_headers(net_http.new(uri.request_uri))
|
296
|
+
end
|
297
|
+
|
298
|
+
def update_content_type(http_method)
|
299
|
+
if @request_body && content_type_json?
|
300
|
+
# If body is a hash or array, encode it; else leave it alone
|
301
|
+
@request.body = if [Hash, Array].include?(@request_body.class)
|
302
|
+
@request_body.to_json
|
303
|
+
else
|
304
|
+
@request_body
|
305
|
+
end
|
306
|
+
@request['Content-Type'] = 'application/json'
|
307
|
+
elsif !@request_body && http_method.to_s == 'post'
|
308
|
+
@request['Content-Type'] = ''
|
309
|
+
else
|
310
|
+
@request.body = @request_body
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def content_type_json?
|
315
|
+
!@request_headers.key?('Content-Type') ||
|
316
|
+
@request_headers['Content-Type'] == 'application/json'
|
317
|
+
end
|
318
|
+
# rubocop:enable Style/MethodMissingSuper
|
319
|
+
# rubocop:enable Style/MissingRespondToMissing
|
223
320
|
end
|
224
321
|
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.1'
|
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,9 +98,9 @@ class TestClient < Minitest::Test
|
|
61
98
|
|
62
99
|
def test_build_query_params
|
63
100
|
url = ''
|
64
|
-
query_params = { 'limit' => 100, 'offset' => 0 }
|
101
|
+
query_params = { 'limit' => 100, 'offset' => 0, 'categories' => %w[category1 category2] }
|
65
102
|
url = @client.build_query_params(url, query_params)
|
66
|
-
assert_equal('?limit=100&offset=0', url)
|
103
|
+
assert_equal('?limit=100&offset=0&categories=category1&categories=category2', url)
|
67
104
|
end
|
68
105
|
|
69
106
|
def test_build_url
|
@@ -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)
|
@@ -120,7 +157,7 @@ class TestClient < Minitest::Test
|
|
120
157
|
)
|
121
158
|
client.build_request('get', nil)
|
122
159
|
assert_equal('application/json', client.request['Content-Type'])
|
123
|
-
|
160
|
+
assert_nil(client.request.body)
|
124
161
|
end
|
125
162
|
|
126
163
|
def test_build_request_post_empty_body
|
@@ -134,7 +171,7 @@ class TestClient < Minitest::Test
|
|
134
171
|
)
|
135
172
|
client.build_request('post', nil)
|
136
173
|
assert_equal('', client.request['Content-Type'])
|
137
|
-
|
174
|
+
assert_nil(client.request.body)
|
138
175
|
end
|
139
176
|
|
140
177
|
def test_build_request_post_multipart
|
@@ -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)
|
@@ -165,10 +258,143 @@ class TestClient < Minitest::Test
|
|
165
258
|
assert_equal(['test'], url1.url_path)
|
166
259
|
end
|
167
260
|
|
261
|
+
def test_ratelimit_core
|
262
|
+
expiry = Time.now.to_i + 1
|
263
|
+
rl = SendGrid::Response::Ratelimit.new(500, 100, expiry)
|
264
|
+
rl2 = SendGrid::Response::Ratelimit.new(500, 0, expiry)
|
265
|
+
|
266
|
+
refute rl.exceeded?
|
267
|
+
assert rl2.exceeded?
|
268
|
+
|
269
|
+
assert_equal(rl.used, 400)
|
270
|
+
assert_equal(rl2.used, 500)
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_response_ratelimit_parsing
|
274
|
+
headers = {
|
275
|
+
'X-RateLimit-Limit' => '500',
|
276
|
+
'X-RateLimit-Remaining' => '300',
|
277
|
+
'X-RateLimit-Reset' => Time.now.to_i.to_s
|
278
|
+
}
|
279
|
+
|
280
|
+
body = ''
|
281
|
+
code = 204
|
282
|
+
http_response = MockHttpResponse.new(code, body, headers)
|
283
|
+
response = SendGrid::Response.new(http_response)
|
284
|
+
|
285
|
+
refute_nil response.ratelimit
|
286
|
+
refute response.ratelimit.exceeded?
|
287
|
+
end
|
288
|
+
|
168
289
|
def test_method_missing
|
169
290
|
response = @client.get
|
170
291
|
assert_equal(200, response.status_code)
|
171
|
-
assert_equal({'message' => 'success'}, response.body)
|
172
|
-
assert_equal({'headers' => 'test'}, response.headers)
|
292
|
+
assert_equal({ 'message' => 'success' }, response.body)
|
293
|
+
assert_equal({ 'headers' => 'test' }, response.headers)
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_http_options
|
297
|
+
url1 = @client_with_options._('test')
|
298
|
+
assert_equal(@host, @client_with_options.host)
|
299
|
+
assert_equal(@headers, @client_with_options.request_headers)
|
300
|
+
assert_equal(['test'], url1.url_path)
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_proxy_options
|
304
|
+
proxy_options = {
|
305
|
+
host: '127.0.0.1', port: 8080, user: 'anonymous', pass: 'secret'
|
306
|
+
}
|
307
|
+
client = MockRequest.new(
|
308
|
+
host: 'https://api.sendgrid.com',
|
309
|
+
request_headers: { 'Authorization' => 'Bearer xxx' },
|
310
|
+
proxy_options: proxy_options
|
311
|
+
).version('v3').api_keys
|
312
|
+
|
313
|
+
assert(client.proxy_address, '127.0.0.1')
|
314
|
+
assert(client.proxy_pass, 'secret')
|
315
|
+
assert(client.proxy_port, 8080)
|
316
|
+
assert(client.proxy_user, 'anonymous')
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_proxy_from_http_proxy_environment_variable
|
320
|
+
ENV['http_proxy'] = 'anonymous:secret@127.0.0.1:8080'
|
321
|
+
|
322
|
+
client = MockRequest.new(
|
323
|
+
host: 'https://api.sendgrid.com',
|
324
|
+
request_headers: { 'Authorization' => 'Bearer xxx' }
|
325
|
+
).version('v3').api_keys
|
326
|
+
|
327
|
+
assert(client.proxy_address, '127.0.0.1')
|
328
|
+
assert(client.proxy_pass, 'secret')
|
329
|
+
assert(client.proxy_port, 8080)
|
330
|
+
assert(client.proxy_user, 'anonymous')
|
331
|
+
ensure
|
332
|
+
ENV.delete('http_proxy')
|
333
|
+
end
|
334
|
+
|
335
|
+
# def test_docker_exists
|
336
|
+
# assert(File.file?('./Dockerfile') || File.file?('./docker/Dockerfile'))
|
337
|
+
# end
|
338
|
+
|
339
|
+
# def test_docker_compose_exists
|
340
|
+
# assert(File.file?('./docker-compose.yml') || File.file?('./docker/docker-compose.yml'))
|
341
|
+
# end
|
342
|
+
|
343
|
+
def test_env_sample_exists
|
344
|
+
assert(File.file?('./.env_sample'))
|
345
|
+
end
|
346
|
+
|
347
|
+
def test_gitignore_exists
|
348
|
+
assert(File.file?('./.gitignore'))
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_travis_exists
|
352
|
+
assert(File.file?('./.travis.yml'))
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_codeclimate_exists
|
356
|
+
assert(File.file?('./.codeclimate.yml'))
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_changelog_exists
|
360
|
+
assert(File.file?('./CHANGELOG.md'))
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_code_of_conduct_exists
|
364
|
+
assert(File.file?('./CODE_OF_CONDUCT.md'))
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_contributing_exists
|
368
|
+
assert(File.file?('./CONTRIBUTING.md'))
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_issue_template_exists
|
372
|
+
assert(File.file?('./ISSUE_TEMPLATE.md'))
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_license_exists
|
376
|
+
assert(File.file?('./LICENSE.md') || File.file?('./LICENSE.txt'))
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_pull_request_template_exists
|
380
|
+
assert(File.file?('./PULL_REQUEST_TEMPLATE.md'))
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_readme_exists
|
384
|
+
assert(File.file?('./README.md'))
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_troubleshooting_exists
|
388
|
+
assert(File.file?('./TROUBLESHOOTING.md'))
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_use_cases_exists
|
392
|
+
assert(File.file?('use_cases/README.md'))
|
393
|
+
end
|
394
|
+
|
395
|
+
def test_license_date_is_updated
|
396
|
+
license_end_year = IO.read('LICENSE.md').match(/Copyright \(C\) (\d{4}), Twilio SendGrid/)[1].to_i
|
397
|
+
current_year = Time.new.year
|
398
|
+
assert_equal(current_year, license_end_year)
|
173
399
|
end
|
174
400
|
end
|