restfully 0.6.3 → 0.7.0.pre
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/README.md +166 -0
- data/Rakefile +35 -35
- data/bin/restfully +68 -10
- data/lib/restfully.rb +8 -14
- data/lib/restfully/collection.rb +70 -90
- data/lib/restfully/error.rb +2 -0
- data/lib/restfully/http.rb +3 -3
- data/lib/restfully/http/error.rb +1 -20
- data/lib/restfully/http/helper.rb +49 -0
- data/lib/restfully/http/request.rb +60 -24
- data/lib/restfully/http/response.rb +55 -24
- data/lib/restfully/link.rb +32 -24
- data/lib/restfully/media_type.rb +70 -0
- data/lib/restfully/media_type/abstract_media_type.rb +162 -0
- data/lib/restfully/media_type/application_json.rb +21 -0
- data/lib/restfully/media_type/application_vnd_bonfire_xml.rb +177 -0
- data/lib/restfully/media_type/application_x_www_form_urlencoded.rb +33 -0
- data/lib/restfully/media_type/grid5000.rb +67 -0
- data/lib/restfully/media_type/wildcard.rb +27 -0
- data/lib/restfully/rack.rb +1 -0
- data/lib/restfully/rack/basic_auth.rb +26 -0
- data/lib/restfully/resource.rb +134 -197
- data/lib/restfully/session.rb +127 -70
- data/lib/restfully/version.rb +3 -0
- data/spec/fixtures/bonfire-collection-with-fragments.xml +6 -0
- data/spec/fixtures/bonfire-compute-existing.xml +43 -0
- data/spec/fixtures/bonfire-empty-collection.xml +4 -0
- data/spec/fixtures/bonfire-experiment-collection.xml +51 -0
- data/spec/fixtures/bonfire-network-collection.xml +35 -0
- data/spec/fixtures/bonfire-network-existing.xml +6 -0
- data/spec/fixtures/bonfire-root.xml +5 -0
- data/spec/fixtures/grid5000-rennes-jobs.json +988 -146
- data/spec/fixtures/grid5000-rennes.json +63 -0
- data/spec/restfully/collection_spec.rb +87 -0
- data/spec/restfully/http/helper_spec.rb +18 -0
- data/spec/restfully/http/request_spec.rb +97 -0
- data/spec/restfully/http/response_spec.rb +53 -0
- data/spec/restfully/link_spec.rb +80 -0
- data/spec/restfully/media_type/application_vnd_bonfire_xml_spec.rb +153 -0
- data/spec/restfully/media_type_spec.rb +117 -0
- data/spec/restfully/resource_spec.rb +109 -0
- data/spec/restfully/session_spec.rb +229 -0
- data/spec/spec_helper.rb +10 -9
- metadata +162 -83
- data/.document +0 -5
- data/CHANGELOG +0 -62
- data/README.rdoc +0 -146
- data/TODO.rdoc +0 -3
- data/VERSION +0 -1
- data/examples/grid5000.rb +0 -33
- data/examples/scratch.rb +0 -37
- data/lib/restfully/extensions.rb +0 -34
- data/lib/restfully/http/adapters/abstract_adapter.rb +0 -29
- data/lib/restfully/http/adapters/patron_adapter.rb +0 -16
- data/lib/restfully/http/adapters/rest_client_adapter.rb +0 -75
- data/lib/restfully/http/headers.rb +0 -20
- data/lib/restfully/parsing.rb +0 -66
- data/lib/restfully/special_array.rb +0 -5
- data/lib/restfully/special_hash.rb +0 -5
- data/restfully.gemspec +0 -114
- data/spec/collection_spec.rb +0 -120
- data/spec/fixtures/configuration_file.yml +0 -4
- data/spec/fixtures/grid5000-sites.json +0 -540
- data/spec/http/error_spec.rb +0 -18
- data/spec/http/headers_spec.rb +0 -17
- data/spec/http/request_spec.rb +0 -49
- data/spec/http/response_spec.rb +0 -19
- data/spec/http/rest_client_adapter_spec.rb +0 -35
- data/spec/link_spec.rb +0 -61
- data/spec/parsing_spec.rb +0 -40
- data/spec/resource_spec.rb +0 -320
- data/spec/restfully_spec.rb +0 -16
- data/spec/session_spec.rb +0 -171
@@ -0,0 +1,63 @@
|
|
1
|
+
{
|
2
|
+
"compilation_server":false,
|
3
|
+
"description":"",
|
4
|
+
"email_contact":"rennes-staff@lists.grid5000.fr",
|
5
|
+
"latitude":48.1,
|
6
|
+
"location":"Rennes,France",
|
7
|
+
"longitude":-1.6667,
|
8
|
+
"name":"Rennes",
|
9
|
+
"security_contact":"rennes-staff@lists.grid5000.fr",
|
10
|
+
"sys_admin_contact":"rennes-staff@lists.grid5000.fr",
|
11
|
+
"type":"site",
|
12
|
+
"uid":"rennes",
|
13
|
+
"user_support_contact":"rennes-staff@lists.grid5000.fr",
|
14
|
+
"web":"http://www.irisa.fr",
|
15
|
+
"version":"fe8e18aaf62cceff002252bcdfa83e4f4c4d9f63",
|
16
|
+
"links": [
|
17
|
+
{
|
18
|
+
"rel":"self",
|
19
|
+
"type":"application/vnd.grid5000+json",
|
20
|
+
"href":"/grid5000/sites/rennes"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"rel":"parent",
|
24
|
+
"type":"application/vnd.grid5000+json",
|
25
|
+
"href":"/grid5000"
|
26
|
+
},
|
27
|
+
{
|
28
|
+
"rel":"versions",
|
29
|
+
"type":"application/vnd.grid5000+json",
|
30
|
+
"href":"/grid5000/sites/rennes/versions"
|
31
|
+
},
|
32
|
+
{
|
33
|
+
"rel":"clusters",
|
34
|
+
"type":"application/vnd.grid5000+json",
|
35
|
+
"href":"/grid5000/sites/rennes/clusters"
|
36
|
+
},
|
37
|
+
{
|
38
|
+
"rel":"environments",
|
39
|
+
"type":"application/vnd.grid5000+json",
|
40
|
+
"href":"/grid5000/sites/rennes/environments"
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"rel":"jobs",
|
44
|
+
"type":"application/vnd.grid5000+json",
|
45
|
+
"href":"/grid5000/sites/rennes/jobs"
|
46
|
+
},
|
47
|
+
{
|
48
|
+
"rel":"deployments",
|
49
|
+
"type":"application/vnd.grid5000+json",
|
50
|
+
"href":"/grid5000/sites/rennes/deployments"
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"rel":"metrics",
|
54
|
+
"type":"application/vnd.grid5000+json",
|
55
|
+
"href":"/grid5000/sites/rennes/metrics"
|
56
|
+
},
|
57
|
+
{
|
58
|
+
"rel":"status",
|
59
|
+
"type":"application/vnd.grid5000+json",
|
60
|
+
"href":"/grid5000/sites/rennes/status"
|
61
|
+
}
|
62
|
+
]
|
63
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::Collection do
|
4
|
+
before do
|
5
|
+
Restfully::MediaType.register Restfully::MediaType::ApplicationVndBonfireXml
|
6
|
+
|
7
|
+
@session = Restfully::Session.new(
|
8
|
+
:uri => "https://api.grid5000.fr"
|
9
|
+
)
|
10
|
+
@request = Restfully::HTTP::Request.new(
|
11
|
+
@session, :get, "/grid5000/sites/rennes/jobs",
|
12
|
+
:head => {'Accept' => 'application/vnd.grid5000+json'}
|
13
|
+
)
|
14
|
+
@response = Restfully::HTTP::Response.new(
|
15
|
+
@session, 200, {
|
16
|
+
'Content-Type' => 'application/vnd.grid5000+json; charset=utf-8',
|
17
|
+
'Allow' => 'GET,POST'
|
18
|
+
}, fixture('grid5000-rennes-jobs.json')
|
19
|
+
)
|
20
|
+
Restfully::MediaType.register Restfully::MediaType::Grid5000
|
21
|
+
@resource = Restfully::Resource.new(@session, @response, @request)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should include the Collection module if the resource is a collection" do
|
25
|
+
@resource.should_receive(:extend).with(Restfully::Collection)
|
26
|
+
@resource.load
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return the total number of elements" do
|
30
|
+
@resource.load.total.should == 366486
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return the offset" do
|
34
|
+
@resource.load.offset.should == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should iterate over the collection" do
|
38
|
+
items = []
|
39
|
+
@resource.load.each{|i| items << i}
|
40
|
+
items.all?{|i| i.kind_of?(Restfully::Resource)}.should be_true
|
41
|
+
items[0].relationships.map(&:to_s).sort.should == ["parent", "self"]
|
42
|
+
items[0]['uid'].should == 376505
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should be empty if no item" do
|
46
|
+
@response = Restfully::HTTP::Response.new(
|
47
|
+
@session, 200, {
|
48
|
+
'Content-Type' => 'application/vnd.bonfire+xml; charset=utf-8'
|
49
|
+
}, fixture('bonfire-empty-collection.xml')
|
50
|
+
)
|
51
|
+
@resource = Restfully::Resource.new(@session, @response, @request).load
|
52
|
+
@resource.collection?.should be_true
|
53
|
+
@resource.should be_empty
|
54
|
+
@resource.total.should == 0
|
55
|
+
@resource.length.should == 0
|
56
|
+
@resource.offset.should == 0
|
57
|
+
@resource.map{|i| i}.should == []
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "finders" do
|
61
|
+
before do
|
62
|
+
@response = Restfully::HTTP::Response.new(
|
63
|
+
@session, 200, {
|
64
|
+
'Content-Type' => 'application/vnd.bonfire+xml; charset=utf-8'
|
65
|
+
}, fixture('bonfire-experiment-collection.xml')
|
66
|
+
)
|
67
|
+
@resource = Restfully::Resource.new(@session, @response, @request).load
|
68
|
+
end
|
69
|
+
it "should find an item by uid" do
|
70
|
+
@resource[:'3'].should_not be_nil
|
71
|
+
end
|
72
|
+
it "should find an item by index" do
|
73
|
+
@resource[0].should == @resource.first
|
74
|
+
end
|
75
|
+
it "should reload the item if not complete" do
|
76
|
+
@resource.map{|i|
|
77
|
+
if i["id"] == "3"
|
78
|
+
i.media_type.should_receive(:complete?).and_return(false)
|
79
|
+
i.should_receive(:reload).once
|
80
|
+
end
|
81
|
+
}
|
82
|
+
@resource[:'3'].should_not be_nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::HTTP::Helper do
|
4
|
+
include Restfully::HTTP::Helper
|
5
|
+
|
6
|
+
it "should correctly sanitize the headers" do
|
7
|
+
sanitize_head({
|
8
|
+
'Cache-control' => 'no-cache',
|
9
|
+
:some_header => 'some value',
|
10
|
+
'accept' => 'application/json'
|
11
|
+
}).should == {
|
12
|
+
'Cache-Control' => 'no-cache',
|
13
|
+
'Some-Header' => 'some value',
|
14
|
+
'Accept' => 'application/json'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::HTTP::Request do
|
4
|
+
before do
|
5
|
+
@session = mock(
|
6
|
+
Restfully::Session,
|
7
|
+
:default_headers => {
|
8
|
+
'Accept' => '*/*; application/xml',
|
9
|
+
:accept_encoding => "gzip, deflate"
|
10
|
+
}
|
11
|
+
)
|
12
|
+
|
13
|
+
@options = {
|
14
|
+
:head => {
|
15
|
+
'Cache-control' => 'no-cache',
|
16
|
+
:some_header => 'some value',
|
17
|
+
'accept' => 'application/json'
|
18
|
+
},
|
19
|
+
:body => {:hello => 'world'}
|
20
|
+
}
|
21
|
+
|
22
|
+
@session.should_receive(:uri_to).with("/path").
|
23
|
+
and_return(Addressable::URI.parse("https://api.grid5000.fr/path"))
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should correctly build the request [no body]" do
|
27
|
+
|
28
|
+
request = Restfully::HTTP::Request.new(@session, :get, "/path", @options)
|
29
|
+
request.head.should == {
|
30
|
+
'Cache-Control' => 'no-cache',
|
31
|
+
'Some-Header' => 'some value',
|
32
|
+
'Accept' => 'application/json',
|
33
|
+
'Accept-Encoding' => 'gzip, deflate'
|
34
|
+
}
|
35
|
+
request.method.should == :get
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should correctly add the query parameters to the URI" do
|
39
|
+
@options[:query] = {:k1 => 'v1'}
|
40
|
+
request = Restfully::HTTP::Request.new(@session, :get, "/path", @options)
|
41
|
+
request.uri.to_s.should == "https://api.grid5000.fr/path?k1=v1"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should correctly update the request with the given parameters" do
|
45
|
+
@options[:query] = {:k1 => 'v1', :k2 => [1,2,3]}
|
46
|
+
@options[:head]['Accept'] = 'text/plain'
|
47
|
+
request = Restfully::HTTP::Request.new(@session, :get, "/path", @options)
|
48
|
+
request.update!(:headers => {'whatever' => 'value'}, :query => {'k1' => 'xx'}).should_not be_nil
|
49
|
+
request.uri.to_s.should == 'https://api.grid5000.fr/path?k1=xx'
|
50
|
+
request.head.should include("Whatever"=>"value", 'Accept' => 'text/plain')
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return nil if no changes were made when updating the request" do
|
54
|
+
@options[:query] = {:k1 => 'v1', :k2 => [1,2,3]}
|
55
|
+
request = Restfully::HTTP::Request.new(@session, :get, "/path", @options)
|
56
|
+
request.update!(@options).should be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should tell if the request is no-cache" do
|
60
|
+
@options[:head]['Cache-Control'] = 'no-cache, max-age=0'
|
61
|
+
request = Restfully::HTTP::Request.new(@session, :get, "/path", @options)
|
62
|
+
request.no_cache?.should be_true
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "with body" do
|
66
|
+
it "should correctly build the request [body as hash, no content-type]" do
|
67
|
+
@options[:body] = {"k1" => 'value1', 'k2' => ['a','b','c']}
|
68
|
+
request = Restfully::HTTP::Request.new(@session, :post, "/path", @options)
|
69
|
+
request.head['Content-Type'].
|
70
|
+
should == 'application/x-www-form-urlencoded'
|
71
|
+
request.method.should == :post
|
72
|
+
request.body.should == "k1=value1&k2[]=a&k2[]=b&k2[]=c"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should correctly build the request [body as hash, content-type=json]" do
|
76
|
+
@options[:body] = {"k1" => 'value1', 'k2' => ['a','b','c']}
|
77
|
+
@options[:head][:content_type] = 'application/json'
|
78
|
+
|
79
|
+
request = Restfully::HTTP::Request.new(@session, :post, "/path", @options)
|
80
|
+
request.head['Content-Type'].
|
81
|
+
should == 'application/json'
|
82
|
+
request.method.should == :post
|
83
|
+
request.body.should == JSON.dump(@options[:body])
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should correctly build the request [body as string, content-type=json]" do
|
87
|
+
@options[:body] = JSON.dump({"k1" => 'value1', 'k2' => ['a','b','c']})
|
88
|
+
@options[:head][:content_type] = 'application/json'
|
89
|
+
request = Restfully::HTTP::Request.new(@session, :post, "/path", @options)
|
90
|
+
|
91
|
+
request.head['Content-Type'].
|
92
|
+
should == 'application/json'
|
93
|
+
request.body.should == @options[:body]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::HTTP::Response do
|
4
|
+
before do
|
5
|
+
@session = mock(Restfully::Session, :logger => Logger.new(STDERR))
|
6
|
+
@io = StringIO.new(fixture('grid5000-rennes.json'))
|
7
|
+
end
|
8
|
+
it "should correctly initialize the response" do
|
9
|
+
content = @io.read
|
10
|
+
@io.rewind
|
11
|
+
response = Restfully::HTTP::Response.new(@session, 200, {
|
12
|
+
'Content-Type' => 'application/json'
|
13
|
+
}, @io)
|
14
|
+
|
15
|
+
response.code.should == 200
|
16
|
+
response.head.should == {"Content-Type"=>"application/json"}
|
17
|
+
response.media_type.should be_a(Restfully::MediaType::ApplicationJson)
|
18
|
+
response.io.should be_a(StringIO)
|
19
|
+
response.body.should == content
|
20
|
+
response.io.read.should == content
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
it "should always allow :get" do
|
25
|
+
response = Restfully::HTTP::Response.new(@session, 200, {
|
26
|
+
'Content-Type' => 'application/json'
|
27
|
+
}, @io)
|
28
|
+
response.allow?(:get).should be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should find the allowed methods in the header (if any)" do
|
32
|
+
response = Restfully::HTTP::Response.new(@session, 200, {
|
33
|
+
'Content-Type' => 'application/json',
|
34
|
+
'Allow' => 'GET, POST'
|
35
|
+
}, @io)
|
36
|
+
|
37
|
+
response.allow?(:get).should be_true
|
38
|
+
response.allow?(:post).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise an error if it cannot find a corresponding media-type" do
|
42
|
+
response = Restfully::HTTP::Response.new(@session, 200, {
|
43
|
+
'Content-Type' => 'whatever'
|
44
|
+
}, @io)
|
45
|
+
lambda{
|
46
|
+
response.media_type
|
47
|
+
}.should raise_error(
|
48
|
+
Restfully::Error,
|
49
|
+
"Cannot find a media-type for content-type=\"whatever\""
|
50
|
+
)
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::Link do
|
4
|
+
before do
|
5
|
+
@uri = URI.parse('/x/y/z')
|
6
|
+
@valid_attributes = {
|
7
|
+
:rel => 'something',
|
8
|
+
:type => 'application/json',
|
9
|
+
:href => '/'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "accessors" do
|
14
|
+
it "should have a rel reader" do
|
15
|
+
link = Restfully::Link.new
|
16
|
+
link.should_not respond_to(:rel=)
|
17
|
+
link.should respond_to(:rel)
|
18
|
+
end
|
19
|
+
it "should have a href reader" do
|
20
|
+
link = Restfully::Link.new
|
21
|
+
link.should_not respond_to(:href=)
|
22
|
+
link.should respond_to(:href)
|
23
|
+
end
|
24
|
+
it "should have a title reader" do
|
25
|
+
link = Restfully::Link.new
|
26
|
+
link.should_not respond_to(:title=)
|
27
|
+
link.should respond_to(:title)
|
28
|
+
end
|
29
|
+
it "should have a errors reader" do
|
30
|
+
link = Restfully::Link.new
|
31
|
+
link.should_not respond_to(:errors=)
|
32
|
+
link.should respond_to(:errors)
|
33
|
+
end
|
34
|
+
it "should respond to valid?" do
|
35
|
+
link = Restfully::Link.new
|
36
|
+
link.should respond_to(:valid?)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "validations" do
|
41
|
+
before do
|
42
|
+
@media_type = mock(Restfully::MediaType::AbstractMediaType)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not be valid if there is no type" do
|
46
|
+
link = Restfully::Link.new(@valid_attributes.merge(:type => ''))
|
47
|
+
link.should_not be_valid
|
48
|
+
link.errors.should == ["type cannot be blank"]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not be valid if a media_type cannot be found" do
|
52
|
+
Restfully::MediaType.catalog.clear
|
53
|
+
link = Restfully::Link.new(@valid_attributes)
|
54
|
+
link.should_not be_valid
|
55
|
+
link.errors.should == ["cannot find a MediaType for type \"application/json\""]
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
describe "with a valid catalog" do
|
60
|
+
before do
|
61
|
+
Restfully::MediaType.stub!(:find).and_return(@media_type)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be valid" do
|
65
|
+
link = Restfully::Link.new(@valid_attributes)
|
66
|
+
link.should be_valid
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should be valid even if the href is ''" do
|
70
|
+
link = Restfully::Link.new(@valid_attributes.merge(:href => ''))
|
71
|
+
link.should be_valid
|
72
|
+
link.href.should == URI.parse("")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Restfully::MediaType::ApplicationVndBonfireXml do
|
4
|
+
before do
|
5
|
+
Restfully::MediaType.register Restfully::MediaType::ApplicationVndBonfireXml
|
6
|
+
|
7
|
+
@expected_compute_hash = {"name"=>"Compute name", "startup"=>{"href"=>"file:///path/to/startup-script/sh"}, "instance_type"=>"small", "__type__"=>"compute", "description"=>"Compute description", "nic"=>[{"device"=>"eth0", "mac"=>"AA:AA:AA:AA", "network"=>{"href"=>"/locations/fr-inria/networks/1"}, "ip"=>"123.123.123.123"}, {"device"=>"eth1", "mac"=>"BB:BB:BB:BB", "network"=>{"href"=>"/locations/fr-inria/networks/2"}, "ip"=>"123.123.124.2"}], "context"=>{"bonfire_credentials"=>"crohr:p4ssw0rd", "monitoring_ip"=>"123.123.123.2"}, "link"=>[{"href"=>"/locations/fr-inria", "rel"=>"location", "type"=>"application/vnd.bonfire+xml"}, {"href"=>"/locations/uk-epcc/computes/1", "rel"=>"self"}], "disk"=>[{"type"=>"OS", "storage"=>{"href"=>"/locations/fr-inria/storages/1"}, "target"=>"sda"}, {"type"=>"CDROM", "storage"=>{"href"=>"/locations/fr-inria/storages/2"}, "target"=>"sdc"}], "state"=>"ACTIVE"}
|
8
|
+
@fixture = fixture("bonfire-compute-existing.xml")
|
9
|
+
@collection = fixture("bonfire-network-collection.xml")
|
10
|
+
@session = Restfully::Session.new(:uri => "http://localhost:8000")
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "loading from xml" do
|
14
|
+
it "should load the io into a Hash" do
|
15
|
+
media = Restfully::MediaType::ApplicationVndBonfireXml.new(@fixture, @session)
|
16
|
+
media.io.should == @fixture
|
17
|
+
media.unserialized.should be_a(Hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should build the Hash from the XML doc [resource]" do
|
21
|
+
media = Restfully::MediaType::ApplicationVndBonfireXml.new(@fixture, @session)
|
22
|
+
media.property.should == @expected_compute_hash
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should build the Hash from the XML doc [resource] 2" do
|
26
|
+
media = Restfully::MediaType::ApplicationVndBonfireXml.new(
|
27
|
+
fixture("bonfire-network-existing.xml"), @session
|
28
|
+
)
|
29
|
+
media.property.should == {"name"=>"Private LAN", "public"=>"YES", "id"=>"29", "__type__"=>"network", "link"=>[{"href"=>"/locations/de-hlrs/networks/29", "rel"=>"self"}]}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should build the Hash from the XML doc [collection]" do
|
33
|
+
media = Restfully::MediaType::ApplicationVndBonfireXml.new(@collection, @session)
|
34
|
+
media.should be_collection
|
35
|
+
media.property.should == {"items"=>[{"address"=>"10.0.0.1", "name"=>"Network1", "size"=>"C", "__type__"=>"network", "description"=>"Network1 description", "link"=>[{"href"=>"/locations/fr-inria", "rel"=>"location"}, {"href"=>"/locations/fr-inria/networks/1", "rel"=>"self"}], "visibility"=>"public"}, {"address"=>"10.0.0.1", "name"=>"Network2", "size"=>"C", "__type__"=>"network", "description"=>"Network2 description", "link"=>[{"href"=>"/locations/fr-inria", "rel"=>"location"}, {"href"=>"/locations/fr-inria/networks/2", "rel"=>"self"}], "visibility"=>"private"}], "total"=>2, "offset"=>0, "__type__"=>"collection", "link"=>[{"href"=>"/locations/fr-inria/networks?limit=20", "rel"=>"top", "type"=>"application/vnd.bonfire+xml"}, {"href"=>"/locations/fr-inria", "rel"=>"parent", "type"=>"application/vnd.bonfire+xml"}, {"href"=>"/locations/fr-inria/networks", "rel"=>"self"}]}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should build the Hash from the XML doc [empty collection]" do
|
39
|
+
media = Restfully::MediaType::ApplicationVndBonfireXml.new(
|
40
|
+
fixture("bonfire-empty-collection.xml"), @session
|
41
|
+
)
|
42
|
+
media.should be_collection
|
43
|
+
items = []
|
44
|
+
media.each{|i| items << i}
|
45
|
+
items.should be_empty
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should be able to iterate over a collection" do
|
49
|
+
media = Restfully::MediaType::ApplicationVndBonfireXml.new(fixture("bonfire-experiment-collection.xml"), @session)
|
50
|
+
items = []
|
51
|
+
media.each{|i| items<<i}
|
52
|
+
items.length.should == 3
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "restfully resource" do
|
59
|
+
it "should correctly load a resource" do
|
60
|
+
req = Restfully::HTTP::Request.new(@session, :get, "http://localhost:8000/locations/de-hlrs/networks/29", :head => {
|
61
|
+
'Accept' => 'application/vnd.bonfire+xml'
|
62
|
+
})
|
63
|
+
|
64
|
+
res = Restfully::HTTP::Response.new(@session, 200, {
|
65
|
+
'Content-Type' => 'application/vnd.bonfire+xml'
|
66
|
+
}, fixture("bonfire-network-existing.xml"))
|
67
|
+
|
68
|
+
res.media_type.should be_a(
|
69
|
+
Restfully::MediaType::ApplicationVndBonfireXml
|
70
|
+
)
|
71
|
+
|
72
|
+
resource = Restfully::Resource.new(@session, res, req).load
|
73
|
+
|
74
|
+
resource.uri.to_s.should == "http://localhost:8000/locations/de-hlrs/networks/29"
|
75
|
+
resource.collection?.should be_false
|
76
|
+
resource.properties.should == {"name"=>"Private LAN", "public"=>"YES", "id"=>"29"}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should correctly load and iterate over a collection" do
|
80
|
+
req = Restfully::HTTP::Request.new(@session, :get, "http://localhost:8000/experiments", :head => {
|
81
|
+
'Accept' => 'application/vnd.bonfire+xml'
|
82
|
+
})
|
83
|
+
|
84
|
+
res = Restfully::HTTP::Response.new(@session, 200, {
|
85
|
+
'Content-Type' => 'application/vnd.bonfire+xml'
|
86
|
+
}, fixture("bonfire-experiment-collection.xml"))
|
87
|
+
|
88
|
+
res.media_type.should be_a(Restfully::MediaType::ApplicationVndBonfireXml)
|
89
|
+
|
90
|
+
collection = Restfully::Resource.new(@session, res, req).load
|
91
|
+
|
92
|
+
collection.uri.to_s.should == "http://localhost:8000/experiments"
|
93
|
+
collection.collection?.should be_true
|
94
|
+
collection.length.should == 3
|
95
|
+
collection.total.should == 3
|
96
|
+
collection.offset.should == 0
|
97
|
+
collection.all?{|i| i.kind_of? Restfully::Resource}.should be_true
|
98
|
+
collection[0].should == collection.first
|
99
|
+
collection[-1].uri.to_s.should == "http://localhost:8000/experiments/3"
|
100
|
+
collection[-1].should == collection[2]
|
101
|
+
collection[-1].should == collection.last
|
102
|
+
collection[10].should be_nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should correctly load an empty collection" do
|
106
|
+
req = Restfully::HTTP::Request.new(@session, :get, "http://localhost:8000/locations/uk-epcc/computes", :head => {
|
107
|
+
'Accept' => 'application/vnd.bonfire+xml'
|
108
|
+
})
|
109
|
+
|
110
|
+
res = Restfully::HTTP::Response.new(@session, 200, {
|
111
|
+
'Content-Type' => 'application/vnd.bonfire+xml'
|
112
|
+
}, fixture("bonfire-empty-collection.xml"))
|
113
|
+
|
114
|
+
res.media_type.should be_a(Restfully::MediaType::ApplicationVndBonfireXml)
|
115
|
+
|
116
|
+
collection = Restfully::Resource.new(@session, res, req).load
|
117
|
+
collection.collection?.should be_true
|
118
|
+
collection.length.should == 0
|
119
|
+
collection.inspect.should == "[]"
|
120
|
+
collection.should be_empty
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should correctly load a collection with non-detailed items" do
|
124
|
+
req = Restfully::HTTP::Request.new(@session, :get, "http://localhost:8000/locations/de-hlrs/networks", :head => {
|
125
|
+
'Accept' => 'application/vnd.bonfire+xml'
|
126
|
+
})
|
127
|
+
|
128
|
+
res = Restfully::HTTP::Response.new(@session, 200, {
|
129
|
+
'Content-Type' => 'application/vnd.bonfire+xml'
|
130
|
+
}, fixture("bonfire-collection-with-fragments.xml"))
|
131
|
+
|
132
|
+
collection = Restfully::Resource.new(@session, res, req).load
|
133
|
+
collection.any?{|item| item.media_type.complete?}.should be_false
|
134
|
+
collection.inspect.should == "[{...}]"
|
135
|
+
|
136
|
+
stub_request(:get, "http://localhost:8000/locations/de-hlrs/networks/29").
|
137
|
+
with(:headers => {'Accept'=>'application/vnd.bonfire+xml', 'Accept-Encoding'=>'gzip, deflate', 'Cache-Control'=>'no-cache'}).
|
138
|
+
to_return(:status => 200, :body => fixture("bonfire-network-existing.xml"), :headers => {'Content-Type' => 'application/vnd.bonfire+xml'})
|
139
|
+
network = collection[0]
|
140
|
+
network.properties.should == {"name"=>"Private LAN", "public"=>"YES", "id"=>"29"}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "serializing to xml" do
|
145
|
+
it "should correctly serialize a resource" do
|
146
|
+
serialized = Restfully::MediaType::ApplicationVndBonfireXml.serialize(
|
147
|
+
@expected_compute_hash,
|
148
|
+
:uri => Addressable::URI.parse('http://path/to/computes')
|
149
|
+
)
|
150
|
+
serialized.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<compute xmlns=\"http://api.bonfire-project.eu/doc/schemas/occi\">\n <startup href=\"file:///path/to/startup-script/sh\"/>\n <name>Compute name</name>\n <instance_type>small</instance_type>\n <link href=\"/locations/fr-inria\" rel=\"location\" type=\"application/vnd.bonfire+xml\"/>\n <link href=\"/locations/uk-epcc/computes/1\" rel=\"self\"/>\n <context>\n <bonfire_credentials>crohr:p4ssw0rd</bonfire_credentials>\n <monitoring_ip>123.123.123.2</monitoring_ip>\n </context>\n <nic>\n <device>eth0</device>\n <mac>AA:AA:AA:AA</mac>\n <network href=\"/locations/fr-inria/networks/1\"/>\n <ip>123.123.123.123</ip>\n </nic>\n <nic>\n <device>eth1</device>\n <mac>BB:BB:BB:BB</mac>\n <network href=\"/locations/fr-inria/networks/2\"/>\n <ip>123.123.124.2</ip>\n </nic>\n <description>Compute description</description>\n <disk>\n <type>OS</type>\n <storage href=\"/locations/fr-inria/storages/1\"/>\n <target>sda</target>\n </disk>\n <disk>\n <type>CDROM</type>\n <storage href=\"/locations/fr-inria/storages/2\"/>\n <target>sdc</target>\n </disk>\n <state>ACTIVE</state>\n</compute>\n"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|