dropmyemail-openstack 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+ module OpenStack
2
+ module Volume
3
+
4
+ class Connection
5
+
6
+ attr_accessor :connection
7
+ attr_reader :volumes_native
8
+
9
+ def initialize(connection)
10
+ @connection = connection
11
+ OpenStack::Authentication.init(@connection)
12
+ @volumes_native, @volume_path = check_if_native("volumes")
13
+ @snapshots_native, @snapshot_path = check_if_native("snapshots")
14
+ end
15
+
16
+ # Returns true if the authentication was successful and returns false otherwise.
17
+ #
18
+ # cs.authok?
19
+ # => true
20
+ def authok?
21
+ @connection.authok
22
+ end
23
+
24
+ #require params: {:display_name, :size}
25
+ #optional params: {:display_description, :metadata=>{:key=>val, ...}, :availability_zone, :volume_type }
26
+ #returns OpenStack::Volume::Volume object
27
+ def create_volume(options)
28
+ raise OpenStack::Exception::MissingArgument, ":display_name and :size must be specified to create a volume" unless (options[:display_name] && options[:size])
29
+ data = JSON.generate(:volume => options)
30
+ response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/#{@volume_path}",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
31
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
32
+ volume_info = JSON.parse(response.body)["volume"]
33
+ volume = OpenStack::Volume::Volume.new(volume_info)
34
+ end
35
+
36
+ #no options documented in API at Nov 2012
37
+ #(e.g. like limit/marker as used in Nova for servers)
38
+ def list_volumes
39
+ response = @connection.req("GET", "/#{@volume_path}")
40
+ volumes_hash = JSON.parse(response.body)["volumes"]
41
+ volumes_hash.inject([]){|res, current| res << OpenStack::Volume::Volume.new(current); res}
42
+ end
43
+ alias :volumes :list_volumes
44
+
45
+
46
+ def get_volume(vol_id)
47
+ response = @connection.req("GET", "/#{@volume_path}/#{vol_id}")
48
+ volume_hash = JSON.parse(response.body)["volume"]
49
+ OpenStack::Volume::Volume.new(volume_hash)
50
+ end
51
+ alias :volume :get_volume
52
+
53
+ def delete_volume(vol_id)
54
+ response = @connection.req("DELETE", "/#{@volume_path}/#{vol_id}")
55
+ true
56
+ end
57
+
58
+ def list_snapshots
59
+ response = @connection.req("GET", "/#{@snapshot_path}")
60
+ snapshot_hash = JSON.parse(response.body)["snapshots"]
61
+ snapshot_hash.inject([]){|res, current| res << OpenStack::Volume::Snapshot.new(current); res}
62
+ end
63
+ alias :snapshots :list_snapshots
64
+
65
+ def get_snapshot(snap_id)
66
+ response = @connection.req("GET", "/#{@snapshot_path}/#{snap_id}")
67
+ snapshot_hash = JSON.parse(response.body)["snapshot"]
68
+ OpenStack::Volume::Snapshot.new(snapshot_hash)
69
+ end
70
+ alias :snapshot :get_snapshot
71
+
72
+ #require params: {:display_name, :volume_id}
73
+ #optional params: {:display_description, :metadata=>{:key=>val, ...}, :availability_zone, :volume_type }
74
+ #returns OpenStack::Volume::Snapshot object
75
+ def create_snapshot(options)
76
+ raise OpenStack::Exception::MissingArgument, ":volume_id and :display_name must be specified to create a snapshot" unless (options[:display_name] && options[:volume_id])
77
+ #:force documented in API but not explained... clarify (fails without)
78
+ options.merge!({:force=>"true"})
79
+ data = JSON.generate(:snapshot => options)
80
+ response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/#{@snapshot_path}",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
81
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
82
+ snapshot_info = JSON.parse(response.body)["snapshot"]
83
+ OpenStack::Volume::Snapshot.new(snapshot_info)
84
+ end
85
+
86
+ def delete_snapshot(snap_id)
87
+ @connection.req("DELETE", "/#{@snapshot_path}/#{snap_id}")
88
+ true
89
+ end
90
+
91
+ private
92
+
93
+ #fudge... not clear if volumes support is available as 'native' volume API or
94
+ #as the os-volumes extension. Need to probe to find out (for now)
95
+ #see https://lists.launchpad.net/openstack/msg16601.html
96
+ def check_if_native(entity) #volumes or snapshots
97
+ native = extension = false
98
+ #check if 'native' volume API present:
99
+ begin
100
+ response = @connection.req("GET", "/#{entity}")
101
+ native = true if response.code.match(/^20.$/)
102
+ return true, entity
103
+ rescue OpenStack::Exception::ItemNotFound => not_found
104
+ native = false
105
+ end
106
+ #check if available as extension:
107
+ begin
108
+ response = @connection.req("GET", "/os-#{entity}")
109
+ extension = true if response.code.match(/^20.$/)
110
+ return false, "os-#{entity}"
111
+ rescue OpenStack::Exception::ItemNotFound => not_found
112
+ extension = false
113
+ end
114
+ raise OpenStack::Exception::NotImplemented.new("No Volumes support for this provider", 501, "No #{entity} Support") unless (native || extension)
115
+ end
116
+
117
+
118
+
119
+
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,25 @@
1
+ module OpenStack
2
+ module Volume
3
+ class Snapshot
4
+
5
+ attr_reader :id
6
+ attr_reader :display_name
7
+ attr_reader :display_description
8
+ attr_reader :volume_id
9
+ attr_reader :status
10
+ attr_reader :size
11
+ attr_reader :created_at
12
+
13
+ def initialize(snap_info)
14
+ @id = snap_info["id"]
15
+ @display_name = snap_info["display_name"] || snap_info["displayName"]
16
+ @display_description = snap_info["display_description"] || snap_info["displayDescription"]
17
+ @volume_id = snap_info["volume_id"] || snap_info["volumeId"]
18
+ @status = snap_info["status"]
19
+ @size = snap_info["size"]
20
+ @created_at = snap_info["created_at"] || snap_info["createdAt"]
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ module OpenStack
2
+ module Volume
3
+ class Volume
4
+
5
+ attr_reader :id
6
+ attr_reader :display_name
7
+ attr_reader :display_description
8
+ attr_reader :size
9
+ attr_reader :volume_type
10
+ attr_reader :metadata
11
+ attr_reader :availability_zone
12
+ attr_reader :snapshot_id
13
+ attr_reader :attachments
14
+ attr_reader :created_at
15
+
16
+ def initialize(volume_info)
17
+ @id = volume_info["id"]
18
+ @display_name = volume_info["display_name"] || volume_info["displayName"]
19
+ @display_description = volume_info["display_description"] || volume_info["displayDescription"]
20
+ @size = volume_info["size"]
21
+ @volume_type = volume_info["volume_type"] || volume_info["volumeType"]
22
+ @metadata = volume_info["metadata"]
23
+ @availability_zone = volume_info["availability_zone"] || volume_info["availabilityZone"]
24
+ @snapshot_id = volume_info["snapshot_id"] || volume_info["snapshotId"]
25
+ @attachments = volume_info["attachments"]
26
+ @created_at = volume_info["created_at"] || volume_info["createdAt"]
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,134 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AuthenticationTest < Test::Unit::TestCase
4
+
5
+ def test_good_authentication
6
+ response = {'x-server-management-url' => 'http://server-manage.example.com/path', 'x-auth-token' => 'dummy_token'}
7
+ response.stubs(:code).returns('204')
8
+ server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
9
+ server.stubs(:get).returns(response)
10
+ Net::HTTP.stubs(:new).returns(server)
11
+ connection = stub(:authuser => 'good_user',:authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :service_type=>"compute", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo')
12
+ result = OpenStack::Authentication.init(connection)
13
+ assert_equal result.class, OpenStack::AuthV10
14
+ end
15
+
16
+ def test_bad_authentication
17
+ response = mock()
18
+ response.stubs(:code).returns('499')
19
+ server = mock(:use_ssl= => true, :verify_mode= => true, :start => true)
20
+ server.stubs(:get).returns(response)
21
+ Net::HTTP.stubs(:new).returns(server)
22
+ connection = stub(:authuser => 'bad_user', :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :authok= => true, :authtoken= => true, :proxy_host => nil, :proxy_port => nil, :api_path => '/foo')
23
+ assert_raises(OpenStack::Exception::Authentication) do
24
+ result = OpenStack::Authentication.init(connection)
25
+ end
26
+ end
27
+
28
+ def test_bad_hostname
29
+ Net::HTTP.stubs(:new).raises(OpenStack::Exception::Connection)
30
+ connection = stub(:authuser => 'bad_user', :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :authok= => true, :authtoken= => true, :proxy_host => nil, :proxy_port => nil, :api_path => '/foo')
31
+ assert_raises(OpenStack::Exception::Connection) do
32
+ result = OpenStack::Authentication.init(connection)
33
+ end
34
+ end
35
+
36
+ def test_service_region
37
+ server = get_test_auth_server
38
+ Net::HTTP.stubs(:new).returns(server)
39
+ server.stubs(:started?).returns(true)
40
+ connection = stub(:authuser => 'good_user', :auth_method => "password",:authtenant => {:type=>"tenantName", :value=>'good_tenant'} , :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v2.0", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo', :service_type => "compute", :service_name => "cloudServers", :region => "South")
41
+ result = OpenStack::Authentication.init(connection)
42
+ assert_equal("compute.south.host", result.uri.host)
43
+ end
44
+
45
+ def test_service_name
46
+ server = get_test_auth_server
47
+ Net::HTTP.stubs(:new).returns(server)
48
+ server.stubs(:started?).returns(true)
49
+ connection = stub(:authuser => 'good_user', :auth_method=>"password", :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v2.0", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo', :service_type => "nova", :service_name => "cloudCompute", :region => "South")
50
+ result = OpenStack::Authentication.init(connection)
51
+ assert_equal("nova.south.host", result.uri.host)
52
+ end
53
+
54
+ def test_service_type
55
+ server = get_test_auth_server
56
+ Net::HTTP.stubs(:new).returns(server)
57
+ server.stubs(:started?).returns(true)
58
+ connection = stub(:authuser => 'good_user', :auth_method => "password", :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v2.0", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo', :service_type => "nova", :service_name => nil, :region => "North")
59
+ result = OpenStack::Authentication.init(connection)
60
+ assert_equal("nova.north.host", result.uri.host)
61
+ end
62
+
63
+
64
+ private
65
+ def get_test_auth_server
66
+ json_response = %{{
67
+ "access":{
68
+ "token":{
69
+ "id":"asdasdasd-adsasdads-asdasdasd-adsadsasd",
70
+ "expires":"2010-11-01T03:32:15-05:00"
71
+ },
72
+ "user":{
73
+ "id":"123",
74
+ "name":"testName",
75
+ "roles":[{
76
+ "id":"234",
77
+ "name":"compute:admin"
78
+ },
79
+ {
80
+ "id":"235",
81
+ "name":"object-store:admin",
82
+ "tenantId":"1"
83
+ }
84
+ ],
85
+ "roles_links":[]
86
+ },
87
+ "serviceCatalog":[{
88
+ "name":"cloudServers",
89
+ "type":"compute",
90
+ "endpoints":[{
91
+ "publicURL":"https://compute.north.host/v1.1",
92
+ "region":"North"
93
+ },
94
+ {
95
+ "publicURL":"https://compute.south.host/v1.1",
96
+ "region":"South"
97
+ }
98
+ ],
99
+ "endpoints_links":[]
100
+ },
101
+ {
102
+ "name":"cloudCompute",
103
+ "type":"nova",
104
+ "endpoints":[{
105
+ "publicURL":"https://nova.north.host/v1.1",
106
+ "region":"North"
107
+ },
108
+ {
109
+ "publicURL":"https://nova.south.host/v1.1",
110
+ "region":"South"
111
+ }
112
+ ],
113
+ "endpoints_links":[{
114
+ "rel":"next",
115
+ "href":"https://identity.north.host/v2.0/endpoints?marker=2"
116
+ }
117
+ ]
118
+ }
119
+ ],
120
+ "serviceCatalog_links":[{
121
+ "rel":"next",
122
+ "href":"https://identity.host/v2.0/endpoints?session=2hfh8Ar&marker=2"
123
+ }
124
+ ]
125
+ }
126
+ }}
127
+
128
+ response = {'x-server-management-url' => 'http://server-manage.example.com/path', 'x-auth-token' => 'dummy_token'}
129
+ response.stubs(:code => "200", :body => json_response)
130
+ server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
131
+ server.stubs(:post).returns(response)
132
+ return server
133
+ end
134
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ComputeConnectionTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ connection = stub()
7
+ OpenStack::Authentication.stubs(:init).returns(connection)
8
+ end
9
+
10
+ def test_init_connection_no_credentials
11
+ assert_raises(OpenStack::Exception::MissingArgument) do
12
+ conn = OpenStack::Connection.create(:api_key => "AABBCCDD11", :auth_url => "a.b.c")
13
+ end
14
+ end
15
+
16
+ def test_init_connection_no_password
17
+ assert_raises(OpenStack::Exception::MissingArgument) do
18
+ conn = OpenStack::Connection.create(:username => "test_account", :auth_url => "a.b.c")
19
+ end
20
+ end
21
+
22
+ def test_init_connection_no_auth_url
23
+ assert_raises(OpenStack::Exception::MissingArgument) do
24
+ conn = OpenStack::Connection.create(:username => "test_account", :api_key => "AABBCCDD11")
25
+ end
26
+ end
27
+
28
+ def test_init_connection_bad_auth_url
29
+ assert_raises(OpenStack::Exception::InvalidArgument) do
30
+ conn = OpenStack::Connection.create(:username => "test_account", :api_key => "AABBCCDD11", :auth_url => "***")
31
+ end
32
+ end
33
+
34
+ def test_init_connection
35
+ conn = OpenStack::Connection.create(:username => "test_account", :api_key => "AABBCCDD11", :auth_url => "https://a.b.c")
36
+ assert_not_nil conn, "Connection.new returned nil."
37
+ end
38
+
39
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ExceptionTest < Test::Unit::TestCase
4
+
5
+ def test_400_cloud_servers_fault
6
+ response = mock()
7
+ response.stubs(:code => "400", :body => "{\"ComputeFault\":{\"message\":\"422 Unprocessable Entity: We could not process your request at this time. We have been notified and are looking into the issue. [E03]\",\"details\":\"com.rackspace.cloud.service.servers.OpenStack::ComputeFault: Fault occured\",\"code\":400}}" )
8
+ exception=nil
9
+ begin
10
+ OpenStack::Exception.raise_exception(response)
11
+ rescue Exception => e
12
+ exception=e
13
+ end
14
+ assert_equal(OpenStack::Exception::ComputeFault, e.class)
15
+ assert_equal("400", e.response_code)
16
+ assert_not_nil(e.response_body)
17
+ end
18
+
19
+ def test_413_over_limit
20
+ response = mock()
21
+ response.stubs(:code => "413", :body => "{\"overLimit\":{\"message\":\"Too many requests...\",\"code\":413,\"retryAfter\":\"2010-08-25T10:47:57.890-05:00\"}}")
22
+ exception=nil
23
+ begin
24
+ OpenStack::Exception.raise_exception(response)
25
+ rescue Exception => e
26
+ exception=e
27
+ end
28
+ assert_equal(OpenStack::Exception::OverLimit, e.class)
29
+ assert_equal("413", e.response_code)
30
+ assert_not_nil(e.response_body)
31
+ end
32
+
33
+ def test_other
34
+ response = mock()
35
+ body="{\"blahblah\":{\"message\":\"Failed...\",\"code\":500}}"
36
+ response.stubs(:code => "500", :body => body)
37
+ exception=nil
38
+ begin
39
+ OpenStack::Exception.raise_exception(response)
40
+ rescue Exception => e
41
+ exception=e
42
+ end
43
+ assert_equal(OpenStack::Exception::Other, exception.class)
44
+ assert_equal("500", exception.response_code)
45
+ assert_not_nil(exception.response_body)
46
+ assert_equal(body, exception.response_body)
47
+ end
48
+
49
+ end
@@ -0,0 +1,210 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class MetadataTest < Test::Unit::TestCase
4
+
5
+ include TestConnection
6
+
7
+ def setup
8
+ @compute=get_test_connection
9
+ end
10
+
11
+ def test_metadata_uses_initial_values
12
+ data = {'key1' => 'value1', 'key2' => 'value2'}
13
+ metadata = OpenStack::Compute::Metadata.new(@conn, 'blah', data)
14
+ assert_equal('value1', metadata['key1'])
15
+ assert_equal('value2', metadata['key2'])
16
+ assert_equal(nil, metadata['key0'])
17
+ end
18
+
19
+ def test_metadata_presents_saved_values
20
+ metadata = OpenStack::Compute::Metadata.new(@conn, 'blah')
21
+ metadata['key3'] = 'value3'
22
+ assert_equal('value3', metadata['key3'])
23
+ assert_equal(nil, metadata['key0'])
24
+ end
25
+
26
+ def test_metadata_presents_stored_values
27
+ metadata = OpenStack::Compute::Metadata.new(@conn, 'blah')
28
+ metadata.store('key3', 'value3')
29
+ assert_equal('value3', metadata['key3'])
30
+ assert_equal(nil, metadata['key0'])
31
+ end
32
+
33
+ def test_metadata_looks_up_values_if_none_provided
34
+ data = {'metadata' => {'key4' => 'value4'}}
35
+ json = JSON.generate(data)
36
+ response = mock()
37
+ response.stubs(:code => "200", :body => json)
38
+ conn = mock()
39
+ @compute.stubs(:connection).returns(conn)
40
+ conn.stubs(:req).returns(response)
41
+ metadata = OpenStack::Compute::Metadata.new(@compute, 'blah')
42
+ assert_equal('value4', metadata['key4'])
43
+ assert_equal(nil, metadata['key0'])
44
+ end
45
+
46
+ def test_metadata_save_nil
47
+ conn = mock()
48
+ metadata = OpenStack::Compute::Metadata.new(conn, 'blah')
49
+ metadata.save # do nothing or we'd likely be deleting unintentionally
50
+ end
51
+
52
+ def test_metadata_save
53
+ data = {'key1' => 'value1', 'key3' => 'value3'}
54
+ json = JSON.generate({'metadata' => data})
55
+ response = mock()
56
+ response.stubs(:code => "200", :body => json)
57
+ compute = mock()
58
+ conn = mock()
59
+ compute.stubs(:connection).returns(conn)
60
+ conn.expects(:req).with('PUT', 'blah/metadata', :data => json).returns(response)
61
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
62
+ metadata.save
63
+ end
64
+
65
+ def test_metadata_update_all
66
+ data_in = {'key5' => 'value5', 'key6' => 'value6'}
67
+ data_out = {'key5' => 'value5', 'key6' => 'value6', 'key7' => 'value7'}
68
+ json_in = JSON.generate({'metadata' => data_in})
69
+ json_out = JSON.generate({'metadata' => data_out})
70
+ response = mock()
71
+ response.stubs(:code => "200", :body => json_out)
72
+ compute = mock()
73
+ conn = mock()
74
+ compute.stubs(:connection).returns(conn)
75
+ conn.expects(:req).with('POST', 'blah/metadata', :data => json_in).returns(response)
76
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
77
+ metadata['key5'] = 'value5'
78
+ metadata['key6'] = 'value6'
79
+ metadata.update
80
+ assert_equal('value5', metadata['key5'])
81
+ assert_equal('value6', metadata['key6'])
82
+ assert_equal('value7', metadata['key7'])
83
+ end
84
+
85
+ def test_metadata_update_some_keys
86
+ json1 = JSON.generate({'meta' => {'key1' => 'value1'}})
87
+ response1 = mock()
88
+ response1.stubs(:code => "200", :body => json1)
89
+ json2 = JSON.generate({'meta' => {'key2' => 'value2'}})
90
+ response2 = mock()
91
+ response2.stubs(:code => "200", :body => json2)
92
+ conn = mock()
93
+ compute = mock()
94
+ compute.stubs(:connection).returns(conn)
95
+ conn.expects(:req).with('PUT', 'blah/metadata/key1', :data => json1).returns(response1)
96
+ conn.expects(:req).with('PUT', 'blah/metadata/key2', :data => json2).returns(response2)
97
+ data = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
98
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
99
+ metadata.update(['key1', 'key2'])
100
+ end
101
+
102
+ def test_metadata_update_one_key
103
+ json = JSON.generate({'meta' => {'key2' => 'value2'}})
104
+ response = mock()
105
+ response.stubs(:code => "200", :body => json)
106
+ compute = mock()
107
+ conn = mock()
108
+ compute.stubs(:connection).returns(conn)
109
+ conn.expects(:req).with('PUT', 'blah/metadata/key2', :data => json).returns(response)
110
+ data = {'key1' => 'value1', 'key2' => 'value2'}
111
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
112
+ metadata.update(['key2'])
113
+ end
114
+
115
+ def test_metadata_update_nonexistent_key
116
+ data = {'key1' => 'value1', 'key2' => 'value2'}
117
+ compute = mock()
118
+ conn = mock()
119
+ compute.stubs(:connection).returns(conn)
120
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
121
+ metadata.update(['key3']) # just asserting nothing is called on conn
122
+ end
123
+
124
+ def test_metadata_update_nil
125
+ compute = mock()
126
+ conn = mock()
127
+ compute.stubs(:connection).returns(conn)
128
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
129
+ metadata.update # just asserting nothing is called on the connection
130
+ end
131
+
132
+ def test_refresh_one_key
133
+ json = JSON.generate({'meta' => {'key1' => 'value1'}})
134
+ response = mock()
135
+ response.stubs(:code => "200", :body => json)
136
+ compute = mock()
137
+ conn = mock()
138
+ compute.stubs(:connection).returns(conn)
139
+ conn.expects(:req).with('GET', 'blah/metadata/key1').returns(response)
140
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
141
+ metadata.refresh(['key1'])
142
+ assert_equal('value1', metadata['key1'])
143
+ end
144
+
145
+ def test_refresh_some_keys_with_key_not_found
146
+ json = JSON.generate({'meta' => {'key1' => 'value1'}})
147
+ response = mock()
148
+ response.stubs(:code => "200", :body => json)
149
+ not_found = mock()
150
+ not_found.stubs(:code => "404")
151
+ compute = mock()
152
+ conn = mock()
153
+ compute.stubs(:connection).returns(conn)
154
+ conn.expects(:req).with('GET', 'blah/metadata/key1').returns(response)
155
+ conn.expects(:req).with('GET', 'blah/metadata/key0').returns(not_found)
156
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
157
+ metadata.refresh(['key1', 'key0'])
158
+ assert_equal('value1', metadata['key1'])
159
+ assert(metadata['key0'].nil?)
160
+ end
161
+
162
+ def test_delete_a_key
163
+ response = mock()
164
+ response.stubs(:code => "204")
165
+ connection = mock()
166
+ compute = mock()
167
+ compute.stubs(:connection).returns(connection)
168
+ connection.expects(:req).with('DELETE', 'blah/metadata/key1').returns(response)
169
+ metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
170
+ metadata.delete!(['key1'])
171
+ end
172
+
173
+ def test_delete_a_key_with_prior_information
174
+ response = mock()
175
+ response.stubs(:code => "204")
176
+ comp = mock()
177
+ conn = mock()
178
+ comp.stubs(:connection).returns(conn)
179
+ conn.expects(:req).with('DELETE', 'blah/metadata/key1').returns(response)
180
+ data = {'key1' => 'value1', 'key2' => 'value2'}
181
+ metadata = OpenStack::Compute::Metadata.new(comp, 'blah', data)
182
+ metadata.delete!(['key1'])
183
+ assert(metadata['key1'].nil?)
184
+ assert_equal('value2', metadata['key2'])
185
+ end
186
+ ##
187
+ def test_delete_keys_softly
188
+ comp = mock()
189
+ conn = mock()
190
+ comp.stubs(:connection).returns(conn)
191
+ data = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
192
+ metadata = OpenStack::Compute::Metadata.new(comp, 'blah', data)
193
+ metadata.delete(['key1', 'key3'])
194
+ assert(metadata['key1'].nil?)
195
+ assert_equal('value2', metadata['key2'])
196
+ assert(metadata['key3'].nil?)
197
+ end
198
+
199
+ def test_each_pair
200
+ comp = mock()
201
+ conn = mock()
202
+ comp.stubs(:connection).returns(conn)
203
+ data = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
204
+ metadata = OpenStack::Compute::Metadata.new(comp, 'blah', data)
205
+ metadata.each_pair do |k,v|
206
+ assert_equal v, data[k]
207
+ end
208
+ end
209
+
210
+ end