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.
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