restfully 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/README.rdoc +82 -92
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/bin/restfully +10 -46
- data/examples/grid5000.rb +5 -5
- data/lib/restfully.rb +3 -2
- data/lib/restfully/collection.rb +64 -139
- data/lib/restfully/extensions.rb +0 -17
- data/lib/restfully/http/adapters/abstract_adapter.rb +1 -1
- data/lib/restfully/http/adapters/rest_client_adapter.rb +25 -3
- data/lib/restfully/http/request.rb +20 -3
- data/lib/restfully/http/response.rb +21 -3
- data/lib/restfully/link.rb +4 -3
- data/lib/restfully/resource.rb +144 -74
- data/lib/restfully/session.rb +36 -22
- data/restfully.gemspec +9 -4
- data/spec/collection_spec.rb +24 -25
- data/spec/http/request_spec.rb +6 -2
- data/spec/http/response_spec.rb +4 -0
- data/spec/http/rest_client_adapter_spec.rb +3 -2
- data/spec/link_spec.rb +7 -4
- data/spec/resource_spec.rb +31 -56
- data/spec/session_spec.rb +77 -41
- metadata +13 -2
data/lib/restfully/session.rb
CHANGED
@@ -10,7 +10,7 @@ module Restfully
|
|
10
10
|
end
|
11
11
|
class Session
|
12
12
|
include Parsing, HTTP::Headers
|
13
|
-
attr_reader :base_uri, :
|
13
|
+
attr_reader :base_uri, :logger, :connection, :root, :default_headers
|
14
14
|
|
15
15
|
# TODO: use CacheableResource
|
16
16
|
def initialize(options = {})
|
@@ -18,38 +18,52 @@ module Restfully
|
|
18
18
|
if (config_filename = options.delete(:configuration_file)) && File.exists?(File.expand_path(config_filename))
|
19
19
|
config = YAML.load_file(File.expand_path(config_filename)).symbolize_keys
|
20
20
|
options.merge!(config)
|
21
|
-
end
|
22
|
-
@base_uri = options.delete(:base_uri) || "http://localhost:8888"
|
23
|
-
|
21
|
+
end
|
22
|
+
@base_uri = URI.parse(options.delete(:base_uri) || "http://localhost:8888") rescue nil
|
23
|
+
raise ArgumentError.new("#{@base_uri} is not a valid URI") if @base_uri.nil? || @base_uri.scheme !~ /^http/i
|
24
24
|
@logger = options.delete(:logger) || NullLogger.new
|
25
|
+
@logger.level = options.delete(:verbose) ? Logger::DEBUG : @logger.level
|
25
26
|
user_default_headers = sanitize_http_headers(options.delete(:default_headers) || {})
|
26
27
|
@default_headers = {'User-Agent' => "Restfully/#{Restfully::VERSION}", 'Accept' => 'application/json'}.merge(user_default_headers)
|
27
|
-
@connection
|
28
|
-
@root
|
28
|
+
@connection = Restfully.adapter.new(base_uri.to_s, options.merge(:logger => logger))
|
29
|
+
@root = Resource.new(@base_uri, self)
|
29
30
|
yield @root.load, self if block_given?
|
30
31
|
end
|
31
32
|
|
32
|
-
#
|
33
|
+
# returns an HTTP::Response object or raise a Restfully::HTTP::Error
|
34
|
+
def head(path, options = {})
|
35
|
+
options = options.symbolize_keys
|
36
|
+
transmit :head, HTTP::Request.new(uri_for(path), :headers => options.delete(:headers), :query => options.delete(:query))
|
37
|
+
end
|
38
|
+
|
39
|
+
# returns an HTTP::Response object or raise a Restfully::HTTP::Error
|
33
40
|
def get(path, options = {})
|
34
|
-
path = path.to_s
|
35
41
|
options = options.symbolize_keys
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
response = deal_with_eventual_errors(response, request)
|
42
|
+
transmit :get, HTTP::Request.new(uri_for(path), :headers => options.delete(:headers), :query => options.delete(:query))
|
43
|
+
end
|
44
|
+
|
45
|
+
# returns an HTTP::Response object or raise a Restfully::HTTP::Error
|
46
|
+
def post(path, body, options = {})
|
47
|
+
options = options.symbolize_keys
|
48
|
+
uri = uri_for(path)
|
49
|
+
transmit :post, HTTP::Request.new(uri_for(path), :body => body, :headers => options.delete(:headers), :query => options.delete(:query))
|
50
|
+
end
|
51
|
+
|
52
|
+
# builds the complete URI, based on the given path and the session's base_uri
|
53
|
+
def uri_for(path)
|
54
|
+
URI.join(base_uri.to_s, path.to_s)
|
50
55
|
end
|
51
56
|
|
52
57
|
protected
|
58
|
+
def transmit(method, request)
|
59
|
+
request.add_headers(default_headers) unless default_headers.empty?
|
60
|
+
logger.info "#{method.to_s.upcase} #{request.uri}" +
|
61
|
+
"\nHeaders: #{request.headers.inspect}" +
|
62
|
+
"#{request.body ? "\nBody: #{request.body.length} bytes" : ""}"
|
63
|
+
response = connection.send(method.to_sym, request)
|
64
|
+
response = deal_with_eventual_errors(response, request)
|
65
|
+
end
|
66
|
+
|
53
67
|
def deal_with_eventual_errors(response, request)
|
54
68
|
case response.status
|
55
69
|
when 400..499
|
data/restfully.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{restfully}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Cyril Rohr"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-16}
|
13
13
|
s.default_executable = %q{restfully}
|
14
14
|
s.description = %q{Experimental code for auto-generation of wrappers on top of RESTful APIs that follow HATEOAS principles and provide OPTIONS methods and/or Allow headers.}
|
15
15
|
s.email = %q{cyril.rohr@gmail.com}
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.files = [
|
22
22
|
".document",
|
23
23
|
".gitignore",
|
24
|
+
"CHANGELOG",
|
24
25
|
"LICENSE",
|
25
26
|
"README.rdoc",
|
26
27
|
"Rakefile",
|
@@ -89,10 +90,14 @@ Gem::Specification.new do |s|
|
|
89
90
|
|
90
91
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
91
92
|
s.add_runtime_dependency(%q<rest-client>, [">= 1.0"])
|
93
|
+
s.add_runtime_dependency(%q<backports>, [">= 0"])
|
92
94
|
else
|
93
95
|
s.add_dependency(%q<rest-client>, [">= 1.0"])
|
96
|
+
s.add_dependency(%q<backports>, [">= 0"])
|
94
97
|
end
|
95
98
|
else
|
96
99
|
s.add_dependency(%q<rest-client>, [">= 1.0"])
|
100
|
+
s.add_dependency(%q<backports>, [">= 0"])
|
97
101
|
end
|
98
102
|
end
|
103
|
+
|
data/spec/collection_spec.rb
CHANGED
@@ -4,53 +4,54 @@ include Restfully
|
|
4
4
|
describe Collection do
|
5
5
|
describe "general behaviour" do
|
6
6
|
before do
|
7
|
-
@
|
7
|
+
@uri = URI.parse('http://api.local/x/y/z')
|
8
|
+
@collection = Collection.new(@uri, session=mock('session')).load(:body => JSON.parse(fixture("grid5000-sites.json")))
|
8
9
|
end
|
9
10
|
it "should be enumerable" do
|
10
11
|
@collection.length.should == 9
|
12
|
+
@collection.size.should == 9
|
11
13
|
@collection.map{|site| site["uid"]}.sort.should == ["bordeaux", "grenoble", "lille", "lyon", "nancy", "orsay", "rennes", "sophia", "toulouse"]
|
12
14
|
end
|
13
15
|
|
14
|
-
it "should have a :total
|
15
|
-
@collection
|
16
|
+
it "should have a :total attribute" do
|
17
|
+
@collection["total"].should == 9
|
16
18
|
end
|
17
19
|
|
18
|
-
it "should have a :offset
|
19
|
-
@collection
|
20
|
+
it "should have a :offset attribute" do
|
21
|
+
@collection["offset"].should == 0
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
describe "loading" do
|
24
26
|
before(:all) do
|
27
|
+
@uri = URI.parse('http://api.local/x/y/z')
|
25
28
|
@raw = fixture("grid5000-sites.json")
|
26
29
|
@response_200 = Restfully::HTTP::Response.new(200, {'Content-Type' => 'application/json;charset=utf-8', 'Content-Length' => @raw.length}, @raw)
|
27
30
|
@logger = Logger.new(STDOUT)
|
28
31
|
end
|
29
32
|
it "should not load if already loaded and no :reload" do
|
30
|
-
collection = Collection.new(
|
31
|
-
|
32
|
-
collection.
|
33
|
-
collection.load(:reload => false).should == collection
|
33
|
+
collection = Collection.new(@uri, mock("session"))
|
34
|
+
options = {:headers => {'key' => 'value'}}
|
35
|
+
collection.should_receive(:executed_requests).and_return({'GET' => {'options' => options, 'body' => {"key", "value"}}})
|
36
|
+
collection.load(options.merge(:reload => false)).should == collection
|
34
37
|
end
|
35
38
|
it "should load when :reload param is true [already loaded]" do
|
36
|
-
collection = Collection.new(
|
37
|
-
collection.should_receive(:loaded?).and_return(true)
|
39
|
+
collection = Collection.new(@uri, session=mock("session", :logger => Logger.new(STDOUT)))
|
38
40
|
session.should_receive(:get).and_return(@response_200)
|
39
41
|
collection.load(:reload => true).should == collection
|
40
42
|
end
|
41
43
|
it "should load when force_reload is true [not loaded]" do
|
42
|
-
collection = Collection.new(
|
43
|
-
collection.should_receive(:loaded?).and_return(false)
|
44
|
+
collection = Collection.new(@uri, session=mock("session", :logger => Logger.new(STDOUT)))
|
44
45
|
session.should_receive(:get).and_return(@response_200)
|
45
46
|
collection.load(:reload => true).should == collection
|
46
47
|
end
|
47
48
|
it "should force reload when query parameters are given" do
|
48
|
-
collection = Collection.new(
|
49
|
+
collection = Collection.new(@uri, session=mock("session", :logger => Logger.new(STDOUT)))
|
49
50
|
session.should_receive(:get).and_return(@response_200)
|
50
51
|
collection.load(:query => {:q1 => 'v1'}).should == collection
|
51
52
|
end
|
52
53
|
it "should not initialize resources lacking a self link" do
|
53
|
-
collection = Collection.new(
|
54
|
+
collection = Collection.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
54
55
|
"total" => 1,
|
55
56
|
"offset" => 0,
|
56
57
|
"items" => [
|
@@ -64,10 +65,10 @@ describe Collection do
|
|
64
65
|
}), :logger => @logger))
|
65
66
|
Resource.should_not_receive(:new)
|
66
67
|
collection.load
|
67
|
-
collection.
|
68
|
+
collection.find{|i| i['uid'] == 'rennes'}.should be_nil
|
68
69
|
end
|
69
70
|
it "should initialize resources having a self link" do
|
70
|
-
collection = Collection.new(
|
71
|
+
collection = Collection.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
71
72
|
"total" => 1,
|
72
73
|
"offset" => 0,
|
73
74
|
"items" => [
|
@@ -82,17 +83,15 @@ describe Collection do
|
|
82
83
|
}), :logger => @logger))
|
83
84
|
collection.load
|
84
85
|
collection.length.should == 1
|
85
|
-
collection.
|
86
|
+
collection.find{|i| i['uid'] == 'rennes'}.class.should == Restfully::Resource
|
86
87
|
end
|
87
88
|
it "should correctly initialize its resources [integration test]" do
|
88
|
-
collection = Collection.new(
|
89
|
+
collection = Collection.new(@uri, session=mock("session", :logger => Logger.new(STDOUT), :get => @response_200))
|
89
90
|
collection.load
|
90
|
-
collection.should
|
91
|
-
collection.
|
92
|
-
collection.
|
93
|
-
collection.
|
94
|
-
collection.by_uid.keys.should =~ ['rennes', 'lille', 'bordeaux', 'nancy', 'sophia', 'toulouse', 'lyon', 'grenoble', 'orsay']
|
95
|
-
collection.by_uid('rennes', 'bordeaux').length.should == 2
|
91
|
+
collection.uri.should == @uri
|
92
|
+
collection.find{|i| i['uid'] == 'rennes'}["uid"].should == 'rennes'
|
93
|
+
collection.find{|i| i['uid'] == 'rennes'}["type"].should == 'site'
|
94
|
+
collection.map{|s| s['uid']}.should =~ ['rennes', 'lille', 'bordeaux', 'nancy', 'sophia', 'toulouse', 'lyon', 'grenoble', 'orsay']
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
data/spec/http/request_spec.rb
CHANGED
@@ -4,16 +4,20 @@ describe Restfully::HTTP::Request do
|
|
4
4
|
it "should correctly initialize the attributes" do
|
5
5
|
request = Restfully::HTTP::Request.new(
|
6
6
|
'https://api.grid5000.fr/sid/grid5000?q1=v1&q2=v2',
|
7
|
-
:headers => {'accept' => 'application/json', :cache_control => 'max-age=0'},
|
8
|
-
:query => {'custom_param1' => [3, 4, 5, 6], 'custom_param2' => 'value_custom_param2'}
|
7
|
+
:headers => {'accept' => 'application/json', :cache_control => 'max-age=0', 'Content-Type' => 'application/json'},
|
8
|
+
:query => {'custom_param1' => [3, 4, 5, 6], 'custom_param2' => 'value_custom_param2'},
|
9
|
+
:body => {"key" => "value"}.to_json
|
9
10
|
)
|
10
11
|
request.uri.should be_a URI
|
11
12
|
request.uri.to_s.should == 'https://api.grid5000.fr/sid/grid5000?q1=v1&q2=v2&custom_param1=3,4,5,6&custom_param2=value_custom_param2'
|
12
13
|
request.uri.query.should == "q1=v1&q2=v2&custom_param1=3,4,5,6&custom_param2=value_custom_param2"
|
13
14
|
request.headers.should == {
|
15
|
+
"Content-Type"=>"application/json",
|
14
16
|
'Accept' => 'application/json',
|
15
17
|
'Cache-Control' => 'max-age=0'
|
16
18
|
}
|
19
|
+
request.body.should == {"key" => "value"}
|
20
|
+
request.raw_body.should == "{\"key\":\"value\"}"
|
17
21
|
request.retries.should == 0
|
18
22
|
end
|
19
23
|
|
data/spec/http/response_spec.rb
CHANGED
@@ -12,4 +12,8 @@ describe Restfully::HTTP::Response do
|
|
12
12
|
'property2' => 'value2'
|
13
13
|
}
|
14
14
|
end
|
15
|
+
it "should return the unserialized body" do
|
16
|
+
response = Restfully::HTTP::Response.new(404, {:content_type => 'application/json;charset=utf-8'}, '{"property1": "value1", "property2": "value2"}')
|
17
|
+
response.raw_body.should == "{\"property1\": \"value1\", \"property2\": \"value2\"}"
|
18
|
+
end
|
15
19
|
end
|
@@ -19,7 +19,7 @@ describe Restfully::HTTP::Adapters::RestClientAdapter do
|
|
19
19
|
end
|
20
20
|
it "should raise a not implemented error when trying to use functions not implemented yet" do
|
21
21
|
adapter = Restfully::HTTP::Adapters::RestClientAdapter.new("https://api.grid5000.fr")
|
22
|
-
lambda{adapter.
|
22
|
+
lambda{adapter.delete(mock("restfully request"))}.should raise_error NotImplementedError, "DELETE is not supported by your adapter."
|
23
23
|
end
|
24
24
|
it "should rescue any RestClient::Exception and correctly populate the response" do
|
25
25
|
res = mock(Net::HTTPResponse, :code => 404, :body => '{"message":"whatever"}', :to_hash => {'Content-Type' => 'application/json;charset=utf-8', 'Content-Length' => 22}, :[] => '')
|
@@ -28,6 +28,7 @@ describe Restfully::HTTP::Adapters::RestClientAdapter do
|
|
28
28
|
response = adapter.get(mock("request", :uri => "uri"))
|
29
29
|
response.status.should == 404
|
30
30
|
response.headers.should == {'Content-Type' => 'application/json;charset=utf-8', 'Content-Length' => 22}
|
31
|
-
response.
|
31
|
+
response.raw_body.should == '{"message":"whatever"}'
|
32
|
+
response.body.should == {"message"=>"whatever"}
|
32
33
|
end
|
33
34
|
end
|
data/spec/link_spec.rb
CHANGED
@@ -2,7 +2,9 @@ require File.expand_path(File.dirname(__FILE__)+'/spec_helper')
|
|
2
2
|
|
3
3
|
include Restfully
|
4
4
|
describe Link do
|
5
|
-
|
5
|
+
before do
|
6
|
+
@uri = URI.parse('/x/y/z')
|
7
|
+
end
|
6
8
|
it "should have a rel reader" do
|
7
9
|
link = Link.new
|
8
10
|
link.should_not respond_to(:rel=)
|
@@ -28,7 +30,7 @@ describe Link do
|
|
28
30
|
link.should respond_to(:valid?)
|
29
31
|
end
|
30
32
|
it "should respond to resolved?" do
|
31
|
-
link = Link.new
|
33
|
+
link = Link.new("href" => @uri)
|
32
34
|
link.should respond_to(:resolved?)
|
33
35
|
end
|
34
36
|
it "should respond to resolvable?" do
|
@@ -43,9 +45,10 @@ describe Link do
|
|
43
45
|
link = Link.new
|
44
46
|
link.should_not be_resolved
|
45
47
|
end
|
46
|
-
it "should
|
48
|
+
it "should be valid even if the href is ''" do
|
47
49
|
link = Link.new 'rel' => 'collection', 'title' => 'my collection'
|
48
|
-
link.
|
50
|
+
link.should be_valid
|
51
|
+
link.href.should == URI.parse("")
|
49
52
|
end
|
50
53
|
it "should not be valid if there is no rel" do
|
51
54
|
link = Link.new 'href' => '/', 'title' => 'my collection'
|
data/spec/resource_spec.rb
CHANGED
@@ -7,16 +7,6 @@ describe Resource do
|
|
7
7
|
@logger = Logger.new(STDOUT)
|
8
8
|
end
|
9
9
|
|
10
|
-
it "should have all the methods of a hash" do
|
11
|
-
resource = Resource.new("uri", session=mock('session'))
|
12
|
-
resource.size.should == 0
|
13
|
-
resource['whatever'] = 'thing'
|
14
|
-
resource.size.should == 1
|
15
|
-
resource.should == {'whatever' => 'thing'}
|
16
|
-
resource.should respond_to(:each)
|
17
|
-
resource.should respond_to(:length)
|
18
|
-
end
|
19
|
-
|
20
10
|
describe "accessors" do
|
21
11
|
it "should have a reader on the session" do
|
22
12
|
resource = Resource.new("uri", session=mock("session"))
|
@@ -26,17 +16,7 @@ describe Resource do
|
|
26
16
|
it "should have a reader on the uri" do
|
27
17
|
resource = Resource.new("uri", session=mock("session"))
|
28
18
|
resource.should_not respond_to(:uri=)
|
29
|
-
resource.uri.should == "uri"
|
30
|
-
end
|
31
|
-
it "should have a reader on the raw property" do
|
32
|
-
resource = Resource.new("uri", session=mock("session"))
|
33
|
-
resource.should_not respond_to(:raw=)
|
34
|
-
resource.load('raw' => {:a => :b}).raw.should == {:a => :b}
|
35
|
-
end
|
36
|
-
it "should have a reader on the state property" do
|
37
|
-
resource = Resource.new("uri", session=mock("session"))
|
38
|
-
resource.should_not respond_to(:state=)
|
39
|
-
resource.state.should == :unloaded
|
19
|
+
resource.uri.should == URI.parse("uri")
|
40
20
|
end
|
41
21
|
end
|
42
22
|
|
@@ -85,97 +65,92 @@ describe Resource do
|
|
85
65
|
'model' => 'XYZ1b'
|
86
66
|
}
|
87
67
|
}
|
88
|
-
}
|
89
|
-
@response_200 = Restfully::HTTP::Response.new(200, {'Content-Type' => 'application/json;utf-8', 'Content-Length' => @raw.length}, @raw)
|
68
|
+
}
|
69
|
+
@response_200 = Restfully::HTTP::Response.new(200, {'Content-Type' => 'application/json;utf-8', 'Content-Length' => @raw.length}, @raw.to_json)
|
70
|
+
@uri = URI.parse("http://api.local/x/y/z")
|
90
71
|
end
|
91
72
|
it "should not be loaded in its initial state" do
|
92
|
-
resource = Resource.new(
|
93
|
-
resource.
|
73
|
+
resource = Resource.new(@uri, mock('session'))
|
74
|
+
resource.executed_requests.should == {}
|
94
75
|
end
|
95
76
|
it "should get the raw representation of the resource via the session if it doesn't have it" do
|
96
|
-
resource = Resource.new(uri
|
77
|
+
resource = Resource.new(@uri, session = mock("session", :logger => Logger.new(STDOUT)))
|
97
78
|
resource.stub!(:define_link) # do not define links
|
98
|
-
|
99
|
-
session.should_receive(:get).with(uri, {}).and_return(@response_200)
|
79
|
+
session.should_receive(:get).with(@uri, {}).and_return(@response_200)
|
100
80
|
resource.load
|
101
|
-
resource.should be_loaded
|
102
81
|
end
|
103
82
|
it "should get the raw representation of the resource via the session if there are query parameters" do
|
104
|
-
resource = Resource.new(uri
|
83
|
+
resource = Resource.new(@uri, session = mock("session", :logger => Logger.new(STDOUT)))
|
105
84
|
resource.stub!(:define_link) # do not define links
|
106
|
-
|
107
|
-
resource.raw.should be_nil
|
108
|
-
session.should_receive(:get).with(uri, {:query => {:q1 => 'v1'}}).and_return(@response_200)
|
85
|
+
session.should_receive(:get).with(@uri, {:query => {:q1 => 'v1'}}).and_return(@response_200)
|
109
86
|
resource.load(:query => {:q1 => 'v1'})
|
110
87
|
end
|
111
88
|
it "should get the raw representation of the resource if forced to do so" do
|
112
|
-
resource = Resource.new(uri
|
89
|
+
resource = Resource.new(@uri, session = mock("session", :logger => Logger.new(STDOUT)))
|
113
90
|
resource.stub!(:define_link) # do not define links
|
114
|
-
|
115
|
-
resource.raw.should be_nil
|
116
|
-
session.should_receive(:get).with(uri, {}).and_return(@response_200)
|
91
|
+
session.should_receive(:get).with(@uri, {}).and_return(@response_200)
|
117
92
|
resource.load(:reload => true)
|
118
93
|
end
|
119
94
|
it "should correctly define the functions to access simple values" do
|
120
|
-
resource = Resource.new(
|
95
|
+
resource = Resource.new(@uri, session = mock("session", :get => @response_200, :logger => @logger))
|
121
96
|
resource.stub!(:define_link) # do not define links
|
122
97
|
resource.load
|
123
98
|
resource['whatever'].should == 'whatever'
|
124
|
-
resource.uri.should ==
|
99
|
+
resource.uri.should == @uri
|
125
100
|
resource["uid"].should == 'rennes'
|
126
101
|
resource['an_array'].should be_a(SpecialArray)
|
127
102
|
resource['an_array'].should == [1,2,3]
|
128
103
|
lambda{resource.clusters}.should raise_error(NoMethodError)
|
129
104
|
end
|
130
105
|
|
131
|
-
it "should correctly define a collection
|
132
|
-
resource = Resource.new(
|
106
|
+
it "should correctly define a collection link" do
|
107
|
+
resource = Resource.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
133
108
|
'links' => [
|
134
109
|
{'rel' => 'self', 'href' => '/grid5000/sites/rennes'},
|
135
110
|
{'rel' => 'collection', 'href' => '/grid5000/sites/rennes/versions', 'resolvable' => false, 'title' => 'versions'}
|
136
111
|
],
|
137
112
|
'uid' => 'rennes'
|
138
113
|
}), :logger => @logger))
|
139
|
-
Collection.should_receive(:new).with('/grid5000/sites/rennes/versions', session, :title => 'versions'
|
114
|
+
Collection.should_receive(:new).with(@uri.merge('/grid5000/sites/rennes/versions'), session, :title => 'versions').and_return(collection=mock("restfully collection"))
|
140
115
|
resource.load
|
141
|
-
resource.
|
116
|
+
resource.links['versions'].should == collection
|
142
117
|
end
|
143
118
|
it "should NOT update the URI with the self link" do
|
144
|
-
resource = Resource.new(
|
119
|
+
resource = Resource.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
145
120
|
'links' => [
|
146
121
|
{'rel' => 'self', 'href' => '/grid5000/sites/rennes'}
|
147
122
|
],
|
148
123
|
'uid' => 'rennes'
|
149
124
|
}), :logger => @logger))
|
150
|
-
resource.uri.should ==
|
125
|
+
resource.uri.should == @uri
|
151
126
|
resource.load
|
152
|
-
resource.uri.should ==
|
127
|
+
resource.uri.should == @uri
|
153
128
|
end
|
154
129
|
it "should correctly define a member association" do
|
155
|
-
resource = Resource.new(
|
130
|
+
resource = Resource.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
156
131
|
'links' => [
|
157
132
|
{'rel' => 'member', 'href' => '/grid5000/sites/rennes/versions/123', 'title' => 'version'}
|
158
133
|
],
|
159
134
|
'uid' => 'rennes'
|
160
135
|
}), :logger => @logger))
|
161
|
-
Resource.should_receive(:new).with('/grid5000/sites/rennes/versions/123', session, :title => 'version'
|
136
|
+
Resource.should_receive(:new).with(@uri.merge('/grid5000/sites/rennes/versions/123'), session, :title => 'version').and_return(member=mock("restfully resource"))
|
162
137
|
resource.load
|
163
|
-
resource.
|
138
|
+
resource.links['version'].should == member
|
164
139
|
end
|
165
140
|
it "should correctly define a parent association" do
|
166
|
-
resource = Resource.new(
|
141
|
+
resource = Resource.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
167
142
|
'links' => [
|
168
143
|
{'rel' => 'self', 'href' => '/grid5000/sites/rennes'},
|
169
144
|
{'rel' => 'parent', 'href' => '/grid5000'}
|
170
145
|
],
|
171
146
|
'uid' => 'rennes'
|
172
147
|
}), :logger => @logger))
|
173
|
-
Resource.should_receive(:new).with('/grid5000', session).and_return(parent=mock("restfully resource"))
|
148
|
+
Resource.should_receive(:new).with(@uri.merge('/grid5000'), session).and_return(parent=mock("restfully resource"))
|
174
149
|
resource.load
|
175
|
-
resource.
|
150
|
+
resource.links['parent'].should == parent
|
176
151
|
end
|
177
152
|
it "should ignore bad links" do
|
178
|
-
resource = Resource.new(
|
153
|
+
resource = Resource.new(@uri, session = mock("session", :get => mock("restfully response", :body => {
|
179
154
|
'links' => [
|
180
155
|
{'rel' => 'self', 'href' => '/grid5000/sites/rennes'},
|
181
156
|
{'rel' => 'invalid_rel', 'href' => '/whatever'},
|
@@ -184,15 +159,15 @@ describe Resource do
|
|
184
159
|
'uid' => 'rennes'
|
185
160
|
}), :logger => @logger))
|
186
161
|
resource.load
|
187
|
-
resource.
|
162
|
+
resource.links.should be_empty
|
188
163
|
end
|
189
164
|
|
190
165
|
it "should correctly define the functions to access links [integration test]" do
|
191
|
-
resource = Resource.new(
|
166
|
+
resource = Resource.new(@uri, session = mock("session", :get => @response_200, :logger => @logger))
|
192
167
|
@logger.should_receive(:warn).with(/collection \/has\/no\/title has no title/)
|
193
168
|
@logger.should_receive(:warn).with(/invalid_rel is not a valid link relationship/)
|
194
169
|
resource.load
|
195
|
-
resource.
|
170
|
+
resource.links.keys.should =~ ['versions', 'clusters', 'environments', 'status', 'parent', 'version']
|
196
171
|
end
|
197
172
|
end
|
198
173
|
end
|