restfully 0.7.1.rc3 → 0.7.1.rc4
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/bin/restfully +3 -0
- data/lib/restfully/collection.rb +5 -16
- data/lib/restfully/http/request.rb +53 -18
- data/lib/restfully/http/response.rb +1 -1
- data/lib/restfully/resource.rb +6 -4
- data/lib/restfully/session.rb +20 -27
- data/lib/restfully/version.rb +1 -1
- data/spec/restfully/http/request_spec.rb +33 -0
- data/spec/restfully/http/response_spec.rb +3 -0
- data/spec/restfully/resource_spec.rb +13 -4
- data/spec/restfully/session_spec.rb +58 -38
- metadata +3 -3
data/bin/restfully
CHANGED
|
@@ -49,6 +49,9 @@ BANNER
|
|
|
49
49
|
@options["logger"] = logger
|
|
50
50
|
end
|
|
51
51
|
opts.on("-v", "--verbose", "Run verbosely") do |v|
|
|
52
|
+
@options["logger"].level = Logger::INFO
|
|
53
|
+
end
|
|
54
|
+
opts.on("--debug", "Run in debug mode") do |v|
|
|
52
55
|
@options["logger"].level = Logger::DEBUG
|
|
53
56
|
end
|
|
54
57
|
opts.on_tail("-h", "--help", "Show this message") do
|
data/lib/restfully/collection.rb
CHANGED
|
@@ -14,13 +14,13 @@ module Restfully
|
|
|
14
14
|
super(property)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
def find_by_uid(symbol)
|
|
19
19
|
found = find{ |i| i.media_type.represents?(symbol) }
|
|
20
20
|
found.expand unless found.nil?
|
|
21
21
|
found
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
def find_by_index(index)
|
|
25
25
|
index = index+length if index < 0
|
|
26
26
|
each_with_index{|item, i|
|
|
@@ -69,27 +69,16 @@ module Restfully
|
|
|
69
69
|
def empty?
|
|
70
70
|
total == 0
|
|
71
71
|
end
|
|
72
|
-
|
|
73
|
-
# Expand the items that
|
|
72
|
+
|
|
73
|
+
# Expand the items that
|
|
74
74
|
def expand
|
|
75
75
|
each {|i| i.expand}
|
|
76
76
|
self
|
|
77
77
|
end
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
def inspect
|
|
80
80
|
map{|item| item}.inspect
|
|
81
81
|
end
|
|
82
|
-
# def (key)
|
|
83
|
-
# p Addressable::URI.parse("./"+key.to_s)
|
|
84
|
-
# p self.uri
|
|
85
|
-
# uri_to_find = Addressable::URI.join(self.uri, "./"+key.to_s)
|
|
86
|
-
# p uri_to_find
|
|
87
|
-
# find{|resource|
|
|
88
|
-
# resource.uri == uri_to_find
|
|
89
|
-
# }
|
|
90
|
-
# end
|
|
91
|
-
|
|
92
|
-
|
|
93
82
|
end
|
|
94
83
|
|
|
95
84
|
end
|
|
@@ -2,27 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
module Restfully
|
|
4
4
|
module HTTP
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
class Request
|
|
7
7
|
include Helper
|
|
8
|
-
|
|
9
|
-
attr_reader :method, :uri, :head, :body
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
|
|
9
|
+
attr_reader :session, :method, :uri, :head, :body, :attempts
|
|
10
|
+
attr_accessor :retry_on_error, :wait_before_retry
|
|
11
|
+
|
|
12
|
+
def initialize(session, method, path, options = {})
|
|
12
13
|
@session = session
|
|
13
|
-
|
|
14
|
+
@attempts = 0
|
|
15
|
+
|
|
14
16
|
request = options.symbolize_keys
|
|
17
|
+
|
|
18
|
+
@retry_on_error = request[:retry_on_error] || session.config[:retry_on_error]
|
|
19
|
+
@wait_before_retry = request[:wait_before_retry] || session.config[:wait_before_retry]
|
|
20
|
+
|
|
15
21
|
request[:method] = method
|
|
16
22
|
|
|
17
23
|
request[:head] = sanitize_head(@session.default_headers).merge(
|
|
18
24
|
build_head(request)
|
|
19
25
|
)
|
|
20
|
-
|
|
26
|
+
|
|
21
27
|
request[:uri] = @session.uri_to(path)
|
|
22
28
|
if request[:query]
|
|
23
29
|
request[:uri].query_values = sanitize_query(request[:query])
|
|
24
30
|
end
|
|
25
|
-
|
|
31
|
+
|
|
26
32
|
request[:body] = if [:post, :put].include?(request[:method])
|
|
27
33
|
build_body(request)
|
|
28
34
|
end
|
|
@@ -30,9 +36,10 @@ module Restfully
|
|
|
30
36
|
@method, @uri, @head, @body = request.values_at(
|
|
31
37
|
:method, :uri, :head, :body
|
|
32
38
|
)
|
|
39
|
+
|
|
33
40
|
end
|
|
34
|
-
|
|
35
|
-
# Updates the request header and query parameters
|
|
41
|
+
|
|
42
|
+
# Updates the request header and query parameters.
|
|
36
43
|
# Returns nil if no changes were made, otherwise self.
|
|
37
44
|
def update!(options = {})
|
|
38
45
|
objects_that_may_be_updated = [@uri, @head]
|
|
@@ -48,33 +55,61 @@ module Restfully
|
|
|
48
55
|
self
|
|
49
56
|
end
|
|
50
57
|
end
|
|
51
|
-
|
|
58
|
+
|
|
52
59
|
def inspect
|
|
53
60
|
"#{method.to_s.upcase} #{uri.to_s}, head=#{head.inspect}, body=#{body.inspect}"
|
|
54
61
|
end
|
|
55
|
-
|
|
62
|
+
|
|
56
63
|
def no_cache?
|
|
57
64
|
head['Cache-Control'] && head['Cache-Control'].include?('no-cache')
|
|
58
65
|
end
|
|
59
|
-
|
|
66
|
+
|
|
60
67
|
def no_cache!
|
|
61
68
|
@forced_cache = true
|
|
62
69
|
head['Cache-Control'] = 'no-cache'
|
|
63
70
|
end
|
|
64
|
-
|
|
71
|
+
|
|
65
72
|
def forced_cache?
|
|
66
73
|
!!@forced_cache
|
|
67
74
|
end
|
|
68
|
-
|
|
75
|
+
|
|
76
|
+
def execute!
|
|
77
|
+
session.logger.debug self.inspect
|
|
78
|
+
resource = RestClient::Resource.new(
|
|
79
|
+
uri.to_s,
|
|
80
|
+
:headers => head
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
reqcode, reqhead, reqbody = resource.send(method, body || {})
|
|
85
|
+
response = Response.new(session, reqcode, reqhead, reqbody)
|
|
86
|
+
session.logger.debug response.inspect
|
|
87
|
+
response
|
|
88
|
+
rescue Errno::ECONNREFUSED => e
|
|
89
|
+
retry! || raise(e)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def retry!
|
|
94
|
+
if @attempts < @retry_on_error
|
|
95
|
+
@attempts+=1
|
|
96
|
+
session.logger.info "Encountered connection or server error. Retrying in #{@wait_before_retry}s... [#{@attempts}/#{@retry_on_error}]"
|
|
97
|
+
sleep @wait_before_retry if @wait_before_retry > 0
|
|
98
|
+
execute!
|
|
99
|
+
else
|
|
100
|
+
false
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
69
104
|
def remove_no_cache!
|
|
70
105
|
@forced_cache = false
|
|
71
106
|
if head['Cache-Control']
|
|
72
|
-
head['Cache-Control'] = head['Cache-Control'].split(/\s+,\s+/).reject{|v|
|
|
107
|
+
head['Cache-Control'] = head['Cache-Control'].split(/\s+,\s+/).reject{|v|
|
|
73
108
|
v =~ /no-cache/i
|
|
74
109
|
}.join(",")
|
|
75
110
|
end
|
|
76
111
|
end
|
|
77
|
-
|
|
112
|
+
|
|
78
113
|
protected
|
|
79
114
|
def build_head(options = {})
|
|
80
115
|
sanitize_head(
|
|
@@ -94,7 +129,7 @@ module Restfully
|
|
|
94
129
|
nil
|
|
95
130
|
end
|
|
96
131
|
end
|
|
97
|
-
|
|
132
|
+
|
|
98
133
|
end
|
|
99
134
|
end
|
|
100
135
|
end
|
data/lib/restfully/resource.rb
CHANGED
|
@@ -25,7 +25,10 @@ module Restfully
|
|
|
25
25
|
# resource["uid"]
|
|
26
26
|
# => "rennes"
|
|
27
27
|
def [](key)
|
|
28
|
-
|
|
28
|
+
unless collection?
|
|
29
|
+
expand
|
|
30
|
+
end
|
|
31
|
+
media_type.property(key)
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
def uri
|
|
@@ -58,7 +61,7 @@ module Restfully
|
|
|
58
61
|
def load(options = {})
|
|
59
62
|
# Send a GET request only if given a different set of options
|
|
60
63
|
if @request.update!(options) || @request.no_cache?
|
|
61
|
-
@response =
|
|
64
|
+
@response = @request.execute!
|
|
62
65
|
@request.remove_no_cache! if @request.forced_cache?
|
|
63
66
|
if session.process(@response, @request)
|
|
64
67
|
@associations.clear
|
|
@@ -121,8 +124,7 @@ module Restfully
|
|
|
121
124
|
end
|
|
122
125
|
|
|
123
126
|
def allow?(method)
|
|
124
|
-
reload
|
|
125
|
-
response.allow?(method)
|
|
127
|
+
response.allow?(method) || reload.response.allow?(method)
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
def inspect
|
data/lib/restfully/session.rb
CHANGED
|
@@ -16,6 +16,8 @@ module Restfully
|
|
|
16
16
|
def initialize(options = {})
|
|
17
17
|
@config = options.symbolize_keys
|
|
18
18
|
@logger = @config.delete(:logger) || Logger.new(STDERR)
|
|
19
|
+
@config[:retry_on_error] ||= 5
|
|
20
|
+
@config[:wait_before_retry] ||= 5
|
|
19
21
|
|
|
20
22
|
@uri = @config.delete(:uri)
|
|
21
23
|
if @uri.nil? || @uri.empty?
|
|
@@ -100,29 +102,14 @@ module Restfully
|
|
|
100
102
|
transmit :delete, path, options
|
|
101
103
|
end
|
|
102
104
|
|
|
103
|
-
# Build and
|
|
105
|
+
# Build and execute the corresponding HTTP request,
|
|
106
|
+
# then process the response.
|
|
104
107
|
def transmit(method, path, options)
|
|
105
108
|
request = HTTP::Request.new(self, method, path, options)
|
|
106
|
-
|
|
107
|
-
response = execute(request)
|
|
108
|
-
|
|
109
|
+
response = request.execute!
|
|
109
110
|
process(response, request)
|
|
110
111
|
end
|
|
111
112
|
|
|
112
|
-
def execute(request)
|
|
113
|
-
resource = RestClient::Resource.new(
|
|
114
|
-
request.uri.to_s,
|
|
115
|
-
:headers => request.head
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
logger.debug request.inspect
|
|
119
|
-
code, head, body = resource.send(request.method, request.body || {})
|
|
120
|
-
|
|
121
|
-
response = Restfully::HTTP::Response.new(self, code, head, body)
|
|
122
|
-
logger.debug response.inspect
|
|
123
|
-
response
|
|
124
|
-
end
|
|
125
|
-
|
|
126
113
|
# Process a Restfully::HTTP::Response.
|
|
127
114
|
def process(response, request)
|
|
128
115
|
case code=response.code
|
|
@@ -135,14 +122,15 @@ module Restfully
|
|
|
135
122
|
when 204
|
|
136
123
|
true
|
|
137
124
|
when 400..499
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
125
|
+
raise HTTP::ClientError, error_message(request, response)
|
|
126
|
+
when 502..504
|
|
127
|
+
if res = request.retry!
|
|
128
|
+
process(res, request)
|
|
129
|
+
else
|
|
130
|
+
raise(HTTP::ServerError, error_message(request, response))
|
|
131
|
+
end
|
|
132
|
+
when 500, 501
|
|
133
|
+
raise HTTP::ServerError, error_message(request, response)
|
|
146
134
|
else
|
|
147
135
|
raise Error, "Restfully does not handle code #{code.inspect}."
|
|
148
136
|
end
|
|
@@ -150,7 +138,12 @@ module Restfully
|
|
|
150
138
|
|
|
151
139
|
protected
|
|
152
140
|
def setup_cache
|
|
153
|
-
enable ::Rack::Cache, :verbose => (logger.level
|
|
141
|
+
enable ::Rack::Cache, :verbose => (logger.level <= Logger::INFO)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def error_message(request, response)
|
|
145
|
+
msg = "Encountered error #{response.code} on #{request.method.upcase} #{request.uri}"
|
|
146
|
+
msg += " --- #{response.body[0..200]}" unless response.body.empty?
|
|
154
147
|
end
|
|
155
148
|
|
|
156
149
|
end
|
data/lib/restfully/version.rb
CHANGED
|
@@ -7,6 +7,11 @@ describe Restfully::HTTP::Request do
|
|
|
7
7
|
:default_headers => {
|
|
8
8
|
'Accept' => '*/*; application/xml',
|
|
9
9
|
:accept_encoding => "gzip, deflate"
|
|
10
|
+
},
|
|
11
|
+
:logger => Logger.new(STDERR),
|
|
12
|
+
:config => {
|
|
13
|
+
:retry_on_error => 5,
|
|
14
|
+
:wait_before_retry => 5
|
|
10
15
|
}
|
|
11
16
|
)
|
|
12
17
|
|
|
@@ -102,5 +107,33 @@ describe Restfully::HTTP::Request do
|
|
|
102
107
|
request.body.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<network xmlns=\"http://api.bonfire-project.eu/doc/schemas/occi\">\n <name>whatever</name>\n</network>\n"
|
|
103
108
|
end
|
|
104
109
|
end
|
|
110
|
+
|
|
111
|
+
describe "execute" do
|
|
112
|
+
before do
|
|
113
|
+
@request = Restfully::HTTP::Request.new(
|
|
114
|
+
@session,
|
|
115
|
+
:get,
|
|
116
|
+
"/path"
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
it "should build the RestClient::Resource and build a response" do
|
|
120
|
+
RestClient::Resource.should_receive(:new).with(
|
|
121
|
+
@request.uri.to_s,
|
|
122
|
+
:headers => @request.head
|
|
123
|
+
).and_return(
|
|
124
|
+
resource = mock(RestClient::Resource)
|
|
125
|
+
)
|
|
126
|
+
resource.should_receive(:get).and_return([
|
|
127
|
+
200,
|
|
128
|
+
{'Content-Type' => 'text/plain'},
|
|
129
|
+
["hello"]
|
|
130
|
+
])
|
|
131
|
+
response = @request.execute!
|
|
132
|
+
response.should be_a(Restfully::HTTP::Response)
|
|
133
|
+
response.code.should == 200
|
|
134
|
+
response.body.should == "hello"
|
|
135
|
+
response.head.should == {'Content-Type' => 'text/plain'}
|
|
136
|
+
end
|
|
137
|
+
end
|
|
105
138
|
|
|
106
139
|
end
|
|
@@ -36,6 +36,9 @@ describe Restfully::HTTP::Response do
|
|
|
36
36
|
|
|
37
37
|
response.allow?(:get).should be_true
|
|
38
38
|
response.allow?(:post).should be_true
|
|
39
|
+
response.allow?("POST").should be_true
|
|
40
|
+
response.allow?("GET").should be_true
|
|
41
|
+
response.allow?("PUT").should be_false
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
it "should raise an error if it cannot find a corresponding media-type" do
|
|
@@ -45,14 +45,23 @@ describe Restfully::Resource do
|
|
|
45
45
|
@resource.clusters
|
|
46
46
|
end
|
|
47
47
|
{:update => "PUT", :submit => "POST", :delete => "DELETE"}.each do |method, http_method|
|
|
48
|
-
it "should
|
|
49
|
-
@resource.should_receive(:reload).once.and_return(@resource)
|
|
48
|
+
it "should get the Allowed HTTP methods when calling #{method.to_sym}" do
|
|
50
49
|
@response.should_receive(:allow?).with(http_method).and_return(true)
|
|
51
50
|
@session.should_receive(http_method.downcase.to_sym).
|
|
52
51
|
and_return(mock(Restfully::HTTP::Response))
|
|
53
52
|
@resource.send(method.to_sym)
|
|
54
53
|
end
|
|
55
54
|
end
|
|
55
|
+
{:update => "PUT", :submit => "POST", :delete => "DELETE"}.each do |method, http_method|
|
|
56
|
+
it "should reload itself to get the Allowed HTTP methods when calling #{method.to_sym}" do
|
|
57
|
+
@response.should_receive(:allow?).with(http_method).and_return(false)
|
|
58
|
+
@response.should_receive(:allow?).with(http_method).and_return(true)
|
|
59
|
+
@resource.should_receive(:reload).once.and_return(@resource)
|
|
60
|
+
@session.should_receive(http_method.downcase.to_sym).
|
|
61
|
+
and_return(mock(Restfully::HTTP::Response))
|
|
62
|
+
@resource.send(method.to_sym)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
56
65
|
it "should not allow to submit if POST not allowed on the resource" do
|
|
57
66
|
@resource.should_receive(:reload).and_return(@resource)
|
|
58
67
|
lambda{
|
|
@@ -125,14 +134,14 @@ describe Restfully::Resource do
|
|
|
125
134
|
end
|
|
126
135
|
|
|
127
136
|
it "should reload the resource even after having reloaded it once before" do
|
|
128
|
-
@
|
|
137
|
+
@request.should_receive(:execute!).twice.
|
|
129
138
|
and_return(@response)
|
|
130
139
|
@resource.reload
|
|
131
140
|
@resource.reload
|
|
132
141
|
end
|
|
133
142
|
|
|
134
143
|
it "should raise an error if it cannot reload the resource" do
|
|
135
|
-
@
|
|
144
|
+
@request.should_receive(:execute!).
|
|
136
145
|
and_return(res=mock(Restfully::HTTP::Response))
|
|
137
146
|
@session.should_receive(:process).with(res, @request).
|
|
138
147
|
and_return(false)
|
|
@@ -10,20 +10,20 @@ describe Restfully::Session do
|
|
|
10
10
|
:logger => @logger
|
|
11
11
|
}
|
|
12
12
|
end
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
it "should initialize a session with the correct properties" do
|
|
15
15
|
session = Restfully::Session.new(@config.merge("key" => "value"))
|
|
16
16
|
session.logger.should == @logger
|
|
17
17
|
session.uri.should == Addressable::URI.parse(@uri)
|
|
18
|
-
session.config.should == {:key
|
|
18
|
+
session.config.should == {:wait_before_retry=>5, :key=>"value", :retry_on_error=>5}
|
|
19
19
|
end
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
it "should raise an error if no URI given" do
|
|
22
22
|
lambda{
|
|
23
23
|
Restfully::Session.new(@config.merge(:uri => ""))
|
|
24
24
|
}.should raise_error(ArgumentError)
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
it "should fetch the root path [no URI path]" do
|
|
28
28
|
session = Restfully::Session.new(@config)
|
|
29
29
|
session.should_receive(:get).with("").
|
|
@@ -31,7 +31,7 @@ describe Restfully::Session do
|
|
|
31
31
|
res.should_receive(:load).and_return(res)
|
|
32
32
|
session.root.should == res
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
it "should fetch the root path [URI path present]" do
|
|
36
36
|
session = Restfully::Session.new(
|
|
37
37
|
@config.merge(:uri => "https://api.grid5000.fr/resource/path")
|
|
@@ -41,21 +41,21 @@ describe Restfully::Session do
|
|
|
41
41
|
res.should_receive(:load).and_return(res)
|
|
42
42
|
session.root.should == res
|
|
43
43
|
end
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
it "should add or replace additional headers to the default set" do
|
|
46
46
|
session = Restfully::Session.new(
|
|
47
47
|
@config.merge(:default_headers => {
|
|
48
|
-
'Accept' => 'application/xml',
|
|
48
|
+
'Accept' => 'application/xml',
|
|
49
49
|
'Cache-Control' => 'no-cache'
|
|
50
50
|
})
|
|
51
51
|
)
|
|
52
52
|
session.default_headers.should == {
|
|
53
|
-
'Accept' => 'application/xml',
|
|
53
|
+
'Accept' => 'application/xml',
|
|
54
54
|
'Cache-Control' => 'no-cache',
|
|
55
55
|
'Accept-Encoding' => 'gzip, deflate'
|
|
56
56
|
}
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
describe "middleware" do
|
|
60
60
|
it "should only have Rack::Cache enabled by default" do
|
|
61
61
|
session = Restfully::Session.new(@config)
|
|
@@ -64,7 +64,7 @@ describe Restfully::Session do
|
|
|
64
64
|
Rack::Cache
|
|
65
65
|
]
|
|
66
66
|
end
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
it "should use Restfully::Rack::BasicAuth if basic authentication is used" do
|
|
69
69
|
session = Restfully::Session.new(@config.merge(
|
|
70
70
|
:username => "crohr", :password => "p4ssw0rd"
|
|
@@ -76,15 +76,15 @@ describe Restfully::Session do
|
|
|
76
76
|
]
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
describe "transmitting requests" do
|
|
81
81
|
before do
|
|
82
82
|
@session = Restfully::Session.new(@config)
|
|
83
83
|
@path = "/path"
|
|
84
84
|
@default_headers = @session.default_headers
|
|
85
85
|
end
|
|
86
|
-
|
|
87
|
-
it "should make a get request" do
|
|
86
|
+
|
|
87
|
+
it "should make a get request" do
|
|
88
88
|
stub_request(:get, @uri+@path+"?k1=v1&k2=v2").with(
|
|
89
89
|
:headers => @default_headers.merge({
|
|
90
90
|
'Accept' => '*/*',
|
|
@@ -106,13 +106,13 @@ describe Restfully::Session do
|
|
|
106
106
|
@response,
|
|
107
107
|
instance_of(Restfully::HTTP::Request)
|
|
108
108
|
)
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
@session.transmit :get, @path, {
|
|
111
111
|
:query => {:k1 => "v1", :k2 => "v2"},
|
|
112
112
|
:headers => {'X-Header' => 'value'}
|
|
113
113
|
}
|
|
114
114
|
end
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
it "should make an authenticated get request" do
|
|
117
117
|
stub_request(:get, "https://crohr:p4ssw0rd@api.grid5000.fr"+@path+"?k1=v1&k2=v2").with(
|
|
118
118
|
:headers => @default_headers.merge({
|
|
@@ -127,57 +127,77 @@ describe Restfully::Session do
|
|
|
127
127
|
:headers => {'X-Header' => 'value'}
|
|
128
128
|
}
|
|
129
129
|
end
|
|
130
|
+
|
|
131
|
+
it "should retry for at most :max_attempts_on_connection_error if connection to the server failed" do
|
|
132
|
+
|
|
133
|
+
end
|
|
130
134
|
end
|
|
131
|
-
|
|
135
|
+
|
|
132
136
|
describe "processing responses" do
|
|
133
137
|
before do
|
|
134
138
|
@session = Restfully::Session.new(@config)
|
|
135
|
-
@request =
|
|
136
|
-
|
|
137
|
-
:
|
|
138
|
-
|
|
139
|
-
:head => mock("head"),
|
|
140
|
-
:update! => nil
|
|
139
|
+
@request = Restfully::HTTP::Request.new(
|
|
140
|
+
@session,
|
|
141
|
+
:get,
|
|
142
|
+
@uri
|
|
141
143
|
)
|
|
144
|
+
@request.stub!(:head).and_return({})
|
|
145
|
+
@request.stub!(:update!).and_return(nil)
|
|
146
|
+
|
|
142
147
|
@response = Restfully::HTTP::Response.new(
|
|
143
148
|
@session,
|
|
144
149
|
200,
|
|
145
|
-
{'X' => 'Y'},
|
|
150
|
+
{'X' => 'Y', 'Content-Type' => 'text/plain'},
|
|
146
151
|
'body'
|
|
147
152
|
)
|
|
148
153
|
end
|
|
149
|
-
|
|
154
|
+
|
|
150
155
|
it "should return true if status=204" do
|
|
151
156
|
@response.stub!(:code).and_return(204)
|
|
152
157
|
@session.process(@response, @request).should be_true
|
|
153
158
|
end
|
|
154
|
-
|
|
159
|
+
|
|
155
160
|
it "should raise a Restfully::HTTP::ClientError if status in 400..499" do
|
|
156
161
|
@response.stub!(:code).and_return(400)
|
|
157
162
|
lambda{
|
|
158
163
|
@session.process(@response, @request)
|
|
159
164
|
}.should raise_error(Restfully::HTTP::ClientError)
|
|
160
165
|
end
|
|
161
|
-
|
|
166
|
+
|
|
162
167
|
it "should raise a Restfully::HTTP::ServerError if status in 500..599" do
|
|
163
168
|
@response.stub!(:code).and_return(500)
|
|
164
169
|
lambda{
|
|
165
170
|
@session.process(@response, @request)
|
|
166
171
|
}.should raise_error(Restfully::HTTP::ServerError)
|
|
167
172
|
end
|
|
168
|
-
|
|
173
|
+
it "should retry if the server returns one of [502,503,504], and request.retry! returns a response" do
|
|
174
|
+
@request.should_receive(:retry!).once.
|
|
175
|
+
and_return(@response)
|
|
176
|
+
@response.should_receive(:code).ordered.and_return(503)
|
|
177
|
+
@response.should_receive(:code).ordered.and_return(200)
|
|
178
|
+
@session.process(@response, @request)
|
|
179
|
+
end
|
|
180
|
+
it "should not retry if the server returns one of [502,503,504], but request.retry! returns false" do
|
|
181
|
+
@request.should_receive(:retry!).once.
|
|
182
|
+
and_return(false)
|
|
183
|
+
@response.stub!(:code).and_return(503)
|
|
184
|
+
lambda{
|
|
185
|
+
@session.process(@response, @request)
|
|
186
|
+
}.should raise_error(Restfully::HTTP::ServerError, /503/)
|
|
187
|
+
end
|
|
188
|
+
|
|
169
189
|
it "should raise an error if the status is not supported" do
|
|
170
190
|
@response.stub!(:code).and_return(50)
|
|
171
191
|
lambda{
|
|
172
192
|
@session.process(@response, @request)
|
|
173
193
|
}.should raise_error(Restfully::Error)
|
|
174
194
|
end
|
|
175
|
-
|
|
195
|
+
|
|
176
196
|
[201, 202].each do |status|
|
|
177
197
|
it "should fetch the resource specified in the Location header if status = #{status}" do
|
|
178
198
|
@response.stub!(:code).and_return(status)
|
|
179
199
|
@response.head['Location'] = @uri+"/path"
|
|
180
|
-
|
|
200
|
+
|
|
181
201
|
@session.should_receive(:get).
|
|
182
202
|
with(@uri+"/path", :head => @request.head).
|
|
183
203
|
and_return(resource=mock("resource"))
|
|
@@ -185,7 +205,7 @@ describe Restfully::Session do
|
|
|
185
205
|
should == resource
|
|
186
206
|
end
|
|
187
207
|
end
|
|
188
|
-
|
|
208
|
+
|
|
189
209
|
it "should return a Restfully::Resource if successful" do
|
|
190
210
|
Restfully::MediaType.register Restfully::MediaType::ApplicationJson
|
|
191
211
|
body = {
|
|
@@ -197,33 +217,33 @@ describe Restfully::Session do
|
|
|
197
217
|
{'Content-Type' => 'application/json'},
|
|
198
218
|
JSON.dump(body)
|
|
199
219
|
)
|
|
200
|
-
|
|
220
|
+
|
|
201
221
|
resource = @session.process(
|
|
202
222
|
@response,
|
|
203
223
|
@request
|
|
204
224
|
)
|
|
205
|
-
|
|
225
|
+
|
|
206
226
|
resource.should be_a(Restfully::Resource)
|
|
207
227
|
resource.uri.should == @request.uri
|
|
208
228
|
resource['key1'].should == body[:key1]
|
|
209
229
|
resource['key2'].should == body[:key2]
|
|
210
230
|
end
|
|
211
|
-
|
|
231
|
+
|
|
212
232
|
it "should raise an error if the response content-type is not supported" do
|
|
213
233
|
@response = Restfully::HTTP::Response.new(
|
|
214
234
|
@session, 200,
|
|
215
235
|
{'Content-Type' => ''},
|
|
216
236
|
'body'
|
|
217
237
|
)
|
|
218
|
-
|
|
219
|
-
lambda{
|
|
220
|
-
@session.process(@response,@request)
|
|
238
|
+
|
|
239
|
+
lambda{
|
|
240
|
+
@session.process(@response,@request)
|
|
221
241
|
}.should raise_error(
|
|
222
|
-
Restfully::Error,
|
|
242
|
+
Restfully::Error,
|
|
223
243
|
"Cannot find a media-type for content-type=\"\""
|
|
224
244
|
)
|
|
225
245
|
end
|
|
226
246
|
end
|
|
227
|
-
|
|
247
|
+
|
|
228
248
|
end
|
|
229
249
|
|
metadata
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: restfully
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 15424101
|
|
5
5
|
prerelease: 6
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
8
|
- 7
|
|
9
9
|
- 1
|
|
10
10
|
- rc
|
|
11
|
-
-
|
|
12
|
-
version: 0.7.1.
|
|
11
|
+
- 4
|
|
12
|
+
version: 0.7.1.rc4
|
|
13
13
|
platform: ruby
|
|
14
14
|
authors:
|
|
15
15
|
- Cyril Rohr
|