curb 0.1.4 → 0.7.15

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,466 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ class TestCurbCurlMulti < Test::Unit::TestCase
4
+ def teardown
5
+ # get a better read on memory loss when running in valgrind
6
+ ObjectSpace.garbage_collect
7
+ end
8
+
9
+ def test_new_multi_01
10
+ d1 = ""
11
+ c1 = Curl::Easy.new($TEST_URL) do |curl|
12
+ curl.headers["User-Agent"] = "myapp-0.0"
13
+ curl.on_body {|d| d1 << d; d.length }
14
+ end
15
+
16
+ d2 = ""
17
+ c2 = Curl::Easy.new($TEST_URL) do |curl|
18
+ curl.headers["User-Agent"] = "myapp-0.0"
19
+ curl.on_body {|d| d2 << d; d.length }
20
+ end
21
+
22
+ m = Curl::Multi.new
23
+
24
+ m.add( c1 )
25
+ m.add( c2 )
26
+
27
+ m.perform
28
+
29
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, d1)
30
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, d2)
31
+
32
+ m = nil
33
+
34
+ end
35
+
36
+ def test_perform_block
37
+ c1 = Curl::Easy.new($TEST_URL)
38
+ c2 = Curl::Easy.new($TEST_URL)
39
+
40
+ m = Curl::Multi.new
41
+
42
+ m.add( c1 )
43
+ m.add( c2 )
44
+
45
+ m.perform do
46
+ # idle
47
+ #puts "idling..."
48
+ end
49
+
50
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c1.body_str)
51
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c2.body_str)
52
+
53
+ m = nil
54
+
55
+ end
56
+
57
+ # NOTE: if this test runs slowly on Mac OSX, it is probably due to the use of a port install curl+ssl+ares install
58
+ # on my MacBook, this causes curl_easy_init to take nearly 0.01 seconds / * 100 below is 1 second too many!
59
+ def test_n_requests
60
+ n = 100
61
+ m = Curl::Multi.new
62
+ responses = []
63
+ n.times do|i|
64
+ responses[i] = ""
65
+ c = Curl::Easy.new($TEST_URL) do|curl|
66
+ curl.on_body{|data| responses[i] << data; data.size }
67
+ end
68
+ m.add c
69
+ end
70
+
71
+ m.perform
72
+
73
+ assert_equal n, responses.size
74
+ n.times do|i|
75
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, responses[i], "response #{i}")
76
+ end
77
+
78
+ m = nil
79
+ end
80
+
81
+ def test_n_requests_with_break
82
+ # process n requests then load the handle again and run it again
83
+ n = 2
84
+ m = Curl::Multi.new
85
+ 5.times do|it|
86
+ responses = []
87
+ n.times do|i|
88
+ responses[i] = ""
89
+ c = Curl::Easy.new($TEST_URL) do|curl|
90
+ curl.on_body{|data| responses[i] << data; data.size }
91
+ end
92
+ m.add c
93
+ end
94
+ m.perform
95
+
96
+ assert_equal n, responses.size
97
+ n.times do|i|
98
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, responses[i], "response #{i}")
99
+ end
100
+ end
101
+
102
+ m = nil
103
+
104
+ end
105
+
106
+ def test_idle_check
107
+ m = Curl::Multi.new
108
+ e = Curl::Easy.new($TEST_URL)
109
+
110
+ assert(m.idle?, 'A new Curl::Multi handle should be idle')
111
+
112
+ m.add(e)
113
+
114
+ assert((not m.idle?), 'A Curl::Multi handle with a request should not be idle')
115
+
116
+ m.perform
117
+
118
+ assert(m.idle?, 'A Curl::Multi handle should be idle after performing its requests')
119
+ end
120
+
121
+ def test_requests
122
+ m = Curl::Multi.new
123
+
124
+ assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests')
125
+
126
+ 10.times do
127
+ m.add(Curl::Easy.new($TEST_URL))
128
+ end
129
+
130
+ assert_equal(10, m.requests.length, 'multi.requests should contain all the active requests')
131
+
132
+ m.perform
133
+
134
+ assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests after a perform')
135
+ end
136
+
137
+ def test_cancel
138
+ m = Curl::Multi.new
139
+ m.cancel! # shouldn't raise anything
140
+
141
+ 10.times do
142
+ m.add(Curl::Easy.new($TEST_URL))
143
+ end
144
+
145
+ m.cancel!
146
+
147
+ assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests after being canceled')
148
+ end
149
+
150
+ def test_with_success
151
+ c1 = Curl::Easy.new($TEST_URL)
152
+ c2 = Curl::Easy.new($TEST_URL)
153
+ success_called1 = false
154
+ success_called2 = false
155
+
156
+ c1.on_success do|c|
157
+ success_called1 = true
158
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
159
+ end
160
+
161
+ c2.on_success do|c|
162
+ success_called2 = true
163
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
164
+ end
165
+
166
+ m = Curl::Multi.new
167
+
168
+ m.add( c1 )
169
+ m.add( c2 )
170
+
171
+ m.perform do
172
+ # idle
173
+ #puts "idling..."
174
+ end
175
+
176
+ assert success_called2
177
+ assert success_called1
178
+
179
+ m = nil
180
+ end
181
+
182
+ def test_with_success_cb_with_404
183
+ c1 = Curl::Easy.new("#{$TEST_URL.gsub(/file:\/\//,'')}/not_here")
184
+ c2 = Curl::Easy.new($TEST_URL)
185
+ success_called1 = false
186
+ success_called2 = false
187
+
188
+ c1.on_success do|c|
189
+ success_called1 = true
190
+ #puts "success 1 called: #{c.body_str.inspect}"
191
+ #assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
192
+ end
193
+
194
+ c1.on_failure do|c,rc|
195
+ # rc => [Curl::Err::MalformedURLError, "URL using bad/illegal format or missing URL"]
196
+ assert_equal Curl::Easy, c.class
197
+ assert_equal Curl::Err::MalformedURLError, rc.first
198
+ assert_equal "URL using bad/illegal format or missing URL", rc.last
199
+ end
200
+
201
+ c2.on_success do|c|
202
+ # puts "success 2 called: #{c.body_str.inspect}"
203
+ success_called2 = true
204
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
205
+ end
206
+
207
+ m = Curl::Multi.new
208
+
209
+ #puts "c1: #{c1.url}"
210
+ m.add( c1 )
211
+ #puts "c2: #{c2.url}"
212
+ m.add( c2 )
213
+
214
+ #puts "calling"
215
+ m.perform do
216
+ # idle
217
+ end
218
+
219
+ assert success_called2
220
+ assert !success_called1
221
+
222
+ m = nil
223
+ end
224
+
225
+ # This tests whether, ruby's GC will trash an out of scope easy handle
226
+ class TestForScope
227
+ attr_reader :buf
228
+
229
+ def t_method
230
+ @buf = ""
231
+ @m = Curl::Multi.new
232
+ 10.times do|i|
233
+ c = Curl::Easy.new($TEST_URL)
234
+ c.on_success{|b| @buf << b.body_str }
235
+ ObjectSpace.garbage_collect
236
+ @m.add(c)
237
+ ObjectSpace.garbage_collect
238
+ end
239
+ ObjectSpace.garbage_collect
240
+ end
241
+
242
+ def t_call
243
+ @m.perform do
244
+ ObjectSpace.garbage_collect
245
+ end
246
+ end
247
+
248
+ def self.test
249
+ ObjectSpace.garbage_collect
250
+ tfs = TestForScope.new
251
+ ObjectSpace.garbage_collect
252
+ tfs.t_method
253
+ ObjectSpace.garbage_collect
254
+ tfs.t_call
255
+ ObjectSpace.garbage_collect
256
+
257
+ tfs.buf
258
+ end
259
+
260
+ end
261
+
262
+ def test_with_garbage_collect
263
+ ObjectSpace.garbage_collect
264
+ buf = TestForScope.test
265
+ ObjectSpace.garbage_collect
266
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, buf)
267
+ end
268
+
269
+ =begin
270
+ def test_remote_requests
271
+ responses = {}
272
+ requests = ["http://google.co.uk/", "http://ruby-lang.org/"]
273
+ m = Curl::Multi.new
274
+ # add a few easy handles
275
+ requests.each do |url|
276
+ responses[url] = ""
277
+ responses["#{url}-header"] = ""
278
+ c = Curl::Easy.new(url) do|curl|
279
+ curl.follow_location = true
280
+ curl.on_header{|data| responses["#{url}-header"] << data; data.size }
281
+ curl.on_body{|data| responses[url] << data; data.size }
282
+ curl.on_success {
283
+ puts curl.last_effective_url
284
+ }
285
+ end
286
+ m.add(c)
287
+ end
288
+
289
+ m.perform
290
+
291
+ requests.each do|url|
292
+ puts responses["#{url}-header"].split("\r\n").inspect
293
+ #puts responses[url].size
294
+ end
295
+ end
296
+ =end
297
+
298
+ def test_multi_easy_get_01
299
+ urls = []
300
+ root_uri = 'http://127.0.0.1:9129/ext/'
301
+ # send a request to fetch all c files in the ext dir
302
+ Dir[File.dirname(__FILE__) + "/../ext/*.c"].each do|path|
303
+ urls << root_uri + File.basename(path)
304
+ end
305
+ urls = urls[0..(urls.size/2)] # keep it fast, webrick...
306
+ Curl::Multi.get(urls, {:follow_location => true}, {:pipeline => true}) do|curl|
307
+ assert_equal 200, curl.response_code
308
+ end
309
+ end
310
+
311
+ def test_multi_easy_download_01
312
+ # test collecting response buffers to file e.g. on_body
313
+ root_uri = 'http://127.0.0.1:9129/ext/'
314
+ urls = []
315
+ downloads = []
316
+ file_info = {}
317
+ FileUtils.mkdir("tmp/")
318
+
319
+ # for each file store the size by file name
320
+ Dir[File.dirname(__FILE__) + "/../ext/*.c"].each do|path|
321
+ urls << (root_uri + File.basename(path))
322
+ downloads << "tmp/" + File.basename(path)
323
+ file_info[File.basename(path)] = {:size => File.size(path), :path => path}
324
+ end
325
+
326
+ # start downloads
327
+ Curl::Multi.download(urls,{},{},downloads) do|curl,download_path|
328
+ assert_equal 200, curl.response_code
329
+ assert File.exist?(download_path)
330
+ store = file_info[File.basename(download_path)]
331
+ assert_equal file_info[File.basename(download_path)][:size], File.size(download_path), "incomplete download: #{download_path}"
332
+ end
333
+ ensure
334
+ FileUtils.rm_rf("tmp/")
335
+ end
336
+
337
+ def test_multi_easy_post_01
338
+ urls = [
339
+ { :url => TestServlet.url + '?q=1', :post_fields => {'field1' => 'value1', 'k' => 'j'}},
340
+ { :url => TestServlet.url + '?q=2', :post_fields => {'field2' => 'value2', 'foo' => 'bar', 'i' => 'j' }},
341
+ { :url => TestServlet.url + '?q=3', :post_fields => {'field3' => 'value3', 'field4' => 'value4'}}
342
+ ]
343
+ Curl::Multi.post(urls, {:follow_location => true, :multipart_form_post => true}, {:pipeline => true}) do|easy|
344
+ str = easy.body_str
345
+ assert_match /POST/, str
346
+ fields = {}
347
+ str.gsub(/POST\n/,'').split('&').map{|sv| k, v = sv.split('='); fields[k] = v }
348
+ expected = urls.find{|s| s[:url] == easy.last_effective_url }
349
+ assert_equal expected[:post_fields], fields
350
+ #puts "#{easy.last_effective_url} #{fields.inspect}"
351
+ end
352
+ end
353
+
354
+ def test_multi_easy_put_01
355
+ urls = [{ :url => TestServlet.url, :method => :put, :put_data => "message",
356
+ :headers => {'Content-Type' => 'application/json' } },
357
+ { :url => TestServlet.url, :method => :put, :put_data => "message",
358
+ :headers => {'Content-Type' => 'application/json' } }]
359
+ Curl::Multi.put(urls, {}, {:pipeline => true}) do|easy|
360
+ assert_match /PUT/, easy.body_str
361
+ assert_match /message/, easy.body_str
362
+ end
363
+ end
364
+
365
+ def test_multi_easy_http_01
366
+ urls = [
367
+ { :url => TestServlet.url + '?q=1', :method => :post, :post_fields => {'field1' => 'value1', 'k' => 'j'}},
368
+ { :url => TestServlet.url + '?q=2', :method => :post, :post_fields => {'field2' => 'value2', 'foo' => 'bar', 'i' => 'j' }},
369
+ { :url => TestServlet.url + '?q=3', :method => :post, :post_fields => {'field3' => 'value3', 'field4' => 'value4'}},
370
+ { :url => TestServlet.url, :method => :put, :put_data => "message",
371
+ :headers => {'Content-Type' => 'application/json' } },
372
+ { :url => TestServlet.url, :method => :get }
373
+ ]
374
+ Curl::Multi.http(urls, {:pipeline => true}) do|easy, code, method|
375
+ assert_equal nil, code
376
+ case method
377
+ when :post
378
+ assert_match /POST/, easy.body_str
379
+ when :get
380
+ assert_match /GET/, easy.body_str
381
+ when :put
382
+ assert_match /PUT/, easy.body_str
383
+ end
384
+ #puts "#{easy.body_str.inspect}, #{method.inspect}, #{code.inspect}"
385
+ end
386
+ end
387
+
388
+ def test_mutli_recieves_500
389
+ m = Curl::Multi.new
390
+ e = Curl::Easy.new("http://127.0.0.1:9129/methods")
391
+ failure = false
392
+ e.post_body = "hello=world&s=500"
393
+ e.on_failure{|c,r| failure = true }
394
+ e.on_success{|c| failure = false }
395
+ m.add(e)
396
+ m.perform
397
+ assert failure
398
+ e2 = Curl::Easy.new(TestServlet.url)
399
+ e2.post_body = "hello=world"
400
+ e2.on_failure{|c,r| failure = true }
401
+ m.add(e2)
402
+ m.perform
403
+ failure = false
404
+ assert !failure
405
+ assert_equal "POST\nhello=world", e2.body_str
406
+ end
407
+
408
+ def test_remove_exception_is_descriptive
409
+ m = Curl::Multi.new
410
+ c = Curl::Easy.new("http://127.9.9.9:999110")
411
+ m.remove(c)
412
+ rescue => e
413
+ assert_equal 'Invalid easy handle', e.message
414
+ assert_equal 0, m.requests.size
415
+ end
416
+
417
+ def test_retry_easy_handle
418
+ m = Curl::Multi.new
419
+
420
+ tries = 10
421
+
422
+ c1 = Curl::Easy.new('http://127.1.1.1:99911') do |curl|
423
+ curl.on_failure {|c,e|
424
+ assert_equal [Curl::Err::MalformedURLError, "URL using bad/illegal format or missing URL"], e
425
+ if tries > 0
426
+ tries -= 1
427
+ m.add(c)
428
+ end
429
+ }
430
+ end
431
+
432
+ tries -= 1
433
+ m.add(c1)
434
+
435
+ m.perform
436
+ assert_equal 0, tries
437
+ assert_equal 0, m.requests.size
438
+ end
439
+
440
+ def test_reusing_handle
441
+ m = Curl::Multi.new
442
+
443
+ c = Curl::Easy.new('http://127.0.0.1') do|easy|
444
+ easy.on_complete{|e,r| puts e.inspect }
445
+ end
446
+
447
+ m.add(c)
448
+ m.add(c)
449
+ rescue => e
450
+ assert_equal Curl::Err::MultiBadEasyHandle, e.class
451
+ end
452
+
453
+ def test_multi_default_timeout
454
+ assert_equal 100, Curl::Multi.default_timeout
455
+ Curl::Multi.default_timeout = 12
456
+ assert_equal 12, Curl::Multi.default_timeout
457
+ assert_equal 100, (Curl::Multi.default_timeout = 100)
458
+ end
459
+
460
+ include TestServerMethods
461
+
462
+ def setup
463
+ server_setup
464
+ end
465
+
466
+ end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'helper')
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
2
 
3
3
  class TestCurbCurlPostfield < Test::Unit::TestCase
4
4
  def test_private_new
@@ -62,6 +62,7 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
62
62
  assert_equal 'foo', pf.name
63
63
  assert_equal 'localname', pf.local_file
64
64
  assert_equal 'localname', pf.remote_file
65
+ assert_nothing_raised { pf.to_s }
65
66
  assert_nil pf.content_type
66
67
  assert_nil pf.content
67
68
  assert_nil pf.set_content_proc
@@ -136,6 +137,7 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
136
137
 
137
138
  def test_to_s_04
138
139
  pf = Curl::PostField.file('foo.file', 'bar.file')
139
- assert_raise(Curl::Err::InvalidPostFieldError) { pf.to_s }
140
+ assert_nothing_raised { pf.to_s }
141
+ #assert_raise(Curl::Err::InvalidPostFieldError) { pf.to_s }
140
142
  end
141
143
  end
data/tests/timeout.rb ADDED
@@ -0,0 +1,100 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ # Run server with: ruby -rubygems timeout_server.rb -p 9128
4
+
5
+ # Note that curl requires all timeouts to be integers -
6
+ # curl_easy_setopt does not have a provision for floating-point values
7
+
8
+ class TestCurbTimeouts < Test::Unit::TestCase
9
+ def test_no_timeout_by_default
10
+ curl = Curl::Easy.new(wait_url(2))
11
+ start = Time.now
12
+ assert_equal true, curl.http_get
13
+ elapsed = Time.now - start
14
+ assert elapsed > 2
15
+ end
16
+
17
+ def test_overall_timeout_on_dead_transfer
18
+ curl = Curl::Easy.new(wait_url(2))
19
+ curl.timeout = 1
20
+ assert_raise(Curl::Err::TimeoutError) do
21
+ curl.http_get
22
+ end
23
+ end
24
+
25
+ def test_clearing_timeout
26
+ curl = Curl::Easy.new(wait_url(2))
27
+ curl.timeout = 1
28
+ curl.timeout = nil
29
+ start = Time.now
30
+ assert_equal true, curl.http_get
31
+ elapsed = Time.now - start
32
+ assert elapsed > 2
33
+ end
34
+
35
+ def test_overall_timeout_on_slow_transfer
36
+ curl = Curl::Easy.new(serve_url(100, 2, 3))
37
+ curl.timeout = 1
38
+ # transfer is aborted despite data being exchanged
39
+ assert_raise(Curl::Err::TimeoutError) do
40
+ curl.http_get
41
+ end
42
+ end
43
+
44
+ def test_low_speed_time_on_slow_transfer
45
+ curl = Curl::Easy.new(serve_url(100, 1, 3))
46
+ curl.low_speed_time = 2
47
+ # use default low_speed_limit of 1
48
+ assert true, curl.http_get
49
+ end
50
+
51
+ def test_low_speed_time_on_very_slow_transfer
52
+ # send data slower than required
53
+ curl = Curl::Easy.new(serve_url(10, 2, 3))
54
+ curl.low_speed_time = 1
55
+ # XXX for some reason this test fails if low speed limit is not specified
56
+ curl.low_speed_limit = 1
57
+ # use default low_speed_limit of 1
58
+ assert_raise(Curl::Err::TimeoutError) do
59
+ curl.http_get
60
+ end
61
+ end
62
+
63
+ def test_low_speed_limit_on_slow_transfer
64
+ curl = Curl::Easy.new(serve_url(10, 1, 3))
65
+ curl.low_speed_time = 2
66
+ curl.low_speed_limit = 1000
67
+ assert_raise(Curl::Err::TimeoutError) do
68
+ curl.http_get
69
+ end
70
+ end
71
+
72
+ def test_clearing_low_speed_time
73
+ curl = Curl::Easy.new(serve_url(100, 2, 3))
74
+ curl.low_speed_time = 1
75
+ curl.low_speed_time = nil
76
+ assert_equal true, curl.http_get
77
+ end
78
+
79
+ def test_clearing_low_speed_limit
80
+ curl = Curl::Easy.new(serve_url(10, 1, 3))
81
+ curl.low_speed_time = 2
82
+ curl.low_speed_limit = 1000
83
+ curl.low_speed_limit = nil
84
+ assert_equal true, curl.http_get
85
+ end
86
+
87
+ private
88
+
89
+ def wait_url(time)
90
+ "#{server_base}/wait/#{time}"
91
+ end
92
+
93
+ def serve_url(chunk_size, time, count)
94
+ "#{server_base}/serve/#{chunk_size}/every/#{time}/for/#{count}"
95
+ end
96
+
97
+ def server_base
98
+ 'http://127.0.0.1:9128'
99
+ end
100
+ end
@@ -0,0 +1,33 @@
1
+ # This Sinatra application must be run with mongrel
2
+ # or possibly with unicorn for the serve action to work properly.
3
+ # See http://efreedom.com/Question/1-3669674/Streaming-Data-Sinatra-Rack-Application
4
+
5
+ require 'sinatra'
6
+
7
+ get '/wait/:time' do |time|
8
+ time = time.to_i
9
+ sleep(time)
10
+ "Slept #{time} at #{Time.now}"
11
+ end
12
+
13
+ # http://efreedom.com/Question/1-3027435/Way-Flush-Html-Wire-Sinatra
14
+ class Streamer
15
+ def initialize(time, chunks)
16
+ @time = time
17
+ @chunks = chunks
18
+ end
19
+
20
+ def each
21
+ @chunks.each do |chunk|
22
+ sleep(@time)
23
+ yield chunk
24
+ end
25
+ end
26
+ end
27
+
28
+ get '/serve/:chunk_size/every/:time/for/:count' do |chunk_size, time, count|
29
+ chunk_size, time, count = chunk_size.to_i, time.to_i, count.to_i
30
+ chunk = 'x' * chunk_size
31
+ chunks = [chunk] * count
32
+ Streamer.new(time, chunks)
33
+ end