rest-core 3.2.0 → 3.3.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/CHANGES.md +23 -0
- data/Gemfile +1 -1
- data/README.md +11 -10
- data/Rakefile +2 -1
- data/lib/rest-core.rb +0 -1
- data/lib/rest-core/builder.rb +59 -12
- data/lib/rest-core/client/universal.rb +11 -10
- data/lib/rest-core/middleware.rb +20 -0
- data/lib/rest-core/middleware/cache.rb +12 -10
- data/lib/rest-core/middleware/default_headers.rb +2 -2
- data/lib/rest-core/middleware/default_payload.rb +2 -26
- data/lib/rest-core/middleware/default_query.rb +2 -10
- data/lib/rest-core/middleware/json_request.rb +2 -1
- data/lib/rest-core/middleware/json_response.rb +5 -2
- data/lib/rest-core/test.rb +3 -12
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +11 -12
- data/task/gemgem.rb +1 -5
- data/test/test_auth_basic.rb +4 -4
- data/test/test_builder.rb +20 -4
- data/test/test_cache.rb +19 -20
- data/test/test_clash.rb +1 -1
- data/test/test_clash_response.rb +11 -11
- data/test/test_client.rb +10 -10
- data/test/test_client_oauth1.rb +3 -3
- data/test/test_config.rb +1 -1
- data/test/test_default_headers.rb +13 -0
- data/test/test_default_payload.rb +11 -3
- data/test/test_default_query.rb +12 -4
- data/test/test_error_detector.rb +1 -1
- data/test/test_error_detector_http.rb +1 -1
- data/test/test_error_handler.rb +5 -5
- data/test/test_event_source.rb +16 -16
- data/test/test_follow_redirect.rb +6 -6
- data/test/test_future.rb +2 -2
- data/test/test_json_request.rb +9 -4
- data/test/test_json_response.rb +9 -9
- data/test/test_oauth1_header.rb +9 -9
- data/test/test_oauth2_header.rb +3 -3
- data/test/test_parse_link.rb +4 -4
- data/test/test_payload.rb +21 -21
- data/test/test_promise.rb +7 -7
- data/test/test_query_response.rb +5 -5
- data/test/test_rest-client.rb +7 -6
- data/test/test_simple.rb +5 -5
- data/test/test_smash.rb +1 -1
- data/test/test_smash_response.rb +11 -11
- data/test/test_thread_pool.rb +1 -1
- data/test/test_timeout.rb +3 -3
- data/test/test_universal.rb +12 -2
- metadata +9 -10
- data/lib/rest-core/wrapper.rb +0 -72
- data/test/test_wrapper.rb +0 -36
data/test/test_payload.rb
CHANGED
@@ -3,31 +3,31 @@ require 'rest-core/test'
|
|
3
3
|
|
4
4
|
describe RC::Payload do
|
5
5
|
describe 'A regular Payload' do
|
6
|
-
|
6
|
+
would 'use standard enctype as default content-type' do
|
7
7
|
RC::Payload::UrlEncoded.new({}).headers['Content-Type'].
|
8
8
|
should.eq 'application/x-www-form-urlencoded'
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
would 'form properly encoded params' do
|
12
12
|
RC::Payload::UrlEncoded.new(:foo => 'bar').read.
|
13
13
|
should.eq 'foo=bar'
|
14
14
|
RC::Payload::UrlEncoded.new(:foo => 'bar', :baz => 'qux').read.
|
15
15
|
should.eq 'baz=qux&foo=bar'
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
would 'escape parameters' do
|
19
19
|
RC::Payload::UrlEncoded.new('foo ' => 'bar').read.
|
20
20
|
should.eq 'foo%20=bar'
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
would 'properly handle arrays as repeated parameters' do
|
24
24
|
RC::Payload::UrlEncoded.new(:foo => ['bar']).read.
|
25
25
|
should.eq 'foo=bar'
|
26
26
|
RC::Payload::UrlEncoded.new(:foo => ['bar', 'baz']).read.
|
27
27
|
should.eq 'foo=bar&foo=baz'
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
would 'not close if stream already closed' do
|
31
31
|
p = RC::Payload::UrlEncoded.new('foo ' => 'bar')
|
32
32
|
p.close
|
33
33
|
2.times{ p.close.should.eq nil }
|
@@ -35,19 +35,19 @@ describe RC::Payload do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
describe 'A multipart Payload' do
|
38
|
-
|
38
|
+
would 'use standard enctype as default content-type' do
|
39
39
|
p = RC::Payload::Multipart.new({})
|
40
40
|
stub(p).boundary{123}
|
41
41
|
p.headers['Content-Type'].should.eq 'multipart/form-data; boundary=123'
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
would 'not error on close if stream already closed' do
|
45
45
|
p = RC::Payload::Multipart.new(:file => File.open(__FILE__))
|
46
46
|
p.close
|
47
47
|
2.times{ p.close.should.eq nil }
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
would 'form properly separated multipart data' do
|
51
51
|
p = RC::Payload::Multipart.new(:bar => 'baz', :foo => 'bar')
|
52
52
|
p.read.should.eq <<-EOS
|
53
53
|
--#{p.boundary}\r
|
@@ -62,7 +62,7 @@ bar\r
|
|
62
62
|
EOS
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
would 'form multiple files with the same name' do
|
66
66
|
with_img do |f, n|
|
67
67
|
with_img do |ff, nn|
|
68
68
|
p = RC::Payload::Multipart.new(:foo => [f, ff])
|
@@ -83,7 +83,7 @@ Content-Type: image/jpeg\r
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
would 'not escape parameters names' do
|
87
87
|
p = RC::Payload::Multipart.new('bar ' => 'baz')
|
88
88
|
p.read.should.eq <<-EOS
|
89
89
|
--#{p.boundary}\r
|
@@ -94,7 +94,7 @@ baz\r
|
|
94
94
|
EOS
|
95
95
|
end
|
96
96
|
|
97
|
-
|
97
|
+
would 'form properly separated multipart data' do
|
98
98
|
with_img do |f, n|
|
99
99
|
p = RC::Payload::Multipart.new(:foo => f)
|
100
100
|
p.read.should.eq <<-EOS
|
@@ -108,7 +108,7 @@ Content-Type: image/jpeg\r
|
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
|
111
|
+
would "ignore the name attribute when it's not set" do
|
112
112
|
with_img do |f, n|
|
113
113
|
p = RC::Payload::Multipart.new(nil => f)
|
114
114
|
p.read.should.eq <<-EOS
|
@@ -122,7 +122,7 @@ Content-Type: image/jpeg\r
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
|
125
|
+
would 'detect optional (original) content type and filename' do
|
126
126
|
File.open(__FILE__) do |f|
|
127
127
|
def f.content_type ; 'image/jpeg'; end
|
128
128
|
def f.original_filename; 'foo.txt' ; end
|
@@ -140,14 +140,14 @@ Content-Type: image/jpeg\r
|
|
140
140
|
end
|
141
141
|
|
142
142
|
describe 'streamed payloads' do
|
143
|
-
|
143
|
+
would 'properly determine the size of file payloads' do
|
144
144
|
File.open(__FILE__) do |f|
|
145
145
|
p = RC::Payload.generate(f)
|
146
146
|
p.size.should.eq f.stat.size
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
-
|
150
|
+
would 'properly determine the size of other kinds of payloads' do
|
151
151
|
s = StringIO.new('foo')
|
152
152
|
p = RC::Payload.generate(s)
|
153
153
|
p.size.should.eq 3
|
@@ -166,37 +166,37 @@ Content-Type: image/jpeg\r
|
|
166
166
|
end
|
167
167
|
|
168
168
|
describe 'Payload generation' do
|
169
|
-
|
169
|
+
would 'recognize standard urlencoded params' do
|
170
170
|
RC::Payload.generate('foo' => 'bar').should.
|
171
171
|
kind_of?(RC::Payload::UrlEncoded)
|
172
172
|
end
|
173
173
|
|
174
|
-
|
174
|
+
would 'recognize multipart params' do
|
175
175
|
File.open(__FILE__) do |f|
|
176
176
|
RC::Payload.generate('foo' => f).should.
|
177
177
|
kind_of?(RC::Payload::Multipart)
|
178
178
|
end
|
179
179
|
end
|
180
180
|
|
181
|
-
|
181
|
+
would 'return data if none of the above' do
|
182
182
|
RC::Payload.generate('data').should.
|
183
183
|
kind_of?(RC::Payload::StreamedString)
|
184
184
|
end
|
185
185
|
|
186
|
-
|
186
|
+
would 'recognize nested multipart payloads in arrays' do
|
187
187
|
File.open(__FILE__) do |f|
|
188
188
|
RC::Payload.generate('foo' => [f]).should.
|
189
189
|
kind_of?(RC::Payload::Multipart)
|
190
190
|
end
|
191
191
|
end
|
192
192
|
|
193
|
-
|
193
|
+
would 'recognize file payloads that can be streamed' do
|
194
194
|
File.open(__FILE__) do |f|
|
195
195
|
RC::Payload.generate(f).should.kind_of?(RC::Payload::Streamed)
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
-
|
199
|
+
would 'recognize other payloads that can be streamed' do
|
200
200
|
RC::Payload.generate(StringIO.new('foo')).should.
|
201
201
|
kind_of?(RC::Payload::Streamed)
|
202
202
|
end
|
data/test/test_promise.rb
CHANGED
@@ -17,7 +17,7 @@ describe RC::Promise do
|
|
17
17
|
Muack.verify
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
would 'work, reject, yield' do
|
21
21
|
@client.pool_size = 1
|
22
22
|
flag = 0
|
23
23
|
@promise.defer do
|
@@ -27,10 +27,10 @@ describe RC::Promise do
|
|
27
27
|
end
|
28
28
|
@promise.yield
|
29
29
|
flag.should.eq 1
|
30
|
-
@promise.send(:error).should.kind_of RC::Error
|
30
|
+
@promise.send(:error).should.kind_of? RC::Error
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
would 'work, fulfill, yield' do
|
34
34
|
@client.pool_size = 2
|
35
35
|
flag = 0
|
36
36
|
@promise.defer do
|
@@ -45,7 +45,7 @@ describe RC::Promise do
|
|
45
45
|
@promise.send(:headers).should.eq('K' => 'V')
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
would 'then then then' do
|
49
49
|
plusone = lambda do |r|
|
50
50
|
r.merge(RC::RESPONSE_BODY => r[RC::RESPONSE_BODY] + 1)
|
51
51
|
end
|
@@ -54,7 +54,7 @@ describe RC::Promise do
|
|
54
54
|
@promise.future_body.should.eq 6
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
would 'call inline if pool_size < 0' do
|
58
58
|
@client.pool_size = -1
|
59
59
|
current_thread = Thread.current
|
60
60
|
@promise.defer do
|
@@ -62,7 +62,7 @@ describe RC::Promise do
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
would 'call in a new thread if pool_size == 0' do
|
66
66
|
@client.pool_size = 0
|
67
67
|
thread = nil
|
68
68
|
mock(Thread).new.with_any_args.peek_return do |t|
|
@@ -75,7 +75,7 @@ describe RC::Promise do
|
|
75
75
|
@promise.yield
|
76
76
|
end
|
77
77
|
|
78
|
-
|
78
|
+
would 'call in thread pool if pool_size > 0' do
|
79
79
|
@client.pool_size = 1
|
80
80
|
flag = 0
|
81
81
|
rd, wr = IO.pipe
|
data/test/test_query_response.rb
CHANGED
@@ -8,15 +8,15 @@ describe RC::QueryResponse do
|
|
8
8
|
RC::REQUEST_HEADERS =>
|
9
9
|
{'Accept' => 'application/x-www-form-urlencoded'}}
|
10
10
|
|
11
|
-
|
11
|
+
would 'give {} for nil' do
|
12
12
|
app.call({}){ |response| response.should.eq(expected) }
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
would 'give {} for ""' do
|
16
16
|
app.call(RC::RESPONSE_BODY => ''){ |r| r.should.eq(expected) }
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
would 'give {"a" => "b"} for "a=b"' do
|
20
20
|
e = expected.merge(RC::RESPONSE_BODY => {'a' => 'b'})
|
21
21
|
app.call(RC::RESPONSE_BODY => 'a=b'){ |r| r.should.eq(e) }
|
22
22
|
end
|
@@ -32,14 +32,14 @@ describe RC::QueryResponse do
|
|
32
32
|
}
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
would 'do nothing' do
|
36
36
|
expected = 'a=b&c=d'
|
37
37
|
client.new(:query_response => false).get(''){ |response|
|
38
38
|
response.should.eq(expected)
|
39
39
|
}.get('').should.eq(expected)
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
would 'parse' do
|
43
43
|
expected = {'a' => 'b', 'c' => 'd'}
|
44
44
|
client.new.get(''){ |response|
|
45
45
|
response.should.eq(expected)
|
data/test/test_rest-client.rb
CHANGED
@@ -14,15 +14,16 @@ describe RC::RestClient do
|
|
14
14
|
c = client.new
|
15
15
|
|
16
16
|
post = lambda do |payload, body|
|
17
|
-
stub_request(:post, path).
|
17
|
+
WebMock::API.stub_request(:post, path).
|
18
|
+
with(:body => body).to_return(:body => ok)
|
18
19
|
c.post(path, payload).should.eq ok
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
+
would 'post with string' do
|
22
23
|
post['string', 'string']
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
+
would 'post with file' do
|
26
27
|
File.open(__FILE__) do |f|
|
27
28
|
b = f.read
|
28
29
|
f.rewind
|
@@ -30,20 +31,20 @@ describe RC::RestClient do
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
would 'post with socket' do
|
34
35
|
rd, wr = IO.pipe
|
35
36
|
wr.write('socket')
|
36
37
|
wr.close
|
37
38
|
post[rd, 'socket']
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
+
would 'not kill the thread if error was coming from the task' do
|
41
42
|
mock(RestClient::Request).execute{ raise 'boom' }.with_any_args
|
42
43
|
c.request(RC::RESPONSE_KEY => RC::FAIL).first.message.should.eq 'boom'
|
43
44
|
Muack.verify
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
+
would 'cancel the task if timing out' do
|
47
48
|
timer = Object.new.instance_eval do
|
48
49
|
def on_timeout; yield ; end
|
49
50
|
def error ; 'boom'; end
|
data/test/test_simple.rb
CHANGED
@@ -8,28 +8,28 @@ describe RC::Simple do
|
|
8
8
|
WebMock.reset!
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
would 'give RESPONSE_BODY' do
|
12
12
|
stub_request(:get, path).to_return(:body => 'OK')
|
13
13
|
RC::Simple.new.get(path).should.eq 'OK'
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
would 'give RESPONSE_HEADERS' do
|
17
17
|
stub_request(:head, path).to_return(:headers => {'A' => 'B'})
|
18
18
|
RC::Simple.new.head(path).should.eq 'A' => 'B'
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
would 'give RESPONSE_HEADERS' do
|
22
22
|
stub_request(:get, path).to_return(:status => 199)
|
23
23
|
RC::Simple.new.get(path, {},
|
24
24
|
RC::RESPONSE_KEY => RC::RESPONSE_STATUS).should.eq 199
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
would 'give RESPONSE_SOCKET' do
|
28
28
|
stub_request(:get, path).to_return(:body => 'OK')
|
29
29
|
RC::Simple.new.get(path, {}, RC::HIJACK => true).read.should.eq 'OK'
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
would 'give REQUEST_URI' do
|
33
33
|
stub_request(:get, "#{path}?a=b").to_return(:body => 'OK')
|
34
34
|
RC::Simple.new.get(path, {:a => 'b'},
|
35
35
|
RC::RESPONSE_KEY => RC::REQUEST_URI).should.eq "#{path}?a=b"
|
data/test/test_smash.rb
CHANGED
data/test/test_smash_response.rb
CHANGED
@@ -5,19 +5,19 @@ describe RC::SmashResponse do
|
|
5
5
|
describe 'app' do
|
6
6
|
app = RC::SmashResponse.new(RC::Dry.new, true)
|
7
7
|
|
8
|
-
|
8
|
+
would 'do nothing' do
|
9
9
|
env = {RC::RESPONSE_BODY => []}
|
10
10
|
app.call(env) do |res|
|
11
11
|
res.should.eq(env)
|
12
|
-
res[RC::RESPONSE_BODY].should.kind_of(Array)
|
12
|
+
res[RC::RESPONSE_BODY].should.kind_of?(Array)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
would 'smash' do
|
17
17
|
app.call(RC::RESPONSE_BODY => {}) do |res|
|
18
18
|
body = res[RC::RESPONSE_BODY]
|
19
|
-
body.should.kind_of(RC::Smash)
|
20
|
-
body.should.empty
|
19
|
+
body.should.kind_of?(RC::Smash)
|
20
|
+
body.should.empty?
|
21
21
|
body[0].should.eq(nil)
|
22
22
|
body[0, 0].should.eq(nil)
|
23
23
|
end
|
@@ -34,22 +34,22 @@ describe RC::SmashResponse do
|
|
34
34
|
}
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
would 'do nothing' do
|
38
38
|
b = client.new(:smash_response => false).get(''){ |res|
|
39
39
|
res.should.eq(body)
|
40
|
-
res.should.kind_of(Hash)
|
40
|
+
res.should.kind_of?(Hash)
|
41
41
|
}.get('')
|
42
42
|
b.should.eq(body)
|
43
|
-
b.should.kind_of(Hash)
|
43
|
+
b.should.kind_of?(Hash)
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
would 'clash' do
|
47
47
|
b = client.new.get(''){ |res|
|
48
48
|
res.should.eq(body)
|
49
|
-
res.should.kind_of(RC::Smash)
|
49
|
+
res.should.kind_of?(RC::Smash)
|
50
50
|
}.get('')
|
51
51
|
b.should.eq(body)
|
52
|
-
b.should.kind_of(RC::Smash)
|
52
|
+
b.should.kind_of?(RC::Smash)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
data/test/test_thread_pool.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
4
|
describe RC::ThreadPool do
|
5
|
-
|
5
|
+
would 'have the same pool for the same client' do
|
6
6
|
client = RC::Builder.client
|
7
7
|
pool = RC::ThreadPool[client]
|
8
8
|
RC::ThreadPool[client].object_id.should.eq pool.object_id
|
data/test/test_timeout.rb
CHANGED
@@ -9,18 +9,18 @@ describe RC::Timeout do
|
|
9
9
|
Muack.verify
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
would 'bypass timeout if timeout is 0' do
|
13
13
|
mock(app).monitor.times(0)
|
14
14
|
app.call({}){ |e| e.should.eq({}) }
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
would 'run the monitor to setup timeout' do
|
18
18
|
env = {'timeout' => 2}
|
19
19
|
mock(app).monitor(env)
|
20
20
|
app.call(env){|e| e[RC::TIMER].should.kind_of?(RC::Timer)}
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
would "not raise timeout error if there's already an error" do
|
24
24
|
env = {'timeout' => 0.01}
|
25
25
|
mock(app.app).call(hash_including(env)){ raise "error" }
|
26
26
|
lambda{ app.call(env){} }.should .raise(RuntimeError)
|
data/test/test_universal.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'rest-core/test'
|
3
3
|
|
4
4
|
describe RC::Universal do
|
5
|
-
|
5
|
+
would 'send Authorization header' do
|
6
6
|
u = RC::Universal.new(:log_method => false)
|
7
7
|
u.username = 'Aladdin'
|
8
8
|
u.password = 'open sesame'
|
@@ -17,7 +17,7 @@ describe RC::Universal do
|
|
17
17
|
{'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}.merge(acc))
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
would 'clash' do
|
21
21
|
url = 'http://localhost/'
|
22
22
|
stub_request(:get, url).to_return(:body => '{"a":{"b":"c"}}')
|
23
23
|
res = RC::Universal.new(:json_response => true,
|
@@ -25,4 +25,14 @@ describe RC::Universal do
|
|
25
25
|
:log_method => false).get(url)
|
26
26
|
res['a']['d'].should.eq({})
|
27
27
|
end
|
28
|
+
|
29
|
+
would 'follow redirect regardless response body' do
|
30
|
+
url = 'http://localhost/'
|
31
|
+
stub_request(:get, url).to_return(:body => 'bad json!',
|
32
|
+
:status => 302, :headers => {'Location' => "#{url}a"})
|
33
|
+
stub_request(:get, "#{url}a").to_return(:body => '{"good":"json!"}')
|
34
|
+
RC::Universal.new(:json_response => true,
|
35
|
+
:log_method => false).
|
36
|
+
get(url).should.eq 'good' => 'json!'
|
37
|
+
end
|
28
38
|
end
|