summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/api/openstack/extensions/foxinsocks.py26
-rw-r--r--nova/tests/api/openstack/fakes.py3
-rw-r--r--nova/tests/api/openstack/test_api.py8
-rw-r--r--nova/tests/api/openstack/test_extensions.py45
-rw-r--r--nova/tests/api/openstack/test_flavors.py4
-rw-r--r--nova/tests/api/openstack/test_image_metadata.py47
-rw-r--r--nova/tests/api/openstack/test_images.py24
-rw-r--r--nova/tests/api/openstack/test_limits.py259
-rw-r--r--nova/tests/api/openstack/test_server_metadata.py62
-rw-r--r--nova/tests/api/openstack/test_servers.py526
-rw-r--r--nova/tests/api/openstack/test_versions.py6
-rw-r--r--nova/tests/api/openstack/test_zones.py44
-rw-r--r--nova/tests/api/test_wsgi.py6
-rw-r--r--nova/tests/db/fakes.py23
-rw-r--r--nova/tests/fake_flags.py28
-rw-r--r--nova/tests/image/test_glance.py8
-rw-r--r--nova/tests/integrated/integrated_helpers.py13
-rw-r--r--nova/tests/integrated/test_servers.py88
-rw-r--r--nova/tests/network/base.py9
-rw-r--r--nova/tests/public_key/dummy.fingerprint1
-rw-r--r--nova/tests/public_key/dummy.pub1
-rw-r--r--nova/tests/test_api.py42
-rw-r--r--nova/tests/test_auth.py40
-rw-r--r--nova/tests/test_cloud.py130
-rw-r--r--nova/tests/test_compute.py52
-rw-r--r--nova/tests/test_console.py2
-rw-r--r--nova/tests/test_crypto.py48
-rw-r--r--nova/tests/test_exception.py (renamed from nova/tests/real_flags.py)20
-rw-r--r--nova/tests/test_flags.py14
-rw-r--r--nova/tests/test_host_filter.py208
-rw-r--r--nova/tests/test_instance_types.py21
-rw-r--r--nova/tests/test_ipv6.py60
-rw-r--r--nova/tests/test_libvirt.py (renamed from nova/tests/test_virt.py)282
-rw-r--r--nova/tests/test_misc.py49
-rw-r--r--nova/tests/test_notifier.py117
-rw-r--r--nova/tests/test_quota.py170
-rw-r--r--nova/tests/test_scheduler.py166
-rw-r--r--nova/tests/test_utils.py27
-rw-r--r--nova/tests/test_volume.py4
-rw-r--r--nova/tests/test_xenapi.py91
-rw-r--r--nova/tests/test_zone_aware_scheduler.py119
-rw-r--r--nova/tests/test_zones.py18
-rw-r--r--nova/tests/xenapi/stubs.py39
43 files changed, 2460 insertions, 490 deletions
diff --git a/nova/tests/api/openstack/extensions/foxinsocks.py b/nova/tests/api/openstack/extensions/foxinsocks.py
index 0860b51ac..dbdd0928a 100644
--- a/nova/tests/api/openstack/extensions/foxinsocks.py
+++ b/nova/tests/api/openstack/extensions/foxinsocks.py
@@ -63,31 +63,33 @@ class Foxinsocks(object):
self._delete_tweedle))
return actions
- def get_response_extensions(self):
- response_exts = []
+ def get_request_extensions(self):
+ request_exts = []
- def _goose_handler(res):
+ def _goose_handler(req, res):
#NOTE: This only handles JSON responses.
# You can use content type header to test for XML.
data = json.loads(res.body)
- data['flavor']['googoose'] = "Gooey goo for chewy chewing!"
- return data
+ data['flavor']['googoose'] = req.GET.get('chewing')
+ res.body = json.dumps(data)
+ return res
- resp_ext = extensions.ResponseExtension('GET', '/v1.1/flavors/:(id)',
+ req_ext1 = extensions.RequestExtension('GET', '/v1.1/flavors/:(id)',
_goose_handler)
- response_exts.append(resp_ext)
+ request_exts.append(req_ext1)
- def _bands_handler(res):
+ def _bands_handler(req, res):
#NOTE: This only handles JSON responses.
# You can use content type header to test for XML.
data = json.loads(res.body)
data['big_bands'] = 'Pig Bands!'
- return data
+ res.body = json.dumps(data)
+ return res
- resp_ext2 = extensions.ResponseExtension('GET', '/v1.1/flavors/:(id)',
+ req_ext2 = extensions.RequestExtension('GET', '/v1.1/flavors/:(id)',
_bands_handler)
- response_exts.append(resp_ext2)
- return response_exts
+ request_exts.append(req_ext2)
+ return request_exts
def _add_tweedle(self, input_dict, req, id):
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 8b0729c35..bf51239e6 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -228,6 +228,9 @@ class FakeToken(object):
# FIXME(sirp): let's not use id here
id = 0
+ def __getitem__(self, key):
+ return getattr(self, key)
+
def __init__(self, **kwargs):
FakeToken.id += 1
self.id = FakeToken.id
diff --git a/nova/tests/api/openstack/test_api.py b/nova/tests/api/openstack/test_api.py
index 5112c486f..c63431a45 100644
--- a/nova/tests/api/openstack/test_api.py
+++ b/nova/tests/api/openstack/test_api.py
@@ -53,13 +53,13 @@ class APITest(test.TestCase):
#api.application = succeed
api = self._wsgi_app(succeed)
resp = Request.blank('/').get_response(api)
- self.assertFalse('computeFault' in resp.body, resp.body)
+ self.assertFalse('cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 200, resp.body)
#api.application = raise_webob_exc
api = self._wsgi_app(raise_webob_exc)
resp = Request.blank('/').get_response(api)
- self.assertFalse('computeFault' in resp.body, resp.body)
+ self.assertFalse('cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 404, resp.body)
#api.application = raise_api_fault
@@ -71,11 +71,11 @@ class APITest(test.TestCase):
#api.application = fail
api = self._wsgi_app(fail)
resp = Request.blank('/').get_response(api)
- self.assertTrue('{"computeFault' in resp.body, resp.body)
+ self.assertTrue('{"cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 500, resp.body)
#api.application = fail
api = self._wsgi_app(fail)
resp = Request.blank('/.xml').get_response(api)
- self.assertTrue('<computeFault' in resp.body, resp.body)
+ self.assertTrue('<cloudServersFault' in resp.body, resp.body)
self.assertEqual(resp.status_int, 500, resp.body)
diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py
index 481d34ed1..544298602 100644
--- a/nova/tests/api/openstack/test_extensions.py
+++ b/nova/tests/api/openstack/test_extensions.py
@@ -45,10 +45,10 @@ class StubController(nova.wsgi.Controller):
class StubExtensionManager(object):
- def __init__(self, resource_ext=None, action_ext=None, response_ext=None):
+ def __init__(self, resource_ext=None, action_ext=None, request_ext=None):
self.resource_ext = resource_ext
self.action_ext = action_ext
- self.response_ext = response_ext
+ self.request_ext = request_ext
def get_name(self):
return "Tweedle Beetle Extension"
@@ -71,11 +71,11 @@ class StubExtensionManager(object):
action_exts.append(self.action_ext)
return action_exts
- def get_response_extensions(self):
- response_exts = []
- if self.response_ext:
- response_exts.append(self.response_ext)
- return response_exts
+ def get_request_extensions(self):
+ request_extensions = []
+ if self.request_ext:
+ request_extensions.append(self.request_ext)
+ return request_extensions
class ExtensionControllerTest(unittest.TestCase):
@@ -183,10 +183,10 @@ class ActionExtensionTest(unittest.TestCase):
self.assertEqual(404, response.status_int)
-class ResponseExtensionTest(unittest.TestCase):
+class RequestExtensionTest(unittest.TestCase):
def setUp(self):
- super(ResponseExtensionTest, self).setUp()
+ super(RequestExtensionTest, self).setUp()
self.stubs = stubout.StubOutForTesting()
fakes.FakeAuthManager.reset_fake_data()
fakes.FakeAuthDatabase.data = {}
@@ -195,42 +195,39 @@ class ResponseExtensionTest(unittest.TestCase):
def tearDown(self):
self.stubs.UnsetAll()
- super(ResponseExtensionTest, self).tearDown()
+ super(RequestExtensionTest, self).tearDown()
def test_get_resources_with_stub_mgr(self):
- test_resp = "Gooey goo for chewy chewing!"
-
- def _resp_handler(res):
+ def _req_handler(req, res):
# only handle JSON responses
data = json.loads(res.body)
- data['flavor']['googoose'] = test_resp
- return data
+ data['flavor']['googoose'] = req.GET.get('chewing')
+ res.body = json.dumps(data)
+ return res
- resp_ext = extensions.ResponseExtension('GET',
+ req_ext = extensions.RequestExtension('GET',
'/v1.1/flavors/:(id)',
- _resp_handler)
+ _req_handler)
- manager = StubExtensionManager(None, None, resp_ext)
+ manager = StubExtensionManager(None, None, req_ext)
app = fakes.wsgi_app()
ext_midware = extensions.ExtensionMiddleware(app, manager)
- request = webob.Request.blank("/v1.1/flavors/1")
+ request = webob.Request.blank("/v1.1/flavors/1?chewing=bluegoo")
request.environ['api.version'] = '1.1'
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
response_data = json.loads(response.body)
- self.assertEqual(test_resp, response_data['flavor']['googoose'])
+ self.assertEqual('bluegoo', response_data['flavor']['googoose'])
def test_get_resources_with_mgr(self):
- test_resp = "Gooey goo for chewy chewing!"
-
app = fakes.wsgi_app()
ext_midware = extensions.ExtensionMiddleware(app)
- request = webob.Request.blank("/v1.1/flavors/1")
+ request = webob.Request.blank("/v1.1/flavors/1?chewing=newblue")
request.environ['api.version'] = '1.1'
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
response_data = json.loads(response.body)
- self.assertEqual(test_resp, response_data['flavor']['googoose'])
+ self.assertEqual('newblue', response_data['flavor']['googoose'])
self.assertEqual("Pig Bands!", response_data['big_bands'])
diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py
index 954d72adf..d1c62e454 100644
--- a/nova/tests/api/openstack/test_flavors.py
+++ b/nova/tests/api/openstack/test_flavors.py
@@ -47,8 +47,8 @@ def return_instance_types(context, num=2):
return instance_types
-def return_instance_type_not_found(context, flavorid):
- raise exception.NotFound()
+def return_instance_type_not_found(context, flavor_id):
+ raise exception.InstanceTypeNotFound(flavor_id=flavor_id)
class FlavorsTest(test.TestCase):
diff --git a/nova/tests/api/openstack/test_image_metadata.py b/nova/tests/api/openstack/test_image_metadata.py
index 9be753f84..56be0f1cc 100644
--- a/nova/tests/api/openstack/test_image_metadata.py
+++ b/nova/tests/api/openstack/test_image_metadata.py
@@ -45,10 +45,8 @@ class ImageMetaDataTest(unittest.TestCase):
'is_public': True,
'deleted_at': None,
'properties': {
- 'type': 'ramdisk',
'key1': 'value1',
- 'key2': 'value2'
- },
+ 'key2': 'value2'},
'size': 5882349},
{'status': 'active',
'name': 'image2',
@@ -62,10 +60,21 @@ class ImageMetaDataTest(unittest.TestCase):
'is_public': True,
'deleted_at': None,
'properties': {
- 'type': 'ramdisk',
'key1': 'value1',
- 'key2': 'value2'
- },
+ 'key2': 'value2'},
+ 'size': 5882349},
+ {'status': 'active',
+ 'name': 'image3',
+ 'deleted': False,
+ 'container_format': None,
+ 'created_at': '2011-03-22T17:40:15',
+ 'disk_format': None,
+ 'updated_at': '2011-03-22T17:40:15',
+ 'id': '3',
+ 'location': 'file:///var/lib/glance/images/2',
+ 'is_public': True,
+ 'deleted_at': None,
+ 'properties': {},
'size': 5882349},
]
@@ -77,6 +86,10 @@ class ImageMetaDataTest(unittest.TestCase):
fakes.FakeAuthManager.auth_data = {}
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_auth(self.stubs)
+ # NOTE(dprince) max out properties/metadata in image 3 for testing
+ img3 = self.IMAGE_FIXTURES[2]
+ for num in range(FLAGS.quota_metadata_items):
+ img3['properties']['key%i' % num] = "blah"
fakes.stub_out_glance(self.stubs, self.IMAGE_FIXTURES)
def tearDown(self):
@@ -164,3 +177,25 @@ class ImageMetaDataTest(unittest.TestCase):
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
+
+ def test_too_many_metadata_items_on_create(self):
+ data = {"metadata": {}}
+ for num in range(FLAGS.quota_metadata_items + 1):
+ data['metadata']['key%i' % num] = "blah"
+ json_string = str(data).replace("\'", "\"")
+ req = webob.Request.blank('/v1.1/images/2/meta')
+ req.environ['api.version'] = '1.1'
+ req.method = 'POST'
+ req.body = json_string
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_too_many_metadata_items_on_put(self):
+ req = webob.Request.blank('/v1.1/images/3/meta/blah')
+ req.environ['api.version'] = '1.1'
+ req.method = 'PUT'
+ req.body = '{"blah": "blah"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index ae86d0686..2c329f920 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -75,6 +75,18 @@ class _BaseImageServiceTests(test.TestCase):
self.context,
'bad image id')
+ def test_create_and_show_non_existing_image_by_name(self):
+ fixture = self._make_fixture('test image')
+ num_images = len(self.service.index(self.context))
+
+ image_id = self.service.create(self.context, fixture)['id']
+
+ self.assertNotEquals(None, image_id)
+ self.assertRaises(exception.ImageNotFound,
+ self.service.show_by_name,
+ self.context,
+ 'bad image id')
+
def test_update(self):
fixture = self._make_fixture('test image')
image_id = self.service.create(self.context, fixture)['id']
@@ -538,7 +550,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
},
{
'id': 127,
- 'name': 'killed backup', 'serverId': 42,
+ 'name': 'killed backup',
+ 'serverId': 42,
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'FAILED',
@@ -584,7 +597,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 124,
'name': 'queued backup',
- 'serverId': 42,
+ 'serverRef': "http://localhost/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'QUEUED',
@@ -606,7 +619,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 125,
'name': 'saving backup',
- 'serverId': 42,
+ 'serverRef': "http://localhost/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'SAVING',
@@ -629,7 +642,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 126,
'name': 'active backup',
- 'serverId': 42,
+ 'serverRef': "http://localhost/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'ACTIVE',
@@ -650,7 +663,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
},
{
'id': 127,
- 'name': 'killed backup', 'serverId': 42,
+ 'name': 'killed backup',
+ 'serverRef': "http://localhost/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'FAILED',
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
index df367005d..70f59eda6 100644
--- a/nova/tests/api/openstack/test_limits.py
+++ b/nova/tests/api/openstack/test_limits.py
@@ -27,16 +27,16 @@ import webob
from xml.dom.minidom import parseString
+import nova.context
from nova.api.openstack import limits
-from nova.api.openstack.limits import Limit
TEST_LIMITS = [
- Limit("GET", "/delayed", "^/delayed", 1, limits.PER_MINUTE),
- Limit("POST", "*", ".*", 7, limits.PER_MINUTE),
- Limit("POST", "/servers", "^/servers", 3, limits.PER_MINUTE),
- Limit("PUT", "*", "", 10, limits.PER_MINUTE),
- Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE),
+ limits.Limit("GET", "/delayed", "^/delayed", 1, limits.PER_MINUTE),
+ limits.Limit("POST", "*", ".*", 7, limits.PER_MINUTE),
+ limits.Limit("POST", "/servers", "^/servers", 3, limits.PER_MINUTE),
+ limits.Limit("PUT", "*", "", 10, limits.PER_MINUTE),
+ limits.Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE),
]
@@ -48,6 +48,13 @@ class BaseLimitTestSuite(unittest.TestCase):
self.time = 0.0
self.stubs = stubout.StubOutForTesting()
self.stubs.Set(limits.Limit, "_get_time", self._get_time)
+ self.absolute_limits = {}
+
+ def stub_get_project_quotas(context, project_id):
+ return self.absolute_limits
+
+ self.stubs.Set(nova.quota, "get_project_quotas",
+ stub_get_project_quotas)
def tearDown(self):
"""Run after each test."""
@@ -58,15 +65,15 @@ class BaseLimitTestSuite(unittest.TestCase):
return self.time
-class LimitsControllerTest(BaseLimitTestSuite):
+class LimitsControllerV10Test(BaseLimitTestSuite):
"""
- Tests for `limits.LimitsController` class.
+ Tests for `limits.LimitsControllerV10` class.
"""
def setUp(self):
"""Run before each test."""
BaseLimitTestSuite.setUp(self)
- self.controller = limits.LimitsController()
+ self.controller = limits.LimitsControllerV10()
def _get_index_request(self, accept_header="application/json"):
"""Helper to set routing arguments."""
@@ -76,17 +83,31 @@ class LimitsControllerTest(BaseLimitTestSuite):
"action": "index",
"controller": "",
})
+ context = nova.context.RequestContext('testuser', 'testproject')
+ request.environ["nova.context"] = context
return request
def _populate_limits(self, request):
"""Put limit info into a request."""
_limits = [
- Limit("GET", "*", ".*", 10, 60).display(),
- Limit("POST", "*", ".*", 5, 60 * 60).display(),
+ limits.Limit("GET", "*", ".*", 10, 60).display(),
+ limits.Limit("POST", "*", ".*", 5, 60 * 60).display(),
]
request.environ["nova.limits"] = _limits
return request
+ def _setup_absolute_limits(self):
+ self.absolute_limits = {
+ 'instances': 5,
+ 'cores': 8,
+ 'ram': 2 ** 13,
+ 'volumes': 21,
+ 'gigabytes': 34,
+ 'metadata_items': 55,
+ 'injected_files': 89,
+ 'injected_file_content_bytes': 144,
+ }
+
def test_empty_index_json(self):
"""Test getting empty limit details in JSON."""
request = self._get_index_request()
@@ -104,6 +125,7 @@ class LimitsControllerTest(BaseLimitTestSuite):
"""Test getting limit details in JSON."""
request = self._get_index_request()
request = self._populate_limits(request)
+ self._setup_absolute_limits()
response = request.get_response(self.controller)
expected = {
"limits": {
@@ -125,7 +147,15 @@ class LimitsControllerTest(BaseLimitTestSuite):
"remaining": 5,
"unit": "HOUR",
}],
- "absolute": {},
+ "absolute": {
+ "maxTotalInstances": 5,
+ "maxTotalCores": 8,
+ "maxTotalRAMSize": 2 ** 13,
+ "maxServerMeta": 55,
+ "maxImageMeta": 55,
+ "maxPersonality": 89,
+ "maxPersonalitySize": 144,
+ },
},
}
body = json.loads(response.body)
@@ -171,6 +201,205 @@ class LimitsControllerTest(BaseLimitTestSuite):
self.assertEqual(expected.toxml(), body.toxml())
+class LimitsControllerV11Test(BaseLimitTestSuite):
+ """
+ Tests for `limits.LimitsControllerV11` class.
+ """
+
+ def setUp(self):
+ """Run before each test."""
+ BaseLimitTestSuite.setUp(self)
+ self.controller = limits.LimitsControllerV11()
+
+ def _get_index_request(self, accept_header="application/json"):
+ """Helper to set routing arguments."""
+ request = webob.Request.blank("/")
+ request.accept = accept_header
+ request.environ["wsgiorg.routing_args"] = (None, {
+ "action": "index",
+ "controller": "",
+ })
+ context = nova.context.RequestContext('testuser', 'testproject')
+ request.environ["nova.context"] = context
+ return request
+
+ def _populate_limits(self, request):
+ """Put limit info into a request."""
+ _limits = [
+ limits.Limit("GET", "*", ".*", 10, 60).display(),
+ limits.Limit("POST", "*", ".*", 5, 60 * 60).display(),
+ limits.Limit("GET", "changes-since*", "changes-since",
+ 5, 60).display(),
+ ]
+ request.environ["nova.limits"] = _limits
+ return request
+
+ def test_empty_index_json(self):
+ """Test getting empty limit details in JSON."""
+ request = self._get_index_request()
+ response = request.get_response(self.controller)
+ expected = {
+ "limits": {
+ "rate": [],
+ "absolute": {},
+ },
+ }
+ body = json.loads(response.body)
+ self.assertEqual(expected, body)
+
+ def test_index_json(self):
+ """Test getting limit details in JSON."""
+ request = self._get_index_request()
+ request = self._populate_limits(request)
+ self.absolute_limits = {
+ 'ram': 512,
+ 'instances': 5,
+ 'cores': 21,
+ }
+ response = request.get_response(self.controller)
+ expected = {
+ "limits": {
+ "rate": [
+ {
+ "regex": ".*",
+ "uri": "*",
+ "limit": [
+ {
+ "verb": "GET",
+ "next-available": 0,
+ "unit": "MINUTE",
+ "value": 10,
+ "remaining": 10,
+ },
+ {
+ "verb": "POST",
+ "next-available": 0,
+ "unit": "HOUR",
+ "value": 5,
+ "remaining": 5,
+ },
+ ],
+ },
+ {
+ "regex": "changes-since",
+ "uri": "changes-since*",
+ "limit": [
+ {
+ "verb": "GET",
+ "next-available": 0,
+ "unit": "MINUTE",
+ "value": 5,
+ "remaining": 5,
+ },
+ ],
+ },
+
+ ],
+ "absolute": {
+ "maxTotalRAMSize": 512,
+ "maxTotalInstances": 5,
+ "maxTotalCores": 21,
+ },
+ },
+ }
+ body = json.loads(response.body)
+ self.assertEqual(expected, body)
+
+ def _populate_limits_diff_regex(self, request):
+ """Put limit info into a request."""
+ _limits = [
+ limits.Limit("GET", "*", ".*", 10, 60).display(),
+ limits.Limit("GET", "*", "*.*", 10, 60).display(),
+ ]
+ request.environ["nova.limits"] = _limits
+ return request
+
+ def test_index_diff_regex(self):
+ """Test getting limit details in JSON."""
+ request = self._get_index_request()
+ request = self._populate_limits_diff_regex(request)
+ response = request.get_response(self.controller)
+ expected = {
+ "limits": {
+ "rate": [
+ {
+ "regex": ".*",
+ "uri": "*",
+ "limit": [
+ {
+ "verb": "GET",
+ "next-available": 0,
+ "unit": "MINUTE",
+ "value": 10,
+ "remaining": 10,
+ },
+ ],
+ },
+ {
+ "regex": "*.*",
+ "uri": "*",
+ "limit": [
+ {
+ "verb": "GET",
+ "next-available": 0,
+ "unit": "MINUTE",
+ "value": 10,
+ "remaining": 10,
+ },
+ ],
+ },
+
+ ],
+ "absolute": {},
+ },
+ }
+ body = json.loads(response.body)
+ self.assertEqual(expected, body)
+
+ def _test_index_absolute_limits_json(self, expected):
+ request = self._get_index_request()
+ response = request.get_response(self.controller)
+ body = json.loads(response.body)
+ self.assertEqual(expected, body['limits']['absolute'])
+
+ def test_index_ignores_extra_absolute_limits_json(self):
+ self.absolute_limits = {'unknown_limit': 9001}
+ self._test_index_absolute_limits_json({})
+
+ def test_index_absolute_ram_json(self):
+ self.absolute_limits = {'ram': 1024}
+ self._test_index_absolute_limits_json({'maxTotalRAMSize': 1024})
+
+ def test_index_absolute_cores_json(self):
+ self.absolute_limits = {'cores': 17}
+ self._test_index_absolute_limits_json({'maxTotalCores': 17})
+
+ def test_index_absolute_instances_json(self):
+ self.absolute_limits = {'instances': 19}
+ self._test_index_absolute_limits_json({'maxTotalInstances': 19})
+
+ def test_index_absolute_metadata_json(self):
+ # NOTE: both server metadata and image metadata are overloaded
+ # into metadata_items
+ self.absolute_limits = {'metadata_items': 23}
+ expected = {
+ 'maxServerMeta': 23,
+ 'maxImageMeta': 23,
+ }
+ self._test_index_absolute_limits_json(expected)
+
+ def test_index_absolute_injected_files(self):
+ self.absolute_limits = {
+ 'injected_files': 17,
+ 'injected_file_content_bytes': 86753,
+ }
+ expected = {
+ 'maxPersonality': 17,
+ 'maxPersonalitySize': 86753,
+ }
+ self._test_index_absolute_limits_json(expected)
+
+
class LimitMiddlewareTest(BaseLimitTestSuite):
"""
Tests for the `limits.RateLimitingMiddleware` class.
@@ -185,7 +414,7 @@ class LimitMiddlewareTest(BaseLimitTestSuite):
"""Prepare middleware for use through fake WSGI app."""
BaseLimitTestSuite.setUp(self)
_limits = [
- Limit("GET", "*", ".*", 1, 60),
+ limits.Limit("GET", "*", ".*", 1, 60),
]
self.app = limits.RateLimitingMiddleware(self._empty_app, _limits)
@@ -238,7 +467,7 @@ class LimitTest(BaseLimitTestSuite):
def test_GET_no_delay(self):
"""Test a limit handles 1 GET per second."""
- limit = Limit("GET", "*", ".*", 1, 1)
+ limit = limits.Limit("GET", "*", ".*", 1, 1)
delay = limit("GET", "/anything")
self.assertEqual(None, delay)
self.assertEqual(0, limit.next_request)
@@ -246,7 +475,7 @@ class LimitTest(BaseLimitTestSuite):
def test_GET_delay(self):
"""Test two calls to 1 GET per second limit."""
- limit = Limit("GET", "*", ".*", 1, 1)
+ limit = limits.Limit("GET", "*", ".*", 1, 1)
delay = limit("GET", "/anything")
self.assertEqual(None, delay)
diff --git a/nova/tests/api/openstack/test_server_metadata.py b/nova/tests/api/openstack/test_server_metadata.py
index c8d456472..c4d1d4fd8 100644
--- a/nova/tests/api/openstack/test_server_metadata.py
+++ b/nova/tests/api/openstack/test_server_metadata.py
@@ -21,11 +21,19 @@ import unittest
import webob
+from nova import flags
from nova.api import openstack
from nova.tests.api.openstack import fakes
import nova.wsgi
+FLAGS = flags.FLAGS
+
+
+def return_create_instance_metadata_max(context, server_id, metadata):
+ return stub_max_server_metadata()
+
+
def return_create_instance_metadata(context, server_id, metadata):
return stub_server_metadata()
@@ -48,8 +56,14 @@ def stub_server_metadata():
"key2": "value2",
"key3": "value3",
"key4": "value4",
- "key5": "value5"
- }
+ "key5": "value5"}
+ return metadata
+
+
+def stub_max_server_metadata():
+ metadata = {"metadata": {}}
+ for num in range(FLAGS.quota_metadata_items):
+ metadata['metadata']['key%i' % num] = "blah"
return metadata
@@ -69,7 +83,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_index(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
- return_server_metadata)
+ return_server_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta')
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
@@ -79,7 +93,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_index_no_data(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
- return_empty_server_metadata)
+ return_empty_server_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta')
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
@@ -89,7 +103,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_show(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
- return_server_metadata)
+ return_server_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta/key5')
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
@@ -99,7 +113,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_show_meta_not_found(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
- return_empty_server_metadata)
+ return_empty_server_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta/key6')
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
@@ -108,7 +122,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_delete(self):
self.stubs.Set(nova.db.api, 'instance_metadata_delete',
- delete_server_metadata)
+ delete_server_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta/key5')
req.environ['api.version'] = '1.1'
req.method = 'DELETE'
@@ -117,7 +131,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_create(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
- return_create_instance_metadata)
+ return_create_instance_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta')
req.environ['api.version'] = '1.1'
req.method = 'POST'
@@ -130,7 +144,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_update_item(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
- return_create_instance_metadata)
+ return_create_instance_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta/key1')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
@@ -143,7 +157,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_update_item_too_many_keys(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
- return_create_instance_metadata)
+ return_create_instance_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta/key1')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
@@ -154,7 +168,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
- return_create_instance_metadata)
+ return_create_instance_metadata)
req = webob.Request.blank('/v1.1/servers/1/meta/bad')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
@@ -162,3 +176,29 @@ class ServerMetaDataTest(unittest.TestCase):
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
+
+ def test_too_many_metadata_items_on_create(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata)
+ data = {"metadata": {}}
+ for num in range(FLAGS.quota_metadata_items + 1):
+ data['metadata']['key%i' % num] = "blah"
+ json_string = str(data).replace("\'", "\"")
+ req = webob.Request.blank('/v1.1/servers/1/meta')
+ req.environ['api.version'] = '1.1'
+ req.method = 'POST'
+ req.body = json_string
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_to_many_metadata_items_on_update_item(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata_max)
+ req = webob.Request.blank('/v1.1/servers/1/meta/key1')
+ req.environ['api.version'] = '1.1'
+ req.method = 'PUT'
+ req.body = '{"a new key": "a new value"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 313676e72..fbde5c9ce 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -32,6 +32,8 @@ from nova import test
import nova.api.openstack
from nova.api.openstack import servers
import nova.compute.api
+from nova.compute import instance_types
+from nova.compute import power_state
import nova.db.api
from nova.db.sqlalchemy.models import Instance
from nova.db.sqlalchemy.models import InstanceMetadata
@@ -55,6 +57,12 @@ def return_server_with_addresses(private, public):
return _return_server
+def return_server_with_power_state(power_state):
+ def _return_server(context, id):
+ return stub_instance(id, power_state=power_state)
+ return _return_server
+
+
def return_servers(context, user_id=1):
return [stub_instance(i, user_id) for i in xrange(5)]
@@ -71,13 +79,19 @@ def instance_address(context, instance_id):
return None
-def stub_instance(id, user_id=1, private_address=None, public_addresses=None):
+def stub_instance(id, user_id=1, private_address=None, public_addresses=None,
+ host=None, power_state=0):
metadata = []
metadata.append(InstanceMetadata(key='seq', value=id))
- if public_addresses == None:
+ inst_type = instance_types.get_instance_type_by_flavor_id(1)
+
+ if public_addresses is None:
public_addresses = list()
+ if host is not None:
+ host = str(host)
+
instance = {
"id": id,
"admin_pass": "",
@@ -89,14 +103,14 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None):
"launch_index": 0,
"key_name": "",
"key_data": "",
- "state": 0,
+ "state": power_state,
"state_description": "",
"memory_mb": 0,
"vcpus": 0,
"local_gb": 0,
"hostname": "",
- "host": None,
- "instance_type": "1",
+ "host": host,
+ "instance_type": dict(inst_type),
"user_data": "",
"reservation_id": "",
"mac_address": "",
@@ -120,6 +134,20 @@ def fake_compute_api(cls, req, id):
return True
+def find_host(self, context, instance_id):
+ return "nova"
+
+
+class MockSetAdminPassword(object):
+ def __init__(self):
+ self.instance_id = None
+ self.password = None
+
+ def __call__(self, context, instance_id, password):
+ self.instance_id = instance_id
+ self.password = password
+
+
class ServersTest(test.TestCase):
def setUp(self):
@@ -165,7 +193,7 @@ class ServersTest(test.TestCase):
self.assertEqual(res_dict['server']['id'], 1)
self.assertEqual(res_dict['server']['name'], 'server1')
- def test_get_server_by_id_v11(self):
+ def test_get_server_by_id_v1_1(self):
req = webob.Request.blank('/v1.1/servers/1')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
@@ -192,6 +220,26 @@ class ServersTest(test.TestCase):
print res_dict['server']
self.assertEqual(res_dict['server']['links'], expected_links)
+ def test_get_server_by_id_with_addresses_xml(self):
+ private = "192.168.0.3"
+ public = ["1.2.3.4"]
+ new_return_server = return_server_with_addresses(private, public)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1')
+ req.headers['Accept'] = 'application/xml'
+ res = req.get_response(fakes.wsgi_app())
+ dom = minidom.parseString(res.body)
+ server = dom.childNodes[0]
+ self.assertEquals(server.nodeName, 'server')
+ self.assertEquals(server.getAttribute('id'), '1')
+ self.assertEquals(server.getAttribute('name'), 'server1')
+ (public,) = server.getElementsByTagName('public')
+ (ip,) = public.getElementsByTagName('ip')
+ self.assertEquals(ip.getAttribute('addr'), '1.2.3.4')
+ (private,) = server.getElementsByTagName('private')
+ (ip,) = private.getElementsByTagName('ip')
+ self.assertEquals(ip.getAttribute('addr'), '192.168.0.3')
+
def test_get_server_by_id_with_addresses(self):
private = "192.168.0.3"
public = ["1.2.3.4"]
@@ -208,7 +256,85 @@ class ServersTest(test.TestCase):
self.assertEqual(len(addresses["private"]), 1)
self.assertEqual(addresses["private"][0], private)
- def test_get_server_by_id_with_addresses_v11(self):
+ def test_get_server_addresses_v1_0(self):
+ private = '192.168.0.3'
+ public = ['1.2.3.4']
+ new_return_server = return_server_with_addresses(private, public)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1/ips')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict, {
+ 'addresses': {'public': public, 'private': [private]}})
+
+ def test_get_server_addresses_xml_v1_0(self):
+ private_expected = "192.168.0.3"
+ public_expected = ["1.2.3.4"]
+ new_return_server = return_server_with_addresses(private_expected,
+ public_expected)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1/ips')
+ req.headers['Accept'] = 'application/xml'
+ res = req.get_response(fakes.wsgi_app())
+ dom = minidom.parseString(res.body)
+ (addresses,) = dom.childNodes
+ self.assertEquals(addresses.nodeName, 'addresses')
+ (public,) = addresses.getElementsByTagName('public')
+ (ip,) = public.getElementsByTagName('ip')
+ self.assertEquals(ip.getAttribute('addr'), public_expected[0])
+ (private,) = addresses.getElementsByTagName('private')
+ (ip,) = private.getElementsByTagName('ip')
+ self.assertEquals(ip.getAttribute('addr'), private_expected)
+
+ def test_get_server_addresses_public_v1_0(self):
+ private = "192.168.0.3"
+ public = ["1.2.3.4"]
+ new_return_server = return_server_with_addresses(private, public)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1/ips/public')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict, {'public': public})
+
+ def test_get_server_addresses_private_v1_0(self):
+ private = "192.168.0.3"
+ public = ["1.2.3.4"]
+ new_return_server = return_server_with_addresses(private, public)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1/ips/private')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict, {'private': [private]})
+
+ def test_get_server_addresses_public_xml_v1_0(self):
+ private = "192.168.0.3"
+ public = ["1.2.3.4"]
+ new_return_server = return_server_with_addresses(private, public)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1/ips/public')
+ req.headers['Accept'] = 'application/xml'
+ res = req.get_response(fakes.wsgi_app())
+ dom = minidom.parseString(res.body)
+ (public_node,) = dom.childNodes
+ self.assertEquals(public_node.nodeName, 'public')
+ (ip,) = public_node.getElementsByTagName('ip')
+ self.assertEquals(ip.getAttribute('addr'), public[0])
+
+ def test_get_server_addresses_private_xml_v1_0(self):
+ private = "192.168.0.3"
+ public = ["1.2.3.4"]
+ new_return_server = return_server_with_addresses(private, public)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ req = webob.Request.blank('/v1.0/servers/1/ips/private')
+ req.headers['Accept'] = 'application/xml'
+ res = req.get_response(fakes.wsgi_app())
+ dom = minidom.parseString(res.body)
+ (private_node,) = dom.childNodes
+ self.assertEquals(private_node.nodeName, 'private')
+ (ip,) = private_node.getElementsByTagName('ip')
+ self.assertEquals(ip.getAttribute('addr'), private)
+
+ def test_get_server_by_id_with_addresses_v1_1(self):
private = "192.168.0.3"
public = ["1.2.3.4"]
new_return_server = return_server_with_addresses(private, public)
@@ -238,7 +364,7 @@ class ServersTest(test.TestCase):
self.assertEqual(s.get('imageId', None), None)
i += 1
- def test_get_server_list_v11(self):
+ def test_get_server_list_v1_1(self):
req = webob.Request.blank('/v1.1/servers')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
@@ -361,6 +487,7 @@ class ServersTest(test.TestCase):
"_get_kernel_ramdisk_from_image", kernel_ramdisk_mapping)
self.stubs.Set(nova.api.openstack.common,
"get_image_id_from_image_hash", image_id_from_hash)
+ self.stubs.Set(nova.compute.api.API, "_find_host", find_host)
def _test_create_instance_helper(self):
self._setup_for_create_instance()
@@ -459,16 +586,16 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
- def test_create_instance_v11(self):
+ def test_create_instance_v1_1(self):
self._setup_for_create_instance()
- imageRef = 'http://localhost/v1.1/images/2'
- flavorRef = 'http://localhost/v1.1/flavors/3'
+ image_ref = 'http://localhost/v1.1/images/2'
+ flavor_ref = 'http://localhost/v1.1/flavors/3'
body = {
'server': {
'name': 'server_test',
- 'imageRef': imageRef,
- 'flavorRef': flavorRef,
+ 'imageRef': image_ref,
+ 'flavorRef': flavor_ref,
'metadata': {
'hello': 'world',
'open': 'stack',
@@ -488,17 +615,17 @@ class ServersTest(test.TestCase):
self.assertEqual(16, len(server['adminPass']))
self.assertEqual('server_test', server['name'])
self.assertEqual(1, server['id'])
- self.assertEqual(flavorRef, server['flavorRef'])
- self.assertEqual(imageRef, server['imageRef'])
+ self.assertEqual(flavor_ref, server['flavorRef'])
+ self.assertEqual(image_ref, server['imageRef'])
self.assertEqual(res.status_int, 200)
- def test_create_instance_v11_bad_href(self):
+ def test_create_instance_v1_1_bad_href(self):
self._setup_for_create_instance()
- imageRef = 'http://localhost/v1.1/images/asdf'
- flavorRef = 'http://localhost/v1.1/flavors/3'
+ image_ref = 'http://localhost/v1.1/images/asdf'
+ flavor_ref = 'http://localhost/v1.1/flavors/3'
body = dict(server=dict(
- name='server_test', imageRef=imageRef, flavorRef=flavorRef,
+ name='server_test', imageRef=image_ref, flavorRef=flavor_ref,
metadata={'hello': 'world', 'open': 'stack'},
personality={}))
req = webob.Request.blank('/v1.1/servers')
@@ -508,6 +635,97 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_create_instance_v1_1_local_href(self):
+ self._setup_for_create_instance()
+
+ image_ref = 'http://localhost/v1.1/images/2'
+ image_ref_local = '2'
+ flavor_ref = 'http://localhost/v1.1/flavors/3'
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_ref_local,
+ 'flavorRef': flavor_ref,
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ res = req.get_response(fakes.wsgi_app())
+
+ server = json.loads(res.body)['server']
+ self.assertEqual(1, server['id'])
+ self.assertEqual(flavor_ref, server['flavorRef'])
+ self.assertEqual(image_ref, server['imageRef'])
+ self.assertEqual(res.status_int, 200)
+
+ def test_create_instance_with_admin_pass_v1_0(self):
+ self._setup_for_create_instance()
+
+ body = {
+ 'server': {
+ 'name': 'test-server-create',
+ 'imageId': 3,
+ 'flavorId': 1,
+ 'adminPass': 'testpass',
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ res = json.loads(res.body)
+ self.assertNotEqual(res['server']['adminPass'],
+ body['server']['adminPass'])
+
+ def test_create_instance_with_admin_pass_v1_1(self):
+ self._setup_for_create_instance()
+
+ image_ref = 'http://localhost/v1.1/images/2'
+ flavor_ref = 'http://localhost/v1.1/flavors/3'
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_ref,
+ 'flavorRef': flavor_ref,
+ 'adminPass': 'testpass',
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ server = json.loads(res.body)['server']
+ self.assertEqual(server['adminPass'], body['server']['adminPass'])
+
+ def test_create_instance_with_empty_admin_pass_v1_1(self):
+ self._setup_for_create_instance()
+
+ image_ref = 'http://localhost/v1.1/images/2'
+ flavor_ref = 'http://localhost/v1.1/flavors/3'
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_ref,
+ 'flavorRef': flavor_ref,
+ 'adminPass': '',
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
def test_update_no_body(self):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
@@ -550,20 +768,22 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
- def test_update_server_v10(self):
+ def test_update_server_v1_0(self):
inst_dict = dict(name='server_test', adminPass='bacon')
self.body = json.dumps(dict(server=inst_dict))
def server_update(context, id, params):
filtered_dict = dict(
- display_name='server_test',
- admin_pass='bacon',
+ display_name='server_test'
)
self.assertEqual(params, filtered_dict)
return filtered_dict
self.stubs.Set(nova.db.api, 'instance_update',
server_update)
+ self.stubs.Set(nova.compute.api.API, "_find_host", find_host)
+ mock_method = MockSetAdminPassword()
+ self.stubs.Set(nova.compute.api.API, 'set_admin_password', mock_method)
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
@@ -571,8 +791,10 @@ class ServersTest(test.TestCase):
req.body = self.body
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 204)
+ self.assertEqual(mock_method.instance_id, '1')
+ self.assertEqual(mock_method.password, 'bacon')
- def test_update_server_adminPass_ignored_v11(self):
+ def test_update_server_adminPass_ignored_v1_1(self):
inst_dict = dict(name='server_test', adminPass='bacon')
self.body = json.dumps(dict(server=inst_dict))
@@ -613,11 +835,27 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 501)
- def test_server_backup_schedule_deprecated_v11(self):
+ def test_server_backup_schedule_deprecated_v1_1(self):
req = webob.Request.blank('/v1.1/servers/1/backup_schedule')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404)
+ def test_get_all_server_details_xml_v1_0(self):
+ req = webob.Request.blank('/v1.0/servers/detail')
+ req.headers['Accept'] = 'application/xml'
+ res = req.get_response(fakes.wsgi_app())
+ print res.body
+ dom = minidom.parseString(res.body)
+ for i, server in enumerate(dom.getElementsByTagName('server')):
+ self.assertEqual(server.getAttribute('id'), str(i))
+ self.assertEqual(server.getAttribute('hostId'), '')
+ self.assertEqual(server.getAttribute('name'), 'server%d' % i)
+ self.assertEqual(server.getAttribute('imageId'), '10')
+ self.assertEqual(server.getAttribute('status'), 'BUILD')
+ (meta,) = server.getElementsByTagName('meta')
+ self.assertEqual(meta.getAttribute('key'), 'seq')
+ self.assertEqual(meta.firstChild.data.strip(), str(i))
+
def test_get_all_server_details_v1_0(self):
req = webob.Request.blank('/v1.0/servers/detail')
res = req.get_response(fakes.wsgi_app())
@@ -628,9 +866,9 @@ class ServersTest(test.TestCase):
self.assertEqual(s['hostId'], '')
self.assertEqual(s['name'], 'server%d' % i)
self.assertEqual(s['imageId'], '10')
- self.assertEqual(s['flavorId'], '1')
+ self.assertEqual(s['flavorId'], 1)
self.assertEqual(s['status'], 'BUILD')
- self.assertEqual(s['metadata']['seq'], i)
+ self.assertEqual(s['metadata']['seq'], str(i))
def test_get_all_server_details_v1_1(self):
req = webob.Request.blank('/v1.1/servers/detail')
@@ -644,7 +882,7 @@ class ServersTest(test.TestCase):
self.assertEqual(s['imageRef'], 'http://localhost/v1.1/images/10')
self.assertEqual(s['flavorRef'], 'http://localhost/v1.1/flavors/1')
self.assertEqual(s['status'], 'BUILD')
- self.assertEqual(s['metadata']['seq'], i)
+ self.assertEqual(s['metadata']['seq'], str(i))
def test_get_all_server_details_with_host(self):
'''
@@ -654,12 +892,8 @@ class ServersTest(test.TestCase):
instances - 2 on one host and 3 on another.
'''
- def stub_instance(id, user_id=1):
- return Instance(id=id, state=0, image_id=10, user_id=user_id,
- display_name='server%s' % id, host='host%s' % (id % 2))
-
def return_servers_with_host(context, user_id=1):
- return [stub_instance(i) for i in xrange(5)]
+ return [stub_instance(i, 1, None, None, i % 2) for i in xrange(5)]
self.stubs.Set(nova.db.api, 'instance_get_all_by_user',
return_servers_with_host)
@@ -677,7 +911,8 @@ class ServersTest(test.TestCase):
self.assertEqual(s['id'], i)
self.assertEqual(s['hostId'], host_ids[i % 2])
self.assertEqual(s['name'], 'server%d' % i)
- self.assertEqual(s['imageId'], 10)
+ self.assertEqual(s['imageId'], '10')
+ self.assertEqual(s['flavorId'], 1)
def test_server_pause(self):
FLAGS.allow_admin_api = True
@@ -774,16 +1009,6 @@ class ServersTest(test.TestCase):
self.assertEqual(res.status_int, 501)
def test_server_change_password_v1_1(self):
-
- class MockSetAdminPassword(object):
- def __init__(self):
- self.instance_id = None
- self.password = None
-
- def __call__(self, context, instance_id, password):
- self.instance_id = instance_id
- self.password = password
-
mock_method = MockSetAdminPassword()
self.stubs.Set(nova.compute.api.API, 'set_admin_password', mock_method)
body = {'changePassword': {'adminPass': '1234pass'}}
@@ -842,15 +1067,175 @@ class ServersTest(test.TestCase):
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
- def test_server_rebuild(self):
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ def test_server_rebuild_accepted(self):
+ body = {
+ "rebuild": {
+ "imageId": 2,
+ },
+ }
+
req = webob.Request.blank('/v1.0/servers/1/action')
req.method = 'POST'
req.content_type = 'application/json'
req.body = json.dumps(body)
+
res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(res.body, "")
+
+ def test_server_rebuild_rejected_when_building(self):
+ body = {
+ "rebuild": {
+ "imageId": 2,
+ },
+ }
+
+ state = power_state.BUILDING
+ new_return_server = return_server_with_power_state(state)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 409)
+
+ def test_server_rebuild_bad_entity(self):
+ body = {
+ "rebuild": {
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_accepted_minimum_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_server_rebuild_rejected_when_building_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ },
+ }
+
+ state = power_state.BUILDING
+ new_return_server = return_server_with_power_state(state)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 409)
+
+ def test_server_rebuild_accepted_with_metadata_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "metadata": {
+ "new": "metadata",
+ },
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_server_rebuild_accepted_with_bad_metadata_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "metadata": "stack",
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_bad_entity_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageId": 2,
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_bad_personality_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "personality": [{
+ "path": "/path/to/file",
+ "contents": "INVALID b64",
+ }]
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_personality_v1_1(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "personality": [{
+ "path": "/path/to/file",
+ "contents": base64.b64encode("Test String"),
+ }]
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
def test_delete_server_instance(self):
req = webob.Request.blank('/v1.0/servers/1')
@@ -973,6 +1358,24 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ 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)
+ req = webob.Request.blank('/v1.0/servers/1')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['server']['status'], 'SHUTDOWN')
+
+ def test_shutoff_status(self):
+ new_server = return_server_with_power_state(power_state.SHUTOFF)
+ self.stubs.Set(nova.db.api, 'instance_get', new_server)
+ req = webob.Request.blank('/v1.0/servers/1')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['server']['status'], 'SHUTOFF')
+
class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
@@ -1254,6 +1657,19 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""",
request = self.deserializer.deserialize(serial_request)
self.assertEqual(request, expected)
+ def test_request_xmlser_with_flavor_image_ref(self):
+ serial_request = """
+ <server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="http://localhost:8774/v1.1/images/1"
+ flavorRef="http://localhost:8774/v1.1/flavors/1">
+ </server>"""
+ request = self.deserializer.deserialize(serial_request)
+ self.assertEquals(request["server"]["flavorRef"],
+ "http://localhost:8774/v1.1/flavors/1")
+ self.assertEquals(request["server"]["imageRef"],
+ "http://localhost:8774/v1.1/images/1")
+
class TestServerInstanceCreation(test.TestCase):
@@ -1525,29 +1941,27 @@ class TestGetKernelRamdiskFromImage(test.TestCase):
def test_not_ami(self):
"""Anything other than ami should return no kernel and no ramdisk"""
- image_meta = {'id': 1, 'status': 'active',
- 'properties': {'disk_format': 'vhd'}}
+ image_meta = {'id': 1, 'status': 'active', 'container_format': 'vhd'}
kernel_id, ramdisk_id = self._get_k_r(image_meta)
self.assertEqual(kernel_id, None)
self.assertEqual(ramdisk_id, None)
def test_ami_no_kernel(self):
"""If an ami is missing a kernel it should raise NotFound"""
- image_meta = {'id': 1, 'status': 'active',
- 'properties': {'disk_format': 'ami', 'ramdisk_id': 1}}
+ image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami',
+ 'properties': {'ramdisk_id': 1}}
self.assertRaises(exception.NotFound, self._get_k_r, image_meta)
def test_ami_no_ramdisk(self):
"""If an ami is missing a ramdisk it should raise NotFound"""
- image_meta = {'id': 1, 'status': 'active',
- 'properties': {'disk_format': 'ami', 'kernel_id': 1}}
+ image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami',
+ 'properties': {'kernel_id': 1}}
self.assertRaises(exception.NotFound, self._get_k_r, image_meta)
def test_ami_kernel_ramdisk_present(self):
"""Return IDs if both kernel and ramdisk are present"""
- image_meta = {'id': 1, 'status': 'active',
- 'properties': {'disk_format': 'ami', 'kernel_id': 1,
- 'ramdisk_id': 2}}
+ image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami',
+ 'properties': {'kernel_id': 1, 'ramdisk_id': 2}}
kernel_id, ramdisk_id = self._get_k_r(image_meta)
self.assertEqual(kernel_id, 1)
self.assertEqual(ramdisk_id, 2)
diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py
index 2640a4ddb..fd8d50904 100644
--- a/nova/tests/api/openstack/test_versions.py
+++ b/nova/tests/api/openstack/test_versions.py
@@ -47,8 +47,7 @@ class VersionsTest(test.TestCase):
{
"rel": "self",
"href": "http://localhost/v1.1",
- }
- ],
+ }],
},
{
"id": "v1.0",
@@ -57,8 +56,7 @@ class VersionsTest(test.TestCase):
{
"rel": "self",
"href": "http://localhost/v1.0",
- }
- ],
+ }],
},
]
self.assertEqual(versions, expected)
diff --git a/nova/tests/api/openstack/test_zones.py b/nova/tests/api/openstack/test_zones.py
index a3f191aaa..fa2e05033 100644
--- a/nova/tests/api/openstack/test_zones.py
+++ b/nova/tests/api/openstack/test_zones.py
@@ -20,6 +20,8 @@ import json
import nova.db
from nova import context
+from nova import crypto
+from nova import exception
from nova import flags
from nova import test
from nova.api.openstack import zones
@@ -75,10 +77,22 @@ def zone_get_all_db(context):
]
-def zone_capabilities(method, context, params):
+def zone_capabilities(method, context):
return dict()
+GLOBAL_BUILD_PLAN = [
+ dict(name='host1', weight=10, ip='10.0.0.1', zone='zone1'),
+ dict(name='host2', weight=9, ip='10.0.0.2', zone='zone2'),
+ dict(name='host3', weight=8, ip='10.0.0.3', zone='zone3'),
+ dict(name='host4', weight=7, ip='10.0.0.4', zone='zone4'),
+ ]
+
+
+def zone_select(context, specs):
+ return GLOBAL_BUILD_PLAN
+
+
class ZonesTest(test.TestCase):
def setUp(self):
super(ZonesTest, self).setUp()
@@ -190,3 +204,31 @@ class ZonesTest(test.TestCase):
self.assertEqual(res_dict['zone']['name'], 'darksecret')
self.assertEqual(res_dict['zone']['cap1'], 'a;b')
self.assertEqual(res_dict['zone']['cap2'], 'c;d')
+
+ def test_zone_select(self):
+ FLAGS.build_plan_encryption_key = 'c286696d887c9aa0611bbb3e2025a45a'
+ self.stubs.Set(api, 'select', zone_select)
+
+ req = webob.Request.blank('/v1.0/zones/select')
+
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(res.status_int, 200)
+
+ self.assertTrue('weights' in res_dict)
+
+ for item in res_dict['weights']:
+ blob = item['blob']
+ decrypt = crypto.decryptor(FLAGS.build_plan_encryption_key)
+ secret_item = json.loads(decrypt(blob))
+ found = False
+ for original_item in GLOBAL_BUILD_PLAN:
+ if original_item['name'] != secret_item['name']:
+ continue
+ found = True
+ for key in ('weight', 'ip', 'zone'):
+ self.assertEqual(secret_item[key], original_item[key])
+
+ self.assertTrue(found)
+ self.assertEqual(len(item), 2)
+ self.assertTrue('weight' in item)
diff --git a/nova/tests/api/test_wsgi.py b/nova/tests/api/test_wsgi.py
index 1ecdd1cfb..5820ecdc2 100644
--- a/nova/tests/api/test_wsgi.py
+++ b/nova/tests/api/test_wsgi.py
@@ -136,6 +136,12 @@ class RequestTest(test.TestCase):
request.body = "asdf<br />"
self.assertRaises(webob.exc.HTTPBadRequest, request.get_content_type)
+ def test_request_content_type_with_charset(self):
+ request = wsgi.Request.blank('/tests/123')
+ request.headers["Content-Type"] = "application/json; charset=UTF-8"
+ result = request.get_content_type()
+ self.assertEqual(result, "application/json")
+
def test_content_type_from_accept_xml(self):
request = wsgi.Request.blank('/tests/123')
request.headers["Accept"] = "application/xml"
diff --git a/nova/tests/db/fakes.py b/nova/tests/db/fakes.py
index 7ddfe377a..8bdea359a 100644
--- a/nova/tests/db/fakes.py
+++ b/nova/tests/db/fakes.py
@@ -28,29 +28,34 @@ def stub_out_db_instance_api(stubs, injected=True):
"""Stubs out the db API for creating Instances."""
INSTANCE_TYPES = {
- 'm1.tiny': dict(memory_mb=512,
+ 'm1.tiny': dict(id=2,
+ memory_mb=512,
vcpus=1,
local_gb=0,
flavorid=1,
rxtx_cap=1),
- 'm1.small': dict(memory_mb=2048,
+ 'm1.small': dict(id=5,
+ memory_mb=2048,
vcpus=1,
local_gb=20,
flavorid=2,
rxtx_cap=2),
'm1.medium':
- dict(memory_mb=4096,
+ dict(id=1,
+ memory_mb=4096,
vcpus=2,
local_gb=40,
flavorid=3,
rxtx_cap=3),
- 'm1.large': dict(memory_mb=8192,
+ 'm1.large': dict(id=3,
+ memory_mb=8192,
vcpus=4,
local_gb=80,
flavorid=4,
rxtx_cap=4),
'm1.xlarge':
- dict(memory_mb=16384,
+ dict(id=4,
+ memory_mb=16384,
vcpus=8,
local_gb=160,
flavorid=5,
@@ -107,13 +112,18 @@ def stub_out_db_instance_api(stubs, injected=True):
def fake_instance_type_get_by_name(context, name):
return INSTANCE_TYPES[name]
+ def fake_instance_type_get_by_id(context, id):
+ for name, inst_type in INSTANCE_TYPES.iteritems():
+ if str(inst_type['id']) == str(id):
+ return inst_type
+ return None
+
def fake_network_get_by_instance(context, instance_id):
# Even instance numbers are on vlan networks
if instance_id % 2 == 0:
return FakeModel(vlan_network_fields)
else:
return FakeModel(flat_network_fields)
- return FakeModel(network_fields)
def fake_network_get_all_by_instance(context, instance_id):
# Even instance numbers are on vlan networks
@@ -136,6 +146,7 @@ def stub_out_db_instance_api(stubs, injected=True):
fake_network_get_all_by_instance)
stubs.Set(db, 'instance_type_get_all', fake_instance_type_get_all)
stubs.Set(db, 'instance_type_get_by_name', fake_instance_type_get_by_name)
+ stubs.Set(db, 'instance_type_get_by_id', fake_instance_type_get_by_id)
stubs.Set(db, 'instance_get_fixed_address',
fake_instance_get_fixed_address)
stubs.Set(db, 'instance_get_fixed_address_v6',
diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py
index 5d7ca98b5..ecefc464a 100644
--- a/nova/tests/fake_flags.py
+++ b/nova/tests/fake_flags.py
@@ -21,24 +21,24 @@ from nova import flags
FLAGS = flags.FLAGS
flags.DECLARE('volume_driver', 'nova.volume.manager')
-FLAGS.volume_driver = 'nova.volume.driver.FakeISCSIDriver'
-FLAGS.connection_type = 'fake'
-FLAGS.fake_rabbit = True
+FLAGS['volume_driver'].SetDefault('nova.volume.driver.FakeISCSIDriver')
+FLAGS['connection_type'].SetDefault('fake')
+FLAGS['fake_rabbit'].SetDefault(True)
flags.DECLARE('auth_driver', 'nova.auth.manager')
-FLAGS.auth_driver = 'nova.auth.dbdriver.DbDriver'
+FLAGS['auth_driver'].SetDefault('nova.auth.dbdriver.DbDriver')
flags.DECLARE('network_size', 'nova.network.manager')
flags.DECLARE('num_networks', 'nova.network.manager')
flags.DECLARE('fake_network', 'nova.network.manager')
-FLAGS.network_size = 8
-FLAGS.num_networks = 2
-FLAGS.fake_network = True
-FLAGS.image_service = 'nova.image.local.LocalImageService'
+FLAGS['network_size'].SetDefault(8)
+FLAGS['num_networks'].SetDefault(2)
+FLAGS['fake_network'].SetDefault(True)
+FLAGS['image_service'].SetDefault('nova.image.local.LocalImageService')
flags.DECLARE('num_shelves', 'nova.volume.driver')
flags.DECLARE('blades_per_shelf', 'nova.volume.driver')
flags.DECLARE('iscsi_num_targets', 'nova.volume.driver')
-FLAGS.num_shelves = 2
-FLAGS.blades_per_shelf = 4
-FLAGS.iscsi_num_targets = 8
-FLAGS.verbose = True
-FLAGS.sqlite_db = "tests.sqlite"
-FLAGS.use_ipv6 = True
+FLAGS['num_shelves'].SetDefault(2)
+FLAGS['blades_per_shelf'].SetDefault(4)
+FLAGS['iscsi_num_targets'].SetDefault(8)
+FLAGS['verbose'].SetDefault(True)
+FLAGS['sqlite_db'].SetDefault("tests.sqlite")
+FLAGS['use_ipv6'].SetDefault(True)
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 9d0b14613..109905ded 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -209,17 +209,17 @@ class TestMutatorDateTimeTests(BaseGlanceTest):
self.assertDateTimesEmpty(image_meta)
def test_update_handles_datetimes(self):
+ self.client.images = {'image1': self._make_datetime_fixture()}
self.client.update_response = self._make_datetime_fixture()
- dummy_id = 'dummy_id'
dummy_meta = {}
- image_meta = self.service.update(self.context, 'dummy_id', dummy_meta)
+ image_meta = self.service.update(self.context, 'image1', dummy_meta)
self.assertDateTimesFilled(image_meta)
def test_update_handles_none_datetimes(self):
+ self.client.images = {'image1': self._make_datetime_fixture()}
self.client.update_response = self._make_none_datetime_fixture()
- dummy_id = 'dummy_id'
dummy_meta = {}
- image_meta = self.service.update(self.context, 'dummy_id', dummy_meta)
+ image_meta = self.service.update(self.context, 'image1', dummy_meta)
self.assertDateTimesEmpty(image_meta)
def _make_datetime_fixture(self):
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
index 2e5d67017..bc98921f0 100644
--- a/nova/tests/integrated/integrated_helpers.py
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -160,7 +160,7 @@ class _IntegratedTestBase(test.TestCase):
#self.start_service('network')
self.start_service('scheduler')
- self.auth_url = self._start_api_service()
+ self._start_api_service()
self.context = IntegratedUnitTestContext(self.auth_url)
@@ -174,8 +174,10 @@ class _IntegratedTestBase(test.TestCase):
if not api_service:
raise Exception("API Service was None")
- auth_url = 'http://localhost:8774/v1.1'
- return auth_url
+ self.api_service = api_service
+
+ host, port = api_service.get_socket_info('osapi')
+ self.auth_url = 'http://%s:%s/v1.1' % (host, port)
def tearDown(self):
self.context.cleanup()
@@ -184,6 +186,11 @@ class _IntegratedTestBase(test.TestCase):
def _get_flags(self):
"""An opportunity to setup flags, before the services are started."""
f = {}
+
+ # Auto-assign ports to allow concurrent tests
+ f['ec2_listen_port'] = 0
+ f['osapi_listen_port'] = 0
+
f['image_service'] = 'nova.image.fake.FakeImageService'
f['fake_network'] = True
return f
diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py
index 749ea8955..e89d0100a 100644
--- a/nova/tests/integrated/test_servers.py
+++ b/nova/tests/integrated/test_servers.py
@@ -134,50 +134,50 @@ class ServersTest(integrated_helpers._IntegratedTestBase):
# Should be gone
self.assertFalse(found_server)
-# TODO(justinsb): Enable this unit test when the metadata bug is fixed
-# def test_create_server_with_metadata(self):
-# """Creates a server with metadata"""
-#
-# # Build the server data gradually, checking errors along the way
-# server = self._build_minimal_create_server_request()
-#
-# for metadata_count in range(30):
-# metadata = {}
-# for i in range(metadata_count):
-# metadata['key_%s' % i] = 'value_%s' % i
-# server['metadata'] = metadata
-#
-# post = {'server': server}
-# created_server = self.api.post_server(post)
-# LOG.debug("created_server: %s" % created_server)
-# self.assertTrue(created_server['id'])
-# created_server_id = created_server['id']
-# # Reenable when bug fixed
-# # self.assertEqual(metadata, created_server.get('metadata'))
-#
-# # Check it's there
-# found_server = self.api.get_server(created_server_id)
-# self.assertEqual(created_server_id, found_server['id'])
-# self.assertEqual(metadata, found_server.get('metadata'))
-#
-# # The server should also be in the all-servers details list
-# servers = self.api.get_servers(detail=True)
-# server_map = dict((server['id'], server) for server in servers)
-# found_server = server_map.get(created_server_id)
-# self.assertTrue(found_server)
-# # Details do include metadata
-# self.assertEqual(metadata, found_server.get('metadata'))
-#
-# # The server should also be in the all-servers summary list
-# servers = self.api.get_servers(detail=False)
-# server_map = dict((server['id'], server) for server in servers)
-# found_server = server_map.get(created_server_id)
-# self.assertTrue(found_server)
-# # Summary should not include metadata
-# self.assertFalse(found_server.get('metadata'))
-#
-# # Cleanup
-# self._delete_server(created_server_id)
+ def test_create_server_with_metadata(self):
+ """Creates a server with metadata."""
+
+ # Build the server data gradually, checking errors along the way
+ server = self._build_minimal_create_server_request()
+
+ metadata = {}
+ for i in range(30):
+ metadata['key_%s' % i] = 'value_%s' % i
+
+ server['metadata'] = metadata
+
+ post = {'server': server}
+ created_server = self.api.post_server(post)
+ LOG.debug("created_server: %s" % created_server)
+ self.assertTrue(created_server['id'])
+ created_server_id = created_server['id']
+
+ # Reenable when bug fixed
+ self.assertEqual(metadata, created_server.get('metadata'))
+ # Check it's there
+
+ found_server = self.api.get_server(created_server_id)
+ self.assertEqual(created_server_id, found_server['id'])
+ self.assertEqual(metadata, found_server.get('metadata'))
+
+ # The server should also be in the all-servers details list
+ servers = self.api.get_servers(detail=True)
+ server_map = dict((server['id'], server) for server in servers)
+ found_server = server_map.get(created_server_id)
+ self.assertTrue(found_server)
+ # Details do include metadata
+ self.assertEqual(metadata, found_server.get('metadata'))
+
+ # The server should also be in the all-servers summary list
+ servers = self.api.get_servers(detail=False)
+ server_map = dict((server['id'], server) for server in servers)
+ found_server = server_map.get(created_server_id)
+ self.assertTrue(found_server)
+ # Summary should not include metadata
+ self.assertFalse(found_server.get('metadata'))
+
+ # Cleanup
+ self._delete_server(created_server_id)
if __name__ == "__main__":
diff --git a/nova/tests/network/base.py b/nova/tests/network/base.py
index 988a1de72..b06271c99 100644
--- a/nova/tests/network/base.py
+++ b/nova/tests/network/base.py
@@ -25,6 +25,7 @@ from nova import context
from nova import db
from nova import exception
from nova import flags
+from nova import ipv6
from nova import log as logging
from nova import test
from nova import utils
@@ -117,15 +118,15 @@ class NetworkTestCase(test.TestCase):
context.get_admin_context(),
instance_ref['id'])
self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
+ ipv6.to_mac(address_v6))
instance_ref2 = db.fixed_ip_get_instance_v6(
context.get_admin_context(),
address_v6)
self.assertEqual(instance_ref['id'], instance_ref2['id'])
self.assertEqual(address_v6,
- utils.to_global_ipv6(
- network_ref['cidr_v6'],
- instance_ref['mac_address']))
+ ipv6.to_global(network_ref['cidr_v6'],
+ instance_ref['mac_address'],
+ 'test'))
self._deallocate_address(0, address)
db.instance_destroy(context.get_admin_context(),
instance_ref['id'])
diff --git a/nova/tests/public_key/dummy.fingerprint b/nova/tests/public_key/dummy.fingerprint
new file mode 100644
index 000000000..715bca27a
--- /dev/null
+++ b/nova/tests/public_key/dummy.fingerprint
@@ -0,0 +1 @@
+1c:87:d1:d9:32:fd:62:3c:78:2b:c0:ad:c0:15:88:df
diff --git a/nova/tests/public_key/dummy.pub b/nova/tests/public_key/dummy.pub
new file mode 100644
index 000000000..d4cf2bc0d
--- /dev/null
+++ b/nova/tests/public_key/dummy.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAMGJlY9XEIm2X234pdO5yFWMp2JuOQx8U0E815IVXhmKxYCBK9ZakgZOIQmPbXoGYyV+mziDPp6HJ0wKYLQxkwLEFr51fAZjWQvRss0SinURRuLkockDfGFtD4pYJthekr/rlqMKlBSDUSpGq8jUWW60UJ18FGooFpxR7ESqQRx/AAAAFQC96LRglaUeeP+E8U/yblEJocuiWwAAAIA3XiMR8Skiz/0aBm5K50SeQznQuMJTyzt9S9uaz5QZWiFu69hOyGSFGw8fqgxEkXFJIuHobQQpGYQubLW0NdaYRqyE/Vud3JUJUb8Texld6dz8vGemyB5d1YvtSeHIo8/BGv2msOqR3u5AZTaGCBD9DhpSGOKHEdNjTtvpPd8S8gAAAIBociGZ5jf09iHLVENhyXujJbxfGRPsyNTyARJfCOGl0oFV6hEzcQyw8U/ePwjgvjc2UizMWLl8tsb2FXKHRdc2v+ND3Us+XqKQ33X3ADP4FZ/+Oj213gMyhCmvFTP0u5FmHog9My4CB7YcIWRuUR42WlhQ2IfPvKwUoTk3R+T6Og== www-data@mk
diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py
index fa0e56597..7c0331eff 100644
--- a/nova/tests/test_api.py
+++ b/nova/tests/test_api.py
@@ -28,10 +28,12 @@ import StringIO
import webob
from nova import context
+from nova import exception
from nova import test
from nova.api import ec2
-from nova.api.ec2 import cloud
from nova.api.ec2 import apirequest
+from nova.api.ec2 import cloud
+from nova.api.ec2 import ec2utils
from nova.auth import manager
@@ -101,6 +103,21 @@ class XmlConversionTestCase(test.TestCase):
self.assertEqual(conv('-0'), 0)
+class Ec2utilsTestCase(test.TestCase):
+ def test_ec2_id_to_id(self):
+ self.assertEqual(ec2utils.ec2_id_to_id('i-0000001e'), 30)
+ self.assertEqual(ec2utils.ec2_id_to_id('ami-1d'), 29)
+
+ def test_bad_ec2_id(self):
+ self.assertRaises(exception.InvalidEc2Id,
+ ec2utils.ec2_id_to_id,
+ 'badone')
+
+ def test_id_to_ec2_id(self):
+ self.assertEqual(ec2utils.id_to_ec2_id(30), 'i-0000001e')
+ self.assertEqual(ec2utils.id_to_ec2_id(29, 'ami-%08x'), 'ami-0000001d')
+
+
class ApiEc2TestCase(test.TestCase):
"""Unit test for the cloud controller on an EC2 API"""
def setUp(self):
@@ -207,6 +224,29 @@ class ApiEc2TestCase(test.TestCase):
self.manager.delete_project(project)
self.manager.delete_user(user)
+ def test_create_duplicate_key_pair(self):
+ """Test that, after successfully generating a keypair,
+ requesting a second keypair with the same name fails sanely"""
+ self.expect_http()
+ self.mox.ReplayAll()
+ keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
+ for x in range(random.randint(4, 8)))
+ user = self.manager.create_user('fake', 'fake', 'fake')
+ project = self.manager.create_project('fake', 'fake', 'fake')
+ # NOTE(vish): create depends on pool, so call helper directly
+ self.ec2.create_key_pair('test')
+
+ try:
+ self.ec2.create_key_pair('test')
+ except EC2ResponseError, e:
+ if e.code == 'KeyPairExists':
+ pass
+ else:
+ self.fail("Unexpected EC2ResponseError: %s "
+ "(expected KeyPairExists)" % e.code)
+ else:
+ self.fail('Exception not raised.')
+
def test_get_all_security_groups(self):
"""Test that we can retrieve security groups"""
self.expect_http()
diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py
index f8a1b1564..f02dd94b7 100644
--- a/nova/tests/test_auth.py
+++ b/nova/tests/test_auth.py
@@ -101,9 +101,43 @@ class _AuthManagerBaseTestCase(test.TestCase):
self.assertEqual('private-party', u.access)
def test_004_signature_is_valid(self):
- #self.assertTrue(self.manager.authenticate(**boto.generate_url ...? ))
- pass
- #raise NotImplementedError
+ with user_generator(self.manager, name='admin', secret='admin',
+ access='admin'):
+ with project_generator(self.manager, name="admin",
+ manager_user='admin'):
+ accesskey = 'admin:admin'
+ expected_result = (self.manager.get_user('admin'),
+ self.manager.get_project('admin'))
+ # captured sig and query string using boto 1.9b/euca2ools 1.2
+ sig = 'd67Wzd9Bwz8xid9QU+lzWXcF2Y3tRicYABPJgrqfrwM='
+ auth_params = {'AWSAccessKeyId': 'admin:admin',
+ 'Action': 'DescribeAvailabilityZones',
+ 'SignatureMethod': 'HmacSHA256',
+ 'SignatureVersion': '2',
+ 'Timestamp': '2011-04-22T11:29:29',
+ 'Version': '2009-11-30'}
+ self.assertTrue(expected_result, self.manager.authenticate(
+ accesskey,
+ sig,
+ auth_params,
+ 'GET',
+ '127.0.0.1:8773',
+ '/services/Cloud/'))
+ # captured sig and query string using RightAWS 1.10.0
+ sig = 'ECYLU6xdFG0ZqRVhQybPJQNJ5W4B9n8fGs6+/fuGD2c='
+ auth_params = {'AWSAccessKeyId': 'admin:admin',
+ 'Action': 'DescribeAvailabilityZones',
+ 'SignatureMethod': 'HmacSHA256',
+ 'SignatureVersion': '2',
+ 'Timestamp': '2011-04-22T11:29:49.000Z',
+ 'Version': '2008-12-01'}
+ self.assertTrue(expected_result, self.manager.authenticate(
+ accesskey,
+ sig,
+ auth_params,
+ 'GET',
+ '127.0.0.1',
+ '/services/Cloud'))
def test_005_can_get_credentials(self):
return
diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py
index 5cb969979..54c0454de 100644
--- a/nova/tests/test_cloud.py
+++ b/nova/tests/test_cloud.py
@@ -36,6 +36,7 @@ from nova import rpc
from nova import service
from nova import test
from nova import utils
+from nova import exception
from nova.auth import manager
from nova.compute import power_state
from nova.api.ec2 import cloud
@@ -247,6 +248,57 @@ class CloudTestCase(test.TestCase):
self.assertRaises(NotFound, describe_images,
self.context, ['ami-fake'])
+ def test_describe_image_attribute(self):
+ describe_image_attribute = self.cloud.describe_image_attribute
+
+ def fake_show(meh, context, id):
+ return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ 'type': 'machine'}, 'is_public': True}
+
+ self.stubs.Set(local.LocalImageService, 'show', fake_show)
+ self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
+ result = describe_image_attribute(self.context, 'ami-00000001',
+ 'launchPermission')
+ self.assertEqual([{'group': 'all'}], result['launchPermission'])
+
+ def test_modify_image_attribute(self):
+ modify_image_attribute = self.cloud.modify_image_attribute
+
+ def fake_show(meh, context, id):
+ return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ 'type': 'machine'}, 'is_public': False}
+
+ def fake_update(meh, context, image_id, metadata, data=None):
+ return metadata
+
+ self.stubs.Set(local.LocalImageService, 'show', fake_show)
+ self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
+ self.stubs.Set(local.LocalImageService, 'update', fake_update)
+ result = modify_image_attribute(self.context, 'ami-00000001',
+ 'launchPermission', 'add',
+ user_group=['all'])
+ self.assertEqual(True, result['is_public'])
+
+ def test_deregister_image(self):
+ deregister_image = self.cloud.deregister_image
+
+ def fake_delete(self, context, id):
+ return None
+
+ self.stubs.Set(local.LocalImageService, 'delete', fake_delete)
+ # valid image
+ result = deregister_image(self.context, 'ami-00000001')
+ self.assertEqual(result['imageId'], 'ami-00000001')
+ # invalid image
+ self.stubs.UnsetAll()
+
+ def fake_detail_empty(self, context):
+ return []
+
+ self.stubs.Set(local.LocalImageService, 'detail', fake_detail_empty)
+ self.assertRaises(exception.ImageNotFound, deregister_image,
+ self.context, 'ami-bad001')
+
def test_console_output(self):
instance_type = FLAGS.default_instance_type
max_count = 1
@@ -258,7 +310,7 @@ class CloudTestCase(test.TestCase):
instance_id = rv['instancesSet'][0]['instanceId']
output = self.cloud.get_console_output(context=self.context,
instance_id=[instance_id])
- self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE OUTPUT')
+ self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE?OUTPUT')
# TODO(soren): We need this until we can stop polling in the rpc code
# for unit tests.
greenthread.sleep(0.3)
@@ -302,44 +354,52 @@ class CloudTestCase(test.TestCase):
self.assertTrue(filter(lambda k: k['keyName'] == 'test1', keys))
self.assertTrue(filter(lambda k: k['keyName'] == 'test2', keys))
+ def test_import_public_key(self):
+ # test when user provides all values
+ result1 = self.cloud.import_public_key(self.context,
+ 'testimportkey1',
+ 'mytestpubkey',
+ 'mytestfprint')
+ self.assertTrue(result1)
+ keydata = db.key_pair_get(self.context,
+ self.context.user.id,
+ 'testimportkey1')
+ self.assertEqual('mytestpubkey', keydata['public_key'])
+ self.assertEqual('mytestfprint', keydata['fingerprint'])
+ # test when user omits fingerprint
+ pubkey_path = os.path.join(os.path.dirname(__file__), 'public_key')
+ f = open(pubkey_path + '/dummy.pub', 'r')
+ dummypub = f.readline().rstrip()
+ f.close
+ f = open(pubkey_path + '/dummy.fingerprint', 'r')
+ dummyfprint = f.readline().rstrip()
+ f.close
+ result2 = self.cloud.import_public_key(self.context,
+ 'testimportkey2',
+ dummypub)
+ self.assertTrue(result2)
+ keydata = db.key_pair_get(self.context,
+ self.context.user.id,
+ 'testimportkey2')
+ self.assertEqual(dummypub, keydata['public_key'])
+ self.assertEqual(dummyfprint, keydata['fingerprint'])
+
def test_delete_key_pair(self):
self._create_key('test')
self.cloud.delete_key_pair(self.context, 'test')
- def test_run_instances(self):
- if FLAGS.connection_type == 'fake':
- LOG.debug(_("Can't test instances without a real virtual env."))
- return
- image_id = FLAGS.default_image
- instance_type = FLAGS.default_instance_type
- max_count = 1
- kwargs = {'image_id': image_id,
- 'instance_type': instance_type,
- 'max_count': max_count}
- rv = self.cloud.run_instances(self.context, **kwargs)
- # TODO: check for proper response
- instance_id = rv['reservationSet'][0].keys()[0]
- instance = rv['reservationSet'][0][instance_id][0]
- LOG.debug(_("Need to watch instance %s until it's running..."),
- instance['instance_id'])
- while True:
- greenthread.sleep(1)
- info = self.cloud._get_instance(instance['instance_id'])
- LOG.debug(info['state'])
- if info['state'] == power_state.RUNNING:
- break
- self.assert_(rv)
-
- if FLAGS.connection_type != 'fake':
- time.sleep(45) # Should use boto for polling here
- for reservations in rv['reservationSet']:
- # for res_id in reservations.keys():
- # LOG.debug(reservations[res_id])
- # for instance in reservations[res_id]:
- for instance in reservations[reservations.keys()[0]]:
- instance_id = instance['instance_id']
- LOG.debug(_("Terminating instance %s"), instance_id)
- rv = self.compute.terminate_instance(instance_id)
+ def test_terminate_instances(self):
+ inst1 = db.instance_create(self.context, {'reservation_id': 'a',
+ 'image_id': 1,
+ 'host': 'host1'})
+ terminate_instances = self.cloud.terminate_instances
+ # valid instance_id
+ result = terminate_instances(self.context, ['i-00000001'])
+ self.assertTrue(result)
+ # non-existing instance_id
+ self.assertRaises(exception.InstanceNotFound, terminate_instances,
+ self.context, ['i-2'])
+ db.instance_destroy(self.context, inst1['id'])
def test_update_of_instance_display_fields(self):
inst = db.instance_create(self.context, {})
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 1b0f426d2..9170837b6 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -21,6 +21,7 @@ Tests For Compute
import datetime
import mox
+import stubout
from nova import compute
from nova import context
@@ -52,6 +53,10 @@ class FakeTime(object):
self.counter += t
+def nop_report_driver_status(self):
+ pass
+
+
class ComputeTestCase(test.TestCase):
"""Test case for compute"""
def setUp(self):
@@ -84,7 +89,8 @@ class ComputeTestCase(test.TestCase):
inst['launch_time'] = '10'
inst['user_id'] = self.user.id
inst['project_id'] = self.project.id
- inst['instance_type'] = 'm1.tiny'
+ type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
+ inst['instance_type_id'] = type_id
inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0
inst.update(params)
@@ -132,7 +138,7 @@ class ComputeTestCase(test.TestCase):
cases = [dict(), dict(display_name=None)]
for instance in cases:
ref = self.compute_api.create(self.context,
- FLAGS.default_instance_type, None, **instance)
+ instance_types.get_default_instance_type(), None, **instance)
try:
self.assertNotEqual(ref[0]['display_name'], None)
finally:
@@ -143,7 +149,7 @@ class ComputeTestCase(test.TestCase):
group = self._create_group()
ref = self.compute_api.create(
self.context,
- instance_type=FLAGS.default_instance_type,
+ instance_type=instance_types.get_default_instance_type(),
image_id=None,
security_group=['testgroup'])
try:
@@ -161,7 +167,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create(
self.context,
- instance_type=FLAGS.default_instance_type,
+ instance_type=instance_types.get_default_instance_type(),
image_id=None,
security_group=['testgroup'])
try:
@@ -177,7 +183,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create(
self.context,
- instance_type=FLAGS.default_instance_type,
+ instance_type=instance_types.get_default_instance_type(),
image_id=None,
security_group=['testgroup'])
@@ -328,6 +334,28 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(self.context, instance_id)
+ def test_finish_resize(self):
+ """Contrived test to ensure finish_resize doesn't raise anything"""
+
+ def fake(*args, **kwargs):
+ pass
+
+ self.stubs.Set(self.compute.driver, 'finish_resize', fake)
+ context = self.context.elevated()
+ instance_id = self._create_instance()
+ self.compute.prep_resize(context, instance_id, 1)
+ migration_ref = db.migration_get_by_instance_and_status(context,
+ instance_id, 'pre-migrating')
+ try:
+ self.compute.finish_resize(context, instance_id,
+ int(migration_ref['id']), {})
+ except KeyError, e:
+ # Only catch key errors. We want other reasons for the test to
+ # fail to actually error out so we don't obscure anything
+ self.fail()
+
+ self.compute.terminate_instance(self.context, instance_id)
+
def test_resize_instance(self):
"""Ensure instance can be migrated/resized"""
instance_id = self._create_instance()
@@ -359,8 +387,9 @@ class ComputeTestCase(test.TestCase):
instance_id = self._create_instance()
self.compute.run_instance(self.context, instance_id)
+ inst_type = instance_types.get_instance_type_by_name('m1.xlarge')
db.instance_update(self.context, instance_id,
- {'instance_type': 'm1.xlarge'})
+ {'instance_type_id': inst_type['id']})
self.assertRaises(exception.ApiError, self.compute_api.resize,
context, instance_id, 1)
@@ -380,8 +409,8 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(context, instance_id)
def test_get_by_flavor_id(self):
- type = instance_types.get_by_flavor_id(1)
- self.assertEqual(type, 'm1.tiny')
+ type = instance_types.get_instance_type_by_flavor_id(1)
+ self.assertEqual(type['name'], 'm1.tiny')
def test_resize_same_source_fails(self):
"""Ensure instance fails to migrate when source and destination are
@@ -647,6 +676,10 @@ class ComputeTestCase(test.TestCase):
def test_run_kill_vm(self):
"""Detect when a vm is terminated behind the scenes"""
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(compute_manager.ComputeManager,
+ '_report_driver_status', nop_report_driver_status)
+
instance_id = self._create_instance()
self.compute.run_instance(self.context, instance_id)
@@ -664,4 +697,5 @@ class ComputeTestCase(test.TestCase):
instances = db.instance_get_all(context.get_admin_context())
LOG.info(_("After force-killing instances: %s"), instances)
- self.assertEqual(len(instances), 0)
+ self.assertEqual(len(instances), 1)
+ self.assertEqual(power_state.SHUTOFF, instances[0]['state'])
diff --git a/nova/tests/test_console.py b/nova/tests/test_console.py
index d47c70d88..1a9a867ee 100644
--- a/nova/tests/test_console.py
+++ b/nova/tests/test_console.py
@@ -62,7 +62,7 @@ class ConsoleTestCase(test.TestCase):
inst['launch_time'] = '10'
inst['user_id'] = self.user.id
inst['project_id'] = self.project.id
- inst['instance_type'] = 'm1.tiny'
+ inst['instance_type_id'] = 1
inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0
return db.instance_create(self.context, inst)['id']
diff --git a/nova/tests/test_crypto.py b/nova/tests/test_crypto.py
new file mode 100644
index 000000000..945d78794
--- /dev/null
+++ b/nova/tests/test_crypto.py
@@ -0,0 +1,48 @@
+# 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.
+"""
+Tests for Crypto module.
+"""
+
+from nova import crypto
+from nova import test
+
+
+class SymmetricKeyTestCase(test.TestCase):
+ """Test case for Encrypt/Decrypt"""
+ def test_encrypt_decrypt(self):
+ key = 'c286696d887c9aa0611bbb3e2025a45a'
+ plain_text = "The quick brown fox jumped over the lazy dog."
+
+ # No IV supplied (all 0's)
+ encrypt = crypto.encryptor(key)
+ cipher_text = encrypt(plain_text)
+ self.assertNotEquals(plain_text, cipher_text)
+
+ decrypt = crypto.decryptor(key)
+ plain = decrypt(cipher_text)
+
+ self.assertEquals(plain_text, plain)
+
+ # IV supplied ...
+ iv = '562e17996d093d28ddb3ba695a2e6f58'
+ encrypt = crypto.encryptor(key, iv)
+ cipher_text = encrypt(plain_text)
+ self.assertNotEquals(plain_text, cipher_text)
+
+ decrypt = crypto.decryptor(key, iv)
+ plain = decrypt(cipher_text)
+
+ self.assertEquals(plain_text, plain)
diff --git a/nova/tests/real_flags.py b/nova/tests/test_exception.py
index 71da04992..4d3b9cc73 100644
--- a/nova/tests/real_flags.py
+++ b/nova/tests/test_exception.py
@@ -16,11 +16,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-from nova import flags
+from nova import test
+from nova import exception
-FLAGS = flags.FLAGS
-FLAGS.connection_type = 'libvirt'
-FLAGS.fake_rabbit = False
-FLAGS.fake_network = False
-FLAGS.verbose = False
+class ApiErrorTestCase(test.TestCase):
+ def test_return_valid_error(self):
+ # without 'code' arg
+ err = exception.ApiError('fake error')
+ self.assertEqual(err.__str__(), 'fake error')
+ self.assertEqual(err.code, None)
+ self.assertEqual(err.msg, 'fake error')
+ # with 'code' arg
+ err = exception.ApiError('fake error', 'blah code')
+ self.assertEqual(err.__str__(), 'blah code: fake error')
+ self.assertEqual(err.code, 'blah code')
+ self.assertEqual(err.msg, 'fake error')
diff --git a/nova/tests/test_flags.py b/nova/tests/test_flags.py
index 707300fcf..05319d91f 100644
--- a/nova/tests/test_flags.py
+++ b/nova/tests/test_flags.py
@@ -91,6 +91,20 @@ class FlagsTestCase(test.TestCase):
self.assert_('runtime_answer' in self.global_FLAGS)
self.assertEqual(self.global_FLAGS.runtime_answer, 60)
+ def test_long_vs_short_flags(self):
+ flags.DEFINE_string('duplicate_answer_long', 'val', 'desc',
+ flag_values=self.global_FLAGS)
+ argv = ['flags_test', '--duplicate_answer=60', 'extra_arg']
+ args = self.global_FLAGS(argv)
+
+ self.assert_('duplicate_answer' not in self.global_FLAGS)
+ self.assert_(self.global_FLAGS.duplicate_answer_long, 60)
+
+ flags.DEFINE_integer('duplicate_answer', 60, 'desc',
+ flag_values=self.global_FLAGS)
+ self.assertEqual(self.global_FLAGS.duplicate_answer, 60)
+ self.assertEqual(self.global_FLAGS.duplicate_answer_long, 'val')
+
def test_flag_leak_left(self):
self.assertEqual(FLAGS.flags_unittest, 'foo')
FLAGS.flags_unittest = 'bar'
diff --git a/nova/tests/test_host_filter.py b/nova/tests/test_host_filter.py
new file mode 100644
index 000000000..c029d41e6
--- /dev/null
+++ b/nova/tests/test_host_filter.py
@@ -0,0 +1,208 @@
+# 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.
+"""
+Tests For Scheduler Host Filter Drivers.
+"""
+
+import json
+
+from nova import exception
+from nova import flags
+from nova import test
+from nova.scheduler import host_filter
+
+FLAGS = flags.FLAGS
+
+
+class FakeZoneManager:
+ pass
+
+
+class HostFilterTestCase(test.TestCase):
+ """Test case for host filter drivers."""
+
+ def _host_caps(self, multiplier):
+ # Returns host capabilities in the following way:
+ # host1 = memory:free 10 (100max)
+ # disk:available 100 (1000max)
+ # hostN = memory:free 10 + 10N
+ # disk:available 100 + 100N
+ # in other words: hostN has more resources than host0
+ # which means ... don't go above 10 hosts.
+ return {'host_name-description': 'XenServer %s' % multiplier,
+ 'host_hostname': 'xs-%s' % multiplier,
+ 'host_memory_total': 100,
+ 'host_memory_overhead': 10,
+ 'host_memory_free': 10 + multiplier * 10,
+ 'host_memory_free-computed': 10 + multiplier * 10,
+ 'host_other-config': {},
+ 'host_ip_address': '192.168.1.%d' % (100 + multiplier),
+ 'host_cpu_info': {},
+ 'disk_available': 100 + multiplier * 100,
+ 'disk_total': 1000,
+ 'disk_used': 0,
+ 'host_uuid': 'xxx-%d' % multiplier,
+ 'host_name-label': 'xs-%s' % multiplier}
+
+ def setUp(self):
+ self.old_flag = FLAGS.default_host_filter_driver
+ FLAGS.default_host_filter_driver = \
+ 'nova.scheduler.host_filter.AllHostsFilter'
+ self.instance_type = dict(name='tiny',
+ memory_mb=50,
+ vcpus=10,
+ local_gb=500,
+ flavorid=1,
+ swap=500,
+ rxtx_quota=30000,
+ rxtx_cap=200)
+
+ self.zone_manager = FakeZoneManager()
+ states = {}
+ for x in xrange(10):
+ states['host%02d' % (x + 1)] = {'compute': self._host_caps(x)}
+ self.zone_manager.service_states = states
+
+ def tearDown(self):
+ FLAGS.default_host_filter_driver = self.old_flag
+
+ def test_choose_driver(self):
+ # Test default driver ...
+ driver = host_filter.choose_driver()
+ self.assertEquals(driver._full_name(),
+ 'nova.scheduler.host_filter.AllHostsFilter')
+ # Test valid driver ...
+ driver = host_filter.choose_driver(
+ 'nova.scheduler.host_filter.FlavorFilter')
+ self.assertEquals(driver._full_name(),
+ 'nova.scheduler.host_filter.FlavorFilter')
+ # Test invalid driver ...
+ try:
+ host_filter.choose_driver('does not exist')
+ self.fail("Should not find driver")
+ except exception.SchedulerHostFilterDriverNotFound:
+ pass
+
+ def test_all_host_driver(self):
+ driver = host_filter.AllHostsFilter()
+ cooked = driver.instance_type_to_filter(self.instance_type)
+ hosts = driver.filter_hosts(self.zone_manager, cooked)
+ self.assertEquals(10, len(hosts))
+ for host, capabilities in hosts:
+ self.assertTrue(host.startswith('host'))
+
+ def test_flavor_driver(self):
+ driver = host_filter.FlavorFilter()
+ # filter all hosts that can support 50 ram and 500 disk
+ name, cooked = driver.instance_type_to_filter(self.instance_type)
+ self.assertEquals('nova.scheduler.host_filter.FlavorFilter', name)
+ hosts = driver.filter_hosts(self.zone_manager, cooked)
+ self.assertEquals(6, len(hosts))
+ just_hosts = [host for host, caps in hosts]
+ just_hosts.sort()
+ self.assertEquals('host05', just_hosts[0])
+ self.assertEquals('host10', just_hosts[5])
+
+ def test_json_driver(self):
+ driver = host_filter.JsonFilter()
+ # filter all hosts that can support 50 ram and 500 disk
+ name, cooked = driver.instance_type_to_filter(self.instance_type)
+ self.assertEquals('nova.scheduler.host_filter.JsonFilter', name)
+ hosts = driver.filter_hosts(self.zone_manager, cooked)
+ self.assertEquals(6, len(hosts))
+ just_hosts = [host for host, caps in hosts]
+ just_hosts.sort()
+ self.assertEquals('host05', just_hosts[0])
+ self.assertEquals('host10', just_hosts[5])
+
+ # Try some custom queries
+
+ raw = ['or',
+ ['and',
+ ['<', '$compute.host_memory_free', 30],
+ ['<', '$compute.disk_available', 300]
+ ],
+ ['and',
+ ['>', '$compute.host_memory_free', 70],
+ ['>', '$compute.disk_available', 700]
+ ]
+ ]
+ cooked = json.dumps(raw)
+ hosts = driver.filter_hosts(self.zone_manager, cooked)
+
+ self.assertEquals(5, len(hosts))
+ just_hosts = [host for host, caps in hosts]
+ just_hosts.sort()
+ for index, host in zip([1, 2, 8, 9, 10], just_hosts):
+ self.assertEquals('host%02d' % index, host)
+
+ raw = ['not',
+ ['=', '$compute.host_memory_free', 30],
+ ]
+ cooked = json.dumps(raw)
+ hosts = driver.filter_hosts(self.zone_manager, cooked)
+
+ self.assertEquals(9, len(hosts))
+ just_hosts = [host for host, caps in hosts]
+ just_hosts.sort()
+ for index, host in zip([1, 2, 4, 5, 6, 7, 8, 9, 10], just_hosts):
+ self.assertEquals('host%02d' % index, host)
+
+ raw = ['in', '$compute.host_memory_free', 20, 40, 60, 80, 100]
+ cooked = json.dumps(raw)
+ hosts = driver.filter_hosts(self.zone_manager, cooked)
+
+ self.assertEquals(5, len(hosts))
+ just_hosts = [host for host, caps in hosts]
+ just_hosts.sort()
+ for index, host in zip([2, 4, 6, 8, 10], just_hosts):
+ self.assertEquals('host%02d' % index, host)
+
+ # Try some bogus input ...
+ raw = ['unknown command', ]
+ cooked = json.dumps(raw)
+ try:
+ driver.filter_hosts(self.zone_manager, cooked)
+ self.fail("Should give KeyError")
+ except KeyError, e:
+ pass
+
+ self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps([])))
+ self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps({})))
+ self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps(
+ ['not', True, False, True, False]
+ )))
+
+ try:
+ driver.filter_hosts(self.zone_manager, json.dumps(
+ 'not', True, False, True, False
+ ))
+ self.fail("Should give KeyError")
+ except KeyError, e:
+ pass
+
+ self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
+ ['=', '$foo', 100]
+ )))
+ self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
+ ['=', '$.....', 100]
+ )))
+ self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
+ ['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]]
+ )))
+
+ self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
+ ['=', {}, ['>', '$missing....foo']]
+ )))
diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py
index edc538879..ef271518c 100644
--- a/nova/tests/test_instance_types.py
+++ b/nova/tests/test_instance_types.py
@@ -40,7 +40,11 @@ class InstanceTypeTestCase(test.TestCase):
max_flavorid = session.query(models.InstanceTypes).\
order_by("flavorid desc").\
first()
+ max_id = session.query(models.InstanceTypes).\
+ order_by("id desc").\
+ first()
self.flavorid = max_flavorid["flavorid"] + 1
+ self.id = max_id["id"] + 1
self.name = str(int(time.time()))
def test_instance_type_create_then_delete(self):
@@ -53,7 +57,7 @@ class InstanceTypeTestCase(test.TestCase):
'instance type was not created')
instance_types.destroy(self.name)
self.assertEqual(1,
- instance_types.get_instance_type(self.name)["deleted"])
+ instance_types.get_instance_type(self.id)["deleted"])
self.assertEqual(starting_inst_list, instance_types.get_all_types())
instance_types.purge(self.name)
self.assertEqual(len(starting_inst_list),
@@ -71,16 +75,25 @@ class InstanceTypeTestCase(test.TestCase):
def test_invalid_create_args_should_fail(self):
"""Ensures that instance type creation fails with invalid args"""
self.assertRaises(
- exception.InvalidInputException,
+ exception.InvalidInput,
instance_types.create, self.name, 0, 1, 120, self.flavorid)
self.assertRaises(
- exception.InvalidInputException,
+ exception.InvalidInput,
instance_types.create, self.name, 256, -1, 120, self.flavorid)
self.assertRaises(
- exception.InvalidInputException,
+ exception.InvalidInput,
instance_types.create, self.name, 256, 1, "aa", self.flavorid)
def test_non_existant_inst_type_shouldnt_delete(self):
"""Ensures that instance type creation fails with invalid args"""
self.assertRaises(exception.ApiError,
instance_types.destroy, "sfsfsdfdfs")
+
+ def test_repeated_inst_types_should_raise_api_error(self):
+ """Ensures that instance duplicates raises ApiError"""
+ new_name = self.name + "dup"
+ instance_types.create(new_name, 256, 1, 120, self.flavorid + 1)
+ instance_types.destroy(new_name)
+ self.assertRaises(
+ exception.ApiError,
+ instance_types.create, new_name, 256, 1, 120, self.flavorid)
diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py
new file mode 100644
index 000000000..11dc2ec98
--- /dev/null
+++ b/nova/tests/test_ipv6.py
@@ -0,0 +1,60 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 OpenStack LLC
+#
+# 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.
+
+"""Test suite for IPv6."""
+
+from nova import flags
+from nova import ipv6
+from nova import log as logging
+from nova import test
+
+LOG = logging.getLogger('nova.tests.test_ipv6')
+
+FLAGS = flags.FLAGS
+
+import sys
+
+
+class IPv6RFC2462TestCase(test.TestCase):
+ """Unit tests for IPv6 rfc2462 backend operations."""
+ def setUp(self):
+ super(IPv6RFC2462TestCase, self).setUp()
+ self.flags(ipv6_backend='rfc2462')
+ ipv6.reset_backend()
+
+ def test_to_global(self):
+ addr = ipv6.to_global('2001:db8::', '02:16:3e:33:44:55', 'test')
+ self.assertEquals(addr, '2001:db8::16:3eff:fe33:4455')
+
+ def test_to_mac(self):
+ mac = ipv6.to_mac('2001:db8::216:3eff:fe33:4455')
+ self.assertEquals(mac, '00:16:3e:33:44:55')
+
+
+class IPv6AccountIdentiferTestCase(test.TestCase):
+ """Unit tests for IPv6 account_identifier backend operations."""
+ def setUp(self):
+ super(IPv6AccountIdentiferTestCase, self).setUp()
+ self.flags(ipv6_backend='account_identifier')
+ ipv6.reset_backend()
+
+ def test_to_global(self):
+ addr = ipv6.to_global('2001:db8::', '02:16:3e:33:44:55', 'test')
+ self.assertEquals(addr, '2001:db8::a94a:8fe5:ff33:4455')
+
+ def test_to_mac(self):
+ mac = ipv6.to_mac('2001:db8::a94a:8fe5:ff33:4455')
+ self.assertEquals(mac, '02:16:3e:33:44:55')
diff --git a/nova/tests/test_virt.py b/nova/tests/test_libvirt.py
index 7c3dbf654..1743b09a2 100644
--- a/nova/tests/test_virt.py
+++ b/nova/tests/test_libvirt.py
@@ -31,10 +31,9 @@ from nova import test
from nova import utils
from nova.api.ec2 import cloud
from nova.auth import manager
-from nova.compute import manager as compute_manager
from nova.compute import power_state
-from nova.db.sqlalchemy import models
-from nova.virt import libvirt_conn
+from nova.virt.libvirt import connection
+from nova.virt.libvirt import firewall
libvirt = None
FLAGS = flags.FLAGS
@@ -46,6 +45,27 @@ def _concurrency(wait, done, target):
done.send()
+def _create_network_info(count=1, ipv6=None):
+ if ipv6 is None:
+ ipv6 = FLAGS.use_ipv6
+ fake = 'fake'
+ fake_ip = '0.0.0.0/0'
+ fake_ip_2 = '0.0.0.1/0'
+ fake_ip_3 = '0.0.0.1/0'
+ network = {'gateway': fake,
+ 'gateway_v6': fake,
+ 'bridge': fake,
+ 'cidr': fake_ip,
+ 'cidr_v6': fake_ip}
+ mapping = {'mac': fake,
+ 'ips': [{'ip': fake_ip}, {'ip': fake_ip}]}
+ if ipv6:
+ mapping['ip6s'] = [{'ip': fake_ip},
+ {'ip': fake_ip_2},
+ {'ip': fake_ip_3}]
+ return [(network, mapping) for x in xrange(0, count)]
+
+
class CacheConcurrencyTestCase(test.TestCase):
def setUp(self):
super(CacheConcurrencyTestCase, self).setUp()
@@ -64,7 +84,7 @@ class CacheConcurrencyTestCase(test.TestCase):
def test_same_fname_concurrency(self):
"""Ensures that the same fname cache runs at a sequentially"""
- conn = libvirt_conn.LibvirtConnection
+ conn = connection.LibvirtConnection
wait1 = eventlet.event.Event()
done1 = eventlet.event.Event()
eventlet.spawn(conn._cache_image, _concurrency,
@@ -85,7 +105,7 @@ class CacheConcurrencyTestCase(test.TestCase):
def test_different_fname_concurrency(self):
"""Ensures that two different fname caches are concurrent"""
- conn = libvirt_conn.LibvirtConnection
+ conn = connection.LibvirtConnection
wait1 = eventlet.event.Event()
done1 = eventlet.event.Event()
eventlet.spawn(conn._cache_image, _concurrency,
@@ -106,7 +126,7 @@ class CacheConcurrencyTestCase(test.TestCase):
class LibvirtConnTestCase(test.TestCase):
def setUp(self):
super(LibvirtConnTestCase, self).setUp()
- libvirt_conn._late_load_cheetah()
+ connection._late_load_cheetah()
self.flags(fake_call=True)
self.manager = manager.AuthManager()
@@ -140,7 +160,7 @@ class LibvirtConnTestCase(test.TestCase):
'vcpus': 2,
'project_id': 'fake',
'bridge': 'br101',
- 'instance_type': 'm1.small'}
+ 'instance_type_id': '5'} # m1.small
def lazy_load_library_exists(self):
"""check if libvirt is available."""
@@ -152,8 +172,8 @@ class LibvirtConnTestCase(test.TestCase):
return False
global libvirt
libvirt = __import__('libvirt')
- libvirt_conn.libvirt = __import__('libvirt')
- libvirt_conn.libxml2 = __import__('libxml2')
+ connection.libvirt = __import__('libvirt')
+ connection.libxml2 = __import__('libxml2')
return True
def create_fake_libvirt_mock(self, **kwargs):
@@ -163,7 +183,7 @@ class LibvirtConnTestCase(test.TestCase):
class FakeLibvirtConnection(object):
pass
- # A fake libvirt_conn.IptablesFirewallDriver
+ # A fake connection.IptablesFirewallDriver
class FakeIptablesFirewallDriver(object):
def __init__(self, **kwargs):
@@ -179,11 +199,11 @@ class LibvirtConnTestCase(test.TestCase):
for key, val in kwargs.items():
fake.__setattr__(key, val)
- # Inevitable mocks for libvirt_conn.LibvirtConnection
- self.mox.StubOutWithMock(libvirt_conn.utils, 'import_class')
- libvirt_conn.utils.import_class(mox.IgnoreArg()).AndReturn(fakeip)
- self.mox.StubOutWithMock(libvirt_conn.LibvirtConnection, '_conn')
- libvirt_conn.LibvirtConnection._conn = fake
+ # Inevitable mocks for connection.LibvirtConnection
+ self.mox.StubOutWithMock(connection.utils, 'import_class')
+ connection.utils.import_class(mox.IgnoreArg()).AndReturn(fakeip)
+ self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
+ connection.LibvirtConnection._conn = fake
def create_service(self, **kwargs):
service_ref = {'host': kwargs.get('host', 'dummy'),
@@ -194,6 +214,37 @@ class LibvirtConnTestCase(test.TestCase):
return db.service_create(context.get_admin_context(), service_ref)
+ def test_preparing_xml_info(self):
+ conn = connection.LibvirtConnection(True)
+ instance_ref = db.instance_create(self.context, self.test_instance)
+
+ result = conn._prepare_xml_info(instance_ref, False)
+ self.assertFalse(result['nics'])
+
+ result = conn._prepare_xml_info(instance_ref, False,
+ _create_network_info())
+ self.assertTrue(len(result['nics']) == 1)
+
+ result = conn._prepare_xml_info(instance_ref, False,
+ _create_network_info(2))
+ self.assertTrue(len(result['nics']) == 2)
+
+ def test_get_nic_for_xml_v4(self):
+ conn = connection.LibvirtConnection(True)
+ network, mapping = _create_network_info()[0]
+ self.flags(use_ipv6=False)
+ params = conn._get_nic_for_xml(network, mapping)['extra_params']
+ self.assertTrue(params.find('PROJNETV6') == -1)
+ self.assertTrue(params.find('PROJMASKV6') == -1)
+
+ def test_get_nic_for_xml_v6(self):
+ conn = connection.LibvirtConnection(True)
+ network, mapping = _create_network_info()[0]
+ self.flags(use_ipv6=True)
+ params = conn._get_nic_for_xml(network, mapping)['extra_params']
+ self.assertTrue(params.find('PROJNETV6') > -1)
+ self.assertTrue(params.find('PROJMASKV6') > -1)
+
def test_xml_and_uri_no_ramdisk_no_kernel(self):
instance_data = dict(self.test_instance)
self._check_xml_and_uri(instance_data,
@@ -229,6 +280,22 @@ class LibvirtConnTestCase(test.TestCase):
instance_data = dict(self.test_instance)
self._check_xml_and_container(instance_data)
+ def test_multi_nic(self):
+ instance_data = dict(self.test_instance)
+ network_info = _create_network_info(2)
+ conn = connection.LibvirtConnection(True)
+ instance_ref = db.instance_create(self.context, instance_data)
+ xml = conn.to_xml(instance_ref, False, network_info)
+ tree = xml_to_tree(xml)
+ interfaces = tree.findall("./devices/interface")
+ self.assertEquals(len(interfaces), 2)
+ parameters = interfaces[0].findall('./filterref/parameter')
+ self.assertEquals(interfaces[0].get('type'), 'bridge')
+ self.assertEquals(parameters[0].get('name'), 'IP')
+ self.assertEquals(parameters[0].get('value'), '0.0.0.0/0')
+ self.assertEquals(parameters[1].get('name'), 'DHCPSERVER')
+ self.assertEquals(parameters[1].get('value'), 'fake')
+
def _check_xml_and_container(self, instance):
user_context = context.RequestContext(project=self.project,
user=self.user)
@@ -247,7 +314,7 @@ class LibvirtConnTestCase(test.TestCase):
'instance_id': instance_ref['id']})
self.flags(libvirt_type='lxc')
- conn = libvirt_conn.LibvirtConnection(True)
+ conn = connection.LibvirtConnection(True)
uri = conn.get_uri()
self.assertEquals(uri, 'lxc:///')
@@ -327,19 +394,13 @@ class LibvirtConnTestCase(test.TestCase):
check = (lambda t: t.find('./os/initrd'), None)
check_list.append(check)
+ parameter = './devices/interface/filterref/parameter'
common_checks = [
(lambda t: t.find('.').tag, 'domain'),
- (lambda t: t.find(
- './devices/interface/filterref/parameter').get('name'), 'IP'),
- (lambda t: t.find(
- './devices/interface/filterref/parameter').get(
- 'value'), '10.11.12.13'),
- (lambda t: t.findall(
- './devices/interface/filterref/parameter')[1].get(
- 'name'), 'DHCPSERVER'),
- (lambda t: t.findall(
- './devices/interface/filterref/parameter')[1].get(
- 'value'), '10.0.0.1'),
+ (lambda t: t.find(parameter).get('name'), 'IP'),
+ (lambda t: t.find(parameter).get('value'), '10.11.12.13'),
+ (lambda t: t.findall(parameter)[1].get('name'), 'DHCPSERVER'),
+ (lambda t: t.findall(parameter)[1].get('value'), '10.0.0.1'),
(lambda t: t.find('./devices/serial/source').get(
'path').split('/')[1], 'console.log'),
(lambda t: t.find('./memory').text, '2097152')]
@@ -359,7 +420,7 @@ class LibvirtConnTestCase(test.TestCase):
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
FLAGS.libvirt_type = libvirt_type
- conn = libvirt_conn.LibvirtConnection(True)
+ conn = connection.LibvirtConnection(True)
uri = conn.get_uri()
self.assertEquals(uri, expected_uri)
@@ -386,7 +447,7 @@ class LibvirtConnTestCase(test.TestCase):
FLAGS.libvirt_uri = testuri
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
FLAGS.libvirt_type = libvirt_type
- conn = libvirt_conn.LibvirtConnection(True)
+ conn = connection.LibvirtConnection(True)
uri = conn.get_uri()
self.assertEquals(uri, testuri)
db.instance_destroy(user_context, instance_ref['id'])
@@ -410,13 +471,13 @@ class LibvirtConnTestCase(test.TestCase):
self.create_fake_libvirt_mock(getVersion=getVersion,
getType=getType,
listDomainsID=listDomainsID)
- self.mox.StubOutWithMock(libvirt_conn.LibvirtConnection,
+ self.mox.StubOutWithMock(connection.LibvirtConnection,
'get_cpu_info')
- libvirt_conn.LibvirtConnection.get_cpu_info().AndReturn('cpuinfo')
+ connection.LibvirtConnection.get_cpu_info().AndReturn('cpuinfo')
# Start test
self.mox.ReplayAll()
- conn = libvirt_conn.LibvirtConnection(False)
+ conn = connection.LibvirtConnection(False)
conn.update_available_resource(self.context, 'dummy')
service_ref = db.service_get(self.context, service_ref['id'])
compute_node = service_ref['compute_node'][0]
@@ -450,8 +511,8 @@ class LibvirtConnTestCase(test.TestCase):
self.create_fake_libvirt_mock()
self.mox.ReplayAll()
- conn = libvirt_conn.LibvirtConnection(False)
- self.assertRaises(exception.Invalid,
+ conn = connection.LibvirtConnection(False)
+ self.assertRaises(exception.ComputeServiceUnavailable,
conn.update_available_resource,
self.context, 'dummy')
@@ -479,15 +540,16 @@ class LibvirtConnTestCase(test.TestCase):
fake_timer = FakeTime()
- self.create_fake_libvirt_mock(nwfilterLookupByName=fake_raise)
+ self.create_fake_libvirt_mock()
instance_ref = db.instance_create(self.context, self.test_instance)
# Start test
self.mox.ReplayAll()
try:
- conn = libvirt_conn.LibvirtConnection(False)
+ conn = connection.LibvirtConnection(False)
conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
+ conn.firewall_driver.setattr('instance_filter_exists', fake_none)
conn.ensure_filtering_rules_for_instance(instance_ref,
time=fake_timer)
except exception.Error, e:
@@ -533,7 +595,7 @@ class LibvirtConnTestCase(test.TestCase):
# Start test
self.mox.ReplayAll()
- conn = libvirt_conn.LibvirtConnection(False)
+ conn = connection.LibvirtConnection(False)
self.assertRaises(libvirt.libvirtError,
conn._live_migration,
self.context, instance_ref, 'dest', '',
@@ -548,6 +610,48 @@ class LibvirtConnTestCase(test.TestCase):
db.volume_destroy(self.context, volume_ref['id'])
db.instance_destroy(self.context, instance_ref['id'])
+ def test_spawn_with_network_info(self):
+ # Skip if non-libvirt environment
+ if not self.lazy_load_library_exists():
+ return
+
+ # Preparing mocks
+ def fake_none(self, instance):
+ return
+
+ self.create_fake_libvirt_mock()
+ instance = db.instance_create(self.context, self.test_instance)
+
+ # Start test
+ self.mox.ReplayAll()
+ conn = connection.LibvirtConnection(False)
+ conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
+ conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
+
+ network = db.project_get_network(context.get_admin_context(),
+ self.project.id)
+ ip_dict = {'ip': self.test_ip,
+ 'netmask': network['netmask'],
+ 'enabled': '1'}
+ mapping = {'label': network['label'],
+ 'gateway': network['gateway'],
+ 'mac': instance['mac_address'],
+ 'dns': [network['dns']],
+ 'ips': [ip_dict]}
+ network_info = [(network, mapping)]
+
+ try:
+ conn.spawn(instance, network_info)
+ except Exception, e:
+ count = (0 <= str(e.message).find('Unexpected method call'))
+
+ self.assertTrue(count)
+
+ def test_get_host_ip_addr(self):
+ conn = connection.LibvirtConnection(False)
+ ip = conn.get_host_ip_addr()
+ self.assertEquals(ip, FLAGS.my_ip)
+
def tearDown(self):
self.manager.delete_project(self.project)
self.manager.delete_user(self.user)
@@ -570,7 +674,7 @@ class IptablesFirewallTestCase(test.TestCase):
"""setup_basic_rules in nwfilter calls this."""
pass
self.fake_libvirt_connection = FakeLibvirtConnection()
- self.fw = libvirt_conn.IptablesFirewallDriver(
+ self.fw = firewall.IptablesFirewallDriver(
get_connection=lambda: self.fake_libvirt_connection)
def tearDown(self):
@@ -615,11 +719,15 @@ class IptablesFirewallTestCase(test.TestCase):
'# Completed on Tue Jan 18 23:47:56 2011',
]
+ def _create_instance_ref(self):
+ return db.instance_create(self.context,
+ {'user_id': 'fake',
+ 'project_id': 'fake',
+ 'mac_address': '56:12:12:12:12:12',
+ 'instance_type_id': 1})
+
def test_static_filters(self):
- instance_ref = db.instance_create(self.context,
- {'user_id': 'fake',
- 'project_id': 'fake',
- 'mac_address': '56:12:12:12:12:12'})
+ instance_ref = self._create_instance_ref()
ip = '10.11.12.13'
network_ref = db.project_get_network(self.context,
@@ -730,6 +838,50 @@ class IptablesFirewallTestCase(test.TestCase):
"TCP port 80/81 acceptance rule wasn't added")
db.instance_destroy(admin_ctxt, instance_ref['id'])
+ def test_filters_for_instance_with_ip_v6(self):
+ self.flags(use_ipv6=True)
+ network_info = _create_network_info()
+ rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info)
+ self.assertEquals(len(rulesv4), 2)
+ self.assertEquals(len(rulesv6), 3)
+
+ def test_filters_for_instance_without_ip_v6(self):
+ self.flags(use_ipv6=False)
+ network_info = _create_network_info()
+ rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info)
+ self.assertEquals(len(rulesv4), 2)
+ self.assertEquals(len(rulesv6), 0)
+
+ def test_multinic_iptables(self):
+ ipv4_rules_per_network = 2
+ ipv6_rules_per_network = 3
+ networks_count = 5
+ instance_ref = self._create_instance_ref()
+ network_info = _create_network_info(networks_count)
+ ipv4_len = len(self.fw.iptables.ipv4['filter'].rules)
+ ipv6_len = len(self.fw.iptables.ipv6['filter'].rules)
+ inst_ipv4, inst_ipv6 = self.fw.instance_rules(instance_ref,
+ network_info)
+ self.fw.add_filters_for_instance(instance_ref, network_info)
+ ipv4 = self.fw.iptables.ipv4['filter'].rules
+ ipv6 = self.fw.iptables.ipv6['filter'].rules
+ ipv4_network_rules = len(ipv4) - len(inst_ipv4) - ipv4_len
+ ipv6_network_rules = len(ipv6) - len(inst_ipv6) - ipv6_len
+ self.assertEquals(ipv4_network_rules,
+ ipv4_rules_per_network * networks_count)
+ self.assertEquals(ipv6_network_rules,
+ ipv6_rules_per_network * networks_count)
+
+ def test_do_refresh_security_group_rules(self):
+ instance_ref = self._create_instance_ref()
+ self.mox.StubOutWithMock(self.fw,
+ 'add_filters_for_instance',
+ use_mock_anything=True)
+ self.fw.add_filters_for_instance(instance_ref, mox.IgnoreArg())
+ self.fw.instances[instance_ref['id']] = instance_ref
+ self.mox.ReplayAll()
+ self.fw.do_refresh_security_group_rules("fake")
+
def test_provider_firewall_rules(self):
# setup basic instance data
instance_ref = db.instance_create(self.context,
@@ -801,7 +953,7 @@ class NWFilterTestCase(test.TestCase):
self.fake_libvirt_connection = Mock()
- self.fw = libvirt_conn.NWFilterFirewall(
+ self.fw = firewall.NWFilterFirewall(
lambda: self.fake_libvirt_connection)
def tearDown(self):
@@ -866,6 +1018,28 @@ class NWFilterTestCase(test.TestCase):
return db.security_group_get_by_name(self.context, 'fake', 'testgroup')
+ def _create_instance(self):
+ return db.instance_create(self.context,
+ {'user_id': 'fake',
+ 'project_id': 'fake',
+ 'mac_address': '00:A0:C9:14:C8:29',
+ 'instance_type_id': 1})
+
+ def _create_instance_type(self, params={}):
+ """Create a test instance"""
+ context = self.context.elevated()
+ inst = {}
+ inst['name'] = 'm1.small'
+ inst['memory_mb'] = '1024'
+ inst['vcpus'] = '1'
+ inst['local_gb'] = '20'
+ inst['flavorid'] = '1'
+ inst['swap'] = '2048'
+ inst['rxtx_quota'] = 100
+ inst['rxtx_cap'] = 200
+ inst.update(params)
+ return db.instance_type_create(context, inst)['id']
+
def test_creates_base_rule_first(self):
# These come pre-defined by libvirt
self.defined_filters = ['no-mac-spoofing',
@@ -894,24 +1068,18 @@ class NWFilterTestCase(test.TestCase):
self.fake_libvirt_connection.nwfilterDefineXML = _filterDefineXMLMock
- instance_ref = db.instance_create(self.context,
- {'user_id': 'fake',
- 'project_id': 'fake',
- 'mac_address': '00:A0:C9:14:C8:29'})
+ instance_ref = self._create_instance()
inst_id = instance_ref['id']
ip = '10.11.12.13'
- network_ref = db.project_get_network(self.context,
- 'fake')
-
- fixed_ip = {'address': ip,
- 'network_id': network_ref['id']}
+ network_ref = db.project_get_network(self.context, 'fake')
+ fixed_ip = {'address': ip, 'network_id': network_ref['id']}
admin_ctxt = context.get_admin_context()
db.fixed_ip_create(admin_ctxt, fixed_ip)
db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
- 'instance_id': instance_ref['id']})
+ 'instance_id': inst_id})
def _ensure_all_called():
instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'],
@@ -937,3 +1105,11 @@ class NWFilterTestCase(test.TestCase):
_ensure_all_called()
self.teardown_security_group()
db.instance_destroy(admin_ctxt, instance_ref['id'])
+
+ def test_create_network_filters(self):
+ instance_ref = self._create_instance()
+ network_info = _create_network_info(3)
+ result = self.fw._create_network_filters(instance_ref,
+ network_info,
+ "fake")
+ self.assertEquals(len(result), 3)
diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py
index 4e17e1ce0..cf8f4c05e 100644
--- a/nova/tests/test_misc.py
+++ b/nova/tests/test_misc.py
@@ -29,11 +29,12 @@ from nova.utils import parse_mailmap, str_dict_replace
class ProjectTestCase(test.TestCase):
def test_authors_up_to_date(self):
topdir = os.path.normpath(os.path.dirname(__file__) + '/../../')
- if os.path.exists(os.path.join(topdir, '.bzr')):
- contributors = set()
-
- mailmap = parse_mailmap(os.path.join(topdir, '.mailmap'))
+ missing = set()
+ contributors = set()
+ mailmap = parse_mailmap(os.path.join(topdir, '.mailmap'))
+ authors_file = open(os.path.join(topdir, 'Authors'), 'r').read()
+ if os.path.exists(os.path.join(topdir, '.bzr')):
import bzrlib.workingtree
tree = bzrlib.workingtree.WorkingTree.open(topdir)
tree.lock_read()
@@ -47,22 +48,36 @@ class ProjectTestCase(test.TestCase):
for r in revs:
for author in r.get_apparent_authors():
email = author.split(' ')[-1]
- contributors.add(str_dict_replace(email, mailmap))
+ contributors.add(str_dict_replace(email,
+ mailmap))
+ finally:
+ tree.unlock()
- authors_file = open(os.path.join(topdir, 'Authors'),
- 'r').read()
+ elif os.path.exists(os.path.join(topdir, '.git')):
+ import git
+ repo = git.Repo(topdir)
+ for commit in repo.head.commit.iter_parents():
+ email = commit.author.email
+ if email is None:
+ email = commit.author.name
+ if 'nova-core' in email:
+ continue
+ if email.split(' ')[-1] == '<>':
+ email = email.split(' ')[-2]
+ email = '<' + email + '>'
+ contributors.add(str_dict_replace(email, mailmap))
- missing = set()
- for contributor in contributors:
- if contributor == 'nova-core':
- continue
- if not contributor in authors_file:
- missing.add(contributor)
+ else:
+ return
- self.assertTrue(len(missing) == 0,
- '%r not listed in Authors' % missing)
- finally:
- tree.unlock()
+ for contributor in contributors:
+ if contributor == 'nova-core':
+ continue
+ if not contributor in authors_file:
+ missing.add(contributor)
+
+ self.assertTrue(len(missing) == 0,
+ '%r not listed in Authors' % missing)
class LockTestCase(test.TestCase):
diff --git a/nova/tests/test_notifier.py b/nova/tests/test_notifier.py
new file mode 100644
index 000000000..b6b0fcc68
--- /dev/null
+++ b/nova/tests/test_notifier.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 nova
+
+from nova import context
+from nova import flags
+from nova import rpc
+import nova.notifier.api
+from nova.notifier.api import notify
+from nova.notifier import no_op_notifier
+from nova.notifier import rabbit_notifier
+from nova import test
+
+import stubout
+
+
+class NotifierTestCase(test.TestCase):
+ """Test case for notifications"""
+ def setUp(self):
+ super(NotifierTestCase, self).setUp()
+ self.stubs = stubout.StubOutForTesting()
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(NotifierTestCase, self).tearDown()
+
+ def test_send_notification(self):
+ self.notify_called = False
+
+ def mock_notify(cls, *args):
+ self.notify_called = True
+
+ self.stubs.Set(nova.notifier.no_op_notifier, 'notify',
+ mock_notify)
+
+ class Mock(object):
+ pass
+ notify('publisher_id', 'event_type',
+ nova.notifier.api.WARN, dict(a=3))
+ self.assertEqual(self.notify_called, True)
+
+ def test_verify_message_format(self):
+ """A test to ensure changing the message format is prohibitively
+ annoying"""
+
+ def message_assert(message):
+ fields = [('publisher_id', 'publisher_id'),
+ ('event_type', 'event_type'),
+ ('priority', 'WARN'),
+ ('payload', dict(a=3))]
+ for k, v in fields:
+ self.assertEqual(message[k], v)
+ self.assertTrue(len(message['message_id']) > 0)
+ self.assertTrue(len(message['timestamp']) > 0)
+
+ self.stubs.Set(nova.notifier.no_op_notifier, 'notify',
+ message_assert)
+ notify('publisher_id', 'event_type',
+ nova.notifier.api.WARN, dict(a=3))
+
+ def test_send_rabbit_notification(self):
+ self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
+ 'nova.notifier.rabbit_notifier')
+ self.mock_cast = False
+
+ def mock_cast(cls, *args):
+ self.mock_cast = True
+
+ class Mock(object):
+ pass
+
+ self.stubs.Set(nova.rpc, 'cast', mock_cast)
+ notify('publisher_id', 'event_type',
+ nova.notifier.api.WARN, dict(a=3))
+
+ self.assertEqual(self.mock_cast, True)
+
+ def test_invalid_priority(self):
+ def mock_cast(cls, *args):
+ pass
+
+ class Mock(object):
+ pass
+
+ self.stubs.Set(nova.rpc, 'cast', mock_cast)
+ self.assertRaises(nova.notifier.api.BadPriorityException,
+ notify, 'publisher_id',
+ 'event_type', 'not a priority', dict(a=3))
+
+ def test_rabbit_priority_queue(self):
+ self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
+ 'nova.notifier.rabbit_notifier')
+ self.stubs.Set(nova.flags.FLAGS, 'notification_topic',
+ 'testnotify')
+
+ self.test_topic = None
+
+ def mock_cast(context, topic, msg):
+ self.test_topic = topic
+
+ self.stubs.Set(nova.rpc, 'cast', mock_cast)
+ notify('publisher_id',
+ 'event_type', 'DEBUG', dict(a=3))
+ self.assertEqual(self.test_topic, 'testnotify.debug')
diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py
index c65bc459d..916fca55e 100644
--- a/nova/tests/test_quota.py
+++ b/nova/tests/test_quota.py
@@ -67,7 +67,7 @@ class QuotaTestCase(test.TestCase):
inst['reservation_id'] = 'r-fakeres'
inst['user_id'] = self.user.id
inst['project_id'] = self.project.id
- inst['instance_type'] = 'm1.large'
+ inst['instance_type_id'] = '3' # m1.large
inst['vcpus'] = cores
inst['mac_address'] = utils.generate_mac()
return db.instance_create(self.context, inst)['id']
@@ -96,39 +96,133 @@ class QuotaTestCase(test.TestCase):
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 2)
- db.quota_create(self.context, {'project_id': self.project.id,
- 'instances': 10})
+ db.quota_create(self.context, self.project.id, 'instances', 10)
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 4)
- db.quota_update(self.context, self.project.id, {'cores': 100})
+ db.quota_create(self.context, self.project.id, 'cores', 100)
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 10)
+ db.quota_create(self.context, self.project.id, 'ram', 3 * 2048)
+ num_instances = quota.allowed_instances(self.context, 100,
+ self._get_instance_type('m1.small'))
+ self.assertEqual(num_instances, 3)
# metadata_items
too_many_items = FLAGS.quota_metadata_items + 1000
num_metadata_items = quota.allowed_metadata_items(self.context,
too_many_items)
self.assertEqual(num_metadata_items, FLAGS.quota_metadata_items)
- db.quota_update(self.context, self.project.id, {'metadata_items': 5})
+ db.quota_create(self.context, self.project.id, 'metadata_items', 5)
num_metadata_items = quota.allowed_metadata_items(self.context,
too_many_items)
self.assertEqual(num_metadata_items, 5)
# Cleanup
- db.quota_destroy(self.context, self.project.id)
+ db.quota_destroy_all_by_project(self.context, self.project.id)
+
+ def test_unlimited_instances(self):
+ FLAGS.quota_instances = 2
+ FLAGS.quota_ram = -1
+ FLAGS.quota_cores = -1
+ instance_type = self._get_instance_type('m1.small')
+ num_instances = quota.allowed_instances(self.context, 100,
+ instance_type)
+ self.assertEqual(num_instances, 2)
+ db.quota_create(self.context, self.project.id, 'instances', None)
+ num_instances = quota.allowed_instances(self.context, 100,
+ instance_type)
+ self.assertEqual(num_instances, 100)
+ num_instances = quota.allowed_instances(self.context, 101,
+ instance_type)
+ self.assertEqual(num_instances, 101)
+
+ def test_unlimited_ram(self):
+ FLAGS.quota_instances = -1
+ FLAGS.quota_ram = 2 * 2048
+ FLAGS.quota_cores = -1
+ instance_type = self._get_instance_type('m1.small')
+ num_instances = quota.allowed_instances(self.context, 100,
+ instance_type)
+ self.assertEqual(num_instances, 2)
+ db.quota_create(self.context, self.project.id, 'ram', None)
+ num_instances = quota.allowed_instances(self.context, 100,
+ instance_type)
+ self.assertEqual(num_instances, 100)
+ num_instances = quota.allowed_instances(self.context, 101,
+ instance_type)
+ self.assertEqual(num_instances, 101)
+
+ def test_unlimited_cores(self):
+ FLAGS.quota_instances = -1
+ FLAGS.quota_ram = -1
+ FLAGS.quota_cores = 2
+ instance_type = self._get_instance_type('m1.small')
+ num_instances = quota.allowed_instances(self.context, 100,
+ instance_type)
+ self.assertEqual(num_instances, 2)
+ db.quota_create(self.context, self.project.id, 'cores', None)
+ num_instances = quota.allowed_instances(self.context, 100,
+ instance_type)
+ self.assertEqual(num_instances, 100)
+ num_instances = quota.allowed_instances(self.context, 101,
+ instance_type)
+ self.assertEqual(num_instances, 101)
+
+ def test_unlimited_volumes(self):
+ FLAGS.quota_volumes = 10
+ FLAGS.quota_gigabytes = -1
+ volumes = quota.allowed_volumes(self.context, 100, 1)
+ self.assertEqual(volumes, 10)
+ db.quota_create(self.context, self.project.id, 'volumes', None)
+ volumes = quota.allowed_volumes(self.context, 100, 1)
+ self.assertEqual(volumes, 100)
+ volumes = quota.allowed_volumes(self.context, 101, 1)
+ self.assertEqual(volumes, 101)
+
+ def test_unlimited_gigabytes(self):
+ FLAGS.quota_volumes = -1
+ FLAGS.quota_gigabytes = 10
+ volumes = quota.allowed_volumes(self.context, 100, 1)
+ self.assertEqual(volumes, 10)
+ db.quota_create(self.context, self.project.id, 'gigabytes', None)
+ volumes = quota.allowed_volumes(self.context, 100, 1)
+ self.assertEqual(volumes, 100)
+ volumes = quota.allowed_volumes(self.context, 101, 1)
+ self.assertEqual(volumes, 101)
+
+ def test_unlimited_floating_ips(self):
+ FLAGS.quota_floating_ips = 10
+ floating_ips = quota.allowed_floating_ips(self.context, 100)
+ self.assertEqual(floating_ips, 10)
+ db.quota_create(self.context, self.project.id, 'floating_ips', None)
+ floating_ips = quota.allowed_floating_ips(self.context, 100)
+ self.assertEqual(floating_ips, 100)
+ floating_ips = quota.allowed_floating_ips(self.context, 101)
+ self.assertEqual(floating_ips, 101)
+
+ def test_unlimited_metadata_items(self):
+ FLAGS.quota_metadata_items = 10
+ items = quota.allowed_metadata_items(self.context, 100)
+ self.assertEqual(items, 10)
+ db.quota_create(self.context, self.project.id, 'metadata_items', None)
+ items = quota.allowed_metadata_items(self.context, 100)
+ self.assertEqual(items, 100)
+ items = quota.allowed_metadata_items(self.context, 101)
+ self.assertEqual(items, 101)
def test_too_many_instances(self):
instance_ids = []
for i in range(FLAGS.quota_instances):
instance_id = self._create_instance()
instance_ids.append(instance_id)
+ inst_type = instance_types.get_instance_type_by_name('m1.small')
self.assertRaises(quota.QuotaError, compute.API().create,
self.context,
min_count=1,
max_count=1,
- instance_type='m1.small',
+ instance_type=inst_type,
image_id=1)
for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id)
@@ -137,11 +231,12 @@ class QuotaTestCase(test.TestCase):
instance_ids = []
instance_id = self._create_instance(cores=4)
instance_ids.append(instance_id)
+ inst_type = instance_types.get_instance_type_by_name('m1.small')
self.assertRaises(quota.QuotaError, compute.API().create,
self.context,
min_count=1,
max_count=1,
- instance_type='m1.small',
+ instance_type=inst_type,
image_id=1)
for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id)
@@ -192,28 +287,68 @@ class QuotaTestCase(test.TestCase):
metadata = {}
for i in range(FLAGS.quota_metadata_items + 1):
metadata['key%s' % i] = 'value%s' % i
+ inst_type = instance_types.get_instance_type_by_name('m1.small')
self.assertRaises(quota.QuotaError, compute.API().create,
self.context,
min_count=1,
max_count=1,
- instance_type='m1.small',
+ instance_type=inst_type,
image_id='fake',
metadata=metadata)
- def test_allowed_injected_files(self):
- self.assertEqual(
- quota.allowed_injected_files(self.context),
- FLAGS.quota_max_injected_files)
+ def test_default_allowed_injected_files(self):
+ FLAGS.quota_max_injected_files = 55
+ self.assertEqual(quota.allowed_injected_files(self.context, 100), 55)
+
+ def test_overridden_allowed_injected_files(self):
+ FLAGS.quota_max_injected_files = 5
+ db.quota_create(self.context, self.project.id, 'injected_files', 77)
+ self.assertEqual(quota.allowed_injected_files(self.context, 100), 77)
+
+ def test_unlimited_default_allowed_injected_files(self):
+ FLAGS.quota_max_injected_files = -1
+ self.assertEqual(quota.allowed_injected_files(self.context, 100), 100)
+
+ def test_unlimited_db_allowed_injected_files(self):
+ FLAGS.quota_max_injected_files = 5
+ db.quota_create(self.context, self.project.id, 'injected_files', None)
+ self.assertEqual(quota.allowed_injected_files(self.context, 100), 100)
+
+ def test_default_allowed_injected_file_content_bytes(self):
+ FLAGS.quota_max_injected_file_content_bytes = 12345
+ limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
+ self.assertEqual(limit, 12345)
+
+ def test_overridden_allowed_injected_file_content_bytes(self):
+ FLAGS.quota_max_injected_file_content_bytes = 12345
+ db.quota_create(self.context, self.project.id,
+ 'injected_file_content_bytes', 5678)
+ limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
+ self.assertEqual(limit, 5678)
+
+ def test_unlimited_default_allowed_injected_file_content_bytes(self):
+ FLAGS.quota_max_injected_file_content_bytes = -1
+ limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
+ self.assertEqual(limit, 23456)
+
+ def test_unlimited_db_allowed_injected_file_content_bytes(self):
+ FLAGS.quota_max_injected_file_content_bytes = 12345
+ db.quota_create(self.context, self.project.id,
+ 'injected_file_content_bytes', None)
+ limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
+ self.assertEqual(limit, 23456)
def _create_with_injected_files(self, files):
api = compute.API(image_service=self.StubImageService())
+ inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, min_count=1, max_count=1,
- instance_type='m1.small', image_id='fake',
+ instance_type=inst_type, image_id='fake',
injected_files=files)
def test_no_injected_files(self):
api = compute.API(image_service=self.StubImageService())
- api.create(self.context, instance_type='m1.small', image_id='fake')
+ inst_type = instance_types.get_instance_type_by_name('m1.small')
+ api.create(self.context, instance_type=inst_type, image_id='fake')
def test_max_injected_files(self):
files = []
@@ -228,11 +363,6 @@ class QuotaTestCase(test.TestCase):
self.assertRaises(quota.QuotaError,
self._create_with_injected_files, files)
- def test_allowed_injected_file_content_bytes(self):
- self.assertEqual(
- quota.allowed_injected_file_content_bytes(self.context),
- FLAGS.quota_max_injected_file_content_bytes)
-
def test_max_injected_file_content_bytes(self):
max = FLAGS.quota_max_injected_file_content_bytes
content = ''.join(['a' for i in xrange(max)])
diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py
index 6df74dd61..54b3f80fb 100644
--- a/nova/tests/test_scheduler.py
+++ b/nova/tests/test_scheduler.py
@@ -120,12 +120,11 @@ class SchedulerTestCase(test.TestCase):
dest = 'dummydest'
ctxt = context.get_admin_context()
- try:
- scheduler.show_host_resources(ctxt, dest)
- except exception.NotFound, e:
- c1 = (e.message.find(_("does not exist or is not a "
- "compute node.")) >= 0)
- self.assertTrue(c1)
+ self.assertRaises(exception.NotFound, scheduler.show_host_resources,
+ ctxt, dest)
+ #TODO(bcwaldon): reimplement this functionality
+ #c1 = (e.message.find(_("does not exist or is not a "
+ # "compute node.")) >= 0)
def _dic_is_equal(self, dic1, dic2, keys=None):
"""Compares 2 dictionary contents(Helper method)"""
@@ -263,7 +262,7 @@ class SimpleDriverTestCase(test.TestCase):
inst['reservation_id'] = 'r-fakeres'
inst['user_id'] = self.user.id
inst['project_id'] = self.project.id
- inst['instance_type'] = 'm1.tiny'
+ inst['instance_type_id'] = '1'
inst['mac_address'] = utils.generate_mac()
inst['vcpus'] = kwargs.get('vcpus', 1)
inst['ami_launch_index'] = 0
@@ -698,14 +697,10 @@ class SimpleDriverTestCase(test.TestCase):
'topic': 'volume', 'report_count': 0}
s_ref = db.service_create(self.context, dic)
- try:
- self.scheduler.driver.schedule_live_migration(self.context,
- instance_id,
- i_ref['host'])
- except exception.Invalid, e:
- c = (e.message.find('volume node is not alive') >= 0)
+ self.assertRaises(exception.VolumeServiceUnavailable,
+ self.scheduler.driver.schedule_live_migration,
+ self.context, instance_id, i_ref['host'])
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
db.volume_destroy(self.context, v_ref['id'])
@@ -718,13 +713,10 @@ class SimpleDriverTestCase(test.TestCase):
s_ref = self._create_compute_service(created_at=t, updated_at=t,
host=i_ref['host'])
- try:
- self.scheduler.driver._live_migration_src_check(self.context,
- i_ref)
- except exception.Invalid, e:
- c = (e.message.find('is not alive') >= 0)
+ self.assertRaises(exception.ComputeServiceUnavailable,
+ self.scheduler.driver._live_migration_src_check,
+ self.context, i_ref)
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -737,7 +729,7 @@ class SimpleDriverTestCase(test.TestCase):
ret = self.scheduler.driver._live_migration_src_check(self.context,
i_ref)
- self.assertTrue(ret == None)
+ self.assertTrue(ret is None)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -749,14 +741,10 @@ class SimpleDriverTestCase(test.TestCase):
s_ref = self._create_compute_service(created_at=t, updated_at=t,
host=i_ref['host'])
- try:
- self.scheduler.driver._live_migration_dest_check(self.context,
- i_ref,
- i_ref['host'])
- except exception.Invalid, e:
- c = (e.message.find('is not alive') >= 0)
+ self.assertRaises(exception.ComputeServiceUnavailable,
+ self.scheduler.driver._live_migration_dest_check,
+ self.context, i_ref, i_ref['host'])
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -766,14 +754,10 @@ class SimpleDriverTestCase(test.TestCase):
i_ref = db.instance_get(self.context, instance_id)
s_ref = self._create_compute_service(host=i_ref['host'])
- try:
- self.scheduler.driver._live_migration_dest_check(self.context,
- i_ref,
- i_ref['host'])
- except exception.Invalid, e:
- c = (e.message.find('choose other host') >= 0)
+ self.assertRaises(exception.UnableToMigrateToSelf,
+ self.scheduler.driver._live_migration_dest_check,
+ self.context, i_ref, i_ref['host'])
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -784,14 +768,10 @@ class SimpleDriverTestCase(test.TestCase):
s_ref = self._create_compute_service(host='somewhere',
memory_mb_used=12)
- try:
- self.scheduler.driver._live_migration_dest_check(self.context,
- i_ref,
- 'somewhere')
- except exception.NotEmpty, e:
- c = (e.message.find('Unable to migrate') >= 0)
+ self.assertRaises(exception.MigrationError,
+ self.scheduler.driver._live_migration_dest_check,
+ self.context, i_ref, 'somewhere')
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -805,7 +785,7 @@ class SimpleDriverTestCase(test.TestCase):
ret = self.scheduler.driver._live_migration_dest_check(self.context,
i_ref,
'somewhere')
- self.assertTrue(ret == None)
+ self.assertTrue(ret is None)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -837,14 +817,10 @@ class SimpleDriverTestCase(test.TestCase):
"args": {'filename': fpath}})
self.mox.ReplayAll()
- try:
- self.scheduler.driver._live_migration_common_check(self.context,
- i_ref,
- dest)
- except exception.Invalid, e:
- c = (e.message.find('does not exist') >= 0)
+ self.assertRaises(exception.SourceHostUnavailable,
+ self.scheduler.driver._live_migration_common_check,
+ self.context, i_ref, dest)
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
@@ -865,14 +841,10 @@ class SimpleDriverTestCase(test.TestCase):
driver.mounted_on_same_shared_storage(mox.IgnoreArg(), i_ref, dest)
self.mox.ReplayAll()
- try:
- self.scheduler.driver._live_migration_common_check(self.context,
- i_ref,
- dest)
- except exception.Invalid, e:
- c = (e.message.find(_('Different hypervisor type')) >= 0)
+ self.assertRaises(exception.InvalidHypervisorType,
+ self.scheduler.driver._live_migration_common_check,
+ self.context, i_ref, dest)
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
db.service_destroy(self.context, s_ref2['id'])
@@ -895,14 +867,10 @@ class SimpleDriverTestCase(test.TestCase):
driver.mounted_on_same_shared_storage(mox.IgnoreArg(), i_ref, dest)
self.mox.ReplayAll()
- try:
- self.scheduler.driver._live_migration_common_check(self.context,
- i_ref,
- dest)
- except exception.Invalid, e:
- c = (e.message.find(_('Older hypervisor version')) >= 0)
+ self.assertRaises(exception.DestinationHypervisorTooOld,
+ self.scheduler.driver._live_migration_common_check,
+ self.context, i_ref, dest)
- self.assertTrue(c)
db.instance_destroy(self.context, instance_id)
db.service_destroy(self.context, s_ref['id'])
db.service_destroy(self.context, s_ref2['id'])
@@ -944,7 +912,8 @@ class SimpleDriverTestCase(test.TestCase):
class FakeZone(object):
- def __init__(self, api_url, username, password):
+ def __init__(self, id, api_url, username, password):
+ self.id = id
self.api_url = api_url
self.username = username
self.password = password
@@ -952,7 +921,7 @@ class FakeZone(object):
def zone_get_all(context):
return [
- FakeZone('http://example.com', 'bob', 'xxx'),
+ FakeZone(1, 'http://example.com', 'bob', 'xxx'),
]
@@ -968,7 +937,7 @@ class FakeRerouteCompute(api.reroute_compute):
def go_boom(self, context, instance):
- raise exception.InstanceNotFound("boom message", instance)
+ raise exception.InstanceNotFound(instance_id=instance)
def found_instance(self, context, instance):
@@ -1017,11 +986,8 @@ class ZoneRedirectTest(test.TestCase):
def test_routing_flags(self):
FLAGS.enable_zone_routing = False
decorator = FakeRerouteCompute("foo")
- try:
- result = decorator(go_boom)(None, None, 1)
- self.assertFail(_("Should have thrown exception."))
- except exception.InstanceNotFound, e:
- self.assertEquals(e.message, 'boom message')
+ self.assertRaises(exception.InstanceNotFound, decorator(go_boom),
+ None, None, 1)
def test_get_collection_context_and_id(self):
decorator = api.reroute_compute("foo")
@@ -1072,7 +1038,7 @@ class FakeNovaClient(object):
class DynamicNovaClientTest(test.TestCase):
def test_issue_novaclient_command_found(self):
- zone = FakeZone('http://example.com', 'bob', 'xxx')
+ zone = FakeZone(1, 'http://example.com', 'bob', 'xxx')
self.assertEquals(api._issue_novaclient_command(
FakeNovaClient(FakeServerCollection()),
zone, "servers", "get", 100).a, 10)
@@ -1086,7 +1052,7 @@ class DynamicNovaClientTest(test.TestCase):
zone, "servers", "pause", 100), None)
def test_issue_novaclient_command_not_found(self):
- zone = FakeZone('http://example.com', 'bob', 'xxx')
+ zone = FakeZone(1, 'http://example.com', 'bob', 'xxx')
self.assertEquals(api._issue_novaclient_command(
FakeNovaClient(FakeEmptyServerCollection()),
zone, "servers", "get", 100), None)
@@ -1098,3 +1064,55 @@ class DynamicNovaClientTest(test.TestCase):
self.assertEquals(api._issue_novaclient_command(
FakeNovaClient(FakeEmptyServerCollection()),
zone, "servers", "any", "name"), None)
+
+
+class FakeZonesProxy(object):
+ def do_something(*args, **kwargs):
+ return 42
+
+ def raises_exception(*args, **kwargs):
+ raise Exception('testing')
+
+
+class FakeNovaClientOpenStack(object):
+ def __init__(self, *args, **kwargs):
+ self.zones = FakeZonesProxy()
+
+ def authenticate(self):
+ pass
+
+
+class CallZoneMethodTest(test.TestCase):
+ def setUp(self):
+ super(CallZoneMethodTest, self).setUp()
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(db, 'zone_get_all', zone_get_all)
+ self.stubs.Set(novaclient, 'OpenStack', FakeNovaClientOpenStack)
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(CallZoneMethodTest, self).tearDown()
+
+ def test_call_zone_method(self):
+ context = {}
+ method = 'do_something'
+ results = api.call_zone_method(context, method)
+ expected = [(1, 42)]
+ self.assertEqual(expected, results)
+
+ def test_call_zone_method_not_present(self):
+ context = {}
+ method = 'not_present'
+ self.assertRaises(AttributeError, api.call_zone_method,
+ context, method)
+
+ def test_call_zone_method_generates_exception(self):
+ context = {}
+ method = 'raises_exception'
+ results = api.call_zone_method(context, method)
+
+ # FIXME(sirp): for now the _error_trap code is catching errors and
+ # converting them to a ("ERROR", "string") tuples. The code (and this
+ # test) should eventually handle real exceptions.
+ expected = [(1, ('ERROR', 'testing'))]
+ self.assertEqual(expected, results)
diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index e08d229b0..8f7e83c3e 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -17,9 +17,9 @@
import os
import tempfile
+from nova import exception
from nova import test
from nova import utils
-from nova import exception
class ExecuteTestCase(test.TestCase):
@@ -250,3 +250,28 @@ class GetFromPathTestCase(test.TestCase):
input = {'a': [1, 2, {'b': 'b_1'}]}
self.assertEquals([1, 2, {'b': 'b_1'}], f(input, "a"))
self.assertEquals(['b_1'], f(input, "a/b"))
+
+
+class GenericUtilsTestCase(test.TestCase):
+ def test_parse_server_string(self):
+ result = utils.parse_server_string('::1')
+ self.assertEqual(('::1', ''), result)
+ result = utils.parse_server_string('[::1]:8773')
+ self.assertEqual(('::1', '8773'), result)
+ result = utils.parse_server_string('2001:db8::192.168.1.1')
+ self.assertEqual(('2001:db8::192.168.1.1', ''), result)
+ result = utils.parse_server_string('[2001:db8::192.168.1.1]:8773')
+ self.assertEqual(('2001:db8::192.168.1.1', '8773'), result)
+ result = utils.parse_server_string('192.168.1.1')
+ self.assertEqual(('192.168.1.1', ''), result)
+ result = utils.parse_server_string('192.168.1.2:8773')
+ self.assertEqual(('192.168.1.2', '8773'), result)
+ result = utils.parse_server_string('192.168.1.3')
+ self.assertEqual(('192.168.1.3', ''), result)
+ result = utils.parse_server_string('www.example.com:8443')
+ self.assertEqual(('www.example.com', '8443'), result)
+ result = utils.parse_server_string('www.example.com')
+ self.assertEqual(('www.example.com', ''), result)
+ # error case
+ result = utils.parse_server_string('www.exa:mple.com:8443')
+ self.assertEqual(('', ''), result)
diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py
index d71b75f3f..236d12434 100644
--- a/nova/tests/test_volume.py
+++ b/nova/tests/test_volume.py
@@ -106,7 +106,7 @@ class VolumeTestCase(test.TestCase):
inst['launch_time'] = '10'
inst['user_id'] = 'fake'
inst['project_id'] = 'fake'
- inst['instance_type'] = 'm1.tiny'
+ inst['instance_type_id'] = '2' # m1.tiny
inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0
instance_id = db.instance_create(self.context, inst)['id']
@@ -142,7 +142,7 @@ class VolumeTestCase(test.TestCase):
self.assertEqual(vol['status'], "available")
self.volume.delete_volume(self.context, volume_id)
- self.assertRaises(exception.Error,
+ self.assertRaises(exception.VolumeNotFound,
db.volume_get,
self.context,
volume_id)
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 17e3f55e9..be1e35697 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -16,7 +16,9 @@
"""Test suite for XenAPI."""
+import eventlet
import functools
+import json
import os
import re
import stubout
@@ -80,7 +82,7 @@ class XenAPIVolumeTestCase(test.TestCase):
'image_id': 1,
'kernel_id': 2,
'ramdisk_id': 3,
- 'instance_type': 'm1.large',
+ 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'}
@@ -197,6 +199,28 @@ class XenAPIVMTestCase(test.TestCase):
self.context = context.RequestContext('fake', 'fake', False)
self.conn = xenapi_conn.get_connection(False)
+ def test_parallel_builds(self):
+ stubs.stubout_loopingcall_delay(self.stubs)
+
+ def _do_build(id, proj, user, *args):
+ values = {
+ 'id': id,
+ 'project_id': proj,
+ 'user_id': user,
+ 'image_id': 1,
+ 'kernel_id': 2,
+ 'ramdisk_id': 3,
+ 'instance_type_id': '3', # m1.large
+ 'mac_address': 'aa:bb:cc:dd:ee:ff',
+ 'os_type': 'linux'}
+ instance = db.instance_create(self.context, values)
+ self.conn.spawn(instance)
+
+ gt1 = eventlet.spawn(_do_build, 1, self.project.id, self.user.id)
+ gt2 = eventlet.spawn(_do_build, 2, self.project.id, self.user.id)
+ gt1.wait()
+ gt2.wait()
+
def test_list_instances_0(self):
instances = self.conn.list_instances()
self.assertEquals(instances, [])
@@ -289,11 +313,11 @@ class XenAPIVMTestCase(test.TestCase):
'enabled':'1'}],
'ip6s': [{'ip': 'fe80::a8bb:ccff:fedd:eeff',
'netmask': '120',
- 'enabled': '1',
- 'gateway': 'fe80::a00:1'}],
+ 'enabled': '1'}],
'mac': 'aa:bb:cc:dd:ee:ff',
'dns': ['10.0.0.2'],
- 'gateway': '10.0.0.1'})
+ 'gateway': '10.0.0.1',
+ 'gateway6': 'fe80::a00:1'})
def check_vm_params_for_windows(self):
self.assertEquals(self.vm['platform']['nx'], 'true')
@@ -328,7 +352,7 @@ class XenAPIVMTestCase(test.TestCase):
self.assertEquals(self.vm['HVM_boot_policy'], '')
def _test_spawn(self, image_id, kernel_id, ramdisk_id,
- instance_type="m1.large", os_type="linux",
+ instance_type_id="3", os_type="linux",
instance_id=1, check_injection=False):
stubs.stubout_loopingcall_start(self.stubs)
values = {'id': instance_id,
@@ -337,7 +361,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': image_id,
'kernel_id': kernel_id,
'ramdisk_id': ramdisk_id,
- 'instance_type': instance_type,
+ 'instance_type_id': instance_type_id,
'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': os_type}
instance = db.instance_create(self.context, values)
@@ -349,7 +373,7 @@ class XenAPIVMTestCase(test.TestCase):
FLAGS.xenapi_image_service = 'glance'
self.assertRaises(Exception,
self._test_spawn,
- 1, 2, 3, "m1.xlarge")
+ 1, 2, 3, "4") # m1.xlarge
def test_spawn_raw_objectstore(self):
FLAGS.xenapi_image_service = 'objectstore'
@@ -523,7 +547,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': 1,
'kernel_id': 2,
'ramdisk_id': 3,
- 'instance_type': 'm1.large',
+ 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'}
instance = db.instance_create(self.context, values)
@@ -580,7 +604,7 @@ class XenAPIMigrateInstance(test.TestCase):
'kernel_id': None,
'ramdisk_id': None,
'local_gb': 5,
- 'instance_type': 'm1.large',
+ 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'}
@@ -665,3 +689,52 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
self.fake_instance.image_id = glance_stubs.FakeGlance.IMAGE_VHD
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_VHD)
+
+
+class FakeXenApi(object):
+ """Fake XenApi for testing HostState."""
+
+ class FakeSR(object):
+ def get_record(self, ref):
+ return {'virtual_allocation': 10000,
+ 'physical_utilisation': 20000}
+
+ SR = FakeSR()
+
+
+class FakeSession(object):
+ """Fake Session class for HostState testing."""
+
+ def async_call_plugin(self, *args):
+ return None
+
+ def wait_for_task(self, *args):
+ vm = {'total': 10,
+ 'overhead': 20,
+ 'free': 30,
+ 'free-computed': 40}
+ return json.dumps({'host_memory': vm})
+
+ def get_xenapi(self):
+ return FakeXenApi()
+
+
+class HostStateTestCase(test.TestCase):
+ """Tests HostState, which holds metrics from XenServer that get
+ reported back to the Schedulers."""
+
+ def _fake_safe_find_sr(self, session):
+ """None SR ref since we're ignoring it in FakeSR."""
+ return None
+
+ def test_host_state(self):
+ self.stubs = stubout.StubOutForTesting()
+ self.stubs.Set(vm_utils, 'safe_find_sr', self._fake_safe_find_sr)
+ host_state = xenapi_conn.HostState(FakeSession())
+ stats = host_state._stats
+ self.assertEquals(stats['disk_total'], 10000)
+ self.assertEquals(stats['disk_used'], 20000)
+ self.assertEquals(stats['host_memory_total'], 10)
+ self.assertEquals(stats['host_memory_overhead'], 20)
+ self.assertEquals(stats['host_memory_free'], 30)
+ self.assertEquals(stats['host_memory_free_computed'], 40)
diff --git a/nova/tests/test_zone_aware_scheduler.py b/nova/tests/test_zone_aware_scheduler.py
new file mode 100644
index 000000000..fdcde34c9
--- /dev/null
+++ b/nova/tests/test_zone_aware_scheduler.py
@@ -0,0 +1,119 @@
+# 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.
+"""
+Tests For Zone Aware Scheduler.
+"""
+
+from nova import test
+from nova.scheduler import driver
+from nova.scheduler import zone_aware_scheduler
+from nova.scheduler import zone_manager
+
+
+class FakeZoneAwareScheduler(zone_aware_scheduler.ZoneAwareScheduler):
+ def filter_hosts(self, num, specs):
+ # NOTE(sirp): this is returning [(hostname, services)]
+ return self.zone_manager.service_states.items()
+
+ def weigh_hosts(self, num, specs, hosts):
+ fake_weight = 99
+ weighted = []
+ for hostname, caps in hosts:
+ weighted.append(dict(weight=fake_weight, name=hostname))
+ return weighted
+
+
+class FakeZoneManager(zone_manager.ZoneManager):
+ def __init__(self):
+ self.service_states = {
+ 'host1': {
+ 'compute': {'ram': 1000}
+ },
+ 'host2': {
+ 'compute': {'ram': 2000}
+ },
+ 'host3': {
+ 'compute': {'ram': 3000}
+ }
+ }
+
+
+class FakeEmptyZoneManager(zone_manager.ZoneManager):
+ def __init__(self):
+ self.service_states = {}
+
+
+def fake_empty_call_zone_method(context, method, specs):
+ return []
+
+
+def fake_call_zone_method(context, method, specs):
+ return [
+ ('zone1', [
+ dict(weight=1, blob='AAAAAAA'),
+ dict(weight=111, blob='BBBBBBB'),
+ dict(weight=112, blob='CCCCCCC'),
+ dict(weight=113, blob='DDDDDDD'),
+ ]),
+ ('zone2', [
+ dict(weight=120, blob='EEEEEEE'),
+ dict(weight=2, blob='FFFFFFF'),
+ dict(weight=122, blob='GGGGGGG'),
+ dict(weight=123, blob='HHHHHHH'),
+ ]),
+ ('zone3', [
+ dict(weight=130, blob='IIIIIII'),
+ dict(weight=131, blob='JJJJJJJ'),
+ dict(weight=132, blob='KKKKKKK'),
+ dict(weight=3, blob='LLLLLLL'),
+ ]),
+ ]
+
+
+class ZoneAwareSchedulerTestCase(test.TestCase):
+ """Test case for Zone Aware Scheduler."""
+
+ def test_zone_aware_scheduler(self):
+ """
+ Create a nested set of FakeZones, ensure that a select call returns the
+ appropriate build plan.
+ """
+ sched = FakeZoneAwareScheduler()
+ self.stubs.Set(sched, '_call_zone_method', fake_call_zone_method)
+
+ zm = FakeZoneManager()
+ sched.set_zone_manager(zm)
+
+ fake_context = {}
+ build_plan = sched.select(fake_context, {})
+
+ self.assertEqual(15, len(build_plan))
+
+ hostnames = [plan_item['name']
+ for plan_item in build_plan if 'name' in plan_item]
+ self.assertEqual(3, len(hostnames))
+
+ def test_empty_zone_aware_scheduler(self):
+ """
+ Ensure empty hosts & child_zones result in NoValidHosts exception.
+ """
+ sched = FakeZoneAwareScheduler()
+ self.stubs.Set(sched, '_call_zone_method', fake_empty_call_zone_method)
+
+ zm = FakeEmptyZoneManager()
+ sched.set_zone_manager(zm)
+
+ fake_context = {}
+ self.assertRaises(driver.NoValidHost, sched.schedule, fake_context, {})
diff --git a/nova/tests/test_zones.py b/nova/tests/test_zones.py
index 688dc704d..e132809dc 100644
--- a/nova/tests/test_zones.py
+++ b/nova/tests/test_zones.py
@@ -78,38 +78,32 @@ class ZoneManagerTestCase(test.TestCase):
def test_service_capabilities(self):
zm = zone_manager.ZoneManager()
- caps = zm.get_zone_capabilities(self, None)
+ caps = zm.get_zone_capabilities(None)
self.assertEquals(caps, {})
zm.update_service_capabilities("svc1", "host1", dict(a=1, b=2))
- caps = zm.get_zone_capabilities(self, None)
+ caps = zm.get_zone_capabilities(None)
self.assertEquals(caps, dict(svc1_a=(1, 1), svc1_b=(2, 2)))
zm.update_service_capabilities("svc1", "host1", dict(a=2, b=3))
- caps = zm.get_zone_capabilities(self, None)
+ caps = zm.get_zone_capabilities(None)
self.assertEquals(caps, dict(svc1_a=(2, 2), svc1_b=(3, 3)))
zm.update_service_capabilities("svc1", "host2", dict(a=20, b=30))
- caps = zm.get_zone_capabilities(self, None)
+ caps = zm.get_zone_capabilities(None)
self.assertEquals(caps, dict(svc1_a=(2, 20), svc1_b=(3, 30)))
zm.update_service_capabilities("svc10", "host1", dict(a=99, b=99))
- caps = zm.get_zone_capabilities(self, None)
+ caps = zm.get_zone_capabilities(None)
self.assertEquals(caps, dict(svc1_a=(2, 20), svc1_b=(3, 30),
svc10_a=(99, 99), svc10_b=(99, 99)))
zm.update_service_capabilities("svc1", "host3", dict(c=5))
- caps = zm.get_zone_capabilities(self, None)
+ caps = zm.get_zone_capabilities(None)
self.assertEquals(caps, dict(svc1_a=(2, 20), svc1_b=(3, 30),
svc1_c=(5, 5), svc10_a=(99, 99),
svc10_b=(99, 99)))
- caps = zm.get_zone_capabilities(self, 'svc1')
- self.assertEquals(caps, dict(svc1_a=(2, 20), svc1_b=(3, 30),
- svc1_c=(5, 5)))
- caps = zm.get_zone_capabilities(self, 'svc10')
- self.assertEquals(caps, dict(svc10_a=(99, 99), svc10_b=(99, 99)))
-
def test_refresh_from_db_replace_existing(self):
zm = zone_manager.ZoneManager()
zone_state = zone_manager.ZoneState()
diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py
index 205f6c902..4833ccb07 100644
--- a/nova/tests/xenapi/stubs.py
+++ b/nova/tests/xenapi/stubs.py
@@ -16,6 +16,7 @@
"""Stubouts, mocks and fixtures for the test suite"""
+import eventlet
from nova.virt import xenapi_conn
from nova.virt.xenapi import fake
from nova.virt.xenapi import volume_utils
@@ -28,29 +29,6 @@ def stubout_instance_snapshot(stubs):
@classmethod
def fake_fetch_image(cls, session, instance_id, image, user, project,
type):
- # Stubout wait_for_task
- def fake_wait_for_task(self, task, id):
- class FakeEvent:
-
- def send(self, value):
- self.rv = value
-
- def wait(self):
- return self.rv
-
- done = FakeEvent()
- self._poll_task(id, task, done)
- rv = done.wait()
- return rv
-
- def fake_loop(self):
- pass
-
- stubs.Set(xenapi_conn.XenAPISession, 'wait_for_task',
- fake_wait_for_task)
-
- stubs.Set(xenapi_conn.XenAPISession, '_stop_loop', fake_loop)
-
from nova.virt.xenapi.fake import create_vdi
name_label = "instance-%s" % instance_id
#TODO: create fake SR record
@@ -63,11 +41,6 @@ def stubout_instance_snapshot(stubs):
stubs.Set(vm_utils.VMHelper, 'fetch_image', fake_fetch_image)
- def fake_parse_xmlrpc_value(val):
- return val
-
- stubs.Set(xenapi_conn, '_parse_xmlrpc_value', fake_parse_xmlrpc_value)
-
def fake_wait_for_vhd_coalesce(session, instance_id, sr_ref, vdi_ref,
original_parent_uuid):
from nova.virt.xenapi.fake import create_vdi
@@ -144,6 +117,16 @@ def stubout_loopingcall_start(stubs):
stubs.Set(utils.LoopingCall, 'start', fake_start)
+def stubout_loopingcall_delay(stubs):
+ def fake_start(self, interval, now=True):
+ self._running = True
+ eventlet.sleep(1)
+ self.f(*self.args, **self.kw)
+ # This would fail before parallel xenapi calls were fixed
+ assert self._running == False
+ stubs.Set(utils.LoopingCall, 'start', fake_start)
+
+
class FakeSessionForVMTests(fake.SessionBase):
""" Stubs out a XenAPISession for VM tests """
def __init__(self, uri):