rest-core 2.1.2 → 3.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.
- 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'
|