rest-core 3.6.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/.travis.yml +0 -1
- data/CHANGES.md +28 -0
- data/Gemfile +0 -2
- data/README.md +14 -95
- data/Rakefile +16 -3
- data/example/simple.rb +1 -0
- data/example/use-cases.rb +15 -3
- data/lib/rest-core.rb +38 -75
- data/lib/rest-core/client/universal.rb +3 -1
- data/lib/rest-core/client_oauth1.rb +64 -59
- data/lib/rest-core/event.rb +9 -11
- data/lib/rest-core/middleware/auth_basic.rb +21 -21
- data/lib/rest-core/middleware/bypass.rb +8 -8
- data/lib/rest-core/middleware/cache.rb +94 -90
- data/lib/rest-core/middleware/clash_response.rb +15 -14
- data/lib/rest-core/middleware/common_logger.rb +27 -26
- data/lib/rest-core/middleware/default_headers.rb +8 -8
- data/lib/rest-core/middleware/default_payload.rb +8 -8
- data/lib/rest-core/middleware/default_query.rb +8 -8
- data/lib/rest-core/middleware/default_site.rb +12 -12
- data/lib/rest-core/middleware/defaults.rb +38 -38
- data/lib/rest-core/middleware/error_detector.rb +10 -10
- data/lib/rest-core/middleware/error_detector_http.rb +6 -4
- data/lib/rest-core/middleware/error_handler.rb +14 -14
- data/lib/rest-core/middleware/follow_redirect.rb +28 -27
- data/lib/rest-core/middleware/json_request.rb +13 -11
- data/lib/rest-core/middleware/json_response.rb +29 -28
- data/lib/rest-core/middleware/oauth1_header.rb +84 -83
- data/lib/rest-core/middleware/oauth2_header.rb +27 -25
- data/lib/rest-core/middleware/oauth2_query.rb +15 -15
- data/lib/rest-core/middleware/query_response.rb +14 -14
- data/lib/rest-core/middleware/retry.rb +25 -23
- data/lib/rest-core/middleware/smash_response.rb +15 -14
- data/lib/rest-core/middleware/timeout.rb +18 -19
- data/lib/rest-core/test.rb +1 -18
- data/lib/rest-core/util/clash.rb +38 -37
- data/lib/rest-core/util/config.rb +40 -39
- data/lib/rest-core/util/dalli_extension.rb +11 -10
- data/lib/rest-core/util/hmac.rb +9 -8
- data/lib/rest-core/util/json.rb +55 -54
- data/lib/rest-core/util/parse_link.rb +13 -12
- data/lib/rest-core/util/parse_query.rb +24 -22
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +121 -158
- data/test/test_cache.rb +2 -0
- data/test/test_default_payload.rb +1 -1
- data/test/test_error_handler.rb +5 -4
- data/test/test_timeout.rb +9 -8
- data/test/test_universal.rb +8 -0
- metadata +9 -73
- data/lib/rest-core/builder.rb +0 -162
- data/lib/rest-core/client.rb +0 -277
- data/lib/rest-core/client/simple.rb +0 -2
- data/lib/rest-core/engine.rb +0 -36
- data/lib/rest-core/engine/dry.rb +0 -9
- data/lib/rest-core/engine/http-client.rb +0 -41
- data/lib/rest-core/error.rb +0 -5
- data/lib/rest-core/event_source.rb +0 -137
- data/lib/rest-core/middleware.rb +0 -151
- data/lib/rest-core/promise.rb +0 -249
- data/lib/rest-core/thread_pool.rb +0 -131
- data/lib/rest-core/timer.rb +0 -58
- data/lib/rest-core/util/payload.rb +0 -173
- data/test/test_builder.rb +0 -40
- data/test/test_client.rb +0 -177
- data/test/test_event_source.rb +0 -159
- data/test/test_future.rb +0 -16
- data/test/test_httpclient.rb +0 -118
- data/test/test_payload.rb +0 -204
- data/test/test_promise.rb +0 -146
- data/test/test_simple.rb +0 -38
- data/test/test_thread_pool.rb +0 -10
@@ -1,131 +0,0 @@
|
|
1
|
-
|
2
|
-
# reference implementation: puma
|
3
|
-
# https://github.com/puma/puma/blob/v2.7.1/lib/puma/thread_pool.rb
|
4
|
-
|
5
|
-
require 'thread'
|
6
|
-
require 'rest-core'
|
7
|
-
|
8
|
-
class RestCore::ThreadPool
|
9
|
-
include RestCore
|
10
|
-
|
11
|
-
class Queue
|
12
|
-
def initialize
|
13
|
-
@queue = []
|
14
|
-
@condv = ConditionVariable.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def size
|
18
|
-
@queue.size
|
19
|
-
end
|
20
|
-
|
21
|
-
def << task
|
22
|
-
queue << task
|
23
|
-
condv.signal
|
24
|
-
end
|
25
|
-
|
26
|
-
def pop mutex, timeout=60
|
27
|
-
if queue.empty?
|
28
|
-
condv.wait(mutex, timeout)
|
29
|
-
queue.shift || lambda{ |_| false } # shutdown idle workers
|
30
|
-
else
|
31
|
-
queue.shift
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def clear
|
36
|
-
queue.clear
|
37
|
-
end
|
38
|
-
|
39
|
-
protected
|
40
|
-
attr_reader :queue, :condv
|
41
|
-
end
|
42
|
-
|
43
|
-
class Task < Struct.new(:job, :mutex, :thread, :cancelled)
|
44
|
-
# this should never fail
|
45
|
-
def call working_thread
|
46
|
-
mutex.synchronize do
|
47
|
-
return if cancelled
|
48
|
-
self.thread = working_thread
|
49
|
-
end
|
50
|
-
job.call
|
51
|
-
true
|
52
|
-
end
|
53
|
-
|
54
|
-
def cancel
|
55
|
-
self.cancelled = true
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.[] client_class
|
60
|
-
(@pools ||= {})[client_class] ||= new(client_class)
|
61
|
-
end
|
62
|
-
|
63
|
-
attr_reader :client_class, :workers
|
64
|
-
|
65
|
-
def initialize client_class
|
66
|
-
@client_class = client_class
|
67
|
-
@queue = Queue.new
|
68
|
-
@mutex = Mutex.new
|
69
|
-
@workers = []
|
70
|
-
@waiting = 0
|
71
|
-
end
|
72
|
-
|
73
|
-
def inspect
|
74
|
-
"#<#{self.class.name} client_class=#{client_class}>"
|
75
|
-
end
|
76
|
-
|
77
|
-
def size
|
78
|
-
workers.size
|
79
|
-
end
|
80
|
-
|
81
|
-
def max_size
|
82
|
-
client_class.pool_size
|
83
|
-
end
|
84
|
-
|
85
|
-
def idle_time
|
86
|
-
client_class.pool_idle_time
|
87
|
-
end
|
88
|
-
|
89
|
-
def defer promise_mutex, &job
|
90
|
-
mutex.synchronize do
|
91
|
-
task = Task.new(job, promise_mutex)
|
92
|
-
queue << task
|
93
|
-
spawn_worker if waiting < queue.size && workers.size < max_size
|
94
|
-
task
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def trim force=false
|
99
|
-
mutex.synchronize do
|
100
|
-
queue << lambda{ |_| false } if force || waiting > 0
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# Block on shutting down, and should not add more jobs while shutting down
|
105
|
-
def shutdown
|
106
|
-
workers.size.times{ trim(true) }
|
107
|
-
workers.first.join && trim(true) until workers.empty?
|
108
|
-
mutex.synchronize{ queue.clear }
|
109
|
-
end
|
110
|
-
|
111
|
-
protected
|
112
|
-
attr_reader :queue, :mutex, :condv, :waiting
|
113
|
-
|
114
|
-
private
|
115
|
-
def spawn_worker
|
116
|
-
workers << Thread.new{
|
117
|
-
Thread.current.abort_on_exception = true
|
118
|
-
|
119
|
-
task = nil
|
120
|
-
begin
|
121
|
-
mutex.synchronize do
|
122
|
-
@waiting += 1
|
123
|
-
task = queue.pop(mutex, idle_time)
|
124
|
-
@waiting -= 1
|
125
|
-
end
|
126
|
-
end while task.call(Thread.current)
|
127
|
-
|
128
|
-
mutex.synchronize{ workers.delete(Thread.current) }
|
129
|
-
}
|
130
|
-
end
|
131
|
-
end
|
data/lib/rest-core/timer.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'thread'
|
3
|
-
require 'timers'
|
4
|
-
|
5
|
-
class RestCore::Timer
|
6
|
-
@mutex = Mutex.new
|
7
|
-
@interval = 1
|
8
|
-
|
9
|
-
singleton_class.module_eval do
|
10
|
-
attr_accessor :interval
|
11
|
-
|
12
|
-
def group
|
13
|
-
@group ||= @mutex.synchronize{ @group ||= group_new }
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
def group_new
|
18
|
-
g = Timers::Group.new
|
19
|
-
g.every(interval){}
|
20
|
-
@thread = Thread.new do
|
21
|
-
begin
|
22
|
-
g.wait
|
23
|
-
rescue => e
|
24
|
-
warn "RestCore::Timer: ERROR: #{e}\n from #{e.backtrace.inspect}"
|
25
|
-
end while g.count > 1
|
26
|
-
@group = nil
|
27
|
-
end
|
28
|
-
g
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
attr_accessor :timeout, :error, :timer
|
33
|
-
def initialize timeout, error, &block
|
34
|
-
self.timeout = timeout
|
35
|
-
self.error = error
|
36
|
-
self.block = block
|
37
|
-
start if block_given?
|
38
|
-
end
|
39
|
-
|
40
|
-
def on_timeout &block
|
41
|
-
self.block = block
|
42
|
-
start if block_given?
|
43
|
-
end
|
44
|
-
|
45
|
-
# should never raise!
|
46
|
-
def cancel
|
47
|
-
timer.cancel if timer
|
48
|
-
self.block = nil
|
49
|
-
end
|
50
|
-
|
51
|
-
def start
|
52
|
-
return if timeout.nil? || timeout.zero?
|
53
|
-
self.timer = self.class.group.after(timeout){ block.call if block }
|
54
|
-
end
|
55
|
-
|
56
|
-
protected
|
57
|
-
attr_accessor :block
|
58
|
-
end
|
@@ -1,173 +0,0 @@
|
|
1
|
-
|
2
|
-
# stolen and modified from rest-client
|
3
|
-
|
4
|
-
require 'rest-core/error'
|
5
|
-
|
6
|
-
begin
|
7
|
-
require 'mime/types/columnar'
|
8
|
-
rescue LoadError
|
9
|
-
require 'mime/types'
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'stringio'
|
13
|
-
require 'tempfile'
|
14
|
-
|
15
|
-
module RestCore; end
|
16
|
-
class RestCore::Payload
|
17
|
-
include RestCore
|
18
|
-
|
19
|
-
def self.generate_with_headers payload, headers
|
20
|
-
h = if p = generate(payload)
|
21
|
-
p.headers.merge(headers)
|
22
|
-
else
|
23
|
-
headers
|
24
|
-
end
|
25
|
-
[p, h]
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.generate payload
|
29
|
-
if payload.respond_to?(:read)
|
30
|
-
Streamed.new(payload)
|
31
|
-
|
32
|
-
elsif payload.kind_of?(String)
|
33
|
-
StreamedString.new(payload)
|
34
|
-
|
35
|
-
elsif payload.kind_of?(Hash)
|
36
|
-
if payload.empty?
|
37
|
-
nil
|
38
|
-
|
39
|
-
elsif Middleware.contain_binary?(payload)
|
40
|
-
Multipart.new(payload)
|
41
|
-
|
42
|
-
else
|
43
|
-
UrlEncoded.new(payload)
|
44
|
-
end
|
45
|
-
|
46
|
-
else
|
47
|
-
raise Error.new("Payload should be either String, Hash, or" \
|
48
|
-
" responding to `read', but: #{payload.inspect}")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Payload API
|
53
|
-
attr_reader :io
|
54
|
-
alias_method :to_io, :io
|
55
|
-
|
56
|
-
def initialize payload; @io = payload ; end
|
57
|
-
def read bytes=nil; io.read(bytes) ; end
|
58
|
-
def close ; io.close unless closed?; end
|
59
|
-
def closed? ; io.closed? ; end
|
60
|
-
def headers ; {} ; end
|
61
|
-
|
62
|
-
def size
|
63
|
-
if io.respond_to?(:size)
|
64
|
-
io.size
|
65
|
-
elsif io.respond_to?(:stat)
|
66
|
-
io.stat.size
|
67
|
-
else
|
68
|
-
0
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class Streamed < Payload
|
73
|
-
def headers
|
74
|
-
{'Content-Length' => size.to_s}
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class StreamedString < Streamed
|
79
|
-
def initialize payload
|
80
|
-
super(StringIO.new(payload))
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class UrlEncoded < StreamedString
|
85
|
-
def initialize payload
|
86
|
-
super(RestCore::Middleware.percent_encode(payload))
|
87
|
-
end
|
88
|
-
|
89
|
-
def headers
|
90
|
-
super.merge('Content-Type' => 'application/x-www-form-urlencoded')
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class Multipart < Streamed
|
95
|
-
EOL = "\r\n"
|
96
|
-
|
97
|
-
def initialize payload
|
98
|
-
super(Tempfile.new("rest-core.payload.#{boundary}"))
|
99
|
-
|
100
|
-
io.binmode
|
101
|
-
|
102
|
-
payload.each_with_index do |(k, v), i|
|
103
|
-
if v.kind_of?(Array)
|
104
|
-
v.each{ |vv| part(k, vv) }
|
105
|
-
else
|
106
|
-
part(k, v)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
io.write("--#{boundary}--#{EOL}")
|
110
|
-
io.rewind
|
111
|
-
end
|
112
|
-
|
113
|
-
def part k, v
|
114
|
-
io.write("--#{boundary}#{EOL}Content-Disposition: form-data")
|
115
|
-
io.write("; name=\"#{k}\"") if k
|
116
|
-
if v.respond_to?(:read)
|
117
|
-
part_binary(k, v)
|
118
|
-
else
|
119
|
-
part_plantext(k, v)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def part_plantext k, v
|
124
|
-
io.write("#{EOL}#{EOL}#{v}#{EOL}")
|
125
|
-
end
|
126
|
-
|
127
|
-
def part_binary k, v
|
128
|
-
if v.respond_to?(:original_filename) # Rails
|
129
|
-
io.write("; filename=\"#{v.original_filename}\"#{EOL}")
|
130
|
-
elsif v.respond_to?(:path) # files
|
131
|
-
io.write("; filename=\"#{File.basename(v.path)}\"#{EOL}")
|
132
|
-
else # io
|
133
|
-
io.write("; filename=\"#{k}\"#{EOL}")
|
134
|
-
end
|
135
|
-
|
136
|
-
# supply your own content type for regular files, will you?
|
137
|
-
if v.respond_to?(:content_type) # Rails
|
138
|
-
io.write("Content-Type: #{v.content_type}#{EOL}#{EOL}")
|
139
|
-
elsif v.respond_to?(:path) && type = mime_type(v.path) # files
|
140
|
-
io.write("Content-Type: #{type}#{EOL}#{EOL}")
|
141
|
-
else
|
142
|
-
io.write(EOL)
|
143
|
-
end
|
144
|
-
|
145
|
-
while data = v.read(8192)
|
146
|
-
io.write(data)
|
147
|
-
end
|
148
|
-
|
149
|
-
io.write(EOL)
|
150
|
-
|
151
|
-
ensure
|
152
|
-
v.close if v.respond_to?(:close)
|
153
|
-
end
|
154
|
-
|
155
|
-
def mime_type path
|
156
|
-
mime = MIME::Types.type_for(path)
|
157
|
-
mime.first && mime.first.content_type
|
158
|
-
end
|
159
|
-
|
160
|
-
def boundary
|
161
|
-
@boundary ||= rand(1_000_000).to_s
|
162
|
-
end
|
163
|
-
|
164
|
-
def headers
|
165
|
-
super.merge('Content-Type' =>
|
166
|
-
"multipart/form-data; boundary=#{boundary}")
|
167
|
-
end
|
168
|
-
|
169
|
-
def close
|
170
|
-
io.close! unless io.closed?
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
data/test/test_builder.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-core/test'
|
3
|
-
|
4
|
-
describe RC::Builder do
|
5
|
-
would 'default client app is a kind of RestCore::Engine' do
|
6
|
-
RC::Builder.client.new.app.should.kind_of? RC::Engine
|
7
|
-
end
|
8
|
-
|
9
|
-
would 'default app is a kind of RestCore::Engine' do
|
10
|
-
RC::Builder.new.to_app.should.kind_of? RC::Engine
|
11
|
-
end
|
12
|
-
|
13
|
-
would 'switch default_engine to RestCore::Dry a' do
|
14
|
-
builder = Class.new(RC::Builder)
|
15
|
-
builder.default_engine = RC::Dry
|
16
|
-
builder.new.to_app.class.should.eq RC::Dry
|
17
|
-
end
|
18
|
-
|
19
|
-
would 'switch default_engine to RestCore::Dry b' do
|
20
|
-
builder = RC::Builder.dup
|
21
|
-
builder.default_engine = RC::Dry
|
22
|
-
builder.client.new.app.class.should.eq RC::Dry
|
23
|
-
end
|
24
|
-
|
25
|
-
would 'accept middleware without a member' do
|
26
|
-
RC::Builder.client{
|
27
|
-
use Class.new.send(:include, RC::Middleware)
|
28
|
-
}.members.should.eq [:config_engine]
|
29
|
-
end
|
30
|
-
|
31
|
-
would 'not have duplicated fields' do
|
32
|
-
middleware = Class.new do
|
33
|
-
def self.members; [:value]; end
|
34
|
-
include RC::Middleware
|
35
|
-
end
|
36
|
-
client = RC::Builder.client(:value){ use middleware }.new
|
37
|
-
client.value = 10
|
38
|
-
client.value.should.eq 10
|
39
|
-
end
|
40
|
-
end
|
data/test/test_client.rb
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-core/test'
|
3
|
-
|
4
|
-
describe RC::Simple do
|
5
|
-
after do
|
6
|
-
WebMock.reset!
|
7
|
-
Muack.verify
|
8
|
-
end
|
9
|
-
|
10
|
-
url = 'http://example.com/'
|
11
|
-
|
12
|
-
would 'do simple request' do
|
13
|
-
c = RC::Simple.new
|
14
|
-
[:get, :post, :delete, :put, :patch].each do |method|
|
15
|
-
stub_request(method, url).to_return(:body => '[]')
|
16
|
-
c.send(method, url).should.eq '[]'
|
17
|
-
end
|
18
|
-
|
19
|
-
stub_request(:head , url).to_return(:headers => {'A' => 'B'})
|
20
|
-
c. head(url).should.eq('A' => 'B')
|
21
|
-
|
22
|
-
stub_request(:options, url).to_return(:headers => {'A' => 'B'})
|
23
|
-
c.options(url).should.eq('A' => 'B')
|
24
|
-
end
|
25
|
-
|
26
|
-
would 'call the callback' do
|
27
|
-
[:get, :post, :delete, :put, :patch].each do |method|
|
28
|
-
stub_request(method, url).to_return(:body => '123')
|
29
|
-
(client = RC::Simple.new).send(method, url){ |res|
|
30
|
-
res.should.eq '123' }.should.eq client
|
31
|
-
client.wait
|
32
|
-
end
|
33
|
-
|
34
|
-
stub_request(:head, url).to_return(:headers => {'A' => 'B'})
|
35
|
-
(client = RC::Simple.new).head(url){ |res|
|
36
|
-
res.should.eq({'A' => 'B'})
|
37
|
-
}.should.eq client
|
38
|
-
client.wait
|
39
|
-
|
40
|
-
stub_request(:options, url).to_return(:headers => {'A' => 'B'})
|
41
|
-
(client = RC::Simple.new).options(url){ |res|
|
42
|
-
res.should.eq('A' => 'B')
|
43
|
-
}.should.eq client
|
44
|
-
client.wait
|
45
|
-
end
|
46
|
-
|
47
|
-
would 'wait for all the requests' do
|
48
|
-
t, i, m = 5, 0, Mutex.new
|
49
|
-
stub_request(:get, url).to_return do
|
50
|
-
m.synchronize{ i += 1 }
|
51
|
-
Thread.pass
|
52
|
-
{}
|
53
|
-
end
|
54
|
-
|
55
|
-
client = RC::Builder.client
|
56
|
-
t.times{ client.new.get(url) }
|
57
|
-
client.wait
|
58
|
-
client.promises.should.empty?
|
59
|
-
i.should.eq t
|
60
|
-
end
|
61
|
-
|
62
|
-
would 'wait for callback' do
|
63
|
-
rd, wr = IO.pipe
|
64
|
-
called = false
|
65
|
-
stub_request(:get, url).to_return(:body => 'nnf')
|
66
|
-
client = RC::Builder.client.new.get(url) do |nnf|
|
67
|
-
wr.puts
|
68
|
-
sleep 0.001 # make sure our callback is slow enough,
|
69
|
-
# so that if `wait` is not waiting for the callback,
|
70
|
-
# it would leave before the callback is completely done.
|
71
|
-
# without sleeping, the callback is very likely to be
|
72
|
-
# done first than `wait` anyway. raising the sleeping time
|
73
|
-
# would make this test more reliable...
|
74
|
-
called = true
|
75
|
-
nil # test against returning nil, so that Promise#response is not set
|
76
|
-
end
|
77
|
-
rd.gets
|
78
|
-
client.wait
|
79
|
-
called.should.eq true
|
80
|
-
end
|
81
|
-
|
82
|
-
would 'cleanup promises' do
|
83
|
-
stub_request(:get, url).to_return(:body => 'nnf')
|
84
|
-
client = RC::Builder.client
|
85
|
-
5.times{ client.new.get(url) }
|
86
|
-
Thread.pass
|
87
|
-
GC.start # can only force GC run on MRI, so we mock for jruby and rubinius
|
88
|
-
stub(any_instance_of(WeakRef)).weakref_alive?{false}
|
89
|
-
client.new.get(url)
|
90
|
-
client.promises.size.should.lt 6
|
91
|
-
client.shutdown
|
92
|
-
client.promises.should.empty?
|
93
|
-
end
|
94
|
-
|
95
|
-
would 'have correct to_i' do
|
96
|
-
stub_request(:get, url).to_return(:body => '123')
|
97
|
-
RC::Simple.new.get(url).to_i.should.eq 123
|
98
|
-
end
|
99
|
-
|
100
|
-
would 'use defaults' do
|
101
|
-
client = RC::Builder.client do
|
102
|
-
use RC::Timeout, 4
|
103
|
-
end
|
104
|
-
c = client.new
|
105
|
-
c.timeout.should.eq 4 # default goes to middleware
|
106
|
-
client.extend(Module.new do
|
107
|
-
def default_timeout
|
108
|
-
3
|
109
|
-
end
|
110
|
-
end)
|
111
|
-
c.timeout.should.eq 4 # default is cached, so it stays the same
|
112
|
-
c.timeout = nil # clear cache
|
113
|
-
c.timeout.should.eq 3 # now default goes to module default
|
114
|
-
class << client
|
115
|
-
def default_timeout # module defaults could be overriden
|
116
|
-
super - 1
|
117
|
-
end
|
118
|
-
end
|
119
|
-
c.timeout = nil
|
120
|
-
c.timeout.should.eq 2 # so it goes to class default
|
121
|
-
c.timeout = 1 # setup instance level value
|
122
|
-
c.build_env( )['timeout'].should.eq 1 # pick instance var
|
123
|
-
c.build_env({'timeout' => 0})['timeout'].should.eq 0 # per-request var
|
124
|
-
c.timeout.should.eq 1 # won't affect underlying instance var
|
125
|
-
c.timeout = nil
|
126
|
-
c.timeout.should.eq 2 # goes back to class default
|
127
|
-
c.timeout = false
|
128
|
-
c.timeout.should.eq false # false would disable default
|
129
|
-
end
|
130
|
-
|
131
|
-
would 'work for inheritance' do
|
132
|
-
stub_request(:get, url).to_return(:body => '123')
|
133
|
-
Class.new(RC::Simple).new.get(url).should.eq '123'
|
134
|
-
end
|
135
|
-
|
136
|
-
would 'not deadlock when exception was raised in the callback' do
|
137
|
-
client = Class.new(RC::Simple).new
|
138
|
-
stub_request(:get, url).to_return(:body => 'nnf')
|
139
|
-
|
140
|
-
(-1..1).each do |size|
|
141
|
-
mock(any_instance_of(RC::Promise)).warn(is_a(String)) do |msg|
|
142
|
-
msg.should.include?('nnf')
|
143
|
-
end
|
144
|
-
client.class.pool_size = size
|
145
|
-
client.get(url) do |body|
|
146
|
-
raise body
|
147
|
-
end
|
148
|
-
client.class.shutdown
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
would 'be able to access caller outside the callback' do
|
153
|
-
client = RC::Simple.new
|
154
|
-
stub_request(:get, url).to_return(:body => 'nnf')
|
155
|
-
client.get(url) do
|
156
|
-
current_file = /^#{__FILE__}/
|
157
|
-
caller.grep(current_file).should.empty?
|
158
|
-
RC::Promise.backtrace.grep(current_file).should.not.empty?
|
159
|
-
client.get(url) do
|
160
|
-
RC::Promise.backtrace.last.should.not =~ /promise\.rb:\d+:in/
|
161
|
-
client = nil
|
162
|
-
end
|
163
|
-
end
|
164
|
-
client.wait
|
165
|
-
client.should.nil? # to make sure the inner most block did run
|
166
|
-
end
|
167
|
-
|
168
|
-
would 'call error_callback' do
|
169
|
-
error = nil
|
170
|
-
error_callback = lambda{ |e| error = e }
|
171
|
-
should.raise(Errno::ECONNREFUSED) do
|
172
|
-
RC::Simple.new(:error_callback => error_callback).
|
173
|
-
get('http://localhost:1').tap{}
|
174
|
-
end
|
175
|
-
error.should.kind_of?(Errno::ECONNREFUSED)
|
176
|
-
end
|
177
|
-
end
|