summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
authorAlex Meade <alex.meade@rackspace.com>2011-07-12 12:13:02 -0400
committerAlex Meade <alex.meade@rackspace.com>2011-07-12 12:13:02 -0400
commitcbcef100c16cc7368527c064ecc6fc7697928153 (patch)
tree77d76e4fd7aff58ecca9b0b4ac2bd01b9011d922 /nova/tests
parent50357685282b9200ccc8c82361c5266f1f413531 (diff)
parent76fbcb9bfd88a56c5a3419bf227cca28334f6844 (diff)
merged trunk
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/api/openstack/contrib/test_floating_ips.py3
-rw-r--r--nova/tests/api/openstack/contrib/test_multinic_xs.py117
-rw-r--r--nova/tests/api/openstack/test_images.py37
-rw-r--r--nova/tests/api/openstack/test_servers.py114
-rw-r--r--nova/tests/api/openstack/test_wsgi.py141
-rw-r--r--nova/tests/integrated/api/client.py9
-rw-r--r--nova/tests/scheduler/test_zone_aware_scheduler.py6
-rw-r--r--nova/tests/test_cloud.py30
-rw-r--r--nova/tests/test_compute.py8
-rw-r--r--nova/tests/test_hosts.py102
-rw-r--r--nova/tests/test_metadata.py76
-rw-r--r--nova/tests/test_xenapi.py42
-rw-r--r--nova/tests/test_zones.py175
-rw-r--r--nova/tests/xenapi/stubs.py39
14 files changed, 811 insertions, 88 deletions
diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py
index de1eb2f53..de006d088 100644
--- a/nova/tests/api/openstack/contrib/test_floating_ips.py
+++ b/nova/tests/api/openstack/contrib/test_floating_ips.py
@@ -139,7 +139,9 @@ class FloatingIpTest(test.TestCase):
def test_floating_ip_allocate(self):
req = webob.Request.blank('/v1.1/os-floating-ips')
req.method = 'POST'
+ req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
+ print res
self.assertEqual(res.status_int, 200)
ip = json.loads(res.body)['allocated']
expected = {
@@ -177,6 +179,7 @@ class FloatingIpTest(test.TestCase):
def test_floating_ip_disassociate(self):
req = webob.Request.blank('/v1.1/os-floating-ips/1/disassociate')
req.method = 'POST'
+ req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
ip = json.loads(res.body)['disassociated']
diff --git a/nova/tests/api/openstack/contrib/test_multinic_xs.py b/nova/tests/api/openstack/contrib/test_multinic_xs.py
new file mode 100644
index 000000000..484cd1c17
--- /dev/null
+++ b/nova/tests/api/openstack/contrib/test_multinic_xs.py
@@ -0,0 +1,117 @@
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import stubout
+import webob
+
+from nova import compute
+from nova import context
+from nova import test
+from nova.tests.api.openstack import fakes
+
+
+last_add_fixed_ip = (None, None)
+last_remove_fixed_ip = (None, None)
+
+
+def compute_api_add_fixed_ip(self, context, instance_id, network_id):
+ global last_add_fixed_ip
+
+ last_add_fixed_ip = (instance_id, network_id)
+
+
+def compute_api_remove_fixed_ip(self, context, instance_id, address):
+ global last_remove_fixed_ip
+
+ last_remove_fixed_ip = (instance_id, address)
+
+
+class FixedIpTest(test.TestCase):
+ def setUp(self):
+ super(FixedIpTest, self).setUp()
+ self.stubs = stubout.StubOutForTesting()
+ fakes.FakeAuthManager.reset_fake_data()
+ fakes.FakeAuthDatabase.data = {}
+ fakes.stub_out_networking(self.stubs)
+ fakes.stub_out_rate_limiting(self.stubs)
+ fakes.stub_out_auth(self.stubs)
+ self.stubs.Set(compute.api.API, "add_fixed_ip",
+ compute_api_add_fixed_ip)
+ # TODO(Vek): Fails until remove_fixed_ip() added
+ # self.stubs.Set(compute.api.API, "remove_fixed_ip",
+ # compute_api_remove_fixed_ip)
+ self.context = context.get_admin_context()
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(FixedIpTest, self).tearDown()
+
+ def test_add_fixed_ip(self):
+ global last_add_fixed_ip
+ last_add_fixed_ip = (None, None)
+
+ body = dict(addFixedIp=dict(networkId='test_net'))
+ req = webob.Request.blank('/v1.1/servers/test_inst/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = 'application/json'
+
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 202)
+ self.assertEqual(last_add_fixed_ip, ('test_inst', 'test_net'))
+
+ def test_add_fixed_ip_no_network(self):
+ global last_add_fixed_ip
+ last_add_fixed_ip = (None, None)
+
+ body = dict(addFixedIp=dict())
+ req = webob.Request.blank('/v1.1/servers/test_inst/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = 'application/json'
+
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 422)
+ self.assertEqual(last_add_fixed_ip, (None, None))
+
+ def test_remove_fixed_ip(self):
+ global last_remove_fixed_ip
+ last_remove_fixed_ip = (None, None)
+
+ body = dict(removeFixedIp=dict(address='10.10.10.1'))
+ req = webob.Request.blank('/v1.1/servers/test_inst/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = 'application/json'
+
+ resp = req.get_response(fakes.wsgi_app())
+ # TODO(Vek): Fails until remove_fixed_ip() added
+ # self.assertEqual(resp.status_int, 202)
+ # self.assertEqual(last_remove_fixed_ip, ('test_inst', '10.10.10.1'))
+
+ def test_remove_fixed_ip_no_address(self):
+ global last_remove_fixed_ip
+ last_remove_fixed_ip = (None, None)
+
+ body = dict(removeFixedIp=dict())
+ req = webob.Request.blank('/v1.1/servers/test_inst/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = 'application/json'
+
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 422)
+ self.assertEqual(last_remove_fixed_ip, (None, None))
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index 87e5c6d7f..306c0b1db 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -1041,6 +1041,43 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
response = req.get_response(fakes.wsgi_app())
self.assertEqual(200, response.status_int)
+ def test_create_image_v1_1_actual_server_ref(self):
+
+ serverRef = 'http://localhost/v1.1/servers/1'
+ body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
+ req = webob.Request.blank('/v1.1/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, response.status_int)
+ result = json.loads(response.body)
+ self.assertEqual(result['image']['serverRef'], serverRef)
+
+ def test_create_image_v1_1_actual_server_ref_port(self):
+
+ serverRef = 'http://localhost:8774/v1.1/servers/1'
+ body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
+ req = webob.Request.blank('/v1.1/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, response.status_int)
+ result = json.loads(response.body)
+ self.assertEqual(result['image']['serverRef'], serverRef)
+
+ def test_create_image_v1_1_server_ref_bad_hostname(self):
+
+ serverRef = 'http://asdf/v1.1/servers/1'
+ body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
+ req = webob.Request.blank('/v1.1/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
def test_create_image_v1_1_no_server_ref(self):
body = dict(image=dict(name='Snapshot 1'))
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 0cb16b4c0..775f66ad0 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -905,7 +905,7 @@ class ServersTest(test.TestCase):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 422)
+ self.assertEqual(res.status_int, 400)
def test_update_nonstring_name(self):
""" Confirm that update is filtering params """
@@ -1433,6 +1433,57 @@ class ServersTest(test.TestCase):
self.assertEqual(res.status, '202 Accepted')
self.assertEqual(self.server_delete_called, True)
+ def test_rescue_accepted(self):
+ FLAGS.allow_admin_api = True
+ body = {}
+
+ self.called = False
+
+ def rescue_mock(*args, **kwargs):
+ self.called = True
+
+ self.stubs.Set(nova.compute.api.API, 'rescue', rescue_mock)
+ req = webob.Request.blank('/v1.0/servers/1/rescue')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+
+ res = req.get_response(fakes.wsgi_app())
+
+ self.assertEqual(self.called, True)
+ self.assertEqual(res.status_int, 202)
+
+ def test_rescue_raises_handled(self):
+ FLAGS.allow_admin_api = True
+ body = {}
+
+ def rescue_mock(*args, **kwargs):
+ raise Exception('Who cares?')
+
+ self.stubs.Set(nova.compute.api.API, 'rescue', rescue_mock)
+ req = webob.Request.blank('/v1.0/servers/1/rescue')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+
+ res = req.get_response(fakes.wsgi_app())
+
+ self.assertEqual(res.status_int, 422)
+
+ def test_delete_server_instance_v1_1(self):
+ req = webob.Request.blank('/v1.1/servers/1')
+ req.method = 'DELETE'
+
+ self.server_delete_called = False
+
+ def instance_destroy_mock(context, id):
+ self.server_delete_called = True
+
+ self.stubs.Set(nova.db.api, 'instance_destroy',
+ instance_destroy_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 204)
+ self.assertEqual(self.server_delete_called, True)
+
def test_resize_server(self):
req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
@@ -1557,6 +1608,23 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_migrate_server(self):
+ """This is basically the same as resize, only we provide the `migrate`
+ attribute in the body's dict.
+ """
+ req = self.webreq('/1/action', 'POST', dict(migrate=None))
+
+ self.resize_called = False
+
+ def resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.resize_called, True)
+
def test_shutdown_status(self):
new_server = return_server_with_power_state(power_state.SHUTDOWN)
self.stubs.Set(nova.db.api, 'instance_get', new_server)
@@ -1591,7 +1659,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"imageId": "1",
"flavorId": "1",
}}
- self.assertEquals(request, expected)
+ self.assertEquals(request['body'], expected)
def test_request_with_empty_metadata(self):
serial_request = """
@@ -1606,7 +1674,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"flavorId": "1",
"metadata": {},
}}
- self.assertEquals(request, expected)
+ self.assertEquals(request['body'], expected)
def test_request_with_empty_personality(self):
serial_request = """
@@ -1621,7 +1689,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"flavorId": "1",
"personality": [],
}}
- self.assertEquals(request, expected)
+ self.assertEquals(request['body'], expected)
def test_request_with_empty_metadata_and_personality(self):
serial_request = """
@@ -1638,7 +1706,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"metadata": {},
"personality": [],
}}
- self.assertEquals(request, expected)
+ self.assertEquals(request['body'], expected)
def test_request_with_empty_metadata_and_personality_reversed(self):
serial_request = """
@@ -1655,7 +1723,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"metadata": {},
"personality": [],
}}
- self.assertEquals(request, expected)
+ self.assertEquals(request['body'], expected)
def test_request_with_one_personality(self):
serial_request = """
@@ -1667,7 +1735,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = [{"path": "/etc/conf", "contents": "aabbccdd"}]
- self.assertEquals(request["server"]["personality"], expected)
+ self.assertEquals(request['body']["server"]["personality"], expected)
def test_request_with_two_personalities(self):
serial_request = """
@@ -1678,7 +1746,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
request = self.deserializer.deserialize(serial_request, 'create')
expected = [{"path": "/etc/conf", "contents": "aabbccdd"},
{"path": "/etc/sudoers", "contents": "abcd"}]
- self.assertEquals(request["server"]["personality"], expected)
+ self.assertEquals(request['body']["server"]["personality"], expected)
def test_request_second_personality_node_ignored(self):
serial_request = """
@@ -1693,7 +1761,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = [{"path": "/etc/conf", "contents": "aabbccdd"}]
- self.assertEquals(request["server"]["personality"], expected)
+ self.assertEquals(request['body']["server"]["personality"], expected)
def test_request_with_one_personality_missing_path(self):
serial_request = """
@@ -1702,7 +1770,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
<personality><file>aabbccdd</file></personality></server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = [{"contents": "aabbccdd"}]
- self.assertEquals(request["server"]["personality"], expected)
+ self.assertEquals(request['body']["server"]["personality"], expected)
def test_request_with_one_personality_empty_contents(self):
serial_request = """
@@ -1711,7 +1779,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
<personality><file path="/etc/conf"></file></personality></server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = [{"path": "/etc/conf", "contents": ""}]
- self.assertEquals(request["server"]["personality"], expected)
+ self.assertEquals(request['body']["server"]["personality"], expected)
def test_request_with_one_personality_empty_contents_variation(self):
serial_request = """
@@ -1720,7 +1788,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
<personality><file path="/etc/conf"/></personality></server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = [{"path": "/etc/conf", "contents": ""}]
- self.assertEquals(request["server"]["personality"], expected)
+ self.assertEquals(request['body']["server"]["personality"], expected)
def test_request_with_one_metadata(self):
serial_request = """
@@ -1732,7 +1800,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"alpha": "beta"}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_request_with_two_metadata(self):
serial_request = """
@@ -1745,7 +1813,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"alpha": "beta", "foo": "bar"}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_request_with_metadata_missing_value(self):
serial_request = """
@@ -1757,7 +1825,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"alpha": ""}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_request_with_two_metadata_missing_value(self):
serial_request = """
@@ -1770,7 +1838,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"alpha": "", "delta": ""}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_request_with_metadata_missing_key(self):
serial_request = """
@@ -1782,7 +1850,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"": "beta"}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_request_with_two_metadata_missing_key(self):
serial_request = """
@@ -1795,7 +1863,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"": "gamma"}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_request_with_metadata_duplicate_key(self):
serial_request = """
@@ -1808,7 +1876,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
expected = {"foo": "baz"}
- self.assertEquals(request["server"]["metadata"], expected)
+ self.assertEquals(request['body']["server"]["metadata"], expected)
def test_canonical_request_from_docs(self):
serial_request = """
@@ -1854,7 +1922,7 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""",
],
}}
request = self.deserializer.deserialize(serial_request, 'create')
- self.assertEqual(request, expected)
+ self.assertEqual(request['body'], expected)
def test_request_xmlser_with_flavor_image_href(self):
serial_request = """
@@ -1864,9 +1932,9 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""",
flavorRef="http://localhost:8774/v1.1/flavors/1">
</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
- self.assertEquals(request["server"]["flavorRef"],
+ self.assertEquals(request['body']["server"]["flavorRef"],
"http://localhost:8774/v1.1/flavors/1")
- self.assertEquals(request["server"]["imageRef"],
+ self.assertEquals(request['body']["server"]["imageRef"],
"http://localhost:8774/v1.1/images/1")
@@ -1931,7 +1999,7 @@ class TestServerInstanceCreation(test.TestCase):
def _get_create_request_json(self, body_dict):
req = webob.Request.blank('/v1.0/servers')
- req.content_type = 'application/json'
+ req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
req.body = json.dumps(body_dict)
return req
diff --git a/nova/tests/api/openstack/test_wsgi.py b/nova/tests/api/openstack/test_wsgi.py
index 73a26a087..5bdda7c7e 100644
--- a/nova/tests/api/openstack/test_wsgi.py
+++ b/nova/tests/api/openstack/test_wsgi.py
@@ -12,8 +12,7 @@ class RequestTest(test.TestCase):
def test_content_type_missing(self):
request = wsgi.Request.blank('/tests/123', method='POST')
request.body = "<body />"
- self.assertRaises(exception.InvalidContentType,
- request.get_content_type)
+ self.assertEqual(None, request.get_content_type())
def test_content_type_unsupported(self):
request = wsgi.Request.blank('/tests/123', method='POST')
@@ -76,24 +75,48 @@ class RequestTest(test.TestCase):
self.assertEqual(result, "application/json")
-class DictSerializerTest(test.TestCase):
+class ActionDispatcherTest(test.TestCase):
def test_dispatch(self):
- serializer = wsgi.DictSerializer()
+ serializer = wsgi.ActionDispatcher()
+ serializer.create = lambda x: 'pants'
+ self.assertEqual(serializer.dispatch({}, action='create'), 'pants')
+
+ def test_dispatch_action_None(self):
+ serializer = wsgi.ActionDispatcher()
serializer.create = lambda x: 'pants'
serializer.default = lambda x: 'trousers'
- self.assertEqual(serializer.serialize({}, 'create'), 'pants')
+ self.assertEqual(serializer.dispatch({}, action=None), 'trousers')
def test_dispatch_default(self):
- serializer = wsgi.DictSerializer()
+ serializer = wsgi.ActionDispatcher()
serializer.create = lambda x: 'pants'
serializer.default = lambda x: 'trousers'
- self.assertEqual(serializer.serialize({}, 'update'), 'trousers')
+ self.assertEqual(serializer.dispatch({}, action='update'), 'trousers')
- def test_dispatch_action_None(self):
+
+class ResponseHeadersSerializerTest(test.TestCase):
+ def test_default(self):
+ serializer = wsgi.ResponseHeadersSerializer()
+ response = webob.Response()
+ serializer.serialize(response, {'v': '123'}, 'asdf')
+ self.assertEqual(response.status_int, 200)
+
+ def test_custom(self):
+ class Serializer(wsgi.ResponseHeadersSerializer):
+ def update(self, response, data):
+ response.status_int = 404
+ response.headers['X-Custom-Header'] = data['v']
+ serializer = Serializer()
+ response = webob.Response()
+ serializer.serialize(response, {'v': '123'}, 'update')
+ self.assertEqual(response.status_int, 404)
+ self.assertEqual(response.headers['X-Custom-Header'], '123')
+
+
+class DictSerializerTest(test.TestCase):
+ def test_dispatch_default(self):
serializer = wsgi.DictSerializer()
- serializer.create = lambda x: 'pants'
- serializer.default = lambda x: 'trousers'
- self.assertEqual(serializer.serialize({}, None), 'trousers')
+ self.assertEqual(serializer.serialize({}, 'update'), '')
class XMLDictSerializerTest(test.TestCase):
@@ -117,23 +140,9 @@ class JSONDictSerializerTest(test.TestCase):
class TextDeserializerTest(test.TestCase):
- def test_dispatch(self):
- deserializer = wsgi.TextDeserializer()
- deserializer.create = lambda x: 'pants'
- deserializer.default = lambda x: 'trousers'
- self.assertEqual(deserializer.deserialize({}, 'create'), 'pants')
-
def test_dispatch_default(self):
deserializer = wsgi.TextDeserializer()
- deserializer.create = lambda x: 'pants'
- deserializer.default = lambda x: 'trousers'
- self.assertEqual(deserializer.deserialize({}, 'update'), 'trousers')
-
- def test_dispatch_action_None(self):
- deserializer = wsgi.TextDeserializer()
- deserializer.create = lambda x: 'pants'
- deserializer.default = lambda x: 'trousers'
- self.assertEqual(deserializer.deserialize({}, None), 'trousers')
+ self.assertEqual(deserializer.deserialize({}, 'update'), {})
class JSONDeserializerTest(test.TestCase):
@@ -144,12 +153,17 @@ class JSONDeserializerTest(test.TestCase):
"bs": ["1", "2", "3", {"c": {"c1": "1"}}],
"d": {"e": "1"},
"f": "1"}}"""
- as_dict = dict(a={
- 'a1': '1',
- 'a2': '2',
- 'bs': ['1', '2', '3', {'c': dict(c1='1')}],
- 'd': {'e': '1'},
- 'f': '1'})
+ as_dict = {
+ 'body': {
+ 'a': {
+ 'a1': '1',
+ 'a2': '2',
+ 'bs': ['1', '2', '3', {'c': {'c1': '1'}}],
+ 'd': {'e': '1'},
+ 'f': '1',
+ },
+ },
+ }
deserializer = wsgi.JSONDeserializer()
self.assertEqual(deserializer.deserialize(data), as_dict)
@@ -163,23 +177,44 @@ class XMLDeserializerTest(test.TestCase):
<f>1</f>
</a>
""".strip()
- as_dict = dict(a={
- 'a1': '1',
- 'a2': '2',
- 'bs': ['1', '2', '3', {'c': dict(c1='1')}],
- 'd': {'e': '1'},
- 'f': '1'})
+ as_dict = {
+ 'body': {
+ 'a': {
+ 'a1': '1',
+ 'a2': '2',
+ 'bs': ['1', '2', '3', {'c': {'c1': '1'}}],
+ 'd': {'e': '1'},
+ 'f': '1',
+ },
+ },
+ }
metadata = {'plurals': {'bs': 'b', 'ts': 't'}}
deserializer = wsgi.XMLDeserializer(metadata=metadata)
self.assertEqual(deserializer.deserialize(xml), as_dict)
def test_xml_empty(self):
xml = """<a></a>"""
- as_dict = {"a": {}}
+ as_dict = {"body": {"a": {}}}
deserializer = wsgi.XMLDeserializer()
self.assertEqual(deserializer.deserialize(xml), as_dict)
+class RequestHeadersDeserializerTest(test.TestCase):
+ def test_default(self):
+ deserializer = wsgi.RequestHeadersDeserializer()
+ req = wsgi.Request.blank('/')
+ self.assertEqual(deserializer.deserialize(req, 'asdf'), {})
+
+ def test_custom(self):
+ class Deserializer(wsgi.RequestHeadersDeserializer):
+ def update(self, request):
+ return {'a': request.headers['X-Custom-Header']}
+ deserializer = Deserializer()
+ req = wsgi.Request.blank('/')
+ req.headers['X-Custom-Header'] = 'b'
+ self.assertEqual(deserializer.deserialize(req, 'update'), {'a': 'b'})
+
+
class ResponseSerializerTest(test.TestCase):
def setUp(self):
class JSONSerializer(object):
@@ -190,29 +225,36 @@ class ResponseSerializerTest(test.TestCase):
def serialize(self, data, action='default'):
return 'pew_xml'
- self.serializers = {
+ class HeadersSerializer(object):
+ def serialize(self, response, data, action):
+ response.status_int = 404
+
+ self.body_serializers = {
'application/json': JSONSerializer(),
'application/XML': XMLSerializer(),
}
- self.serializer = wsgi.ResponseSerializer(serializers=self.serializers)
+ self.serializer = wsgi.ResponseSerializer(self.body_serializers,
+ HeadersSerializer())
def tearDown(self):
pass
def test_get_serializer(self):
- self.assertEqual(self.serializer.get_serializer('application/json'),
- self.serializers['application/json'])
+ ctype = 'application/json'
+ self.assertEqual(self.serializer.get_body_serializer(ctype),
+ self.body_serializers[ctype])
def test_get_serializer_unknown_content_type(self):
self.assertRaises(exception.InvalidContentType,
- self.serializer.get_serializer,
+ self.serializer.get_body_serializer,
'application/unknown')
def test_serialize_response(self):
response = self.serializer.serialize({}, 'application/json')
self.assertEqual(response.headers['Content-Type'], 'application/json')
self.assertEqual(response.body, 'pew_json')
+ self.assertEqual(response.status_int, 404)
def test_serialize_response_dict_to_unknown_content_type(self):
self.assertRaises(exception.InvalidContentType,
@@ -230,24 +272,23 @@ class RequestDeserializerTest(test.TestCase):
def deserialize(self, data, action='default'):
return 'pew_xml'
- self.deserializers = {
+ self.body_deserializers = {
'application/json': JSONDeserializer(),
'application/XML': XMLDeserializer(),
}
- self.deserializer = wsgi.RequestDeserializer(
- deserializers=self.deserializers)
+ self.deserializer = wsgi.RequestDeserializer(self.body_deserializers)
def tearDown(self):
pass
def test_get_deserializer(self):
- expected = self.deserializer.get_deserializer('application/json')
- self.assertEqual(expected, self.deserializers['application/json'])
+ expected = self.deserializer.get_body_deserializer('application/json')
+ self.assertEqual(expected, self.body_deserializers['application/json'])
def test_get_deserializer_unknown_content_type(self):
self.assertRaises(exception.InvalidContentType,
- self.deserializer.get_deserializer,
+ self.deserializer.get_body_deserializer,
'application/unknown')
def test_get_expected_content_type(self):
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 76c03c5fa..59cc3b564 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -71,8 +71,8 @@ class TestOpenStackClient(object):
self.auth_uri = auth_uri
def request(self, url, method='GET', body=None, headers=None):
- if headers is None:
- headers = {}
+ _headers = {'Content-Type': 'application/json'}
+ _headers.update(headers or {})
parsed_url = urlparse.urlparse(url)
port = parsed_url.port
@@ -94,9 +94,8 @@ class TestOpenStackClient(object):
LOG.info(_("Doing %(method)s on %(relative_url)s") % locals())
if body:
LOG.info(_("Body: %s") % body)
- headers.setdefault('Content-Type', 'application/json')
- conn.request(method, relative_url, body, headers)
+ conn.request(method, relative_url, body, _headers)
response = conn.getresponse()
return response
@@ -175,7 +174,7 @@ class TestOpenStackClient(object):
def api_delete(self, relative_uri, **kwargs):
kwargs['method'] = 'DELETE'
- kwargs.setdefault('check_response_status', [200, 202])
+ kwargs.setdefault('check_response_status', [200, 202, 204])
return self.api_request(relative_uri, **kwargs)
def get_server(self, server_id):
diff --git a/nova/tests/scheduler/test_zone_aware_scheduler.py b/nova/tests/scheduler/test_zone_aware_scheduler.py
index 5950f4551..d74b71fb6 100644
--- a/nova/tests/scheduler/test_zone_aware_scheduler.py
+++ b/nova/tests/scheduler/test_zone_aware_scheduler.py
@@ -122,19 +122,19 @@ def fake_decrypt_blob_returns_child_info(blob):
def fake_call_zone_method(context, method, specs, zones):
return [
- ('zone1', [
+ (1, [
dict(weight=1, blob='AAAAAAA'),
dict(weight=111, blob='BBBBBBB'),
dict(weight=112, blob='CCCCCCC'),
dict(weight=113, blob='DDDDDDD'),
]),
- ('zone2', [
+ (2, [
dict(weight=120, blob='EEEEEEE'),
dict(weight=2, blob='FFFFFFF'),
dict(weight=122, blob='GGGGGGG'),
dict(weight=123, blob='HHHHHHH'),
]),
- ('zone3', [
+ (3, [
dict(weight=130, blob='IIIIIII'),
dict(weight=131, blob='JJJJJJJ'),
dict(weight=132, blob='KKKKKKK'),
diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py
index bf7a2b7ca..d71a03aff 100644
--- a/nova/tests/test_cloud.py
+++ b/nova/tests/test_cloud.py
@@ -67,7 +67,8 @@ class CloudTestCase(test.TestCase):
host = self.network.host
def fake_show(meh, context, id):
- return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ return {'id': 1, 'container_format': 'ami',
+ 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine', 'image_state': 'available'}}
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
@@ -418,7 +419,8 @@ class CloudTestCase(test.TestCase):
describe_images = self.cloud.describe_images
def fake_detail(meh, context):
- return [{'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ return [{'id': 1, 'container_format': 'ami',
+ 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}}]
def fake_show_none(meh, context, id):
@@ -448,7 +450,8 @@ class CloudTestCase(test.TestCase):
def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
- 'type': 'machine'}, 'is_public': True}
+ 'type': 'machine'}, 'container_format': 'ami',
+ 'is_public': True}
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show)
@@ -460,7 +463,8 @@ class CloudTestCase(test.TestCase):
modify_image_attribute = self.cloud.modify_image_attribute
def fake_show(meh, context, id):
- return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ return {'id': 1, 'container_format': 'ami',
+ 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}, 'is_public': False}
def fake_update(meh, context, image_id, metadata, data=None):
@@ -494,6 +498,16 @@ class CloudTestCase(test.TestCase):
self.assertRaises(exception.ImageNotFound, deregister_image,
self.context, 'ami-bad001')
+ def test_deregister_image_wrong_container_type(self):
+ deregister_image = self.cloud.deregister_image
+
+ def fake_delete(self, context, id):
+ return None
+
+ self.stubs.Set(fake._FakeImageService, 'delete', fake_delete)
+ self.assertRaises(exception.NotFound, deregister_image, self.context,
+ 'aki-00000001')
+
def _run_instance(self, **kwargs):
rv = self.cloud.run_instances(self.context, **kwargs)
instance_id = rv['instancesSet'][0]['instanceId']
@@ -609,7 +623,7 @@ class CloudTestCase(test.TestCase):
def fake_show_no_state(self, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
- 'type': 'machine'}}
+ 'type': 'machine'}, 'container_format': 'ami'}
self.stubs.UnsetAll()
self.stubs.Set(fake._FakeImageService, 'show', fake_show_no_state)
@@ -623,7 +637,8 @@ class CloudTestCase(test.TestCase):
run_instances = self.cloud.run_instances
def fake_show_decrypt(self, context, id):
- return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ return {'id': 1, 'container_format': 'ami',
+ 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine', 'image_state': 'decrypting'}}
self.stubs.UnsetAll()
@@ -638,7 +653,8 @@ class CloudTestCase(test.TestCase):
run_instances = self.cloud.run_instances
def fake_show_stat_active(self, context, id):
- return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ return {'id': 1, 'container_format': 'ami',
+ 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}, 'status': 'active'}
self.stubs.Set(fake._FakeImageService, 'show', fake_show_stat_active)
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 45cd2f764..04bb194d5 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -532,6 +532,14 @@ class ComputeTestCase(test.TestCase):
self.context, instance_id, 1)
self.compute.terminate_instance(self.context, instance_id)
+ def test_migrate(self):
+ context = self.context.elevated()
+ instance_id = self._create_instance()
+ self.compute.run_instance(self.context, instance_id)
+ # Migrate simply calls resize() without a flavor_id.
+ self.compute_api.resize(context, instance_id, None)
+ self.compute.terminate_instance(context, instance_id)
+
def _setup_other_managers(self):
self.volume_manager = utils.import_object(FLAGS.volume_manager)
self.network_manager = utils.import_object(FLAGS.network_manager)
diff --git a/nova/tests/test_hosts.py b/nova/tests/test_hosts.py
new file mode 100644
index 000000000..548f81f8b
--- /dev/null
+++ b/nova/tests/test_hosts.py
@@ -0,0 +1,102 @@
+# Copyright (c) 2011 Openstack, LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import stubout
+import webob.exc
+
+from nova import context
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova.api.openstack.contrib import hosts as os_hosts
+from nova.scheduler import api as scheduler_api
+
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.hosts')
+# Simulate the hosts returned by the zone manager.
+HOST_LIST = [
+ {"host_name": "host_c1", "service": "compute"},
+ {"host_name": "host_c2", "service": "compute"},
+ {"host_name": "host_v1", "service": "volume"},
+ {"host_name": "host_v2", "service": "volume"}]
+
+
+def stub_get_host_list(req):
+ return HOST_LIST
+
+
+def stub_set_host_enabled(context, host, enabled):
+ # We'll simulate success and failure by assuming
+ # that 'host_c1' always succeeds, and 'host_c2'
+ # always fails
+ fail = (host == "host_c2")
+ status = "enabled" if (enabled ^ fail) else "disabled"
+ return status
+
+
+class FakeRequest(object):
+ environ = {"nova.context": context.get_admin_context()}
+
+
+class HostTestCase(test.TestCase):
+ """Test Case for hosts."""
+
+ def setUp(self):
+ super(HostTestCase, self).setUp()
+ self.controller = os_hosts.HostController()
+ self.req = FakeRequest()
+ self.stubs.Set(scheduler_api, 'get_host_list', stub_get_host_list)
+ self.stubs.Set(self.controller.compute_api, 'set_host_enabled',
+ stub_set_host_enabled)
+
+ def test_list_hosts(self):
+ """Verify that the compute hosts are returned."""
+ hosts = os_hosts._list_hosts(self.req)
+ self.assertEqual(hosts, HOST_LIST)
+
+ compute_hosts = os_hosts._list_hosts(self.req, "compute")
+ expected = [host for host in HOST_LIST
+ if host["service"] == "compute"]
+ self.assertEqual(compute_hosts, expected)
+
+ def test_disable_host(self):
+ dis_body = {"status": "disable"}
+ result_c1 = self.controller.update(self.req, "host_c1", body=dis_body)
+ self.assertEqual(result_c1["status"], "disabled")
+ result_c2 = self.controller.update(self.req, "host_c2", body=dis_body)
+ self.assertEqual(result_c2["status"], "enabled")
+
+ def test_enable_host(self):
+ en_body = {"status": "enable"}
+ result_c1 = self.controller.update(self.req, "host_c1", body=en_body)
+ self.assertEqual(result_c1["status"], "enabled")
+ result_c2 = self.controller.update(self.req, "host_c2", body=en_body)
+ self.assertEqual(result_c2["status"], "disabled")
+
+ def test_bad_status_value(self):
+ bad_body = {"status": "bad"}
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+ self.req, "host_c1", body=bad_body)
+
+ def test_bad_update_key(self):
+ bad_body = {"crazy": "bad"}
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
+ self.req, "host_c1", body=bad_body)
+
+ def test_bad_host(self):
+ self.assertRaises(exception.HostNotFound, self.controller.update,
+ self.req, "bogus_host_name", body={"status": "disable"})
diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
new file mode 100644
index 000000000..c862726ab
--- /dev/null
+++ b/nova/tests/test_metadata.py
@@ -0,0 +1,76 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Tests for the testing the metadata code."""
+
+import base64
+import httplib
+
+import webob
+
+from nova import test
+from nova import wsgi
+from nova.api.ec2 import metadatarequesthandler
+from nova.db.sqlalchemy import api
+
+
+class MetadataTestCase(test.TestCase):
+ """Test that metadata is returning proper values."""
+
+ def setUp(self):
+ super(MetadataTestCase, self).setUp()
+ self.instance = ({'id': 1,
+ 'project_id': 'test',
+ 'key_name': None,
+ 'host': 'test',
+ 'launch_index': 1,
+ 'instance_type': 'm1.tiny',
+ 'reservation_id': 'r-xxxxxxxx',
+ 'user_data': '',
+ 'image_ref': 7,
+ 'hostname': 'test'})
+
+ def instance_get(*args, **kwargs):
+ return self.instance
+
+ def floating_get(*args, **kwargs):
+ return '99.99.99.99'
+
+ self.stubs.Set(api, 'instance_get', instance_get)
+ self.stubs.Set(api, 'fixed_ip_get_instance', instance_get)
+ self.stubs.Set(api, 'instance_get_floating_address', floating_get)
+ self.app = metadatarequesthandler.MetadataRequestHandler()
+
+ def request(self, relative_url):
+ request = webob.Request.blank(relative_url)
+ request.remote_addr = "127.0.0.1"
+ return request.get_response(self.app).body
+
+ def test_base(self):
+ self.assertEqual(self.request('/'), 'meta-data/\nuser-data')
+
+ def test_user_data(self):
+ self.instance['user_data'] = base64.b64encode('happy')
+ self.assertEqual(self.request('/user-data'), 'happy')
+
+ def test_security_groups(self):
+ def sg_get(*args, **kwargs):
+ return [{'name': 'default'}, {'name': 'other'}]
+ self.stubs.Set(api, 'security_group_get_by_instance', sg_get)
+ self.assertEqual(self.request('/meta-data/security-groups'),
+ 'default\nother')
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index af7f7f338..4cb7447d3 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -381,6 +381,18 @@ class XenAPIVMTestCase(test.TestCase):
self.assertEquals(self.vm['HVM_boot_params'], {})
self.assertEquals(self.vm['HVM_boot_policy'], '')
+ def _list_vdis(self):
+ url = FLAGS.xenapi_connection_url
+ username = FLAGS.xenapi_connection_username
+ password = FLAGS.xenapi_connection_password
+ session = xenapi_conn.XenAPISession(url, username, password)
+ return session.call_xenapi('VDI.get_all')
+
+ def _check_vdis(self, start_list, end_list):
+ for vdi_ref in end_list:
+ if not vdi_ref in start_list:
+ self.fail('Found unexpected VDI:%s' % vdi_ref)
+
def _test_spawn(self, image_ref, kernel_id, ramdisk_id,
instance_type_id="3", os_type="linux",
architecture="x86-64", instance_id=1,
@@ -422,6 +434,36 @@ class XenAPIVMTestCase(test.TestCase):
self._test_spawn,
1, 2, 3, "4") # m1.xlarge
+ def test_spawn_fail_cleanup_1(self):
+ """Simulates an error while downloading an image.
+
+ Verifies that VDIs created are properly cleaned up.
+
+ """
+ vdi_recs_start = self._list_vdis()
+ FLAGS.xenapi_image_service = 'glance'
+ stubs.stubout_fetch_image_glance_disk(self.stubs)
+ self.assertRaises(xenapi_fake.Failure,
+ self._test_spawn, 1, 2, 3)
+ # No additional VDI should be found.
+ vdi_recs_end = self._list_vdis()
+ self._check_vdis(vdi_recs_start, vdi_recs_end)
+
+ def test_spawn_fail_cleanup_2(self):
+ """Simulates an error while creating VM record.
+
+ It verifies that VDIs created are properly cleaned up.
+
+ """
+ vdi_recs_start = self._list_vdis()
+ FLAGS.xenapi_image_service = 'glance'
+ stubs.stubout_create_vm(self.stubs)
+ self.assertRaises(xenapi_fake.Failure,
+ self._test_spawn, 1, 2, 3)
+ # No additional VDI should be found.
+ vdi_recs_end = self._list_vdis()
+ self._check_vdis(vdi_recs_start, vdi_recs_end)
+
def test_spawn_raw_objectstore(self):
FLAGS.xenapi_image_service = 'objectstore'
self._test_spawn(1, None, None)
diff --git a/nova/tests/test_zones.py b/nova/tests/test_zones.py
index e132809dc..a943fee27 100644
--- a/nova/tests/test_zones.py
+++ b/nova/tests/test_zones.py
@@ -198,3 +198,178 @@ class ZoneManagerTestCase(test.TestCase):
self.assertEquals(zone_state.attempt, 3)
self.assertFalse(zone_state.is_active)
self.assertEquals(zone_state.name, None)
+
+ def test_host_service_caps_stale_no_stale_service(self):
+ zm = zone_manager.ZoneManager()
+
+ # services just updated capabilities
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc2", "host1", dict(a=3, b=4))
+ self.assertFalse(zm.host_service_caps_stale("host1", "svc1"))
+ self.assertFalse(zm.host_service_caps_stale("host1", "svc2"))
+
+ def test_host_service_caps_stale_all_stale_services(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # Both services became stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc2", "host1", dict(a=3, b=4))
+ time_future = utils.utcnow() + datetime.timedelta(seconds=expiry_time)
+ utils.set_time_override(time_future)
+ self.assertTrue(zm.host_service_caps_stale("host1", "svc1"))
+ self.assertTrue(zm.host_service_caps_stale("host1", "svc2"))
+ utils.clear_time_override()
+
+ def test_host_service_caps_stale_one_stale_service(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # One service became stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc2", "host1", dict(a=3, b=4))
+ caps = zm.service_states["host1"]["svc1"]
+ caps["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ self.assertTrue(zm.host_service_caps_stale("host1", "svc1"))
+ self.assertFalse(zm.host_service_caps_stale("host1", "svc2"))
+
+ def test_delete_expired_host_services_del_one_service(self):
+ zm = zone_manager.ZoneManager()
+
+ # Delete one service in a host
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc2", "host1", dict(a=3, b=4))
+ stale_host_services = {"host1": ["svc1"]}
+ zm.delete_expired_host_services(stale_host_services)
+ self.assertFalse("svc1" in zm.service_states["host1"])
+ self.assertTrue("svc2" in zm.service_states["host1"])
+
+ def test_delete_expired_host_services_del_all_hosts(self):
+ zm = zone_manager.ZoneManager()
+
+ # Delete all services in a host
+ zm.update_service_capabilities("svc2", "host1", dict(a=3, b=4))
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ stale_host_services = {"host1": ["svc1", "svc2"]}
+ zm.delete_expired_host_services(stale_host_services)
+ self.assertFalse("host1" in zm.service_states)
+
+ def test_delete_expired_host_services_del_one_service_per_host(self):
+ zm = zone_manager.ZoneManager()
+
+ # Delete one service per host
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ stale_host_services = {"host1": ["svc1"], "host2": ["svc1"]}
+ zm.delete_expired_host_services(stale_host_services)
+ self.assertFalse("host1" in zm.service_states)
+ self.assertFalse("host2" in zm.service_states)
+
+ def test_get_zone_capabilities_one_host(self):
+ zm = zone_manager.ZoneManager()
+
+ # Service capabilities recent
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, dict(svc1_a=(1, 1), svc1_b=(2, 2)))
+
+ def test_get_zone_capabilities_expired_host(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # Service capabilities stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ time_future = utils.utcnow() + datetime.timedelta(seconds=expiry_time)
+ utils.set_time_override(time_future)
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, {})
+ utils.clear_time_override()
+
+ def test_get_zone_capabilities_multiple_hosts(self):
+ zm = zone_manager.ZoneManager()
+
+ # Both host service capabilities recent
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, dict(svc1_a=(1, 3), svc1_b=(2, 4)))
+
+ def test_get_zone_capabilities_one_stale_host(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # One host service capabilities become stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ serv_caps = zm.service_states["host1"]["svc1"]
+ serv_caps["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, dict(svc1_a=(3, 3), svc1_b=(4, 4)))
+
+ def test_get_zone_capabilities_multiple_service_per_host(self):
+ zm = zone_manager.ZoneManager()
+
+ # Multiple services per host
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ zm.update_service_capabilities("svc2", "host1", dict(a=5, b=6))
+ zm.update_service_capabilities("svc2", "host2", dict(a=7, b=8))
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, dict(svc1_a=(1, 3), svc1_b=(2, 4),
+ svc2_a=(5, 7), svc2_b=(6, 8)))
+
+ def test_get_zone_capabilities_one_stale_service_per_host(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # Two host services among four become stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ zm.update_service_capabilities("svc2", "host1", dict(a=5, b=6))
+ zm.update_service_capabilities("svc2", "host2", dict(a=7, b=8))
+ serv_caps_1 = zm.service_states["host1"]["svc2"]
+ serv_caps_1["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ serv_caps_2 = zm.service_states["host2"]["svc1"]
+ serv_caps_2["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, dict(svc1_a=(1, 1), svc1_b=(2, 2),
+ svc2_a=(7, 7), svc2_b=(8, 8)))
+
+ def test_get_zone_capabilities_three_stale_host_services(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # Three host services among four become stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ zm.update_service_capabilities("svc2", "host1", dict(a=5, b=6))
+ zm.update_service_capabilities("svc2", "host2", dict(a=7, b=8))
+ serv_caps_1 = zm.service_states["host1"]["svc2"]
+ serv_caps_1["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ serv_caps_2 = zm.service_states["host2"]["svc1"]
+ serv_caps_2["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ serv_caps_3 = zm.service_states["host2"]["svc2"]
+ serv_caps_3["timestamp"] = utils.utcnow() - \
+ datetime.timedelta(seconds=expiry_time)
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, dict(svc1_a=(1, 1), svc1_b=(2, 2)))
+
+ def test_get_zone_capabilities_all_stale_host_services(self):
+ zm = zone_manager.ZoneManager()
+ expiry_time = (FLAGS.periodic_interval * 3) + 1
+
+ # All the host services become stale
+ zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
+ zm.update_service_capabilities("svc1", "host2", dict(a=3, b=4))
+ zm.update_service_capabilities("svc2", "host1", dict(a=5, b=6))
+ zm.update_service_capabilities("svc2", "host2", dict(a=7, b=8))
+ time_future = utils.utcnow() + datetime.timedelta(seconds=expiry_time)
+ utils.set_time_override(time_future)
+ caps = zm.get_zone_capabilities(None)
+ self.assertEquals(caps, {})
diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py
index 151a3e909..66c79d465 100644
--- a/nova/tests/xenapi/stubs.py
+++ b/nova/tests/xenapi/stubs.py
@@ -98,6 +98,42 @@ def stubout_is_vdi_pv(stubs):
stubs.Set(vm_utils, '_is_vdi_pv', f)
+def stubout_determine_is_pv_objectstore(stubs):
+ """Assumes VMs never have PV kernels"""
+
+ @classmethod
+ def f(cls, *args):
+ return False
+ stubs.Set(vm_utils.VMHelper, '_determine_is_pv_objectstore', f)
+
+
+def stubout_lookup_image(stubs):
+ """Simulates a failure in lookup image."""
+ def f(_1, _2, _3, _4):
+ raise Exception("Test Exception raised by fake lookup_image")
+ stubs.Set(vm_utils, 'lookup_image', f)
+
+
+def stubout_fetch_image_glance_disk(stubs):
+ """Simulates a failure in fetch image_glance_disk."""
+
+ @classmethod
+ def f(cls, *args):
+ raise fake.Failure("Test Exception raised by " +
+ "fake fetch_image_glance_disk")
+ stubs.Set(vm_utils.VMHelper, '_fetch_image_glance_disk', f)
+
+
+def stubout_create_vm(stubs):
+ """Simulates a failure in create_vm."""
+
+ @classmethod
+ def f(cls, *args):
+ raise fake.Failure("Test Exception raised by " +
+ "fake create_vm")
+ stubs.Set(vm_utils.VMHelper, 'create_vm', f)
+
+
def stubout_loopingcall_start(stubs):
def fake_start(self, interval, now=True):
self.f(*self.args, **self.kw)
@@ -120,6 +156,9 @@ class FakeSessionForVMTests(fake.SessionBase):
super(FakeSessionForVMTests, self).__init__(uri)
def host_call_plugin(self, _1, _2, plugin, method, _5):
+ # If the call is for 'copy_kernel_vdi' return None.
+ if method == 'copy_kernel_vdi':
+ return
sr_ref = fake.get_all('SR')[0]
vdi_ref = fake.create_vdi('', False, sr_ref, False)
vdi_rec = fake.get_record('VDI', vdi_ref)