restfully 0.6.3 → 0.7.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|