rest-core 1.0.3 → 2.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.
- data/.travis.yml +6 -7
- data/CHANGES.md +137 -0
- data/Gemfile +1 -1
- data/README.md +183 -191
- data/TODO.md +5 -8
- data/example/multi.rb +31 -24
- data/example/simple.rb +28 -0
- data/example/use-cases.rb +194 -0
- data/lib/rest-core.rb +26 -19
- data/lib/rest-core/builder.rb +2 -2
- data/lib/rest-core/client.rb +40 -27
- data/lib/rest-core/client/universal.rb +16 -13
- data/lib/rest-core/client_oauth1.rb +5 -5
- data/lib/rest-core/engine/auto.rb +25 -0
- data/lib/rest-core/{app → engine}/dry.rb +1 -2
- data/lib/rest-core/engine/em-http-request.rb +39 -0
- data/lib/rest-core/engine/future/future.rb +106 -0
- data/lib/rest-core/engine/future/future_fiber.rb +39 -0
- data/lib/rest-core/engine/future/future_thread.rb +29 -0
- data/lib/rest-core/engine/rest-client.rb +56 -0
- data/lib/rest-core/middleware.rb +27 -5
- data/lib/rest-core/middleware/auth_basic.rb +5 -5
- data/lib/rest-core/middleware/bypass.rb +2 -2
- data/lib/rest-core/middleware/cache.rb +67 -54
- data/lib/rest-core/middleware/common_logger.rb +5 -8
- data/lib/rest-core/middleware/default_headers.rb +2 -2
- data/lib/rest-core/middleware/default_payload.rb +26 -2
- data/lib/rest-core/middleware/default_query.rb +4 -2
- data/lib/rest-core/middleware/default_site.rb +8 -6
- data/lib/rest-core/middleware/error_detector.rb +9 -16
- data/lib/rest-core/middleware/error_handler.rb +25 -11
- data/lib/rest-core/middleware/follow_redirect.rb +11 -14
- data/lib/rest-core/middleware/json_request.rb +19 -0
- data/lib/rest-core/middleware/json_response.rb +28 -0
- data/lib/rest-core/middleware/oauth1_header.rb +2 -7
- data/lib/rest-core/middleware/oauth2_header.rb +4 -7
- data/lib/rest-core/middleware/oauth2_query.rb +2 -2
- data/lib/rest-core/middleware/timeout.rb +21 -65
- data/lib/rest-core/middleware/timeout/{eventmachine_timer.rb → timer_em.rb} +3 -1
- data/lib/rest-core/middleware/timeout/timer_thread.rb +36 -0
- data/lib/rest-core/patch/multi_json.rb +8 -0
- data/lib/rest-core/test.rb +3 -12
- data/lib/rest-core/util/json.rb +65 -0
- data/lib/rest-core/util/parse_query.rb +2 -2
- data/lib/rest-core/version.rb +1 -1
- data/lib/rest-core/wrapper.rb +16 -16
- data/rest-core.gemspec +28 -27
- data/test/test_auth_basic.rb +14 -10
- data/test/test_builder.rb +7 -7
- data/test/test_cache.rb +126 -37
- data/test/test_client.rb +3 -1
- data/test/test_client_oauth1.rb +2 -3
- data/test/test_default_query.rb +17 -23
- data/test/test_em_http_request.rb +146 -0
- data/test/test_error_detector.rb +0 -1
- data/test/test_error_handler.rb +44 -0
- data/test/test_follow_redirect.rb +17 -19
- data/test/test_json_request.rb +28 -0
- data/test/test_json_response.rb +51 -0
- data/test/test_oauth1_header.rb +4 -4
- data/test/test_payload.rb +20 -12
- data/test/test_simple.rb +14 -0
- data/test/test_timeout.rb +11 -19
- data/test/test_universal.rb +5 -5
- data/test/test_wrapper.rb +19 -13
- metadata +28 -29
- data/doc/ToC.md +0 -7
- data/doc/dependency.md +0 -4
- data/doc/design.md +0 -4
- data/example/auto.rb +0 -51
- data/example/coolio.rb +0 -21
- data/example/eventmachine.rb +0 -30
- data/example/rest-client.rb +0 -16
- data/lib/rest-core/app/abstract/async_fiber.rb +0 -13
- data/lib/rest-core/app/auto.rb +0 -23
- data/lib/rest-core/app/coolio-async.rb +0 -32
- data/lib/rest-core/app/coolio-fiber.rb +0 -30
- data/lib/rest-core/app/coolio.rb +0 -9
- data/lib/rest-core/app/em-http-request-async.rb +0 -37
- data/lib/rest-core/app/em-http-request-fiber.rb +0 -45
- data/lib/rest-core/app/em-http-request.rb +0 -9
- data/lib/rest-core/app/rest-client.rb +0 -41
- data/lib/rest-core/middleware/json_decode.rb +0 -93
- data/lib/rest-core/middleware/timeout/coolio_timer.rb +0 -10
- data/pending/test_multi.rb +0 -123
- data/pending/test_test_util.rb +0 -86
- data/test/test_json_decode.rb +0 -24
data/test/test_auth_basic.rb
CHANGED
@@ -1,36 +1,40 @@
|
|
1
1
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe RC::AuthBasic do
|
5
5
|
before do
|
6
|
-
@auth =
|
6
|
+
@auth = RC::AuthBasic.new(RC::Dry.new, nil, nil)
|
7
7
|
end
|
8
8
|
|
9
9
|
should 'do nothing' do
|
10
|
-
@auth.call({}).should.eq({})
|
10
|
+
@auth.call({}){ |res| res.should.eq({}) }
|
11
11
|
end
|
12
12
|
|
13
13
|
should 'send Authorization header' do
|
14
14
|
@auth.instance_eval{@username = 'Aladdin'}
|
15
15
|
@auth.instance_eval{@password = 'open sesame'}
|
16
16
|
|
17
|
-
@auth.call({})
|
18
|
-
{
|
17
|
+
@auth.call({}){ |res|
|
18
|
+
res.should.eq({RC::REQUEST_HEADERS =>
|
19
|
+
{'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}})
|
20
|
+
}
|
19
21
|
|
20
22
|
acc = {'Accept' => 'text/plain'}
|
21
|
-
env = {
|
23
|
+
env = {RC::REQUEST_HEADERS => acc}
|
22
24
|
|
23
|
-
@auth.call(env)
|
24
|
-
{
|
25
|
+
@auth.call(env){ |res|
|
26
|
+
res.should.eq({RC::REQUEST_HEADERS =>
|
27
|
+
{'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}.merge(acc)})
|
28
|
+
}
|
25
29
|
end
|
26
30
|
|
27
31
|
should 'leave a log if username are not both provided' do
|
28
32
|
@auth.instance_eval{@username = 'Aladdin'}
|
29
|
-
@auth.call({})[
|
33
|
+
@auth.call({}){ |res| res[RC::LOG].size.should.eq 1 }
|
30
34
|
end
|
31
35
|
|
32
36
|
should 'leave a log if password are not both provided' do
|
33
37
|
@auth.instance_eval{@password = 'open sesame'}
|
34
|
-
@auth.call({})[
|
38
|
+
@auth.call({}){ |res| res[RC::LOG].size.should.eq 1 }
|
35
39
|
end
|
36
40
|
end
|
data/test/test_builder.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
|
-
describe
|
5
|
-
should 'default app is RestCore::
|
6
|
-
|
4
|
+
describe RC::Builder do
|
5
|
+
should 'default app is RestCore::Auto' do
|
6
|
+
RC::Builder.client.new.app.class.should.eq RC::Auto
|
7
7
|
end
|
8
8
|
|
9
|
-
should 'switch
|
10
|
-
builder =
|
11
|
-
builder.
|
12
|
-
builder.client.new.app.class.should.eq
|
9
|
+
should 'switch default_engine to RestCore::Dry' do
|
10
|
+
builder = RC::Builder.dup
|
11
|
+
builder.default_engine = RC::Dry
|
12
|
+
builder.client.new.app.class.should.eq RC::Dry
|
13
13
|
end
|
14
14
|
end
|
data/test/test_cache.rb
CHANGED
@@ -7,7 +7,7 @@ describe RC::Cache do
|
|
7
7
|
RR.verify
|
8
8
|
end
|
9
9
|
|
10
|
-
should 'basic' do
|
10
|
+
should 'basic 0' do
|
11
11
|
c = RC::Builder.client do
|
12
12
|
use RC::Cache, {}, 3600
|
13
13
|
run Class.new{
|
@@ -17,71 +17,160 @@ describe RC::Cache do
|
|
17
17
|
end
|
18
18
|
def call env
|
19
19
|
self.tick +=1
|
20
|
-
env.merge(RC::RESPONSE_BODY
|
20
|
+
yield(env.merge(RC::RESPONSE_BODY => 'response',
|
21
|
+
RC::RESPONSE_HEADERS => {'A' => 'B'},
|
22
|
+
RC::RESPONSE_STATUS => 200))
|
21
23
|
end
|
22
24
|
}
|
23
25
|
end.new
|
24
26
|
c.get('/')
|
25
|
-
|
27
|
+
key = Digest::MD5.hexdigest('get:/:')
|
28
|
+
c.cache.should.eq("rest-core:cache:#{key}" => "200\nA: B\n\nresponse")
|
26
29
|
c.app.app.tick.should.eq 1
|
27
30
|
c.get('/')
|
28
31
|
c.app.app.tick.should.eq 1
|
29
32
|
c.cache.clear
|
30
33
|
c.get('/')
|
31
34
|
c.app.app.tick.should.eq 2
|
35
|
+
c.head('/').should.eq('A' => 'B')
|
36
|
+
c.get('/').should.eq 'response'
|
37
|
+
c.request({RC::REQUEST_PATH => '/'}, RC::RESPONSE_STATUS).should.eq 200
|
32
38
|
end
|
33
39
|
|
34
|
-
should '
|
35
|
-
|
36
|
-
|
40
|
+
should 'basic 1' do
|
41
|
+
path = 'http://a'
|
42
|
+
stub_request(:get , path).to_return(:body => 'OK')
|
43
|
+
stub_request(:post, path).to_return(:body => 'OK')
|
44
|
+
c = RC::Builder.client do
|
45
|
+
use RC::Cache, nil, nil
|
37
46
|
end
|
38
|
-
|
39
|
-
|
47
|
+
|
48
|
+
c.new . get(path).should.eq('OK')
|
49
|
+
c.new(:cache => (h={})).post(path).should.eq('OK')
|
50
|
+
h.should.eq({})
|
51
|
+
c.new(:cache => (h={})). get(path).should.eq('OK')
|
52
|
+
h.size.should.eq 1
|
53
|
+
c.new(:cache => (h={})). get(path, {}, :cache => false).should.eq('OK')
|
54
|
+
h.should.eq({})
|
55
|
+
c.new . get(path, {}, 'cache.update' => true).
|
56
|
+
should.eq('OK')
|
57
|
+
end
|
58
|
+
|
59
|
+
should 'not raise error if headers is nil' do
|
60
|
+
path = 'http://a'
|
61
|
+
stub_request(:get , path).to_return(:body => 'OK', :headers => nil)
|
40
62
|
c = RC::Builder.client do
|
41
|
-
use RC::
|
42
|
-
use RC::Cache, {}, 3600
|
43
|
-
run RC::EmHttpRequestFiber
|
63
|
+
use RC::Cache, {}, nil
|
44
64
|
end.new
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end if defined?(Fiber)
|
51
|
-
|
52
|
-
should 'cancel timeout for async' do
|
53
|
-
path = 'http://example.com/'
|
54
|
-
any_instance_of(RC::Timeout::EventMachineTimer) do |timer|
|
55
|
-
mock(timer).cancel.times(2)
|
56
|
-
end
|
57
|
-
stub_request(:get, path).to_return(:body => 'response')
|
65
|
+
c.get(path).should.eq 'OK'
|
66
|
+
c.get(path).should.eq 'OK'
|
67
|
+
end
|
68
|
+
|
69
|
+
should 'head then get' do
|
58
70
|
c = RC::Builder.client do
|
59
|
-
use RC::
|
60
|
-
use RC::Cache, {}, 3600
|
61
|
-
run RC::EmHttpRequestAsync
|
71
|
+
use RC::Cache, {}, nil
|
62
72
|
end.new
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
c.
|
73
|
+
path = 'http://example.com'
|
74
|
+
stub_request(:head, path).to_return(:headers => {'A' => 'B'})
|
75
|
+
c.head(path).should.eq('A' => 'B')
|
76
|
+
stub_request(:get , path).to_return(:body => 'body')
|
77
|
+
c.get(path).should.eq('body')
|
68
78
|
end
|
69
79
|
|
70
80
|
should 'only [] and []= should be implemented' do
|
71
81
|
cache = Class.new do
|
72
|
-
def initialize ; @h = {}
|
73
|
-
def [] key ; @h[key]
|
74
|
-
def []= key, value; @h[key] = value
|
82
|
+
def initialize ; @h = {} ; end
|
83
|
+
def [] key ; @h[key] ; end
|
84
|
+
def []= key, value; @h[key] = value.sub('4', '5'); end
|
75
85
|
end.new
|
76
86
|
c = RC::Builder.client do
|
77
87
|
use RC::Cache, cache, 0
|
78
88
|
run Class.new{
|
79
89
|
def call env
|
80
|
-
env.merge(RC::RESPONSE_BODY
|
90
|
+
yield(env.merge(RC::RESPONSE_BODY => env[RC::REQUEST_PATH],
|
91
|
+
RC::RESPONSE_STATUS => 200))
|
81
92
|
end
|
82
93
|
}
|
83
94
|
end.new
|
84
95
|
c.get('4')
|
85
|
-
c.get('4').should.eq '
|
96
|
+
c.get('4').should.eq '5'
|
97
|
+
end
|
98
|
+
|
99
|
+
should 'cache the original response' do
|
100
|
+
c = RC::Builder.client do
|
101
|
+
use RC::Cache, {}, 3600 do
|
102
|
+
use RC::JsonResponse, true
|
103
|
+
end
|
104
|
+
end.new
|
105
|
+
stub_request(:get, 'me').to_return(:body => body = '{"a":"b"}')
|
106
|
+
c.get('me').should.eq 'a' => 'b'
|
107
|
+
c.cache.values.first.should.eq "200\n\n\n#{body}"
|
108
|
+
end
|
109
|
+
|
110
|
+
should "follow redirect with cache.update correctly" do
|
111
|
+
c = RC::Builder.client do
|
112
|
+
use RC::FollowRedirect, 10
|
113
|
+
use RC::Cache, {}, nil
|
114
|
+
end.new
|
115
|
+
x, y, z = 'http://X', 'http://Y', 'http://Z'
|
116
|
+
stub_request(:get, x).to_return(:headers => {'Location' => y},
|
117
|
+
:status => 301)
|
118
|
+
stub_request(:get, y).to_return(:headers => {'Location' => z},
|
119
|
+
:status => 302)
|
120
|
+
stub_request(:get, z).to_return(:body => 'OK')
|
121
|
+
c.get(x, {}, 'cache.update' => true).should.eq 'OK'
|
122
|
+
end
|
123
|
+
|
124
|
+
should 'not cache post/put/delete' do
|
125
|
+
[:put, :post, :delete].each{ |meth|
|
126
|
+
url, body = "https://cache", 'ok'
|
127
|
+
stub_request(meth, url).to_return(:body => body).times(3)
|
128
|
+
|
129
|
+
cache = {}
|
130
|
+
c = RC::Builder.client{use RC::Cache, cache, nil}.new
|
131
|
+
3.times{
|
132
|
+
if meth == :delete
|
133
|
+
c.send(meth, url).should.eq(body)
|
134
|
+
else
|
135
|
+
c.send(meth, url, 'payload').should.eq(body)
|
136
|
+
end
|
137
|
+
}
|
138
|
+
cache.should.eq({})
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
should 'update cache if there is cache option set to false' do
|
143
|
+
url, body = "https://cache", 'ok'
|
144
|
+
stub_request(:get, url).to_return(:body => body)
|
145
|
+
c = RC::Builder.client{use RC::Cache, {}, nil}.new
|
146
|
+
|
147
|
+
c.get(url) .should.eq body
|
148
|
+
stub_request(:get, url).to_return(:body => body.reverse).times(2)
|
149
|
+
c.get(url) .should.eq body
|
150
|
+
c.get(url, {}, 'cache.update' => true).should.eq body.reverse
|
151
|
+
c.get(url) .should.eq body.reverse
|
152
|
+
c.cache = nil
|
153
|
+
c.get(url, {}, 'cache.update' => true).should.eq body.reverse
|
154
|
+
end
|
155
|
+
|
156
|
+
describe 'expires_in' do
|
157
|
+
before do
|
158
|
+
@url, @body = "https://cache", 'ok'
|
159
|
+
stub_request(:get, @url).to_return(:body => @body)
|
160
|
+
@cache = {}
|
161
|
+
mock(@cache).method(:store){ mock!.arity{ -3 } }
|
162
|
+
mock(@cache).store(is_a(String), is_a(String), :expires_in => 3)
|
163
|
+
@cache
|
164
|
+
end
|
165
|
+
|
166
|
+
should 'respect in options' do
|
167
|
+
c = RC::Builder.client{use RC::Cache, nil, nil}.new
|
168
|
+
c.get(@url, {}, :cache => @cache, :expires_in => 3).should.eq @body
|
169
|
+
end
|
170
|
+
|
171
|
+
should 'respect in middleware' do
|
172
|
+
c = RC::Builder.client{use RC::Cache, nil, 3}.new(:cache => @cache)
|
173
|
+
c.get(@url).should.eq @body
|
174
|
+
end
|
86
175
|
end
|
87
176
|
end
|
data/test/test_client.rb
CHANGED
@@ -24,12 +24,14 @@ describe RC::Simple do
|
|
24
24
|
stub_request(method, url).to_return(:body => '123')
|
25
25
|
(client = RC::Simple.new).send(method, url){ |res|
|
26
26
|
res.should.eq '123' }.should.eq client
|
27
|
+
client.wait
|
27
28
|
end
|
28
29
|
|
29
30
|
stub_request(:head, url).to_return(:headers => {'A' => 'B'})
|
30
31
|
(client = RC::Simple.new).head(url){ |res|
|
31
32
|
res.should.eq({'A' => 'B'})
|
32
33
|
}.should.eq client
|
34
|
+
client.wait
|
33
35
|
end
|
34
36
|
|
35
37
|
should 'have correct to_i' do
|
@@ -38,7 +40,7 @@ describe RC::Simple do
|
|
38
40
|
end
|
39
41
|
|
40
42
|
should 'use defaults' do
|
41
|
-
client =
|
43
|
+
client = RC::Builder.client do
|
42
44
|
use RC::Timeout, 4
|
43
45
|
end
|
44
46
|
c = client.new
|
data/test/test_client_oauth1.rb
CHANGED
@@ -17,7 +17,7 @@ describe RC::ClientOauth1 do
|
|
17
17
|
data = {'a' => 'b', 'c' => 'd'}
|
18
18
|
sig = Digest::MD5.hexdigest('e&a=b&c=d')
|
19
19
|
data_sig = data.merge('sig' => sig)
|
20
|
-
data_json = RC::
|
20
|
+
data_json = RC::Json.encode(data_sig)
|
21
21
|
@client = client.new(:data => data, :consumer_secret => 'e')
|
22
22
|
|
23
23
|
@client.send(:calculate_sig).should.eq sig
|
@@ -26,8 +26,7 @@ describe RC::ClientOauth1 do
|
|
26
26
|
@client.data_json = data_json
|
27
27
|
@client.data.should.eq data_sig
|
28
28
|
|
29
|
-
@client.data_json = RC::
|
30
|
-
data_sig.merge('sig' => 'wrong'))
|
29
|
+
@client.data_json = RC::Json.encode(data_sig.merge('sig' => 'wrong'))
|
31
30
|
@client.data.should.eq({})
|
32
31
|
|
33
32
|
@client.data_json = data_json
|
data/test/test_default_query.rb
CHANGED
@@ -2,44 +2,38 @@
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
4
|
describe RC::DefaultQuery do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
def app
|
11
|
-
@app
|
12
|
-
end
|
5
|
+
before do
|
6
|
+
@app = RC::DefaultQuery.new(RC::Dry.new, {})
|
7
|
+
end
|
13
8
|
|
9
|
+
describe 'when given query' do
|
14
10
|
should 'do nothing' do
|
15
|
-
app.call({})[RC::REQUEST_QUERY].should.eq({})
|
11
|
+
@app.call({}){ |r| r[RC::REQUEST_QUERY].should.eq({}) }
|
16
12
|
end
|
17
13
|
|
18
14
|
should 'merge query' do
|
19
|
-
app.instance_eval{@query = {'q' => 'uery'}}
|
15
|
+
@app.instance_eval{@query = {'q' => 'uery'}}
|
20
16
|
|
21
|
-
app.call({}).should.eq({RC::REQUEST_QUERY =>
|
22
|
-
{'q' => 'uery'}})
|
17
|
+
@app.call({}){ |r| r.should.eq({RC::REQUEST_QUERY => {'q' => 'uery'}}) }
|
23
18
|
|
24
19
|
format = {'format' => 'json'}
|
25
20
|
env = {RC::REQUEST_QUERY => format}
|
26
21
|
|
27
|
-
app.call(env)
|
28
|
-
{'q' => 'uery'}.merge(format)})
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe 'when not given query' do
|
33
|
-
before do
|
34
|
-
@app = RC::DefaultQuery.new(RC::Dry.new)
|
22
|
+
@app.call(env){ |r|
|
23
|
+
r.should.eq({RC::REQUEST_QUERY => {'q' => 'uery'}.merge(format)}) }
|
35
24
|
end
|
36
25
|
|
37
|
-
|
38
|
-
|
26
|
+
should 'string_keys in query' do
|
27
|
+
env = {'query' => {:symbol => 'value'}}
|
28
|
+
@app.call(env){ |r|
|
29
|
+
r.should.eq({RC::REQUEST_QUERY => {'symbol' => 'value'}}.merge(env))
|
30
|
+
}
|
39
31
|
end
|
32
|
+
end
|
40
33
|
|
34
|
+
describe 'when not given query' do
|
41
35
|
should 'merge query with {}' do
|
42
|
-
app.call({}).should.eq({RC::REQUEST_QUERY => {}})
|
36
|
+
@app.call({}){ |r| r.should.eq({RC::REQUEST_QUERY => {}}) }
|
43
37
|
end
|
44
38
|
end
|
45
39
|
end
|
@@ -0,0 +1,146 @@
|
|
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
|
+
# ----------------------------------------------------------------------
|
22
|
+
|
23
|
+
describe RC::Simple do
|
24
|
+
before do
|
25
|
+
@path = 'http://example.com'
|
26
|
+
stub_request(:get, @path).to_return(:body => 'OK')
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'work with EM' do
|
30
|
+
EM.run{Fiber.new{
|
31
|
+
RC::Simple.new.get(@path).should.eq 'OK'; EM.stop}.resume}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# ----------------------------------------------------------------------
|
36
|
+
|
37
|
+
describe RC::Timeout do
|
38
|
+
after do
|
39
|
+
WebMock.reset!
|
40
|
+
RR.verify
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'cancel timeout for fiber' do
|
44
|
+
any_instance_of(RC::Timeout::TimerEm) do |timer|
|
45
|
+
proxy.mock(timer).cancel.times(2)
|
46
|
+
end
|
47
|
+
path = 'http://example.com/'
|
48
|
+
stub_request(:get, path).to_return(:body => 'response')
|
49
|
+
c = RC::Builder.client do
|
50
|
+
use RC::Timeout, 10
|
51
|
+
use RC::Cache, {}, 3600
|
52
|
+
run RC::EmHttpRequest
|
53
|
+
end.new
|
54
|
+
EM.run{ Fiber.new{
|
55
|
+
c.request(RC::REQUEST_PATH => path).should.eq 'response'
|
56
|
+
c.request(RC::REQUEST_PATH => path).should.eq 'response'
|
57
|
+
EM.stop }.resume }
|
58
|
+
c.cache.size.should.eq 1
|
59
|
+
end
|
60
|
+
|
61
|
+
should 'cancel timeout for async' do
|
62
|
+
path = 'http://example.com/'
|
63
|
+
any_instance_of(RC::Timeout::TimerEm) do |timer|
|
64
|
+
mock(timer).cancel.times(2)
|
65
|
+
end
|
66
|
+
stub_request(:get, path).to_return(:body => 'response')
|
67
|
+
c = RC::Builder.client do
|
68
|
+
use RC::Timeout, 10
|
69
|
+
use RC::Cache, {}, 3600
|
70
|
+
run RC::EmHttpRequest
|
71
|
+
end.new
|
72
|
+
EM.run{
|
73
|
+
c.request_full(RC::REQUEST_PATH => path){
|
74
|
+
c.request_full(RC::REQUEST_PATH => path){
|
75
|
+
EM.stop }}}
|
76
|
+
c.cache.size.should.eq 1
|
77
|
+
end
|
78
|
+
|
79
|
+
should 'return correct result for futures' do
|
80
|
+
path = 'http://example.com/'
|
81
|
+
stub_request(:get, path).to_return(:body => 'response')
|
82
|
+
|
83
|
+
c = RC::Builder.client do
|
84
|
+
use RC::Timeout, 10
|
85
|
+
run RC::EmHttpRequest
|
86
|
+
end.new
|
87
|
+
EM.run{Fiber.new{c.get(path).should.eq('response');EM.stop}.resume}
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'raise exception' do
|
91
|
+
should 'default timeout' do
|
92
|
+
c = RC::Builder.client do
|
93
|
+
use RC::Timeout, 0.00001
|
94
|
+
run Class.new{
|
95
|
+
def call env
|
96
|
+
sleep 1
|
97
|
+
yield(env)
|
98
|
+
end
|
99
|
+
}
|
100
|
+
end.new
|
101
|
+
lambda{ c.get('') }.should.raise ::Timeout::Error
|
102
|
+
end
|
103
|
+
|
104
|
+
should 'future timeout' do
|
105
|
+
port = 35795
|
106
|
+
path = "http://localhost:#{port}/"
|
107
|
+
|
108
|
+
c = RC::Builder.client do
|
109
|
+
use RC::Timeout, 0.00001
|
110
|
+
run RC::EmHttpRequest
|
111
|
+
end.new
|
112
|
+
|
113
|
+
EM.run{
|
114
|
+
EM.start_server '127.0.0.1', port, Module.new{
|
115
|
+
def receive_data data; end
|
116
|
+
}
|
117
|
+
Fiber.new{
|
118
|
+
begin
|
119
|
+
c.get(path).tap{}
|
120
|
+
rescue => e
|
121
|
+
e.should.kind_of ::Timeout::Error
|
122
|
+
EM.stop
|
123
|
+
end
|
124
|
+
}.resume}
|
125
|
+
end
|
126
|
+
|
127
|
+
should 'async timeout' do
|
128
|
+
port = 35795
|
129
|
+
path = "http://localhost:#{port}/"
|
130
|
+
|
131
|
+
c = RC::Builder.client do
|
132
|
+
use RC::Timeout, 0.00001
|
133
|
+
use RC::ErrorHandler
|
134
|
+
run RC::EmHttpRequest
|
135
|
+
end.new
|
136
|
+
|
137
|
+
EM.run{
|
138
|
+
EM.start_server '127.0.0.1', port, Module.new{
|
139
|
+
def receive_data data; end
|
140
|
+
}
|
141
|
+
c.get(path){ |e| e.should.kind_of ::Timeout::Error; EM.stop }
|
142
|
+
}
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end unless RUBY_ENGINE == 'jruby'
|