summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
authorChris Behrens <cbehrens@codestud.com>2011-07-12 16:13:01 -0700
committerChris Behrens <cbehrens@codestud.com>2011-07-12 16:13:01 -0700
commite547f4bde48a0142fbdb407a4c51f4b6f8fa56e2 (patch)
tree36b98fac8f2890294d0a1fb42f72545652227fb7 /nova/tests
parentbbd8f482b916168871d1d83192b354355858e77c (diff)
parent11611716e30f368df77816b40c4c77de0e0e047f (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.py13
-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_metadata.py76
-rw-r--r--nova/tests/test_zones.py175
11 files changed, 604 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 54601f35a..f451ee145 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -1046,6 +1046,19 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
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'
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 0190a5f73..bdf2edd50 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -533,6 +533,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_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_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, {})