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.
Files changed (73) hide show
  1. data/README.md +166 -0
  2. data/Rakefile +35 -35
  3. data/bin/restfully +68 -10
  4. data/lib/restfully.rb +8 -14
  5. data/lib/restfully/collection.rb +70 -90
  6. data/lib/restfully/error.rb +2 -0
  7. data/lib/restfully/http.rb +3 -3
  8. data/lib/restfully/http/error.rb +1 -20
  9. data/lib/restfully/http/helper.rb +49 -0
  10. data/lib/restfully/http/request.rb +60 -24
  11. data/lib/restfully/http/response.rb +55 -24
  12. data/lib/restfully/link.rb +32 -24
  13. data/lib/restfully/media_type.rb +70 -0
  14. data/lib/restfully/media_type/abstract_media_type.rb +162 -0
  15. data/lib/restfully/media_type/application_json.rb +21 -0
  16. data/lib/restfully/media_type/application_vnd_bonfire_xml.rb +177 -0
  17. data/lib/restfully/media_type/application_x_www_form_urlencoded.rb +33 -0
  18. data/lib/restfully/media_type/grid5000.rb +67 -0
  19. data/lib/restfully/media_type/wildcard.rb +27 -0
  20. data/lib/restfully/rack.rb +1 -0
  21. data/lib/restfully/rack/basic_auth.rb +26 -0
  22. data/lib/restfully/resource.rb +134 -197
  23. data/lib/restfully/session.rb +127 -70
  24. data/lib/restfully/version.rb +3 -0
  25. data/spec/fixtures/bonfire-collection-with-fragments.xml +6 -0
  26. data/spec/fixtures/bonfire-compute-existing.xml +43 -0
  27. data/spec/fixtures/bonfire-empty-collection.xml +4 -0
  28. data/spec/fixtures/bonfire-experiment-collection.xml +51 -0
  29. data/spec/fixtures/bonfire-network-collection.xml +35 -0
  30. data/spec/fixtures/bonfire-network-existing.xml +6 -0
  31. data/spec/fixtures/bonfire-root.xml +5 -0
  32. data/spec/fixtures/grid5000-rennes-jobs.json +988 -146
  33. data/spec/fixtures/grid5000-rennes.json +63 -0
  34. data/spec/restfully/collection_spec.rb +87 -0
  35. data/spec/restfully/http/helper_spec.rb +18 -0
  36. data/spec/restfully/http/request_spec.rb +97 -0
  37. data/spec/restfully/http/response_spec.rb +53 -0
  38. data/spec/restfully/link_spec.rb +80 -0
  39. data/spec/restfully/media_type/application_vnd_bonfire_xml_spec.rb +153 -0
  40. data/spec/restfully/media_type_spec.rb +117 -0
  41. data/spec/restfully/resource_spec.rb +109 -0
  42. data/spec/restfully/session_spec.rb +229 -0
  43. data/spec/spec_helper.rb +10 -9
  44. metadata +162 -83
  45. data/.document +0 -5
  46. data/CHANGELOG +0 -62
  47. data/README.rdoc +0 -146
  48. data/TODO.rdoc +0 -3
  49. data/VERSION +0 -1
  50. data/examples/grid5000.rb +0 -33
  51. data/examples/scratch.rb +0 -37
  52. data/lib/restfully/extensions.rb +0 -34
  53. data/lib/restfully/http/adapters/abstract_adapter.rb +0 -29
  54. data/lib/restfully/http/adapters/patron_adapter.rb +0 -16
  55. data/lib/restfully/http/adapters/rest_client_adapter.rb +0 -75
  56. data/lib/restfully/http/headers.rb +0 -20
  57. data/lib/restfully/parsing.rb +0 -66
  58. data/lib/restfully/special_array.rb +0 -5
  59. data/lib/restfully/special_hash.rb +0 -5
  60. data/restfully.gemspec +0 -114
  61. data/spec/collection_spec.rb +0 -120
  62. data/spec/fixtures/configuration_file.yml +0 -4
  63. data/spec/fixtures/grid5000-sites.json +0 -540
  64. data/spec/http/error_spec.rb +0 -18
  65. data/spec/http/headers_spec.rb +0 -17
  66. data/spec/http/request_spec.rb +0 -49
  67. data/spec/http/response_spec.rb +0 -19
  68. data/spec/http/rest_client_adapter_spec.rb +0 -35
  69. data/spec/link_spec.rb +0 -61
  70. data/spec/parsing_spec.rb +0 -40
  71. data/spec/resource_spec.rb +0 -320
  72. data/spec/restfully_spec.rb +0 -16
  73. 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