rest-man 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/multi-matrix-test.yml +35 -0
  3. data/.github/workflows/single-matrix-test.yml +27 -0
  4. data/.gitignore +13 -0
  5. data/.mailmap +10 -0
  6. data/.rspec +2 -0
  7. data/.rubocop +2 -0
  8. data/.rubocop-disables.yml +386 -0
  9. data/.rubocop.yml +8 -0
  10. data/AUTHORS +106 -0
  11. data/CHANGELOG.md +7 -0
  12. data/Gemfile +11 -0
  13. data/LICENSE +21 -0
  14. data/README.md +843 -0
  15. data/Rakefile +140 -0
  16. data/exe/restman +92 -0
  17. data/lib/rest-man.rb +2 -0
  18. data/lib/rest_man.rb +2 -0
  19. data/lib/restman/abstract_response.rb +252 -0
  20. data/lib/restman/exceptions.rb +238 -0
  21. data/lib/restman/params_array.rb +72 -0
  22. data/lib/restman/payload.rb +234 -0
  23. data/lib/restman/platform.rb +49 -0
  24. data/lib/restman/raw_response.rb +49 -0
  25. data/lib/restman/request.rb +859 -0
  26. data/lib/restman/resource.rb +178 -0
  27. data/lib/restman/response.rb +90 -0
  28. data/lib/restman/utils.rb +274 -0
  29. data/lib/restman/version.rb +8 -0
  30. data/lib/restman/windows/root_certs.rb +105 -0
  31. data/lib/restman/windows.rb +8 -0
  32. data/lib/restman.rb +183 -0
  33. data/matrixeval.yml +73 -0
  34. data/rest-man.gemspec +41 -0
  35. data/spec/ISS.jpg +0 -0
  36. data/spec/cassettes/request_httpbin_with_basic_auth.yml +83 -0
  37. data/spec/cassettes/request_httpbin_with_cookies.yml +49 -0
  38. data/spec/cassettes/request_httpbin_with_cookies_2.yml +94 -0
  39. data/spec/cassettes/request_httpbin_with_cookies_3.yml +49 -0
  40. data/spec/cassettes/request_httpbin_with_encoding_deflate.yml +45 -0
  41. data/spec/cassettes/request_httpbin_with_encoding_deflate_and_accept_headers.yml +44 -0
  42. data/spec/cassettes/request_httpbin_with_encoding_gzip.yml +45 -0
  43. data/spec/cassettes/request_httpbin_with_encoding_gzip_and_accept_headers.yml +44 -0
  44. data/spec/cassettes/request_httpbin_with_user_agent.yml +44 -0
  45. data/spec/cassettes/request_mozilla_org.yml +151 -0
  46. data/spec/cassettes/request_mozilla_org_callback_returns_true.yml +178 -0
  47. data/spec/cassettes/request_mozilla_org_with_system_cert.yml +152 -0
  48. data/spec/cassettes/request_mozilla_org_with_system_cert_and_callback.yml +151 -0
  49. data/spec/helpers.rb +54 -0
  50. data/spec/integration/_lib.rb +1 -0
  51. data/spec/integration/capath_digicert/README +8 -0
  52. data/spec/integration/capath_digicert/ce5e74ef.0 +1 -0
  53. data/spec/integration/capath_digicert/digicert.crt +20 -0
  54. data/spec/integration/capath_digicert/update +1 -0
  55. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  56. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  57. data/spec/integration/capath_verisign/README +8 -0
  58. data/spec/integration/capath_verisign/verisign.crt +14 -0
  59. data/spec/integration/certs/digicert.crt +20 -0
  60. data/spec/integration/certs/verisign.crt +14 -0
  61. data/spec/integration/httpbin_spec.rb +137 -0
  62. data/spec/integration/integration_spec.rb +118 -0
  63. data/spec/integration/request_spec.rb +134 -0
  64. data/spec/spec_helper.rb +40 -0
  65. data/spec/unit/_lib.rb +1 -0
  66. data/spec/unit/abstract_response_spec.rb +145 -0
  67. data/spec/unit/exceptions_spec.rb +108 -0
  68. data/spec/unit/params_array_spec.rb +36 -0
  69. data/spec/unit/payload_spec.rb +295 -0
  70. data/spec/unit/raw_response_spec.rb +22 -0
  71. data/spec/unit/request2_spec.rb +54 -0
  72. data/spec/unit/request_spec.rb +1205 -0
  73. data/spec/unit/resource_spec.rb +134 -0
  74. data/spec/unit/response_spec.rb +252 -0
  75. data/spec/unit/restclient_spec.rb +80 -0
  76. data/spec/unit/utils_spec.rb +147 -0
  77. data/spec/unit/windows/root_certs_spec.rb +22 -0
  78. metadata +336 -0
@@ -0,0 +1,134 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestMan::Resource do
4
+ before do
5
+ @resource = RestMan::Resource.new('http://some/resource', :user => 'jane', :password => 'mypass', :headers => {'X-Something' => '1'})
6
+ end
7
+
8
+ context "Resource delegation" do
9
+ it "GET" do
10
+ expect(RestMan::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil)
11
+ @resource.get
12
+ end
13
+
14
+ it "HEAD" do
15
+ expect(RestMan::Request).to receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil)
16
+ @resource.head
17
+ end
18
+
19
+ it "POST" do
20
+ expect(RestMan::Request).to receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil)
21
+ @resource.post 'abc', :content_type => 'image/jpg'
22
+ end
23
+
24
+ it "PUT" do
25
+ expect(RestMan::Request).to receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil)
26
+ @resource.put 'abc', :content_type => 'image/jpg'
27
+ end
28
+
29
+ it "PATCH" do
30
+ expect(RestMan::Request).to receive(:execute).with(:method => :patch, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil)
31
+ @resource.patch 'abc', :content_type => 'image/jpg'
32
+ end
33
+
34
+ it "DELETE" do
35
+ expect(RestMan::Request).to receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil)
36
+ @resource.delete
37
+ end
38
+
39
+ it "overrides resource headers" do
40
+ expect(RestMan::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '2'}, :user => 'jane', :password => 'mypass', :log => nil)
41
+ @resource.get 'X-Something' => '2'
42
+ end
43
+ end
44
+
45
+ it "can instantiate with no user/password" do
46
+ @resource = RestMan::Resource.new('http://some/resource')
47
+ end
48
+
49
+ it "is backwards compatible with previous constructor" do
50
+ @resource = RestMan::Resource.new('http://some/resource', 'user', 'pass')
51
+ expect(@resource.user).to eq 'user'
52
+ expect(@resource.password).to eq 'pass'
53
+ end
54
+
55
+ it "concatenates urls, inserting a slash when it needs one" do
56
+ expect(@resource.concat_urls('http://example.com', 'resource')).to eq 'http://example.com/resource'
57
+ end
58
+
59
+ it "concatenates urls, using no slash if the first url ends with a slash" do
60
+ expect(@resource.concat_urls('http://example.com/', 'resource')).to eq 'http://example.com/resource'
61
+ end
62
+
63
+ it "concatenates urls, using no slash if the second url starts with a slash" do
64
+ expect(@resource.concat_urls('http://example.com', '/resource')).to eq 'http://example.com/resource'
65
+ end
66
+
67
+ it "concatenates even non-string urls, :posts + 1 => 'posts/1'" do
68
+ expect(@resource.concat_urls(:posts, 1)).to eq 'posts/1'
69
+ end
70
+
71
+ it "offers subresources via []" do
72
+ parent = RestMan::Resource.new('http://example.com')
73
+ expect(parent['posts'].url).to eq 'http://example.com/posts'
74
+ end
75
+
76
+ it "transports options to subresources" do
77
+ parent = RestMan::Resource.new('http://example.com', :user => 'user', :password => 'password')
78
+ expect(parent['posts'].user).to eq 'user'
79
+ expect(parent['posts'].password).to eq 'password'
80
+ end
81
+
82
+ it "passes a given block to subresources" do
83
+ block = proc {|r| r}
84
+ parent = RestMan::Resource.new('http://example.com', &block)
85
+ expect(parent['posts'].block).to eq block
86
+ end
87
+
88
+ it "the block should be overrideable" do
89
+ block1 = proc {|r| r}
90
+ block2 = proc {|r| }
91
+ parent = RestMan::Resource.new('http://example.com', &block1)
92
+ # parent['posts', &block2].block.should eq block2 # ruby 1.9 syntax
93
+ expect(parent.send(:[], 'posts', &block2).block).to eq block2
94
+ expect(parent.send(:[], 'posts', &block2).block).not_to eq block1
95
+ end
96
+
97
+ # Test fails on jruby 9.1.[0-5].* due to
98
+ # https://github.com/jruby/jruby/issues/4217
99
+ it "the block should be overrideable in ruby 1.9 syntax",
100
+ :unless => (RUBY_ENGINE == 'jruby' && JRUBY_VERSION =~ /\A9\.1\.[0-5]\./) \
101
+ do
102
+ block1 = proc {|r| r}
103
+ block2 = ->(r) {}
104
+
105
+ parent = RestMan::Resource.new('http://example.com', &block1)
106
+ expect(parent['posts', &block2].block).to eq block2
107
+ expect(parent['posts', &block2].block).not_to eq block1
108
+ end
109
+
110
+ it "prints its url with to_s" do
111
+ expect(RestMan::Resource.new('x').to_s).to eq 'x'
112
+ end
113
+
114
+ describe 'block' do
115
+ it 'can use block when creating the resource' do
116
+ stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404)
117
+ resource = RestMan::Resource.new('www.example.com') { |response, request| 'foo' }
118
+ expect(resource.get).to eq 'foo'
119
+ end
120
+
121
+ it 'can use block when executing the resource' do
122
+ stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404)
123
+ resource = RestMan::Resource.new('www.example.com')
124
+ expect(resource.get { |response, request| 'foo' }).to eq 'foo'
125
+ end
126
+
127
+ it 'execution block override resource block' do
128
+ stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404)
129
+ resource = RestMan::Resource.new('www.example.com') { |response, request| 'foo' }
130
+ expect(resource.get { |response, request| 'bar' }).to eq 'bar'
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,252 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestMan::Response, :include_helpers do
4
+ before do
5
+ @net_http_res = res_double(to_hash: {'Status' => ['200 OK']}, code: '200', body: 'abc')
6
+ @example_url = 'http://example.com'
7
+ @request = request_double(url: @example_url, method: 'get')
8
+ @response = response_from_res_double(@net_http_res, @request, duration: 1)
9
+ end
10
+
11
+ it "behaves like string" do
12
+ expect(@response.to_s).to eq 'abc'
13
+ expect(@response.to_str).to eq 'abc'
14
+
15
+ expect(@response).to receive(:warn)
16
+ expect(@response.to_i).to eq 0
17
+ end
18
+
19
+ it "accepts nil strings and sets it to empty for the case of HEAD" do
20
+ # TODO
21
+ expect(RestMan::Response.create(nil, @net_http_res, @request).to_s).to eq ""
22
+ end
23
+
24
+ describe 'header processing' do
25
+ it "test headers and raw headers" do
26
+ expect(@response.raw_headers["Status"][0]).to eq "200 OK"
27
+ expect(@response.headers[:status]).to eq "200 OK"
28
+ end
29
+
30
+ it 'handles multiple headers by joining with comma' do
31
+ net_http_res = res_double(to_hash: {'My-Header' => ['foo', 'bar']}, code: '200', body: nil)
32
+ example_url = 'http://example.com'
33
+ request = request_double(url: example_url, method: 'get')
34
+ response = response_from_res_double(net_http_res, request)
35
+
36
+ expect(response.raw_headers['My-Header']).to eq ['foo', 'bar']
37
+ expect(response.headers[:my_header]).to eq 'foo, bar'
38
+ end
39
+ end
40
+
41
+ describe "cookie processing" do
42
+ it "should correctly deal with one Set-Cookie header with one cookie inside" do
43
+ header_val = "main_page=main_page_no_rewrite; path=/; expires=Sat, 10-Jan-2037 15:03:14 GMT".freeze
44
+
45
+ net_http_res = double('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => [header_val]})
46
+ response = RestMan::Response.create('abc', net_http_res, @request)
47
+ expect(response.headers[:set_cookie]).to eq [header_val]
48
+ expect(response.cookies).to eq({ "main_page" => "main_page_no_rewrite" })
49
+ end
50
+
51
+ it "should correctly deal with multiple cookies [multiple Set-Cookie headers]" do
52
+ net_http_res = double('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Sat, 10-Jan-2037 15:03:14 GMT", "remember_me=; path=/; expires=Sat, 10-Jan-2037 00:00:00 GMT", "user=somebody; path=/; expires=Sat, 10-Jan-2037 00:00:00 GMT"]})
53
+ response = RestMan::Response.create('abc', net_http_res, @request)
54
+ expect(response.headers[:set_cookie]).to eq ["main_page=main_page_no_rewrite; path=/; expires=Sat, 10-Jan-2037 15:03:14 GMT", "remember_me=; path=/; expires=Sat, 10-Jan-2037 00:00:00 GMT", "user=somebody; path=/; expires=Sat, 10-Jan-2037 00:00:00 GMT"]
55
+ expect(response.cookies).to eq({
56
+ "main_page" => "main_page_no_rewrite",
57
+ "remember_me" => "",
58
+ "user" => "somebody"
59
+ })
60
+ end
61
+
62
+ it "should correctly deal with multiple cookies [one Set-Cookie header with multiple cookies]" do
63
+ net_http_res = double('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Sat, 10-Jan-2037 15:03:14 GMT, remember_me=; path=/; expires=Sat, 10-Jan-2037 00:00:00 GMT, user=somebody; path=/; expires=Sat, 10-Jan-2037 00:00:00 GMT"]})
64
+ response = RestMan::Response.create('abc', net_http_res, @request)
65
+ expect(response.cookies).to eq({
66
+ "main_page" => "main_page_no_rewrite",
67
+ "remember_me" => "",
68
+ "user" => "somebody"
69
+ })
70
+ end
71
+ end
72
+
73
+ describe "exceptions processing" do
74
+ it "should return itself for normal codes" do
75
+ (200..206).each do |code|
76
+ net_http_res = res_double(:code => '200')
77
+ resp = RestMan::Response.create('abc', net_http_res, @request)
78
+ resp.return!
79
+ end
80
+ end
81
+
82
+ it "should throw an exception for other codes" do
83
+ RestMan::Exceptions::EXCEPTIONS_MAP.each_pair do |code, exc|
84
+ unless (200..207).include? code
85
+ net_http_res = res_double(:code => code.to_i)
86
+ resp = RestMan::Response.create('abc', net_http_res, @request)
87
+ allow(@request).to receive(:max_redirects).and_return(5)
88
+ expect { resp.return! }.to raise_error(exc)
89
+ end
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ describe "redirection" do
96
+
97
+ it "follows a redirection when the request is a get" do
98
+ stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'})
99
+ stub_request(:get, 'http://new/resource').to_return(:body => 'Foo')
100
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :get).body).to eq 'Foo'
101
+ end
102
+
103
+ it "keeps redirection history" do
104
+ stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'})
105
+ stub_request(:get, 'http://new/resource').to_return(:body => 'Foo')
106
+ r = RestMan::Request.execute(url: 'http://some/resource', method: :get)
107
+ expect(r.body).to eq 'Foo'
108
+ expect(r.history.length).to eq 1
109
+ expect(r.history.fetch(0)).to be_a(RestMan::Response)
110
+ expect(r.history.fetch(0).code).to be 301
111
+ end
112
+
113
+ it "follows a redirection and keep the parameters" do
114
+ stub_request(:get, 'http://some/resource').with(:headers => {'Accept' => 'application/json'}, :basic_auth => ['foo', 'bar']).to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'})
115
+ stub_request(:get, 'http://new/resource').with(:headers => {'Accept' => 'application/json'}, :basic_auth => ['foo', 'bar']).to_return(:body => 'Foo')
116
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :get, :user => 'foo', :password => 'bar', :headers => {:accept => :json}).body).to eq 'Foo'
117
+ end
118
+
119
+ it "follows a redirection and keep the cookies" do
120
+ stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Set-Cookie' => 'Foo=Bar', 'Location' => 'http://some/new_resource', })
121
+ stub_request(:get, 'http://some/new_resource').with(:headers => {'Cookie' => 'Foo=Bar'}).to_return(:body => 'Qux')
122
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :get).body).to eq 'Qux'
123
+ end
124
+
125
+ it 'respects cookie domains on redirect' do
126
+ stub_request(:get, 'http://some.example.com/').to_return(:body => '', :status => 301,
127
+ :headers => {'Set-Cookie' => 'Foo=Bar', 'Location' => 'http://new.example.com/', })
128
+ stub_request(:get, 'http://new.example.com/').with(
129
+ :headers => {'Cookie' => 'passedthrough=1'}).to_return(:body => 'Qux')
130
+
131
+ expect(RestMan::Request.execute(:url => 'http://some.example.com/', :method => :get, cookies: [HTTP::Cookie.new('passedthrough', '1', domain: 'new.example.com', path: '/')]).body).to eq 'Qux'
132
+ end
133
+
134
+ it "doesn't follow a 301 when the request is a post" do
135
+ net_http_res = res_double(:code => 301)
136
+ response = response_from_res_double(net_http_res, request_double(method: 'post'))
137
+
138
+ expect {
139
+ response.return!
140
+ }.to raise_error(RestMan::MovedPermanently)
141
+ end
142
+
143
+ it "doesn't follow a 302 when the request is a post" do
144
+ net_http_res = res_double(:code => 302)
145
+ response = response_from_res_double(net_http_res, request_double(method: 'post'))
146
+
147
+ expect {
148
+ response.return!
149
+ }.to raise_error(RestMan::Found)
150
+ end
151
+
152
+ it "doesn't follow a 307 when the request is a post" do
153
+ net_http_res = res_double(:code => 307)
154
+ response = response_from_res_double(net_http_res, request_double(method: 'post'))
155
+
156
+ expect(response).not_to receive(:follow_redirection)
157
+ expect {
158
+ response.return!
159
+ }.to raise_error(RestMan::TemporaryRedirect)
160
+ end
161
+
162
+ it "doesn't follow a redirection when the request is a put" do
163
+ net_http_res = res_double(:code => 301)
164
+ response = response_from_res_double(net_http_res, request_double(method: 'put'))
165
+ expect {
166
+ response.return!
167
+ }.to raise_error(RestMan::MovedPermanently)
168
+ end
169
+
170
+ it "follows a redirection when the request is a post and result is a 303" do
171
+ stub_request(:put, 'http://some/resource').to_return(:body => '', :status => 303, :headers => {'Location' => 'http://new/resource'})
172
+ stub_request(:get, 'http://new/resource').to_return(:body => 'Foo')
173
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :put).body).to eq 'Foo'
174
+ end
175
+
176
+ it "follows a redirection when the request is a head" do
177
+ stub_request(:head, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'})
178
+ stub_request(:head, 'http://new/resource').to_return(:body => 'Foo')
179
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :head).body).to eq 'Foo'
180
+ end
181
+
182
+ it "handles redirects with relative paths" do
183
+ stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'index'})
184
+ stub_request(:get, 'http://some/index').to_return(:body => 'Foo')
185
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :get).body).to eq 'Foo'
186
+ end
187
+
188
+ it "handles redirects with relative path and query string" do
189
+ stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'index?q=1'})
190
+ stub_request(:get, 'http://some/index?q=1').to_return(:body => 'Foo')
191
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :get).body).to eq 'Foo'
192
+ end
193
+
194
+ it "follow a redirection when the request is a get and the response is in the 30x range" do
195
+ stub_request(:get, 'http://some/resource').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'})
196
+ stub_request(:get, 'http://new/resource').to_return(:body => 'Foo')
197
+ expect(RestMan::Request.execute(:url => 'http://some/resource', :method => :get).body).to eq 'Foo'
198
+ end
199
+
200
+ it "follows no more than 10 redirections before raising error" do
201
+ stub_request(:get, 'http://some/redirect-1').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'})
202
+ stub_request(:get, 'http://some/redirect-2').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'})
203
+ expect {
204
+ RestMan::Request.execute(url: 'http://some/redirect-1', method: :get)
205
+ }.to raise_error(RestMan::MovedPermanently) { |ex|
206
+ ex.response.history.each {|r| expect(r).to be_a(RestMan::Response) }
207
+ expect(ex.response.history.length).to eq 10
208
+ }
209
+ expect(WebMock).to have_requested(:get, 'http://some/redirect-2').times(10)
210
+ end
211
+
212
+ it "follows no more than max_redirects redirections, if specified" do
213
+ stub_request(:get, 'http://some/redirect-1').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'})
214
+ stub_request(:get, 'http://some/redirect-2').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/redirect-2'})
215
+ expect {
216
+ RestMan::Request.execute(url: 'http://some/redirect-1', method: :get, max_redirects: 5)
217
+ }.to raise_error(RestMan::MovedPermanently) { |ex|
218
+ expect(ex.response.history.length).to eq 5
219
+ }
220
+ expect(WebMock).to have_requested(:get, 'http://some/redirect-2').times(5)
221
+ end
222
+
223
+ it "allows for manual following of redirects" do
224
+ stub_request(:get, 'http://some/redirect-1').to_return(:body => '', :status => 301, :headers => {'Location' => 'http://some/resource'})
225
+ stub_request(:get, 'http://some/resource').to_return(:body => 'Qux', :status => 200)
226
+
227
+ begin
228
+ RestMan::Request.execute(url: 'http://some/redirect-1', method: :get, max_redirects: 0)
229
+ rescue RestMan::MovedPermanently => err
230
+ resp = err.response.follow_redirection
231
+ else
232
+ raise 'notreached'
233
+ end
234
+
235
+ expect(resp.code).to eq 200
236
+ expect(resp.body).to eq 'Qux'
237
+ end
238
+ end
239
+
240
+ describe "logging" do
241
+ it "uses the request's logger" do
242
+ stub_request(:get, 'http://some/resource').to_return(body: 'potato', status: 200)
243
+
244
+ logger = double('logger', '<<' => true)
245
+ request = RestMan::Request.new(url: 'http://some/resource', method: :get, log: logger)
246
+
247
+ expect(logger).to receive(:<<)
248
+
249
+ request.execute
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,80 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestMan do
4
+ describe "API" do
5
+ it "GET" do
6
+ expect(RestMan::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {})
7
+ RestMan.get('http://some/resource')
8
+ end
9
+
10
+ it "POST" do
11
+ expect(RestMan::Request).to receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'payload', :headers => {})
12
+ RestMan.post('http://some/resource', 'payload')
13
+ end
14
+
15
+ it "PUT" do
16
+ expect(RestMan::Request).to receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'payload', :headers => {})
17
+ RestMan.put('http://some/resource', 'payload')
18
+ end
19
+
20
+ it "PATCH" do
21
+ expect(RestMan::Request).to receive(:execute).with(:method => :patch, :url => 'http://some/resource', :payload => 'payload', :headers => {})
22
+ RestMan.patch('http://some/resource', 'payload')
23
+ end
24
+
25
+ it "DELETE" do
26
+ expect(RestMan::Request).to receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {})
27
+ RestMan.delete('http://some/resource')
28
+ end
29
+
30
+ it "HEAD" do
31
+ expect(RestMan::Request).to receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {})
32
+ RestMan.head('http://some/resource')
33
+ end
34
+
35
+ it "OPTIONS" do
36
+ expect(RestMan::Request).to receive(:execute).with(:method => :options, :url => 'http://some/resource', :headers => {})
37
+ RestMan.options('http://some/resource')
38
+ end
39
+ end
40
+
41
+ describe "logging" do
42
+ after do
43
+ RestMan.log = nil
44
+ end
45
+
46
+ it "uses << if the log is not a string" do
47
+ log = RestMan.log = []
48
+ expect(log).to receive(:<<).with('xyz')
49
+ RestMan.log << 'xyz'
50
+ end
51
+
52
+ it "displays the log to stdout" do
53
+ RestMan.log = 'stdout'
54
+ expect(STDOUT).to receive(:puts).with('xyz')
55
+ RestMan.log << 'xyz'
56
+ end
57
+
58
+ it "displays the log to stderr" do
59
+ RestMan.log = 'stderr'
60
+ expect(STDERR).to receive(:puts).with('xyz')
61
+ RestMan.log << 'xyz'
62
+ end
63
+
64
+ it "append the log to the requested filename" do
65
+ RestMan.log = '/tmp/restman.log'
66
+ f = double('file handle')
67
+ expect(File).to receive(:open).with('/tmp/restman.log', 'a').and_yield(f)
68
+ expect(f).to receive(:puts).with('xyz')
69
+ RestMan.log << 'xyz'
70
+ end
71
+ end
72
+
73
+ describe 'version' do
74
+ # test that there is a sane version number to avoid accidental 0.0.0 again
75
+ it 'has a version > 1.0.0.alpha, < 2.0' do
76
+ ver = Gem::Version.new(RestMan.version)
77
+ expect(Gem::Requirement.new('> 1.0.0.alpha', '< 2.0')).to be_satisfied_by(ver)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,147 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestMan::Utils do
4
+ describe '.get_encoding_from_headers' do
5
+ it 'assumes no encoding by default for text' do
6
+ headers = {:content_type => 'text/plain'}
7
+ expect(RestMan::Utils.get_encoding_from_headers(headers)).
8
+ to eq nil
9
+ end
10
+
11
+ it 'returns nil on failures' do
12
+ expect(RestMan::Utils.get_encoding_from_headers(
13
+ {:content_type => 'blah'})).to eq nil
14
+ expect(RestMan::Utils.get_encoding_from_headers(
15
+ {})).to eq nil
16
+ expect(RestMan::Utils.get_encoding_from_headers(
17
+ {:content_type => 'foo; bar=baz'})).to eq nil
18
+ end
19
+
20
+ it 'handles various charsets' do
21
+ expect(RestMan::Utils.get_encoding_from_headers(
22
+ {:content_type => 'text/plain; charset=UTF-8'})).to eq 'UTF-8'
23
+ expect(RestMan::Utils.get_encoding_from_headers(
24
+ {:content_type => 'application/json; charset=ISO-8859-1'})).
25
+ to eq 'ISO-8859-1'
26
+ expect(RestMan::Utils.get_encoding_from_headers(
27
+ {:content_type => 'text/html; charset=windows-1251'})).
28
+ to eq 'windows-1251'
29
+
30
+ expect(RestMan::Utils.get_encoding_from_headers(
31
+ {:content_type => 'text/html; charset="UTF-16"'})).
32
+ to eq 'UTF-16'
33
+ end
34
+ end
35
+
36
+ describe '.cgi_parse_header' do
37
+ it 'parses headers', :unless => RUBY_VERSION.start_with?('2.0') do
38
+ expect(RestMan::Utils.cgi_parse_header('text/plain')).
39
+ to eq ['text/plain', {}]
40
+
41
+ expect(RestMan::Utils.cgi_parse_header('text/vnd.just.made.this.up')).
42
+ to eq ['text/vnd.just.made.this.up', {}]
43
+
44
+ expect(RestMan::Utils.cgi_parse_header('text/plain;charset=us-ascii')).
45
+ to eq ['text/plain', {'charset' => 'us-ascii'}]
46
+
47
+ expect(RestMan::Utils.cgi_parse_header('text/plain ; charset="us-ascii"')).
48
+ to eq ['text/plain', {'charset' => 'us-ascii'}]
49
+
50
+ expect(RestMan::Utils.cgi_parse_header(
51
+ 'text/plain ; charset="us-ascii"; another=opt')).
52
+ to eq ['text/plain', {'charset' => 'us-ascii', 'another' => 'opt'}]
53
+
54
+ expect(RestMan::Utils.cgi_parse_header(
55
+ 'foo/bar; filename="silly.txt"')).
56
+ to eq ['foo/bar', {'filename' => 'silly.txt'}]
57
+
58
+ expect(RestMan::Utils.cgi_parse_header(
59
+ 'foo/bar; filename="strange;name"')).
60
+ to eq ['foo/bar', {'filename' => 'strange;name'}]
61
+
62
+ expect(RestMan::Utils.cgi_parse_header(
63
+ 'foo/bar; filename="strange;name";size=123')).to eq \
64
+ ['foo/bar', {'filename' => 'strange;name', 'size' => '123'}]
65
+
66
+ expect(RestMan::Utils.cgi_parse_header(
67
+ 'foo/bar; name="files"; filename="fo\\"o;bar"')).to eq \
68
+ ['foo/bar', {'name' => 'files', 'filename' => 'fo"o;bar'}]
69
+ end
70
+ end
71
+
72
+ describe '.encode_query_string' do
73
+ it 'handles simple hashes' do
74
+ {
75
+ {foo: 123, bar: 456} => 'foo=123&bar=456',
76
+ {'foo' => 123, 'bar' => 456} => 'foo=123&bar=456',
77
+ {foo: 'abc', bar: 'one two'} => 'foo=abc&bar=one+two',
78
+ {escaped: '1+2=3'} => 'escaped=1%2B2%3D3',
79
+ {'escaped + key' => 'foo'} => 'escaped+%2B+key=foo',
80
+ }.each_pair do |input, expected|
81
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
82
+ end
83
+ end
84
+
85
+ it 'handles simple arrays' do
86
+ {
87
+ {foo: [1, 2, 3]} => 'foo[]=1&foo[]=2&foo[]=3',
88
+ {foo: %w{a b c}, bar: [1, 2, 3]} => 'foo[]=a&foo[]=b&foo[]=c&bar[]=1&bar[]=2&bar[]=3',
89
+ {foo: ['one two', 3]} => 'foo[]=one+two&foo[]=3',
90
+ {'a+b' => [1,2,3]} => 'a%2Bb[]=1&a%2Bb[]=2&a%2Bb[]=3',
91
+ }.each_pair do |input, expected|
92
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
93
+ end
94
+ end
95
+
96
+ it 'handles nested hashes' do
97
+ {
98
+ {outer: {foo: 123, bar: 456}} => 'outer[foo]=123&outer[bar]=456',
99
+ {outer: {foo: [1, 2, 3], bar: 'baz'}} => 'outer[foo][]=1&outer[foo][]=2&outer[foo][]=3&outer[bar]=baz',
100
+ }.each_pair do |input, expected|
101
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
102
+ end
103
+ end
104
+
105
+ it 'handles null and empty values' do
106
+ {
107
+ {string: '', empty: nil, list: [], hash: {}, falsey: false } =>
108
+ 'string=&empty&list&hash&falsey=false',
109
+ }.each_pair do |input, expected|
110
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
111
+ end
112
+ end
113
+
114
+ it 'handles nested nulls' do
115
+ {
116
+ {foo: {string: '', empty: nil}} => 'foo[string]=&foo[empty]',
117
+ }.each_pair do |input, expected|
118
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
119
+ end
120
+ end
121
+
122
+ it 'handles deep nesting' do
123
+ {
124
+ {coords: [{x: 1, y: 0}, {x: 2}, {x: 3}]} => 'coords[][x]=1&coords[][y]=0&coords[][x]=2&coords[][x]=3',
125
+ }.each_pair do |input, expected|
126
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
127
+ end
128
+ end
129
+
130
+ it 'handles multiple fields with the same name using ParamsArray' do
131
+ {
132
+ RestMan::ParamsArray.new([[:foo, 1], [:foo, 2], [:foo, 3]]) => 'foo=1&foo=2&foo=3',
133
+ }.each_pair do |input, expected|
134
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
135
+ end
136
+ end
137
+
138
+ it 'handles nested ParamsArrays' do
139
+ {
140
+ {foo: RestMan::ParamsArray.new([[:a, 1], [:a, 2]])} => 'foo[a]=1&foo[a]=2',
141
+ RestMan::ParamsArray.new([[:foo, {a: 1}], [:foo, {a: 2}]]) => 'foo[a]=1&foo[a]=2',
142
+ }.each_pair do |input, expected|
143
+ expect(RestMan::Utils.encode_query_string(input)).to eq expected
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,22 @@
1
+ require_relative '../_lib'
2
+
3
+ describe 'RestMan::Windows::RootCerts',
4
+ :if => RestMan::Platform.windows? do
5
+ let(:x509_store) { RestMan::Windows::RootCerts.instance.to_a }
6
+
7
+ it 'should return at least one X509 certificate' do
8
+ expect(x509_store.to_a.size).to be >= 1
9
+ end
10
+
11
+ it 'should return an X509 certificate with a subject' do
12
+ x509 = x509_store.first
13
+
14
+ expect(x509.subject.to_s).to match(/CN=.*/)
15
+ end
16
+
17
+ it 'should return X509 certificate objects' do
18
+ x509_store.each do |cert|
19
+ expect(cert).to be_a(OpenSSL::X509::Certificate)
20
+ end
21
+ end
22
+ end