rest-core 1.0.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/.travis.yml +6 -7
  2. data/CHANGES.md +137 -0
  3. data/Gemfile +1 -1
  4. data/README.md +183 -191
  5. data/TODO.md +5 -8
  6. data/example/multi.rb +31 -24
  7. data/example/simple.rb +28 -0
  8. data/example/use-cases.rb +194 -0
  9. data/lib/rest-core.rb +26 -19
  10. data/lib/rest-core/builder.rb +2 -2
  11. data/lib/rest-core/client.rb +40 -27
  12. data/lib/rest-core/client/universal.rb +16 -13
  13. data/lib/rest-core/client_oauth1.rb +5 -5
  14. data/lib/rest-core/engine/auto.rb +25 -0
  15. data/lib/rest-core/{app → engine}/dry.rb +1 -2
  16. data/lib/rest-core/engine/em-http-request.rb +39 -0
  17. data/lib/rest-core/engine/future/future.rb +106 -0
  18. data/lib/rest-core/engine/future/future_fiber.rb +39 -0
  19. data/lib/rest-core/engine/future/future_thread.rb +29 -0
  20. data/lib/rest-core/engine/rest-client.rb +56 -0
  21. data/lib/rest-core/middleware.rb +27 -5
  22. data/lib/rest-core/middleware/auth_basic.rb +5 -5
  23. data/lib/rest-core/middleware/bypass.rb +2 -2
  24. data/lib/rest-core/middleware/cache.rb +67 -54
  25. data/lib/rest-core/middleware/common_logger.rb +5 -8
  26. data/lib/rest-core/middleware/default_headers.rb +2 -2
  27. data/lib/rest-core/middleware/default_payload.rb +26 -2
  28. data/lib/rest-core/middleware/default_query.rb +4 -2
  29. data/lib/rest-core/middleware/default_site.rb +8 -6
  30. data/lib/rest-core/middleware/error_detector.rb +9 -16
  31. data/lib/rest-core/middleware/error_handler.rb +25 -11
  32. data/lib/rest-core/middleware/follow_redirect.rb +11 -14
  33. data/lib/rest-core/middleware/json_request.rb +19 -0
  34. data/lib/rest-core/middleware/json_response.rb +28 -0
  35. data/lib/rest-core/middleware/oauth1_header.rb +2 -7
  36. data/lib/rest-core/middleware/oauth2_header.rb +4 -7
  37. data/lib/rest-core/middleware/oauth2_query.rb +2 -2
  38. data/lib/rest-core/middleware/timeout.rb +21 -65
  39. data/lib/rest-core/middleware/timeout/{eventmachine_timer.rb → timer_em.rb} +3 -1
  40. data/lib/rest-core/middleware/timeout/timer_thread.rb +36 -0
  41. data/lib/rest-core/patch/multi_json.rb +8 -0
  42. data/lib/rest-core/test.rb +3 -12
  43. data/lib/rest-core/util/json.rb +65 -0
  44. data/lib/rest-core/util/parse_query.rb +2 -2
  45. data/lib/rest-core/version.rb +1 -1
  46. data/lib/rest-core/wrapper.rb +16 -16
  47. data/rest-core.gemspec +28 -27
  48. data/test/test_auth_basic.rb +14 -10
  49. data/test/test_builder.rb +7 -7
  50. data/test/test_cache.rb +126 -37
  51. data/test/test_client.rb +3 -1
  52. data/test/test_client_oauth1.rb +2 -3
  53. data/test/test_default_query.rb +17 -23
  54. data/test/test_em_http_request.rb +146 -0
  55. data/test/test_error_detector.rb +0 -1
  56. data/test/test_error_handler.rb +44 -0
  57. data/test/test_follow_redirect.rb +17 -19
  58. data/test/test_json_request.rb +28 -0
  59. data/test/test_json_response.rb +51 -0
  60. data/test/test_oauth1_header.rb +4 -4
  61. data/test/test_payload.rb +20 -12
  62. data/test/test_simple.rb +14 -0
  63. data/test/test_timeout.rb +11 -19
  64. data/test/test_universal.rb +5 -5
  65. data/test/test_wrapper.rb +19 -13
  66. metadata +28 -29
  67. data/doc/ToC.md +0 -7
  68. data/doc/dependency.md +0 -4
  69. data/doc/design.md +0 -4
  70. data/example/auto.rb +0 -51
  71. data/example/coolio.rb +0 -21
  72. data/example/eventmachine.rb +0 -30
  73. data/example/rest-client.rb +0 -16
  74. data/lib/rest-core/app/abstract/async_fiber.rb +0 -13
  75. data/lib/rest-core/app/auto.rb +0 -23
  76. data/lib/rest-core/app/coolio-async.rb +0 -32
  77. data/lib/rest-core/app/coolio-fiber.rb +0 -30
  78. data/lib/rest-core/app/coolio.rb +0 -9
  79. data/lib/rest-core/app/em-http-request-async.rb +0 -37
  80. data/lib/rest-core/app/em-http-request-fiber.rb +0 -45
  81. data/lib/rest-core/app/em-http-request.rb +0 -9
  82. data/lib/rest-core/app/rest-client.rb +0 -41
  83. data/lib/rest-core/middleware/json_decode.rb +0 -93
  84. data/lib/rest-core/middleware/timeout/coolio_timer.rb +0 -10
  85. data/pending/test_multi.rb +0 -123
  86. data/pending/test_test_util.rb +0 -86
  87. data/test/test_json_decode.rb +0 -24
@@ -1,36 +1,40 @@
1
1
 
2
2
  require 'rest-core/test'
3
3
 
4
- describe RestCore::AuthBasic do
4
+ describe RC::AuthBasic do
5
5
  before do
6
- @auth = RestCore::AuthBasic.new(RestCore::Dry.new, nil, nil)
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({}).should.eq({RestCore::REQUEST_HEADERS =>
18
- {'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}})
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 = {RestCore::REQUEST_HEADERS => acc}
23
+ env = {RC::REQUEST_HEADERS => acc}
22
24
 
23
- @auth.call(env).should.eq({RestCore::REQUEST_HEADERS =>
24
- {'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}.merge(acc)})
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({})[RestCore::LOG].size.should.eq 1
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({})[RestCore::LOG].size.should.eq 1
38
+ @auth.call({}){ |res| res[RC::LOG].size.should.eq 1 }
35
39
  end
36
40
  end
@@ -1,14 +1,14 @@
1
1
 
2
2
  require 'rest-core/test'
3
3
 
4
- describe RestCore::Builder do
5
- should 'default app is RestCore::RestClient' do
6
- RestCore::Builder.client.new.app.class.should.eq RestCore::RestClient
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 default_app to RestCore::Dry' do
10
- builder = RestCore::Builder.dup
11
- builder.default_app = RestCore::Dry
12
- builder.client.new.app.class.should.eq RestCore::Dry
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
@@ -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 => 'response')
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
- c.cache.should.eq({Digest::MD5.hexdigest('/') => 'response'})
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 'cancel timeout for fiber' do
35
- any_instance_of(RC::Timeout::EventMachineTimer) do |timer|
36
- proxy.mock(timer).cancel.times(2)
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
- path = 'http://example.com/'
39
- stub_request(:get, path).to_return(:body => 'response')
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::Timeout, 10
42
- use RC::Cache, {}, 3600
43
- run RC::EmHttpRequestFiber
63
+ use RC::Cache, {}, nil
44
64
  end.new
45
- EM.run{ Fiber.new{
46
- c.request_full(RC::REQUEST_PATH => path)
47
- c.request_full(RC::REQUEST_PATH => path)
48
- EM.stop }.resume }
49
- c.cache.size.should.eq 1
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::Timeout, 10
60
- use RC::Cache, {}, 3600
61
- run RC::EmHttpRequestAsync
71
+ use RC::Cache, {}, nil
62
72
  end.new
63
- EM.run{
64
- c.request_full(RC::REQUEST_PATH => path){
65
- c.request_full(RC::REQUEST_PATH => path){
66
- EM.stop }}}
67
- c.cache.size.should.eq 1
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 = {} ; end
73
- def [] key ; @h[key] ; end
74
- def []= key, value; @h[key] = value * 2; end
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 => env[RC::REQUEST_PATH])
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 '44'
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
@@ -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 = RestCore::Builder.client do
43
+ client = RC::Builder.client do
42
44
  use RC::Timeout, 4
43
45
  end
44
46
  c = client.new
@@ -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::JsonDecode.json_encode(data_sig)
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::JsonDecode.json_encode(
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
@@ -2,44 +2,38 @@
2
2
  require 'rest-core/test'
3
3
 
4
4
  describe RC::DefaultQuery do
5
- describe 'when given query' do
6
- before do
7
- @app = RC::DefaultQuery.new(RC::Dry.new, {})
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).should.eq({RC::REQUEST_QUERY =>
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
- def app
38
- @app
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'