patron-new 0.4.19

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.
@@ -0,0 +1,275 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Copyright (c) 2008 The Hive http://www.thehive.com/
4
+ ##
5
+ ## Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ ## of this software and associated documentation files (the "Software"), to deal
7
+ ## in the Software without restriction, including without limitation the rights
8
+ ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ ## copies of the Software, and to permit persons to whom the Software is
10
+ ## furnished to do so, subject to the following conditions:
11
+ ##
12
+ ## The above copyright notice and this permission notice shall be included in
13
+ ## all copies or substantial portions of the Software.
14
+ ##
15
+ ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ ## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ ## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ ## THE SOFTWARE.
22
+ ##
23
+ ## -------------------------------------------------------------------
24
+ require File.expand_path("./spec") + '/spec_helper.rb'
25
+ require 'webrick'
26
+ require 'yaml'
27
+ require 'base64'
28
+ require 'fileutils'
29
+
30
+ describe Patron::Session do
31
+
32
+ before(:each) do
33
+ @session = Patron::Session.new
34
+ @session.base_url = "https://localhost:9043"
35
+ @session.insecure = true
36
+ end
37
+
38
+ it "should retrieve a url with :get" do
39
+ response = @session.get("/test")
40
+ body = YAML::load(response.body)
41
+ body.request_method.should == "GET"
42
+ end
43
+
44
+ it "should download content with :get and a file path" do
45
+ tmpfile = "/tmp/patron_test.yaml"
46
+ response = @session.get_file "/test", tmpfile
47
+ response.body.should be_nil
48
+ body = YAML::load_file(tmpfile)
49
+ body.request_method.should == "GET"
50
+ FileUtils.rm tmpfile
51
+ end
52
+
53
+ it "should download correctly(md5 ok) with get_file" do
54
+ tmpfile = "/tmp/picture"
55
+ response = @session.get_file "/picture", tmpfile
56
+ response.body.should be_nil
57
+ File.size(File.join(File.dirname(__FILE__),"../pic.png")).should == File.size(tmpfile)
58
+ FileUtils.rm tmpfile
59
+ end
60
+
61
+ it "should include custom headers in a request" do
62
+ response = @session.get("/test", {"User-Agent" => "PatronTest"})
63
+ body = YAML::load(response.body)
64
+ body.header["user-agent"].should == ["PatronTest"]
65
+ end
66
+
67
+ it "should merge custom headers with session headers" do
68
+ @session.headers["X-Test"] = "Testing"
69
+ response = @session.get("/test", {"User-Agent" => "PatronTest"})
70
+ body = YAML::load(response.body)
71
+ body.header["user-agent"].should == ["PatronTest"]
72
+ body.header["x-test"].should == ["Testing"]
73
+ end
74
+
75
+ it "should raise an exception on timeout" do
76
+ @session.timeout = 1
77
+ lambda {@session.get("/timeout")}.should raise_error(Patron::TimeoutError)
78
+ end
79
+
80
+ it "should follow redirects by default" do
81
+ @session.max_redirects = 1
82
+ response = @session.get("/redirect")
83
+ body = YAML::load(response.body)
84
+ response.status.should == 200
85
+ body.path.should == "/test"
86
+ end
87
+
88
+ it "should include redirect count in response" do
89
+ @session.max_redirects = 1
90
+ response = @session.get("/redirect")
91
+ response.redirect_count.should == 1
92
+ end
93
+
94
+ it "should not follow redirects when configured to do so" do
95
+ @session.max_redirects = 0
96
+ response = @session.get("/redirect")
97
+ response.status.should == 301
98
+ response.body.should be_empty
99
+ end
100
+
101
+ it "should retrieve URL metadata with :head" do
102
+ response = @session.head("/test")
103
+ response.status.should == 200
104
+ response.body.should be_empty
105
+ response.headers.should_not be_empty
106
+ end
107
+
108
+ it "should send a delete request with :delete" do
109
+ response = @session.delete("/test")
110
+ body = YAML::load(response.body)
111
+ body.request_method.should == "DELETE"
112
+ end
113
+
114
+ it "should send a COPY request with :copy" do
115
+ response = @session.copy("/test", "/test2")
116
+ body = YAML::load(response.body)
117
+ body.request_method.should == "COPY"
118
+ end
119
+
120
+ it "should include a Destination header in COPY requests" do
121
+ response = @session.copy("/test", "/test2")
122
+ body = YAML::load(response.body)
123
+ body.header['destination'].first.should == "/test2"
124
+ end
125
+
126
+ it "should upload data with :get" do
127
+ data = "upload data"
128
+ response = @session.request(:get, "/test", {}, :data => data)
129
+ body = YAML::load(response.body)
130
+ body.request_method.should == "GET"
131
+ body.header['content-length'].should == [data.size.to_s]
132
+ end
133
+
134
+ it "should upload data with :put" do
135
+ data = "upload data"
136
+ response = @session.put("/test", data)
137
+ body = YAML::load(response.body)
138
+ body.request_method.should == "PUT"
139
+ body.header['content-length'].should == [data.size.to_s]
140
+ end
141
+
142
+ it "should raise when no data is provided to :put" do
143
+ lambda { @session.put("/test", nil) }.should raise_error(ArgumentError)
144
+ end
145
+
146
+ it "should upload a file with :put" do
147
+ response = @session.put_file("/test", "LICENSE")
148
+ body = YAML::load(response.body)
149
+ body.request_method.should == "PUT"
150
+ end
151
+
152
+ it "should raise when no file is provided to :put" do
153
+ lambda { @session.put_file("/test", nil) }.should raise_error(ArgumentError)
154
+ end
155
+
156
+ it "should use chunked encoding when uploading a file with :put" do
157
+ response = @session.put_file("/test", "LICENSE")
158
+ body = YAML::load(response.body)
159
+ body.header['transfer-encoding'].first.should == "chunked"
160
+ end
161
+
162
+ it "should upload data with :post" do
163
+ data = "upload data"
164
+ response = @session.post("/test", data)
165
+ body = YAML::load(response.body)
166
+ body.request_method.should == "POST"
167
+ body.header['content-length'].should == [data.size.to_s]
168
+ end
169
+
170
+ it "should post a hash of arguments as a urlencoded form" do
171
+ data = {:foo => 123, 'baz' => '++hello world++'}
172
+ response = @session.post("/testpost", data)
173
+ body = YAML::load(response.body)
174
+ body['content_type'].should == "application/x-www-form-urlencoded"
175
+ body['body'].should match(/baz=%2B%2Bhello%20world%2B%2B/)
176
+ body['body'].should match(/foo=123/)
177
+ end
178
+
179
+ it "should raise when no data is provided to :post" do
180
+ lambda { @session.post("/test", nil) }.should raise_error(ArgumentError)
181
+ end
182
+
183
+ it "should upload a file with :post" do
184
+ response = @session.post_file("/test", "LICENSE")
185
+ body = YAML::load(response.body)
186
+ body.request_method.should == "POST"
187
+ end
188
+
189
+ it "should upload a multipart with :post" do
190
+ response = @session.post_multipart("/test", { :test_data => "123" }, { :test_file => "LICENSE" } )
191
+ body = YAML::load(response.body)
192
+ body.request_method.should == "POST"
193
+ end
194
+
195
+ it "should raise when no file is provided to :post" do
196
+ lambda { @session.post_file("/test", nil) }.should raise_error(ArgumentError)
197
+ end
198
+
199
+ it "should use chunked encoding when uploading a file with :post" do
200
+ response = @session.post_file("/test", "LICENSE")
201
+ body = YAML::load(response.body)
202
+ body.header['transfer-encoding'].first.should == "chunked"
203
+ end
204
+
205
+ it "should handle cookies if set" do
206
+ @session.handle_cookies
207
+ response = @session.get("/setcookie").body
208
+ YAML::load(response).header['cookie'].first.should == "session_id=foo123"
209
+ end
210
+
211
+ it "should not handle cookies by default" do
212
+ response = @session.get("/setcookie").body
213
+ YAML::load(response).header.should_not include('cookie')
214
+ end
215
+
216
+ it "should ignore a wrong Content-Length when asked to" do
217
+ lambda {
218
+ @session.ignore_content_length = true
219
+ @session.get("/wrongcontentlength")
220
+ }.should_not raise_error
221
+ end
222
+
223
+ it "should fail by default with a Content-Length too high" do
224
+ lambda {
225
+ @session.ignore_content_length = nil
226
+ @session.get("/wrongcontentlength")
227
+ }.should raise_error(Patron::PartialFileError)
228
+ end
229
+
230
+ it "should raise exception if cookie store is not writable or readable" do
231
+ lambda { @session.handle_cookies("/trash/clash/foo") }.should raise_error(ArgumentError)
232
+ end
233
+
234
+ it "should work with multiple threads" do
235
+ threads = []
236
+ 3.times do
237
+ threads << Thread.new do
238
+ session = Patron::Session.new
239
+ session.base_url = "https://localhost:9043"
240
+ session.insecure = true
241
+ session.post_file("/test", "LICENSE")
242
+ end
243
+ end
244
+ threads.each {|t| t.join }
245
+ end
246
+
247
+ it "should fail when insecure mode is off" do
248
+ lambda {
249
+ @session.insecure = nil
250
+ response = @session.get("/test")
251
+ }.should raise_error(Patron::Error)
252
+ end
253
+
254
+ it "should work when insecure mode is off but certificate is supplied" do
255
+ @session.insecure = nil
256
+ @session.cacert = 'spec/certs/cacert.pem'
257
+ response = @session.get("/test")
258
+ body = YAML::load(response.body)
259
+ body.request_method.should == "GET"
260
+ end
261
+
262
+ # ------------------------------------------------------------------------
263
+ describe 'when debug is enabled' do
264
+ it 'it should not clobber stderr' do
265
+ rdev = STDERR.stat.rdev
266
+
267
+ @session.enable_debug
268
+ STDERR.stat.rdev.should be == rdev
269
+
270
+ @session.enable_debug
271
+ STDERR.stat.rdev.should be == rdev
272
+ end
273
+ end
274
+
275
+ end
@@ -0,0 +1,33 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Copyright (c) 2008 The Hive http://www.thehive.com/
4
+ ##
5
+ ## Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ ## of this software and associated documentation files (the "Software"), to deal
7
+ ## in the Software without restriction, including without limitation the rights
8
+ ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ ## copies of the Software, and to permit persons to whom the Software is
10
+ ## furnished to do so, subject to the following conditions:
11
+ ##
12
+ ## The above copyright notice and this permission notice shall be included in
13
+ ## all copies or substantial portions of the Software.
14
+ ##
15
+ ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ ## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ ## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ ## THE SOFTWARE.
22
+ ##
23
+ ## -------------------------------------------------------------------
24
+ require 'rspec'
25
+
26
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
27
+ $:.unshift(File.dirname(__FILE__) + '/../ext')
28
+ require 'patron'
29
+
30
+ Dir['./spec/support/**/*.rb'].each { |fn| require fn }
31
+
32
+ PatronTestServer.start(nil, false, 9001) if RUBY_VERSION >= '1.9'
33
+ PatronTestServer.start(nil, true, 9043) if RUBY_VERSION >= '1.9'
@@ -0,0 +1,189 @@
1
+ ## -------------------------------------------------------------------
2
+ ##
3
+ ## Patron HTTP Client: HTTP test server for integration tests
4
+ ## Copyright (c) 2008 The Hive http://www.thehive.com/
5
+ ##
6
+ ## Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ ## of this software and associated documentation files (the "Software"), to deal
8
+ ## in the Software without restriction, including without limitation the rights
9
+ ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ ## copies of the Software, and to permit persons to whom the Software is
11
+ ## furnished to do so, subject to the following conditions:
12
+ ##
13
+ ## The above copyright notice and this permission notice shall be included in
14
+ ## all copies or substantial portions of the Software.
15
+ ##
16
+ ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ ## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ ## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ ## THE SOFTWARE.
23
+ ##
24
+ ## -------------------------------------------------------------------
25
+ require 'yaml'
26
+ require 'webrick'
27
+ require 'webrick/https'
28
+ require 'openssl'
29
+
30
+ include WEBrick
31
+
32
+ # This ugly little hack is necessary to make the specs pass when running
33
+ # the test_server script under Ruby 1.9. URI::Parser#to_yaml generates
34
+ # regexp representations that YAML.parse cannot parse.
35
+ class URI::Parser
36
+ def to_yaml(opts = {})
37
+ {}.to_yaml(opts)
38
+ end
39
+ end
40
+
41
+ module RespondWith
42
+ def respond_with(method, req, res)
43
+ res.body = req.to_yaml
44
+ res['Content-Type'] = "text/plain"
45
+ end
46
+ end
47
+
48
+ class TestServlet < HTTPServlet::AbstractServlet
49
+
50
+ include RespondWith
51
+
52
+ def do_GET(req,res)
53
+ respond_with(:GET, req, res)
54
+ end
55
+
56
+ def do_POST(req,res)
57
+ respond_with(:POST, req, res)
58
+ end
59
+
60
+ def do_PUT(req,res)
61
+ respond_with(:PUT, req, res)
62
+ end
63
+
64
+ def do_DELETE(req,res)
65
+ respond_with(:DELETE, req, res)
66
+ end
67
+
68
+ def do_COPY(req,res)
69
+ respond_with(:COPY, req, res)
70
+ end
71
+ end
72
+
73
+ class TimeoutServlet < HTTPServlet::AbstractServlet
74
+ def do_GET(req,res)
75
+ sleep(1.1)
76
+ end
77
+ end
78
+
79
+ class RedirectServlet < HTTPServlet::AbstractServlet
80
+ def do_GET(req,res)
81
+ res['Location'] = "http://localhost:9001/test"
82
+ res.status = 301
83
+ end
84
+ end
85
+
86
+
87
+ class TestPostBodyServlet < HTTPServlet::AbstractServlet
88
+ include RespondWith
89
+ def do_POST(req, res)
90
+ respond_with(:POST, {'body' => req.body, 'content_type' => req.content_type}, res)
91
+ end
92
+ end
93
+
94
+
95
+
96
+ class SetCookieServlet < HTTPServlet::AbstractServlet
97
+ def do_GET(req, res)
98
+ res['Set-Cookie'] = "session_id=foo123"
99
+ res['Location'] = "http://localhost:9001/test"
100
+ res.status = 301
101
+ end
102
+ end
103
+
104
+ class RepetitiveHeaderServlet < HTTPServlet::AbstractServlet
105
+ def do_GET(req, res)
106
+ # the only way to get webrick to output two headers with the same name is using cookies, so that's what we'll do:
107
+ res.cookies << Cookie.new('a', '1')
108
+ res.cookies << Cookie.new('b', '2')
109
+ res['Content-Type'] = "text/plain"
110
+ res.body = "Hi."
111
+ end
112
+ end
113
+
114
+ class PictureServlet < HTTPServlet::AbstractServlet
115
+ def do_GET(req, res)
116
+ res['Content-Type'] = "image/png"
117
+ res.body = File.read("./pic.png")
118
+ end
119
+ end
120
+
121
+ class WrongContentLengthServlet < HTTPServlet::AbstractServlet
122
+ def do_GET(req, res)
123
+ res.keep_alive = false
124
+ res.content_length = 1024
125
+ res.body = "Hello."
126
+ end
127
+ end
128
+
129
+ class PatronTestServer
130
+
131
+ def self.start( log_file = nil, ssl = false, port = 9001 )
132
+ new(log_file, ssl, port).start
133
+ end
134
+
135
+ def initialize( log_file = nil, ssl = false, port = 9001 )
136
+ log_file ||= StringIO.new
137
+ log = WEBrick::Log.new(log_file)
138
+
139
+ options = {
140
+ :Port => port,
141
+ :Logger => log,
142
+ :AccessLog => [
143
+ [ log, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
144
+ [ log, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
145
+ ]
146
+ }
147
+
148
+ if ssl
149
+ options[:SSLEnable] = true
150
+ options[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.open("spec/certs/cacert.pem").read)
151
+ options[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.open("spec/certs/privkey.pem").read)
152
+ options[:SSLCertName] = [ ["CN", WEBrick::Utils::getservername ] ]
153
+ end
154
+
155
+ @server = WEBrick::HTTPServer.new(options)
156
+
157
+ @server.mount("/test", TestServlet)
158
+ @server.mount("/testpost", TestPostBodyServlet)
159
+ @server.mount("/timeout", TimeoutServlet)
160
+ @server.mount("/redirect", RedirectServlet)
161
+ @server.mount("/picture", PictureServlet)
162
+ @server.mount("/setcookie", SetCookieServlet)
163
+ @server.mount("/repetitiveheader", RepetitiveHeaderServlet)
164
+ @server.mount("/wrongcontentlength", WrongContentLengthServlet)
165
+
166
+ end
167
+
168
+ def start
169
+ trap('INT') {
170
+ begin
171
+ @server.shutdown unless @server.nil?
172
+ rescue Object => e
173
+ $stderr.puts "Error #{__FILE__}:#{__LINE__}\n#{e.message}"
174
+ end
175
+ }
176
+
177
+ @thread = Thread.new { @server.start }
178
+ Thread.pass
179
+ self
180
+ end
181
+
182
+ def join
183
+ if defined? @thread and @thread
184
+ @thread.join
185
+ end
186
+ self
187
+ end
188
+ end
189
+