rest-core 2.1.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/.travis.yml +3 -5
- data/CHANGES.md +65 -5
- data/Gemfile +10 -5
- data/NOTE.md +1 -1
- data/README.md +194 -128
- data/Rakefile +8 -34
- data/TODO.md +3 -2
- data/example/simple.rb +6 -4
- data/example/use-cases.rb +39 -122
- data/lib/rest-core.rb +14 -5
- data/lib/rest-core/builder.rb +12 -2
- data/lib/rest-core/client.rb +31 -25
- data/lib/rest-core/engine.rb +39 -0
- data/lib/rest-core/engine/http-client.rb +41 -0
- data/lib/rest-core/engine/net-http-persistent.rb +21 -0
- data/lib/rest-core/engine/rest-client.rb +13 -42
- data/lib/rest-core/event_source.rb +91 -0
- data/lib/rest-core/middleware.rb +17 -11
- data/lib/rest-core/middleware/error_detector.rb +1 -6
- data/lib/rest-core/middleware/oauth1_header.rb +1 -0
- data/lib/rest-core/middleware/oauth2_header.rb +20 -8
- data/lib/rest-core/middleware/oauth2_query.rb +1 -0
- data/lib/rest-core/middleware/timeout.rb +5 -19
- data/lib/rest-core/promise.rb +137 -0
- data/lib/rest-core/test.rb +2 -43
- data/lib/rest-core/thread_pool.rb +122 -0
- data/lib/rest-core/timer.rb +30 -0
- data/lib/rest-core/util/hmac.rb +0 -8
- data/lib/rest-core/version.rb +1 -1
- data/lib/rest-core/wrapper.rb +1 -1
- data/rest-core.gemspec +36 -25
- data/task/README.md +54 -0
- data/task/gemgem.rb +150 -156
- data/test/test_builder.rb +2 -2
- data/test/test_cache.rb +8 -8
- data/test/test_client.rb +16 -6
- data/test/test_client_oauth1.rb +1 -1
- data/test/test_event_source.rb +77 -0
- data/test/test_follow_redirect.rb +1 -1
- data/test/test_future.rb +16 -0
- data/test/test_oauth2_header.rb +28 -0
- data/test/test_promise.rb +89 -0
- data/test/test_rest-client.rb +21 -0
- data/test/test_thread_pool.rb +10 -0
- data/test/test_timeout.rb +13 -8
- metadata +61 -37
- data/example/multi.rb +0 -44
- data/lib/rest-core/engine/auto.rb +0 -25
- data/lib/rest-core/engine/em-http-request.rb +0 -90
- data/lib/rest-core/engine/future/future.rb +0 -107
- data/lib/rest-core/engine/future/future_fiber.rb +0 -32
- data/lib/rest-core/engine/future/future_thread.rb +0 -29
- data/lib/rest-core/middleware/timeout/timer_em.rb +0 -26
- data/lib/rest-core/middleware/timeout/timer_thread.rb +0 -36
- data/task/.gitignore +0 -1
- data/test/test_em-http-request.rb +0 -186
data/example/multi.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'fiber'
|
3
|
-
require 'em-http-request'
|
4
|
-
require 'rest-core'
|
5
|
-
|
6
|
-
YourClient = RC::Builder.client do
|
7
|
-
use RC::DefaultSite , 'https://api.github.com/users/'
|
8
|
-
use RC::JsonResponse, true
|
9
|
-
use RC::CommonLogger, method(:puts)
|
10
|
-
use RC::Cache , nil, 3600
|
11
|
-
end
|
12
|
-
|
13
|
-
client = YourClient.new
|
14
|
-
puts "rest-client with threads doing concurrent requests"
|
15
|
-
a = [client.get('cardinalblue'), client.get('godfat')]
|
16
|
-
puts "It's not blocking... but doing concurrent requests underneath"
|
17
|
-
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
18
|
-
puts "DONE"
|
19
|
-
|
20
|
-
puts; puts
|
21
|
-
|
22
|
-
puts "eventmachine with threads doing concurrent requests"
|
23
|
-
EM.run{
|
24
|
-
Thread.new{
|
25
|
-
a = [client.get('cardinalblue'), client.get('godfat')]
|
26
|
-
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
27
|
-
puts "DONE"
|
28
|
-
EM.stop
|
29
|
-
}
|
30
|
-
puts "It's not blocking... but doing concurrent requests underneath"
|
31
|
-
}
|
32
|
-
|
33
|
-
puts; puts
|
34
|
-
|
35
|
-
puts "eventmachine with fibers doing concurrent requests"
|
36
|
-
EM.run{
|
37
|
-
Fiber.new{
|
38
|
-
a = [client.get('cardinalblue'), client.get('godfat')]
|
39
|
-
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
40
|
-
puts "DONE"
|
41
|
-
EM.stop
|
42
|
-
}.resume
|
43
|
-
puts "It's not blocking... but doing concurrent requests underneath"
|
44
|
-
}
|
@@ -1,25 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-core/middleware'
|
3
|
-
|
4
|
-
class RestCore::Auto
|
5
|
-
include RestCore::Middleware
|
6
|
-
def call env, &k
|
7
|
-
client = http_client
|
8
|
-
client.call(log(env, "Auto picked: #{client.class}"), &k)
|
9
|
-
end
|
10
|
-
|
11
|
-
def http_client
|
12
|
-
if Object.const_defined?(:EventMachine) &&
|
13
|
-
::EventMachine.const_defined?(:HttpRequest) &&
|
14
|
-
::EventMachine.reactor_running? &&
|
15
|
-
# it should be either wrapped around a thread or a fiber
|
16
|
-
((Thread.main != Thread.current) ||
|
17
|
-
(Fiber.respond_to?(:current) && RootFiber != Fiber.current))
|
18
|
-
|
19
|
-
@emhttprequest ||= RestCore::EmHttpRequest.new
|
20
|
-
|
21
|
-
else
|
22
|
-
@restclient ||= RestCore::RestClient.new
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'em-http-request'
|
3
|
-
require 'restclient/payload'
|
4
|
-
|
5
|
-
require 'rest-core/engine/future/future'
|
6
|
-
require 'rest-core/middleware'
|
7
|
-
|
8
|
-
class RestCore::EmHttpRequest
|
9
|
-
include RestCore::Middleware
|
10
|
-
def call env, &k
|
11
|
-
future = Future.create(env, k, env[ASYNC])
|
12
|
-
|
13
|
-
# eventmachine is not thread-safe, so...
|
14
|
-
# https://github.com/igrigorik/em-http-request/issues/190#issuecomment-16995528
|
15
|
-
::EventMachine.schedule{ request(future, env) }
|
16
|
-
|
17
|
-
env.merge(RESPONSE_BODY => future.proxy_body,
|
18
|
-
RESPONSE_STATUS => future.proxy_status,
|
19
|
-
RESPONSE_HEADERS => future.proxy_headers,
|
20
|
-
FUTURE => future)
|
21
|
-
end
|
22
|
-
|
23
|
-
def request future, env
|
24
|
-
payload, headers = Payload.generate_with_headers(env[REQUEST_PAYLOAD],
|
25
|
-
env[REQUEST_HEADERS])
|
26
|
-
args = if payload.nil?
|
27
|
-
{}
|
28
|
-
else
|
29
|
-
tmpfile = payload2file(payload)
|
30
|
-
if tmpfile.respond_to?(:path)
|
31
|
-
{:file => tmpfile.path}
|
32
|
-
else
|
33
|
-
{:body => tmpfile}
|
34
|
-
end
|
35
|
-
end.merge(:head => headers)
|
36
|
-
|
37
|
-
client = ::EventMachine::HttpRequest.new(request_uri(env)).
|
38
|
-
send(env[REQUEST_METHOD], args)
|
39
|
-
|
40
|
-
client.callback{
|
41
|
-
close_tmpfile(tmpfile)
|
42
|
-
future.on_load(client.response,
|
43
|
-
client.response_header.status,
|
44
|
-
client.response_header)}
|
45
|
-
|
46
|
-
client.errback{
|
47
|
-
close_client(client)
|
48
|
-
close_tmpfile(tmpfile)
|
49
|
-
future.on_error(client.error)}
|
50
|
-
|
51
|
-
env[TIMER].on_timeout{
|
52
|
-
close_client(client)
|
53
|
-
close_tmpfile(tmpfile)
|
54
|
-
future.on_error(env[TIMER].error)
|
55
|
-
} if env[TIMER]
|
56
|
-
end
|
57
|
-
|
58
|
-
def payload2file payload
|
59
|
-
if payload.io.respond_to?(:path) # already a file
|
60
|
-
payload.io
|
61
|
-
|
62
|
-
elsif payload.size == 0 || # probably a socket, buffer to disc
|
63
|
-
payload.size >= 81920 # probably too large, buffer to disc
|
64
|
-
create_tmpfile(payload.io)
|
65
|
-
|
66
|
-
else # probably not worth buffering to disc
|
67
|
-
payload.read
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def create_tmpfile io
|
72
|
-
tempfile = Tempfile.new("rest-core.em-http-request.#{rand(1_000_000)}")
|
73
|
-
IO.copy_stream(io, tempfile)
|
74
|
-
tempfile
|
75
|
-
end
|
76
|
-
|
77
|
-
def close_client client
|
78
|
-
(client.instance_variable_get(:@callbacks)||[]).clear
|
79
|
-
(client.instance_variable_get(:@errbacks )||[]).clear
|
80
|
-
client.close
|
81
|
-
end
|
82
|
-
|
83
|
-
def close_tmpfile tmpfile
|
84
|
-
if tmpfile.respond_to?(:close!) # tempfile
|
85
|
-
tmpfile.close!
|
86
|
-
elsif tmpfile.respond_to?(:close) # regular IO
|
87
|
-
tmpfile.close
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,107 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-core'
|
3
|
-
|
4
|
-
class RestCore::Future
|
5
|
-
include RestCore
|
6
|
-
|
7
|
-
class Proxy < BasicObject
|
8
|
-
def initialize future, target
|
9
|
-
@future, @target = future, target
|
10
|
-
end
|
11
|
-
|
12
|
-
def method_missing msg, *args, &block
|
13
|
-
@future.yield[@target].__send__(msg, *args, &block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.create *args, &block
|
18
|
-
if Fiber.respond_to?(:current) && RootFiber != Fiber.current &&
|
19
|
-
# because under a thread, Fiber.current won't return the root fiber
|
20
|
-
Thread.main == Thread.current
|
21
|
-
FutureFiber .new(*args, &block)
|
22
|
-
else
|
23
|
-
FutureThread.new(*args, &block)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize env, k, immediate
|
28
|
-
self.env = env
|
29
|
-
self.k = k
|
30
|
-
self.immediate = immediate
|
31
|
-
self.response, self.body, self.status, self.headers, self.error = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def proxy_body ; Proxy.new(self, RESPONSE_BODY ); end
|
35
|
-
def proxy_status ; Proxy.new(self, RESPONSE_STATUS ); end
|
36
|
-
def proxy_headers; Proxy.new(self, RESPONSE_HEADERS); end
|
37
|
-
|
38
|
-
def wrap ; raise NotImplementedError; end
|
39
|
-
def wait ; raise NotImplementedError; end
|
40
|
-
def resume; raise NotImplementedError; end
|
41
|
-
|
42
|
-
def loaded?
|
43
|
-
!!status
|
44
|
-
end
|
45
|
-
|
46
|
-
def yield
|
47
|
-
wait
|
48
|
-
callback
|
49
|
-
end
|
50
|
-
|
51
|
-
def callback
|
52
|
-
self.response ||= k.call(
|
53
|
-
env.merge(RESPONSE_BODY => body ,
|
54
|
-
RESPONSE_STATUS => status,
|
55
|
-
RESPONSE_HEADERS => headers,
|
56
|
-
FAIL => ((env[FAIL]||[]) + [error]).compact,
|
57
|
-
LOG => (env[LOG] ||[]) +
|
58
|
-
["Future picked: #{self.class}"]))
|
59
|
-
end
|
60
|
-
|
61
|
-
def callback_in_async
|
62
|
-
callback
|
63
|
-
rescue Exception => e
|
64
|
-
# nothing we can do here for an asynchronous exception,
|
65
|
-
# so we just log the error
|
66
|
-
logger = method(:warn) # TODO: add error_log_method
|
67
|
-
logger.call "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
|
68
|
-
end
|
69
|
-
|
70
|
-
def on_load body, status, headers
|
71
|
-
env[TIMER].cancel if env[TIMER]
|
72
|
-
synchronize{
|
73
|
-
self.body, self.status, self.headers = body, status, headers
|
74
|
-
}
|
75
|
-
# under ASYNC callback, should call immediately
|
76
|
-
next_tick{ callback_in_async } if immediate
|
77
|
-
resume # client or response might be waiting
|
78
|
-
end
|
79
|
-
|
80
|
-
def on_error error
|
81
|
-
self.error = if error.kind_of?(Exception)
|
82
|
-
error
|
83
|
-
else
|
84
|
-
Error.new(error || 'unknown')
|
85
|
-
end
|
86
|
-
on_load('', 0, {})
|
87
|
-
end
|
88
|
-
|
89
|
-
protected
|
90
|
-
attr_accessor :env, :k, :immediate,
|
91
|
-
:response, :body, :status, :headers, :error
|
92
|
-
|
93
|
-
private
|
94
|
-
def synchronize; yield; end
|
95
|
-
# next_tick is used for telling the reactor that there's something else
|
96
|
-
# should be done, don't sleep and don't stop at the moment
|
97
|
-
def next_tick
|
98
|
-
if Object.const_defined?(:EventMachine) && EventMachine.reactor_running?
|
99
|
-
EventMachine.next_tick{ yield }
|
100
|
-
else
|
101
|
-
yield
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
autoload :FutureFiber , 'rest-core/engine/future/future_fiber'
|
106
|
-
autoload :FutureThread, 'rest-core/engine/future/future_thread'
|
107
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'fiber'
|
3
|
-
|
4
|
-
class RestCore::Future::FutureFiber < RestCore::Future
|
5
|
-
def initialize *args
|
6
|
-
super
|
7
|
-
self.fibers = []
|
8
|
-
end
|
9
|
-
|
10
|
-
def wrap
|
11
|
-
Fiber.new{ yield }.resume
|
12
|
-
end
|
13
|
-
|
14
|
-
def wait
|
15
|
-
fibers << Fiber.current
|
16
|
-
Fiber.yield until loaded? # it might be resumed by some other futures!
|
17
|
-
end
|
18
|
-
|
19
|
-
def resume
|
20
|
-
return if fibers.empty?
|
21
|
-
current_fibers = fibers.dup
|
22
|
-
fibers.clear
|
23
|
-
current_fibers.each{ |f|
|
24
|
-
next unless f.alive?
|
25
|
-
next_tick{ f.resume }
|
26
|
-
}
|
27
|
-
resume
|
28
|
-
end
|
29
|
-
|
30
|
-
protected
|
31
|
-
attr_accessor :fibers
|
32
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
class RestCore::Future::FutureThread < RestCore::Future
|
5
|
-
def initialize *args
|
6
|
-
super
|
7
|
-
self.condv = ConditionVariable.new
|
8
|
-
self.mutex = Mutex.new
|
9
|
-
end
|
10
|
-
|
11
|
-
def wrap
|
12
|
-
Thread.new{ yield }
|
13
|
-
end
|
14
|
-
|
15
|
-
def wait
|
16
|
-
# it might be awaken by some other futures!
|
17
|
-
synchronize{ condv.wait(mutex) until loaded? } unless loaded?
|
18
|
-
end
|
19
|
-
|
20
|
-
def resume
|
21
|
-
condv.broadcast
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
attr_accessor :condv, :mutex
|
26
|
-
|
27
|
-
private
|
28
|
-
def synchronize; mutex.synchronize{ yield }; end
|
29
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'eventmachine'
|
3
|
-
|
4
|
-
class RestCore::Timeout::TimerEm < ::EventMachine::Timer
|
5
|
-
attr_accessor :timeout, :error
|
6
|
-
|
7
|
-
def initialize timeout, error, &block
|
8
|
-
super(timeout, &block) if block_given?
|
9
|
-
self.timeout = timeout
|
10
|
-
self.error = error
|
11
|
-
@canceled = false
|
12
|
-
end
|
13
|
-
|
14
|
-
def on_timeout &block
|
15
|
-
send(:initialize, timeout, error, &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def cancel
|
19
|
-
super
|
20
|
-
@canceled = true
|
21
|
-
end
|
22
|
-
|
23
|
-
def canceled?
|
24
|
-
@canceled
|
25
|
-
end
|
26
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
|
2
|
-
class RestCore::Timeout::TimerThread
|
3
|
-
attr_accessor :timeout, :error
|
4
|
-
|
5
|
-
def initialize timeout, error, &block
|
6
|
-
t = Thread.current
|
7
|
-
self.timeout = timeout
|
8
|
-
self.error = error
|
9
|
-
self.block = block || lambda{ t.raise error }
|
10
|
-
@canceled = false
|
11
|
-
start
|
12
|
-
end
|
13
|
-
|
14
|
-
def on_timeout &block
|
15
|
-
self.block = block
|
16
|
-
end
|
17
|
-
|
18
|
-
def cancel
|
19
|
-
@canceled = true
|
20
|
-
end
|
21
|
-
|
22
|
-
def canceled?
|
23
|
-
@canceled
|
24
|
-
end
|
25
|
-
|
26
|
-
def start
|
27
|
-
return if timeout.nil? || timeout.zero?
|
28
|
-
self.thread = Thread.new{
|
29
|
-
sleep(timeout)
|
30
|
-
block.call unless canceled?
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
attr_accessor :block, :thread
|
36
|
-
end
|
data/task/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
*.rbc
|
@@ -1,186 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-core/test'
|
3
|
-
|
4
|
-
describe RC::EmHttpRequest do
|
5
|
-
should 'raise RC::Error' do
|
6
|
-
EM.run{Fiber.new{
|
7
|
-
lambda{
|
8
|
-
RC::Universal.new.get('http://localhost:1').tap{}
|
9
|
-
}.should.raise(RC::Error)
|
10
|
-
EM.stop
|
11
|
-
}.resume}
|
12
|
-
end
|
13
|
-
|
14
|
-
should 'never crash EM!' do
|
15
|
-
EM.error_handler{ |e| e.should.kind_of?(NoMethodError); EM.stop}
|
16
|
-
EM.run{Fiber.new{
|
17
|
-
RC::Simple.new.get('http://localhost:1').no_such_method
|
18
|
-
}.resume}
|
19
|
-
end
|
20
|
-
|
21
|
-
describe 'POST Payload' do
|
22
|
-
after do
|
23
|
-
WebMock.reset!
|
24
|
-
end
|
25
|
-
|
26
|
-
client = RC::Builder.client
|
27
|
-
client.builder.run(RC::EmHttpRequest)
|
28
|
-
path = 'http://example.com'
|
29
|
-
ok = 'OK'
|
30
|
-
c = client.new
|
31
|
-
|
32
|
-
post = lambda do |payload, body|
|
33
|
-
stub_request(:post, path).with(:body => body).to_return(:body => ok)
|
34
|
-
EM.error_handler{ |e| e.should.kind_of?(NilClass); EM.stop }
|
35
|
-
EM.run{ EM.defer{
|
36
|
-
c.post(path, payload).should.eq ok
|
37
|
-
EM.next_tick{ EM.stop }
|
38
|
-
}}
|
39
|
-
end
|
40
|
-
|
41
|
-
should 'post with string' do
|
42
|
-
post['string', 'string']
|
43
|
-
end
|
44
|
-
|
45
|
-
should 'post with file' do
|
46
|
-
File.open(__FILE__) do |f|
|
47
|
-
b = f.read
|
48
|
-
f.rewind
|
49
|
-
post[f, b]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
should 'post with socket' do
|
54
|
-
rd, wr = IO.pipe
|
55
|
-
wr.write('socket')
|
56
|
-
wr.close
|
57
|
-
post[rd, 'socket']
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# ----------------------------------------------------------------------
|
62
|
-
|
63
|
-
describe RC::Simple do
|
64
|
-
before do
|
65
|
-
@path = 'http://example.com'
|
66
|
-
stub_request(:get, @path).to_return(:body => 'OK')
|
67
|
-
end
|
68
|
-
|
69
|
-
should 'work with EM' do
|
70
|
-
EM.run{Fiber.new{
|
71
|
-
RC::Simple.new.get(@path).should.eq 'OK'; EM.stop}.resume}
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# ----------------------------------------------------------------------
|
76
|
-
|
77
|
-
describe RC::Timeout do
|
78
|
-
after do
|
79
|
-
WebMock.reset!
|
80
|
-
RR.verify
|
81
|
-
end
|
82
|
-
|
83
|
-
should 'cancel timeout for fiber' do
|
84
|
-
any_instance_of(RC::Timeout::TimerEm) do |timer|
|
85
|
-
proxy.mock(timer).cancel.times(2)
|
86
|
-
end
|
87
|
-
path = 'http://example.com/'
|
88
|
-
stub_request(:get, path).to_return(:body => 'response')
|
89
|
-
c = RC::Builder.client do
|
90
|
-
use RC::Timeout, 10
|
91
|
-
use RC::Cache, {}, 3600
|
92
|
-
run RC::EmHttpRequest
|
93
|
-
end.new
|
94
|
-
EM.run{ Fiber.new{
|
95
|
-
c.request(RC::REQUEST_PATH => path).should.eq 'response'
|
96
|
-
c.request(RC::REQUEST_PATH => path).should.eq 'response'
|
97
|
-
EM.stop }.resume }
|
98
|
-
c.cache.size.should.eq 1
|
99
|
-
end
|
100
|
-
|
101
|
-
should 'cancel timeout for async' do
|
102
|
-
path = 'http://example.com/'
|
103
|
-
any_instance_of(RC::Timeout::TimerEm) do |timer|
|
104
|
-
mock(timer).cancel.times(2)
|
105
|
-
end
|
106
|
-
stub_request(:get, path).to_return(:body => 'response')
|
107
|
-
c = RC::Builder.client do
|
108
|
-
use RC::Timeout, 10
|
109
|
-
use RC::Cache, {}, 3600
|
110
|
-
run RC::EmHttpRequest
|
111
|
-
end.new
|
112
|
-
EM.run{
|
113
|
-
c.request_full(RC::REQUEST_PATH => path){
|
114
|
-
c.request_full(RC::REQUEST_PATH => path){
|
115
|
-
EM.stop }}}
|
116
|
-
c.cache.size.should.eq 1
|
117
|
-
end
|
118
|
-
|
119
|
-
should 'return correct result for futures' do
|
120
|
-
path = 'http://example.com/'
|
121
|
-
stub_request(:get, path).to_return(:body => 'response')
|
122
|
-
|
123
|
-
c = RC::Builder.client do
|
124
|
-
use RC::Timeout, 10
|
125
|
-
run RC::EmHttpRequest
|
126
|
-
end.new
|
127
|
-
EM.run{Fiber.new{c.get(path).should.eq('response');EM.stop}.resume}
|
128
|
-
end
|
129
|
-
|
130
|
-
describe 'raise exception' do
|
131
|
-
should 'default timeout' do
|
132
|
-
c = RC::Builder.client do
|
133
|
-
use RC::Timeout, 0.00001
|
134
|
-
run Class.new{
|
135
|
-
def call env
|
136
|
-
sleep 1
|
137
|
-
yield(env)
|
138
|
-
end
|
139
|
-
}
|
140
|
-
end.new
|
141
|
-
lambda{ c.get('') }.should.raise ::Timeout::Error
|
142
|
-
end
|
143
|
-
|
144
|
-
should 'future timeout' do
|
145
|
-
port = 35795
|
146
|
-
path = "http://localhost:#{port}/"
|
147
|
-
|
148
|
-
c = RC::Builder.client do
|
149
|
-
use RC::Timeout, 0.00001
|
150
|
-
run RC::EmHttpRequest
|
151
|
-
end.new
|
152
|
-
|
153
|
-
EM.run{
|
154
|
-
EM.start_server '127.0.0.1', port, Module.new{
|
155
|
-
def receive_data data; end
|
156
|
-
}
|
157
|
-
Fiber.new{
|
158
|
-
begin
|
159
|
-
c.get(path).tap{}
|
160
|
-
rescue => e
|
161
|
-
e.should.kind_of ::Timeout::Error
|
162
|
-
EM.stop
|
163
|
-
end
|
164
|
-
}.resume}
|
165
|
-
end
|
166
|
-
|
167
|
-
should 'async timeout' do
|
168
|
-
port = 35795
|
169
|
-
path = "http://localhost:#{port}/"
|
170
|
-
|
171
|
-
c = RC::Builder.client do
|
172
|
-
use RC::Timeout, 0.00001
|
173
|
-
use RC::ErrorHandler
|
174
|
-
run RC::EmHttpRequest
|
175
|
-
end.new
|
176
|
-
|
177
|
-
EM.run{
|
178
|
-
EM.start_server '127.0.0.1', port, Module.new{
|
179
|
-
def receive_data data; end
|
180
|
-
}
|
181
|
-
c.get(path){ |e| e.should.kind_of ::Timeout::Error; EM.stop }
|
182
|
-
}
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end unless RUBY_ENGINE == 'jruby'
|