rest-core 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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_default_query.rb
CHANGED
@@ -9,11 +9,11 @@ describe RC::DefaultQuery do
|
|
9
9
|
env = {RC::REQUEST_QUERY => {}}
|
10
10
|
|
11
11
|
describe 'when given query' do
|
12
|
-
|
12
|
+
would 'do nothing' do
|
13
13
|
@app.call(env){ |r| r[RC::REQUEST_QUERY].should.eq({}) }
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
would 'merge query' do
|
17
17
|
@app.instance_eval{@query = {'q' => 'uery'}}
|
18
18
|
|
19
19
|
@app.call(env){ |r| r.should.eq({RC::REQUEST_QUERY => {'q' => 'uery'}}) }
|
@@ -25,16 +25,24 @@ describe RC::DefaultQuery do
|
|
25
25
|
r.should.eq({RC::REQUEST_QUERY => {'q' => 'uery'}.merge(format)}) }
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
would 'string_keys in query' do
|
29
29
|
e = {'query' => {:symbol => 'value'}}
|
30
30
|
@app.call(env.merge(e)){ |r|
|
31
31
|
r.should.eq({RC::REQUEST_QUERY => {'symbol' => 'value'}}.merge(e))
|
32
32
|
}
|
33
33
|
end
|
34
|
+
|
35
|
+
would 'also merge the very default query' do
|
36
|
+
@app.query = {'a' => 'b'}
|
37
|
+
@app.call('query' => {'b' => 'c'},
|
38
|
+
RC::REQUEST_QUERY => {'c' => 'd'}) do |r|
|
39
|
+
r[RC::REQUEST_QUERY].should.eq 'a' => 'b', 'b' => 'c', 'c' => 'd'
|
40
|
+
end
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
44
|
describe 'when not given query' do
|
37
|
-
|
45
|
+
would 'merge query with {}' do
|
38
46
|
@app.call(env){ |r| r.should.eq(RC::REQUEST_QUERY => {}) }
|
39
47
|
end
|
40
48
|
end
|
data/test/test_error_detector.rb
CHANGED
data/test/test_error_handler.rb
CHANGED
@@ -10,13 +10,13 @@ describe RC::ErrorHandler do
|
|
10
10
|
exp = Class.new(Exception)
|
11
11
|
|
12
12
|
describe 'there is an exception' do
|
13
|
-
|
13
|
+
would 'raise an error with future' do
|
14
14
|
lambda{
|
15
15
|
client.new.get('/', {}, RC::FAIL => [exp.new('fail')])
|
16
16
|
}.should.raise(exp)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
would 'give an error with callback' do
|
20
20
|
client.new.get('/', {}, RC::FAIL => [exp.new('fail')]){ |res|
|
21
21
|
res.should.kind_of?(exp)
|
22
22
|
}
|
@@ -24,20 +24,20 @@ describe RC::ErrorHandler do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe 'error_handler gives an exception' do
|
27
|
-
|
27
|
+
would 'raise an error with future' do
|
28
28
|
lambda{
|
29
29
|
client.new(:error_handler => lambda{ |res| exp.new }).
|
30
30
|
get('/', {}, RC::FAIL => [true])
|
31
31
|
}.should.raise(exp)
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
would 'give an error with callback' do
|
35
35
|
client.new(:error_handler => lambda{ |res| exp.new }).
|
36
36
|
get('/', {}, RC::FAIL => [true]){ |res| res.should.kind_of?(exp) }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
would 'no exception but errors' do
|
41
41
|
client.new(:error_handler => lambda{ |res| 1 }).
|
42
42
|
request(RC::FAIL => [0], RC::RESPONSE_KEY => RC::FAIL).should.eq [0, 1]
|
43
43
|
end
|
data/test/test_event_source.rb
CHANGED
@@ -35,24 +35,24 @@ SSE
|
|
35
35
|
[client.event_source(path, :a => 'b'), m, t]
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
would 'work regularly' do
|
39
39
|
es, m, t = server.call
|
40
40
|
flag = 0
|
41
41
|
|
42
42
|
es.onopen do |sock|
|
43
|
-
sock.should.kind_of IO
|
43
|
+
sock.should.kind_of? IO
|
44
44
|
flag.should.eq 0
|
45
45
|
flag += 1
|
46
46
|
end.
|
47
47
|
onmessage do |event, data, sock|
|
48
48
|
{'event' => event, 'data' => data}.should.eq m.shift
|
49
|
-
sock.should.kind_of IO
|
49
|
+
sock.should.kind_of? IO
|
50
50
|
sock.should.not.closed?
|
51
51
|
flag += 1
|
52
52
|
end.
|
53
53
|
onerror do |error, sock|
|
54
|
-
error.should.kind_of EOFError
|
55
|
-
m.should.empty
|
54
|
+
error.should.kind_of? EOFError
|
55
|
+
m.should.empty?
|
56
56
|
sock.should.closed?
|
57
57
|
flag.should.eq 3
|
58
58
|
flag += 1
|
@@ -62,7 +62,7 @@ SSE
|
|
62
62
|
t.join
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
would 'close' do
|
66
66
|
es, _, t = server.call(false)
|
67
67
|
flag = 0
|
68
68
|
es.onmessage do
|
@@ -74,7 +74,7 @@ SSE
|
|
74
74
|
t.join
|
75
75
|
end
|
76
76
|
|
77
|
-
|
77
|
+
would 'reconnect' do
|
78
78
|
stub_request(:get, 'https://a?b=c').to_return(:body => <<-SSE)
|
79
79
|
event: put
|
80
80
|
data: 0
|
@@ -95,19 +95,19 @@ SSE
|
|
95
95
|
data.should.eq m.shift
|
96
96
|
|
97
97
|
end.onerror do |error|
|
98
|
-
error.should.kind_of EOFError
|
98
|
+
error.should.kind_of? EOFError
|
99
99
|
es.query = {:c => 'd'}
|
100
100
|
|
101
101
|
end.onreconnect do |error, sock|
|
102
|
-
error.should.kind_of EOFError
|
103
|
-
sock.should.respond_to :read
|
102
|
+
error.should.kind_of? EOFError
|
103
|
+
sock.should.respond_to? :read
|
104
104
|
!m.empty? # not empty to reconnect
|
105
105
|
|
106
106
|
end.start.wait
|
107
|
-
m.should.empty
|
107
|
+
m.should.empty?
|
108
108
|
end
|
109
109
|
|
110
|
-
|
110
|
+
would 'not cache' do
|
111
111
|
stub_request(:get, 'https://a?b=c').to_return(:body => <<-SSE)
|
112
112
|
event: put
|
113
113
|
data: 0
|
@@ -121,14 +121,14 @@ SSE
|
|
121
121
|
data.should.eq m.shift
|
122
122
|
|
123
123
|
end.onerror do |error|
|
124
|
-
error.should.kind_of EOFError
|
124
|
+
error.should.kind_of? EOFError
|
125
125
|
|
126
126
|
end.onreconnect do |error, sock|
|
127
|
-
error.should.kind_of EOFError
|
128
|
-
sock.should.respond_to :read
|
127
|
+
error.should.kind_of? EOFError
|
128
|
+
sock.should.respond_to? :read
|
129
129
|
!m.empty? # not empty to reconnect
|
130
130
|
|
131
131
|
end.start.wait
|
132
|
-
m.should.empty
|
132
|
+
m.should.empty?
|
133
133
|
end
|
134
134
|
end
|
@@ -16,30 +16,30 @@ describe RC::FollowRedirect do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
[301, 302, 303, 307].each do |status|
|
19
|
-
|
19
|
+
would "not follow redirect if reached max_redirects: #{status}" do
|
20
20
|
dry.status = status
|
21
21
|
app.call(RC::REQUEST_METHOD => :get, 'max_redirects' => 0) do |res|
|
22
22
|
res[RC::RESPONSE_HEADERS]['LOCATION'].should.eq 'location'
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
would "follow once: #{status}" do
|
27
27
|
dry.status = status
|
28
28
|
app.call(RC::REQUEST_METHOD => :get) do |res|
|
29
29
|
res[RC::RESPONSE_HEADERS]['LOCATION'].should.eq 'location'
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
would "not carry query string: #{status}" do
|
34
34
|
dry.status = status
|
35
35
|
app.call(RC::REQUEST_METHOD => :get,
|
36
36
|
RC::REQUEST_QUERY => {:a => 'a'}) do |res|
|
37
37
|
res[RC::REQUEST_PATH] .should.eq 'location'
|
38
|
-
res[RC::REQUEST_QUERY].should.empty
|
38
|
+
res[RC::REQUEST_QUERY].should.empty?
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
would "carry payload for #{status}" do
|
43
43
|
dry.status = status
|
44
44
|
app.call(RC::REQUEST_METHOD => :put,
|
45
45
|
RC::REQUEST_PAYLOAD => {:a => 'a'}) do |res|
|
@@ -49,7 +49,7 @@ describe RC::FollowRedirect do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
[200, 201, 404, 500].each do |status|
|
52
|
-
|
52
|
+
would "not follow redirect if it's not a redirect status: #{status}" do
|
53
53
|
dry.status = status
|
54
54
|
app.call(RC::REQUEST_METHOD => :get, 'max_redirects' => 9) do |res|
|
55
55
|
res[RC::RESPONSE_HEADERS]['LOCATION'].should.eq 'location'
|
data/test/test_future.rb
CHANGED
@@ -3,14 +3,14 @@ require 'stringio'
|
|
3
3
|
require 'rest-core/test'
|
4
4
|
|
5
5
|
describe RC::Promise::Future do
|
6
|
-
|
6
|
+
would 'fulfill the future' do
|
7
7
|
promise = RC::Promise.new(RC::FAIL => [])
|
8
8
|
promise.fulfill('body', 200, {'A' => 'B'}, StringIO.new)
|
9
9
|
|
10
10
|
promise.future_body .should.eq 'body'
|
11
11
|
promise.future_status .should.eq 200
|
12
12
|
promise.future_headers .should.eq('A' => 'B')
|
13
|
-
promise.future_socket .should.kind_of(StringIO)
|
13
|
+
promise.future_socket .should.kind_of?(StringIO)
|
14
14
|
promise.future_failures.should.eq []
|
15
15
|
end
|
16
16
|
end
|
data/test/test_json_request.rb
CHANGED
@@ -10,7 +10,7 @@ describe RC::JsonRequest do
|
|
10
10
|
'nested' => {'k' => 'v', 'a' => [4, 5, 6]}
|
11
11
|
}
|
12
12
|
|
13
|
-
|
13
|
+
would 'encode payload as json' do
|
14
14
|
e = env.merge(RC::REQUEST_METHOD => :post,
|
15
15
|
RC::REQUEST_PAYLOAD => request_params)
|
16
16
|
|
@@ -21,8 +21,13 @@ describe RC::JsonRequest do
|
|
21
21
|
RC::REQUEST_PAYLOAD => RC::Json.encode(request_params))}
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
app.call(
|
24
|
+
would 'do nothing if payload is empty' do
|
25
|
+
e = env.merge(RC::REQUEST_PAYLOAD => {})
|
26
|
+
app.call(e){ |res| res.should.eq e }
|
27
|
+
end
|
28
|
+
|
29
|
+
would 'do nothing if json_request is false' do
|
30
|
+
a = RC::JsonRequest.new(RC::Dry.new, false)
|
31
|
+
a.call(env){ |res| res.should.eq env }
|
27
32
|
end
|
28
33
|
end
|
data/test/test_json_response.rb
CHANGED
@@ -6,13 +6,13 @@ describe RC::JsonResponse do
|
|
6
6
|
app = RC::JsonResponse.new(RC::Dry.new, true)
|
7
7
|
bad = 'bad json'
|
8
8
|
|
9
|
-
|
9
|
+
would 'do nothing' do
|
10
10
|
expected = {RC::RESPONSE_BODY => nil,
|
11
11
|
RC::REQUEST_HEADERS => {'Accept' => 'application/json'}}
|
12
12
|
app.call({}){ |response| response.should.eq(expected) }
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
would 'decode' do
|
16
16
|
expected = {RC::RESPONSE_BODY => {},
|
17
17
|
RC::REQUEST_HEADERS => {'Accept' => 'application/json'}}
|
18
18
|
app.call(RC::RESPONSE_BODY => '{}') do |response|
|
@@ -20,18 +20,18 @@ describe RC::JsonResponse do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
would 'give proper parse error' do
|
24
24
|
app.call(RC::RESPONSE_BODY => bad) do |response|
|
25
25
|
err = response[RC::FAIL].first
|
26
|
-
err.should.kind_of(RC::Json.const_get(:ParseError))
|
27
|
-
err.should.kind_of(RC::JsonResponse::ParseError)
|
26
|
+
err.should.kind_of?(RC::Json.const_get(:ParseError))
|
27
|
+
err.should.kind_of?(RC::JsonResponse::ParseError)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
would 'give me original text' do
|
32
32
|
app.call(RC::RESPONSE_BODY => bad) do |response|
|
33
33
|
err = response[RC::FAIL].first
|
34
|
-
err.message .should.include(bad)
|
34
|
+
err.message .should.include?(bad)
|
35
35
|
err.body .should.eq(bad)
|
36
36
|
err.cause.class.should.eq(RC::Json.const_get(:ParseError))
|
37
37
|
end
|
@@ -48,14 +48,14 @@ describe RC::JsonResponse do
|
|
48
48
|
}
|
49
49
|
end
|
50
50
|
|
51
|
-
|
51
|
+
would 'do nothing' do
|
52
52
|
expected = '{}'
|
53
53
|
client.new(:json_response => false).get(''){ |response|
|
54
54
|
response.should.eq(expected)
|
55
55
|
}.get('').should.eq(expected)
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
would 'decode' do
|
59
59
|
expected = {}
|
60
60
|
client.new.get(''){ |response|
|
61
61
|
response.should.eq(expected)
|
data/test/test_oauth1_header.rb
CHANGED
@@ -24,7 +24,7 @@ describe RC::Oauth1Header do
|
|
24
24
|
'GDdmIQH6jhtmLUypg82g',
|
25
25
|
'MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98')
|
26
26
|
|
27
|
-
|
27
|
+
would 'have correct signature' do
|
28
28
|
auth.signature(env, oauth_params).should.eq(
|
29
29
|
'8wUi7m5HFQy76nowoCThusfgB+Q=')
|
30
30
|
end
|
@@ -43,36 +43,36 @@ describe RC::Oauth1Header do
|
|
43
43
|
auth.base_string(e, oauth_params).should.eq b
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
would 'have correct base_string' do
|
47
47
|
check[env, base_string]
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
would 'not use payload in multipart request for base_string' do
|
51
51
|
File.open(__FILE__) do |f|
|
52
52
|
check[env.merge(RC::REQUEST_PAYLOAD => {'file' => f}), base_string]
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
|
56
|
+
would 'not use payload if it contains binary' do
|
57
57
|
File.open(__FILE__) do |f|
|
58
58
|
check[env.merge(RC::REQUEST_PAYLOAD => f), base_string]
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
|
62
|
+
would 'not use payload if it contains [binary]' do
|
63
63
|
File.open(__FILE__) do |f|
|
64
64
|
check[env.merge(RC::REQUEST_PAYLOAD => [f]), base_string]
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
68
|
+
would 'not use payload if Content-Type is not x-www-form-urlencoded' do
|
69
69
|
check[
|
70
70
|
env.merge(RC::REQUEST_PAYLOAD => {'pay' => 'load'},
|
71
71
|
RC::REQUEST_HEADERS => {'Content-Type' => 'text/plain'}),
|
72
72
|
base_string]
|
73
73
|
end
|
74
74
|
|
75
|
-
|
75
|
+
would 'use payload if Content-Type is x-www-form-urlencoded' do
|
76
76
|
check[env.merge(
|
77
77
|
RC::REQUEST_PAYLOAD => {'pay' => 'load'},
|
78
78
|
RC::REQUEST_HEADERS =>
|
@@ -80,12 +80,12 @@ describe RC::Oauth1Header do
|
|
80
80
|
base_string + '%26pay%3Dload']
|
81
81
|
end
|
82
82
|
|
83
|
-
|
83
|
+
would 'use payload if there is no binary data' do
|
84
84
|
check[env.merge(RC::REQUEST_PAYLOAD => {'pay' => 'load'}),
|
85
85
|
base_string + '%26pay%3Dload']
|
86
86
|
end
|
87
87
|
|
88
|
-
|
88
|
+
would 'not escape ~' do
|
89
89
|
check[env.merge(RC::REQUEST_PAYLOAD => {'tilde' => '~'}),
|
90
90
|
base_string + '%26tilde%3D~']
|
91
91
|
end
|
data/test/test_oauth2_header.rb
CHANGED
@@ -5,18 +5,18 @@ describe RC::Oauth2Header do
|
|
5
5
|
env = {RC::REQUEST_HEADERS => {}}
|
6
6
|
auth = RC::Oauth2Header.new(RC::Dry.new)
|
7
7
|
|
8
|
-
|
8
|
+
would 'do nothing if no access token' do
|
9
9
|
auth.call(env){ |res| res.should.eq(env) }
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
would 'Bearer token' do
|
13
13
|
auth.call(env.merge('access_token_type' => 'Bearer',
|
14
14
|
'access_token' => 'token')){ |res|
|
15
15
|
res[RC::REQUEST_HEADERS].should.eq 'Authorization' => 'Bearer token'
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
would 'MAC token' do # http://tools.ietf.org/html/rfc6749#section-7.1
|
20
20
|
auth.call(env.merge('access_token_type' => 'MAC',
|
21
21
|
'access_token' =>
|
22
22
|
{'id' => 'h480djs93hd8',
|
data/test/test_parse_link.rb
CHANGED
@@ -3,7 +3,7 @@ require 'rest-core/test'
|
|
3
3
|
|
4
4
|
describe RC::ParseLink do
|
5
5
|
describe 'http://tools.ietf.org/html/rfc5988' do
|
6
|
-
|
6
|
+
would '5.5 a' do
|
7
7
|
link = '<http://example.com/TheBook/chapter2>; rel="previous"; title="previous chapter"'
|
8
8
|
RC::ParseLink.parse_link(link).should.eq(
|
9
9
|
'previous' => {'uri' => 'http://example.com/TheBook/chapter2',
|
@@ -11,14 +11,14 @@ describe RC::ParseLink do
|
|
11
11
|
'title' => 'previous chapter'})
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
would '5.5 b' do
|
15
15
|
link = '</>; rel="http://example.net/foo"'
|
16
16
|
RC::ParseLink.parse_link(link).should.eq(
|
17
17
|
'http://example.net/foo' => {'uri' => '/',
|
18
18
|
'rel' => 'http://example.net/foo'})
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
would '5.5 c (we did not implement * and unescape for now)' do
|
22
22
|
link = <<-LINK
|
23
23
|
</TheBook/chapter2>; rel="previous"; title*=UTF-8'de'letztes%20Kapitel, </TheBook/chapter4>; rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel
|
24
24
|
LINK
|
@@ -31,7 +31,7 @@ describe RC::ParseLink do
|
|
31
31
|
'title*' => "UTF-8'de'n%c3%a4chstes%20Kapitel"})
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
would '5.5 d' do
|
35
35
|
link = '<http://example.org/>; rel="start http://example.net/relation/other"'
|
36
36
|
|
37
37
|
RC::ParseLink.parse_link(link).should.eq(
|