rest-man 1.0.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/.github/workflows/multi-matrix-test.yml +35 -0
- data/.github/workflows/single-matrix-test.yml +27 -0
- data/.gitignore +13 -0
- data/.mailmap +10 -0
- data/.rspec +2 -0
- data/.rubocop +2 -0
- data/.rubocop-disables.yml +386 -0
- data/.rubocop.yml +8 -0
- data/AUTHORS +106 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +843 -0
- data/Rakefile +140 -0
- data/exe/restman +92 -0
- data/lib/rest-man.rb +2 -0
- data/lib/rest_man.rb +2 -0
- data/lib/restman/abstract_response.rb +252 -0
- data/lib/restman/exceptions.rb +238 -0
- data/lib/restman/params_array.rb +72 -0
- data/lib/restman/payload.rb +234 -0
- data/lib/restman/platform.rb +49 -0
- data/lib/restman/raw_response.rb +49 -0
- data/lib/restman/request.rb +859 -0
- data/lib/restman/resource.rb +178 -0
- data/lib/restman/response.rb +90 -0
- data/lib/restman/utils.rb +274 -0
- data/lib/restman/version.rb +8 -0
- data/lib/restman/windows/root_certs.rb +105 -0
- data/lib/restman/windows.rb +8 -0
- data/lib/restman.rb +183 -0
- data/matrixeval.yml +73 -0
- data/rest-man.gemspec +41 -0
- data/spec/ISS.jpg +0 -0
- data/spec/cassettes/request_httpbin_with_basic_auth.yml +83 -0
- data/spec/cassettes/request_httpbin_with_cookies.yml +49 -0
- data/spec/cassettes/request_httpbin_with_cookies_2.yml +94 -0
- data/spec/cassettes/request_httpbin_with_cookies_3.yml +49 -0
- data/spec/cassettes/request_httpbin_with_encoding_deflate.yml +45 -0
- data/spec/cassettes/request_httpbin_with_encoding_deflate_and_accept_headers.yml +44 -0
- data/spec/cassettes/request_httpbin_with_encoding_gzip.yml +45 -0
- data/spec/cassettes/request_httpbin_with_encoding_gzip_and_accept_headers.yml +44 -0
- data/spec/cassettes/request_httpbin_with_user_agent.yml +44 -0
- data/spec/cassettes/request_mozilla_org.yml +151 -0
- data/spec/cassettes/request_mozilla_org_callback_returns_true.yml +178 -0
- data/spec/cassettes/request_mozilla_org_with_system_cert.yml +152 -0
- data/spec/cassettes/request_mozilla_org_with_system_cert_and_callback.yml +151 -0
- data/spec/helpers.rb +54 -0
- data/spec/integration/_lib.rb +1 -0
- data/spec/integration/capath_digicert/README +8 -0
- data/spec/integration/capath_digicert/ce5e74ef.0 +1 -0
- data/spec/integration/capath_digicert/digicert.crt +20 -0
- data/spec/integration/capath_digicert/update +1 -0
- data/spec/integration/capath_verisign/415660c1.0 +14 -0
- data/spec/integration/capath_verisign/7651b327.0 +14 -0
- data/spec/integration/capath_verisign/README +8 -0
- data/spec/integration/capath_verisign/verisign.crt +14 -0
- data/spec/integration/certs/digicert.crt +20 -0
- data/spec/integration/certs/verisign.crt +14 -0
- data/spec/integration/httpbin_spec.rb +137 -0
- data/spec/integration/integration_spec.rb +118 -0
- data/spec/integration/request_spec.rb +134 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/unit/_lib.rb +1 -0
- data/spec/unit/abstract_response_spec.rb +145 -0
- data/spec/unit/exceptions_spec.rb +108 -0
- data/spec/unit/params_array_spec.rb +36 -0
- data/spec/unit/payload_spec.rb +295 -0
- data/spec/unit/raw_response_spec.rb +22 -0
- data/spec/unit/request2_spec.rb +54 -0
- data/spec/unit/request_spec.rb +1205 -0
- data/spec/unit/resource_spec.rb +134 -0
- data/spec/unit/response_spec.rb +252 -0
- data/spec/unit/restclient_spec.rb +80 -0
- data/spec/unit/utils_spec.rb +147 -0
- data/spec/unit/windows/root_certs_spec.rb +22 -0
- metadata +336 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
3
|
+
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
4
|
+
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
5
|
+
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
6
|
+
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
7
|
+
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
8
|
+
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
9
|
+
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
10
|
+
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
11
|
+
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
12
|
+
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
13
|
+
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
14
|
+
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
15
|
+
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
16
|
+
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
17
|
+
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
18
|
+
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
19
|
+
rqXRfboQnoZsG4q5WTP468SQvvG5
|
20
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,14 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
|
3
|
+
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
|
4
|
+
cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
|
5
|
+
MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
|
6
|
+
BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
|
7
|
+
YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
|
8
|
+
ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
|
9
|
+
BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
|
10
|
+
I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
|
11
|
+
CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
|
12
|
+
lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
|
13
|
+
AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
|
14
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'zlib'
|
5
|
+
|
6
|
+
describe RestMan::Request do
|
7
|
+
|
8
|
+
def default_httpbin_url
|
9
|
+
# add a hack to work around java/jruby bug
|
10
|
+
# java.lang.RuntimeException: Could not generate DH keypair with backtrace
|
11
|
+
# Also (2017-04-09) Travis Jruby versions have a broken CA keystore
|
12
|
+
if ENV['TRAVIS_RUBY_VERSION'] =~ /\Ajruby-/
|
13
|
+
'http://httpbin.org/'
|
14
|
+
else
|
15
|
+
'https://httpbin.org/'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def httpbin(suffix='')
|
20
|
+
url = ENV.fetch('HTTPBIN_URL', default_httpbin_url)
|
21
|
+
unless url.end_with?('/')
|
22
|
+
url += '/'
|
23
|
+
end
|
24
|
+
|
25
|
+
url + suffix
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_httpbin(suffix, opts={})
|
29
|
+
opts = {url: httpbin(suffix)}.merge(opts)
|
30
|
+
RestMan::Request.execute(opts)
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute_httpbin_json(suffix, opts={})
|
34
|
+
JSON.parse(execute_httpbin(suffix, opts))
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.execute' do
|
38
|
+
it 'sends a user agent' do
|
39
|
+
VCR.use_cassette("request_httpbin_with_user_agent") do
|
40
|
+
data = execute_httpbin_json('user-agent', method: :get)
|
41
|
+
expect(data['user-agent']).to match(/rest-man/)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'receives cookies on 302' do
|
46
|
+
VCR.use_cassette("request_httpbin_with_cookies") do
|
47
|
+
expect {
|
48
|
+
execute_httpbin('cookies/set?foo=bar', method: :get, max_redirects: 0)
|
49
|
+
}.to raise_error(RestMan::Found) { |ex|
|
50
|
+
expect(ex.http_code).to eq 302
|
51
|
+
expect(ex.response.cookies['foo']).to eq 'bar'
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'passes along cookies through 302' do
|
57
|
+
VCR.use_cassette("request_httpbin_with_cookies_2") do
|
58
|
+
data = execute_httpbin_json('cookies/set?foo=bar', method: :get)
|
59
|
+
expect(data).to have_key('cookies')
|
60
|
+
expect(data['cookies']['foo']).to eq 'bar'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'handles quote wrapped cookies' do
|
65
|
+
VCR.use_cassette("request_httpbin_with_cookies_3") do
|
66
|
+
expect {
|
67
|
+
execute_httpbin('cookies/set?foo=' + CGI.escape('"bar:baz"'),
|
68
|
+
method: :get, max_redirects: 0)
|
69
|
+
}.to raise_error(RestMan::Found) { |ex|
|
70
|
+
expect(ex.http_code).to eq 302
|
71
|
+
expect(ex.response.cookies['foo']).to eq '"bar:baz"'
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'sends basic auth' do
|
77
|
+
VCR.use_cassette("request_httpbin_with_basic_auth") do
|
78
|
+
user = 'user'
|
79
|
+
pass = 'pass'
|
80
|
+
|
81
|
+
data = execute_httpbin_json("basic-auth/#{user}/#{pass}", method: :get, user: user, password: pass)
|
82
|
+
expect(data).to eq({'authenticated' => true, 'user' => user})
|
83
|
+
|
84
|
+
expect {
|
85
|
+
execute_httpbin_json("basic-auth/#{user}/#{pass}", method: :get, user: user, password: 'badpass')
|
86
|
+
}.to raise_error(RestMan::Unauthorized) { |ex|
|
87
|
+
expect(ex.http_code).to eq 401
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'handles gzipped/deflated responses' do
|
93
|
+
[['gzip', 'gzipped'], ['deflate', 'deflated']].each do |encoding, var|
|
94
|
+
VCR.use_cassette("request_httpbin_with_encoding_#{encoding}") do
|
95
|
+
raw = execute_httpbin(encoding, method: :get)
|
96
|
+
|
97
|
+
begin
|
98
|
+
data = JSON.parse(raw)
|
99
|
+
rescue StandardError
|
100
|
+
puts "Failed to parse: " + raw.inspect
|
101
|
+
raise
|
102
|
+
end
|
103
|
+
|
104
|
+
expect(data['method']).to eq 'GET'
|
105
|
+
expect(data.fetch(var)).to be true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'does not uncompress response when accept-encoding is set' do
|
111
|
+
VCR.use_cassette("request_httpbin_with_encoding_gzip_and_accept_headers") do
|
112
|
+
# == gzip ==
|
113
|
+
raw = execute_httpbin('gzip', method: :get, headers: {accept_encoding: 'gzip, deflate'})
|
114
|
+
|
115
|
+
# check for gzip magic number
|
116
|
+
expect(raw.body).to start_with("\x1F\x8B".b)
|
117
|
+
|
118
|
+
decoded = Zlib::GzipReader.new(StringIO.new(raw.body)).read
|
119
|
+
parsed = JSON.parse(decoded)
|
120
|
+
|
121
|
+
expect(parsed['method']).to eq 'GET'
|
122
|
+
expect(parsed.fetch('gzipped')).to be true
|
123
|
+
end
|
124
|
+
|
125
|
+
VCR.use_cassette("request_httpbin_with_encoding_deflate_and_accept_headers") do
|
126
|
+
# == delate ==
|
127
|
+
raw = execute_httpbin('deflate', method: :get, headers: {accept_encoding: 'gzip, deflate'})
|
128
|
+
|
129
|
+
decoded = Zlib::Inflate.new.inflate(raw.body)
|
130
|
+
parsed = JSON.parse(decoded)
|
131
|
+
|
132
|
+
expect(parsed['method']).to eq 'GET'
|
133
|
+
expect(parsed.fetch('deflated')).to be true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '_lib'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
describe RestMan do
|
6
|
+
|
7
|
+
it "a simple request" do
|
8
|
+
body = 'abc'
|
9
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
|
10
|
+
response = RestMan.get "www.example.com"
|
11
|
+
expect(response.code).to eq 200
|
12
|
+
expect(response.body).to eq body
|
13
|
+
end
|
14
|
+
|
15
|
+
it "a 404" do
|
16
|
+
body = "Ho hai ! I'm not here !"
|
17
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)
|
18
|
+
begin
|
19
|
+
RestMan.get "www.example.com"
|
20
|
+
raise
|
21
|
+
rescue RestMan::ResourceNotFound => e
|
22
|
+
expect(e.http_code).to eq 404
|
23
|
+
expect(e.response.code).to eq 404
|
24
|
+
expect(e.response.body).to eq body
|
25
|
+
expect(e.http_body).to eq body
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'charset parsing' do
|
30
|
+
it 'handles utf-8' do
|
31
|
+
body = "λ".force_encoding('ASCII-8BIT')
|
32
|
+
stub_request(:get, "www.example.com").to_return(
|
33
|
+
:body => body, :status => 200, :headers => {
|
34
|
+
'Content-Type' => 'text/plain; charset=UTF-8'
|
35
|
+
})
|
36
|
+
response = RestMan.get "www.example.com"
|
37
|
+
expect(response.encoding).to eq Encoding::UTF_8
|
38
|
+
expect(response.valid_encoding?).to eq true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'handles windows-1252' do
|
42
|
+
body = "\xff".force_encoding('ASCII-8BIT')
|
43
|
+
stub_request(:get, "www.example.com").to_return(
|
44
|
+
:body => body, :status => 200, :headers => {
|
45
|
+
'Content-Type' => 'text/plain; charset=windows-1252'
|
46
|
+
})
|
47
|
+
response = RestMan.get "www.example.com"
|
48
|
+
expect(response.encoding).to eq Encoding::WINDOWS_1252
|
49
|
+
expect(response.encode('utf-8')).to eq "ÿ"
|
50
|
+
expect(response.valid_encoding?).to eq true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'handles binary' do
|
54
|
+
body = "\xfe".force_encoding('ASCII-8BIT')
|
55
|
+
stub_request(:get, "www.example.com").to_return(
|
56
|
+
:body => body, :status => 200, :headers => {
|
57
|
+
'Content-Type' => 'application/octet-stream; charset=binary'
|
58
|
+
})
|
59
|
+
response = RestMan.get "www.example.com"
|
60
|
+
expect(response.encoding).to eq Encoding::BINARY
|
61
|
+
expect {
|
62
|
+
response.encode('utf-8')
|
63
|
+
}.to raise_error(Encoding::UndefinedConversionError)
|
64
|
+
expect(response.valid_encoding?).to eq true
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'handles euc-jp' do
|
68
|
+
body = "\xA4\xA2\xA4\xA4\xA4\xA6\xA4\xA8\xA4\xAA".
|
69
|
+
force_encoding(Encoding::BINARY)
|
70
|
+
body_utf8 = 'あいうえお'
|
71
|
+
expect(body_utf8.encoding).to eq Encoding::UTF_8
|
72
|
+
|
73
|
+
stub_request(:get, 'www.example.com').to_return(
|
74
|
+
:body => body, :status => 200, :headers => {
|
75
|
+
'Content-Type' => 'text/plain; charset=EUC-JP'
|
76
|
+
})
|
77
|
+
response = RestMan.get 'www.example.com'
|
78
|
+
expect(response.encoding).to eq Encoding::EUC_JP
|
79
|
+
expect(response.valid_encoding?).to eq true
|
80
|
+
expect(response.length).to eq 5
|
81
|
+
expect(response.encode('utf-8')).to eq body_utf8
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'defaults to the default encoding' do
|
85
|
+
stub_request(:get, 'www.example.com').to_return(
|
86
|
+
body: 'abc', status: 200, headers: {
|
87
|
+
'Content-Type' => 'text/plain'
|
88
|
+
})
|
89
|
+
|
90
|
+
response = RestMan.get 'www.example.com'
|
91
|
+
# expect(response.encoding).to eq Encoding.default_external
|
92
|
+
expect(response.encoding).to eq Encoding::UTF_8
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'handles invalid encoding' do
|
96
|
+
stub_request(:get, 'www.example.com').to_return(
|
97
|
+
body: 'abc', status: 200, headers: {
|
98
|
+
'Content-Type' => 'text; charset=plain'
|
99
|
+
})
|
100
|
+
|
101
|
+
response = RestMan.get 'www.example.com'
|
102
|
+
# expect(response.encoding).to eq Encoding.default_external
|
103
|
+
expect(response.encoding).to eq Encoding::UTF_8
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'leaves images as binary' do
|
107
|
+
gif = Base64.strict_decode64('R0lGODlhAQABAAAAADs=')
|
108
|
+
|
109
|
+
stub_request(:get, 'www.example.com').to_return(
|
110
|
+
body: gif, status: 200, headers: {
|
111
|
+
'Content-Type' => 'image/gif'
|
112
|
+
})
|
113
|
+
|
114
|
+
response = RestMan.get 'www.example.com'
|
115
|
+
expect(response.encoding).to eq Encoding::BINARY
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
describe RestMan::Request do
|
4
|
+
|
5
|
+
describe "ssl verification" do
|
6
|
+
it "is successful with the correct ca_file" do
|
7
|
+
VCR.use_cassette('request_mozilla_org') do
|
8
|
+
request = RestMan::Request.new(
|
9
|
+
:method => :get,
|
10
|
+
:url => 'https://www.mozilla.org',
|
11
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "digicert.crt")
|
12
|
+
)
|
13
|
+
expect { request.execute }.to_not raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is successful with the correct ca_path" do
|
18
|
+
VCR.use_cassette('request_mozilla_org') do
|
19
|
+
request = RestMan::Request.new(
|
20
|
+
:method => :get,
|
21
|
+
:url => 'https://www.mozilla.org',
|
22
|
+
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_digicert")
|
23
|
+
)
|
24
|
+
expect { request.execute }.to_not raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "is unsuccessful with an incorrect ca_file", :unless => RestMan::Platform.mac_mri? do
|
29
|
+
VCR.use_cassette('request_mozilla_org_with_incorrect_ca_file') do
|
30
|
+
request = RestMan::Request.new(
|
31
|
+
:method => :get,
|
32
|
+
:url => 'https://www.mozilla.org',
|
33
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt")
|
34
|
+
)
|
35
|
+
expect { request.execute }.to raise_error(OpenSSL::SSL::SSLError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# On OS X, this test fails since Apple has patched OpenSSL to always fall
|
40
|
+
# back on the system CA store.
|
41
|
+
it "is unsuccessful with an incorrect ca_path", :unless => RestMan::Platform.mac_mri? do
|
42
|
+
VCR.use_cassette('request_mozilla_org_with_incorrect_ca_path') do
|
43
|
+
request = RestMan::Request.new(
|
44
|
+
:method => :get,
|
45
|
+
:url => 'https://www.mozilla.org',
|
46
|
+
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_verisign")
|
47
|
+
)
|
48
|
+
expect { request.execute }.to raise_error(OpenSSL::SSL::SSLError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "is successful using the default system cert store" do
|
53
|
+
VCR.use_cassette('request_mozilla_org_with_system_cert') do
|
54
|
+
request = RestMan::Request.new(
|
55
|
+
:method => :get,
|
56
|
+
:url => 'https://www.mozilla.org',
|
57
|
+
:verify_ssl => true,
|
58
|
+
)
|
59
|
+
expect {request.execute }.to_not raise_error
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# verify_callback is not works well with VCR
|
65
|
+
# it "executes the verify_callback", focus: true do
|
66
|
+
# ran_callback = false
|
67
|
+
# request = RestMan::Request.new(
|
68
|
+
# :method => :get,
|
69
|
+
# :url => 'https://www.mozilla.org',
|
70
|
+
# :verify_ssl => true,
|
71
|
+
# :ssl_verify_callback => lambda { |preverify_ok, store_ctx|
|
72
|
+
# ran_callback = true
|
73
|
+
# preverify_ok
|
74
|
+
# },
|
75
|
+
# )
|
76
|
+
# expect {request.execute }.to_not raise_error
|
77
|
+
# expect(ran_callback).to eq(true)
|
78
|
+
# end
|
79
|
+
|
80
|
+
it "fails verification when the callback returns false",
|
81
|
+
:unless => RestMan::Platform.mac_mri? do
|
82
|
+
VCR.use_cassette('request_mozilla_org_callback_returns_false') do
|
83
|
+
request = RestMan::Request.new(
|
84
|
+
:method => :get,
|
85
|
+
:url => 'https://www.mozilla.org',
|
86
|
+
:verify_ssl => true,
|
87
|
+
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| false },
|
88
|
+
)
|
89
|
+
expect { request.execute }.to raise_error(OpenSSL::SSL::SSLError)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "succeeds verification when the callback returns true",
|
94
|
+
:unless => RestMan::Platform.mac_mri? do
|
95
|
+
VCR.use_cassette('request_mozilla_org_callback_returns_true') do
|
96
|
+
request = RestMan::Request.new(
|
97
|
+
:method => :get,
|
98
|
+
:url => 'https://www.mozilla.org',
|
99
|
+
:verify_ssl => true,
|
100
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt"),
|
101
|
+
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| true },
|
102
|
+
)
|
103
|
+
expect { request.execute }.to_not raise_error
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "timeouts" do
|
109
|
+
it "raises OpenTimeout when it hits an open timeout" do
|
110
|
+
allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(Net::OpenTimeout.new)
|
111
|
+
|
112
|
+
request = RestMan::Request.new(
|
113
|
+
:method => :get,
|
114
|
+
:url => 'http://www.mozilla.org',
|
115
|
+
:open_timeout => 1e-10,
|
116
|
+
)
|
117
|
+
expect { request.execute }.to(
|
118
|
+
raise_error(RestMan::Exceptions::OpenTimeout))
|
119
|
+
end
|
120
|
+
|
121
|
+
it "raises ReadTimeout when it hits a read timeout via :read_timeout" do
|
122
|
+
allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(Net::ReadTimeout.new)
|
123
|
+
|
124
|
+
request = RestMan::Request.new(
|
125
|
+
:method => :get,
|
126
|
+
:url => 'https://www.mozilla.org',
|
127
|
+
:read_timeout => 1e-10,
|
128
|
+
)
|
129
|
+
expect { request.execute }.to(
|
130
|
+
raise_error(RestMan::Exceptions::ReadTimeout))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
require 'rest-man'
|
3
|
+
|
4
|
+
require_relative './helpers'
|
5
|
+
require 'byebug' unless RUBY_PLATFORM == 'java'
|
6
|
+
require 'ruby-debug' if RUBY_PLATFORM == 'java'
|
7
|
+
require 'vcr'
|
8
|
+
|
9
|
+
VCR.configure do |config|
|
10
|
+
config.default_cassette_options = { match_requests_on: %i[uri method] }
|
11
|
+
config.cassette_library_dir = 'spec/cassettes'
|
12
|
+
config.hook_into :webmock
|
13
|
+
end
|
14
|
+
|
15
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.raise_errors_for_deprecations!
|
18
|
+
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
21
|
+
# the seed, which is printed after each run.
|
22
|
+
# --seed 1234
|
23
|
+
config.order = 'random'
|
24
|
+
|
25
|
+
# always run with ruby warnings enabled
|
26
|
+
# TODO: figure out why this is so obscenely noisy (rspec bug?)
|
27
|
+
# config.warnings = true
|
28
|
+
|
29
|
+
# add helpers
|
30
|
+
config.include Helpers, :include_helpers
|
31
|
+
|
32
|
+
config.filter_run_when_matching :focus
|
33
|
+
|
34
|
+
config.mock_with :rspec do |mocks|
|
35
|
+
mocks.yield_receiver_to_any_instance_implementation_blocks = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# always run with ruby warnings enabled (see above)
|
40
|
+
$VERBOSE = true
|
data/spec/unit/_lib.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../spec_helper'
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
describe RestMan::AbstractResponse, :include_helpers do
|
4
|
+
|
5
|
+
# Sample class implementing AbstractResponse used for testing.
|
6
|
+
class MyAbstractResponse
|
7
|
+
|
8
|
+
include RestMan::AbstractResponse
|
9
|
+
|
10
|
+
attr_accessor :size
|
11
|
+
|
12
|
+
def initialize(net_http_res, request)
|
13
|
+
response_set_vars(net_http_res, request, Time.now - 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
@net_http_res = res_double()
|
20
|
+
@request = request_double(url: 'http://example.com', method: 'get')
|
21
|
+
@response = MyAbstractResponse.new(@net_http_res, @request)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fetches the numeric response code" do
|
25
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
26
|
+
expect(@response.code).to eq 200
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has a nice description" do
|
30
|
+
expect(@net_http_res).to receive(:to_hash).and_return({'Content-Type' => ['application/pdf']})
|
31
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
32
|
+
expect(@response.description).to eq "200 OK | application/pdf bytes\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.beautify_headers' do
|
36
|
+
it "beautifies the headers by turning the keys to symbols" do
|
37
|
+
h = RestMan::AbstractResponse.beautify_headers('content-type' => [ 'x' ])
|
38
|
+
expect(h.keys.first).to eq :content_type
|
39
|
+
end
|
40
|
+
|
41
|
+
it "beautifies the headers by turning the values to strings instead of one-element arrays" do
|
42
|
+
h = RestMan::AbstractResponse.beautify_headers('x' => [ 'text/html' ] )
|
43
|
+
expect(h.values.first).to eq 'text/html'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'joins multiple header values by comma' do
|
47
|
+
expect(RestMan::AbstractResponse.beautify_headers(
|
48
|
+
{'My-Header' => ['one', 'two']}
|
49
|
+
)).to eq({:my_header => 'one, two'})
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'leaves set-cookie headers as array' do
|
53
|
+
expect(RestMan::AbstractResponse.beautify_headers(
|
54
|
+
{'Set-Cookie' => ['cookie1=foo', 'cookie2=bar']}
|
55
|
+
)).to eq({:set_cookie => ['cookie1=foo', 'cookie2=bar']})
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "fetches the headers" do
|
60
|
+
expect(@net_http_res).to receive(:to_hash).and_return('content-type' => [ 'text/html' ])
|
61
|
+
expect(@response.headers).to eq({ :content_type => 'text/html' })
|
62
|
+
end
|
63
|
+
|
64
|
+
it "extracts cookies from response headers" do
|
65
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
66
|
+
expect(@response.cookies).to eq({ 'session_id' => '1' })
|
67
|
+
end
|
68
|
+
|
69
|
+
it "extract strange cookies" do
|
70
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/'])
|
71
|
+
expect(@response.headers).to eq({:set_cookie => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/']})
|
72
|
+
expect(@response.cookies).to eq({ 'session_id' => 'ZJ/HQVH6YE+rVkTpn0zvTQ==' })
|
73
|
+
end
|
74
|
+
|
75
|
+
it "doesn't escape cookies" do
|
76
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/'])
|
77
|
+
expect(@response.cookies).to eq({ 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' })
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.cookie_jar' do
|
81
|
+
it 'extracts cookies into cookie jar' do
|
82
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
83
|
+
expect(@response.cookie_jar).to be_a HTTP::CookieJar
|
84
|
+
|
85
|
+
cookie = @response.cookie_jar.cookies.first
|
86
|
+
expect(cookie.domain).to eq 'example.com'
|
87
|
+
expect(cookie.name).to eq 'session_id'
|
88
|
+
expect(cookie.value).to eq '1'
|
89
|
+
expect(cookie.path).to eq '/'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'handles cookies when URI scheme is implicit' do
|
93
|
+
net_http_res = double('net http response')
|
94
|
+
expect(net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
95
|
+
request = double('request', url: 'example.com', uri: URI.parse('http://example.com'),
|
96
|
+
method: 'get', cookie_jar: HTTP::CookieJar.new, redirection_history: nil)
|
97
|
+
response = MyAbstractResponse.new(net_http_res, request)
|
98
|
+
expect(response.cookie_jar).to be_a HTTP::CookieJar
|
99
|
+
|
100
|
+
cookie = response.cookie_jar.cookies.first
|
101
|
+
expect(cookie.domain).to eq 'example.com'
|
102
|
+
expect(cookie.name).to eq 'session_id'
|
103
|
+
expect(cookie.value).to eq '1'
|
104
|
+
expect(cookie.path).to eq '/'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "can access the net http result directly" do
|
109
|
+
expect(@response.net_http_res).to eq @net_http_res
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#return!" do
|
113
|
+
it "should return the response itself on 200-codes" do
|
114
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
115
|
+
expect(@response.return!).to be_equal(@response)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should raise RequestFailed on unknown codes" do
|
119
|
+
expect(@net_http_res).to receive(:code).and_return('1000')
|
120
|
+
expect { @response.return! }.to raise_error RestMan::RequestFailed
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should raise an error on a redirection after non-GET/HEAD requests" do
|
124
|
+
expect(@net_http_res).to receive(:code).and_return('301')
|
125
|
+
expect(@request).to receive(:method).and_return('put')
|
126
|
+
expect(@response).not_to receive(:follow_redirection)
|
127
|
+
expect { @response.return! }.to raise_error RestMan::RequestFailed
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should follow 302 redirect" do
|
131
|
+
expect(@net_http_res).to receive(:code).and_return('302')
|
132
|
+
expect(@response).to receive(:check_max_redirects).and_return('fake-check')
|
133
|
+
expect(@response).to receive(:follow_redirection).and_return('fake-redirection')
|
134
|
+
expect(@response.return!).to eq 'fake-redirection'
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should gracefully handle 302 redirect with no location header" do
|
138
|
+
@net_http_res = res_double(code: 302)
|
139
|
+
@request = request_double()
|
140
|
+
@response = MyAbstractResponse.new(@net_http_res, @request)
|
141
|
+
expect(@response).to receive(:check_max_redirects).and_return('fake-check')
|
142
|
+
expect { @response.return! }.to raise_error RestMan::Found
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|