summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-06-29 06:24:09 -0700
committerSandy Walsh <sandy.walsh@rackspace.com>2011-06-29 06:24:09 -0700
commit47ba396d19f40563ee1b810b98ec74aa1b0b3b53 (patch)
treef7a015d51d6511a7705a77f06ca7dd96b3a63488 /nova/tests
parent625816f16486a329ae0fb61c92fdf7915669923c (diff)
parent014c646ad36c0e790006a9832660d9ecd0c5b370 (diff)
moved migration again & trunk merge
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/__init__.py2
-rw-r--r--nova/tests/api/openstack/contrib/__init__.py15
-rw-r--r--nova/tests/api/openstack/contrib/test_floating_ips.py186
-rw-r--r--nova/tests/api/openstack/extensions/test_flavors_extra_specs.py198
-rw-r--r--nova/tests/api/openstack/fakes.py13
-rw-r--r--nova/tests/api/openstack/test_image_metadata.py123
-rw-r--r--nova/tests/api/openstack/test_images.py41
-rw-r--r--nova/tests/integrated/integrated_helpers.py14
-rw-r--r--nova/tests/network/base.py2
-rw-r--r--nova/tests/scheduler/test_host_filter.py36
-rw-r--r--nova/tests/test_adminapi.py111
-rw-r--r--nova/tests/test_auth.py10
-rw-r--r--nova/tests/test_compute.py77
-rw-r--r--nova/tests/test_flat_network.py6
-rw-r--r--nova/tests/test_host_filter.py3
-rw-r--r--nova/tests/test_instance_types_extra_specs.py165
-rw-r--r--nova/tests/test_libvirt.py69
-rw-r--r--nova/tests/test_network.py32
-rw-r--r--nova/tests/test_objectstore.py9
-rw-r--r--nova/tests/test_service.py30
-rw-r--r--nova/tests/test_vlan_network.py6
-rw-r--r--nova/tests/test_wsgi.py95
22 files changed, 1194 insertions, 49 deletions
diff --git a/nova/tests/__init__.py b/nova/tests/__init__.py
index 7fba02a93..5e0cb718e 100644
--- a/nova/tests/__init__.py
+++ b/nova/tests/__init__.py
@@ -50,7 +50,7 @@ def setup():
testdb = os.path.join(FLAGS.state_path, FLAGS.sqlite_db)
if os.path.exists(testdb):
- os.unlink(testdb)
+ return
migration.db_sync()
ctxt = context.get_admin_context()
network_manager.VlanManager().create_networks(ctxt,
diff --git a/nova/tests/api/openstack/contrib/__init__.py b/nova/tests/api/openstack/contrib/__init__.py
new file mode 100644
index 000000000..848908a95
--- /dev/null
+++ b/nova/tests/api/openstack/contrib/__init__.py
@@ -0,0 +1,15 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 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.
diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py
new file mode 100644
index 000000000..de1eb2f53
--- /dev/null
+++ b/nova/tests/api/openstack/contrib/test_floating_ips.py
@@ -0,0 +1,186 @@
+# Copyright 2011 Eldar Nugaev
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import stubout
+import webob
+
+from nova import context
+from nova import db
+from nova import test
+from nova import network
+from nova.tests.api.openstack import fakes
+
+
+from nova.api.openstack.contrib.floating_ips import FloatingIPController
+from nova.api.openstack.contrib.floating_ips import _translate_floating_ip_view
+
+
+def network_api_get_floating_ip(self, context, id):
+ return {'id': 1, 'address': '10.10.10.10',
+ 'fixed_ip': {'address': '11.0.0.1'}}
+
+
+def network_api_list_floating_ips(self, context):
+ return [{'id': 1,
+ 'address': '10.10.10.10',
+ 'instance': {'id': 11},
+ 'fixed_ip': {'address': '10.0.0.1'}},
+ {'id': 2,
+ 'address': '10.10.10.11'}]
+
+
+def network_api_allocate(self, context):
+ return '10.10.10.10'
+
+
+def network_api_release(self, context, address):
+ pass
+
+
+def network_api_associate(self, context, floating_ip, fixed_ip):
+ pass
+
+
+def network_api_disassociate(self, context, floating_address):
+ pass
+
+
+class FloatingIpTest(test.TestCase):
+ address = "10.10.10.10"
+
+ def _create_floating_ip(self):
+ """Create a floating ip object."""
+ host = "fake_host"
+ return db.floating_ip_create(self.context,
+ {'address': self.address,
+ 'host': host})
+
+ def _delete_floating_ip(self):
+ db.floating_ip_destroy(self.context, self.address)
+
+ def setUp(self):
+ super(FloatingIpTest, self).setUp()
+ self.controller = FloatingIPController()
+ self.stubs = stubout.StubOutForTesting()
+ fakes.FakeAuthManager.reset_fake_data()
+ fakes.FakeAuthDatabase.data = {}
+ fakes.stub_out_networking(self.stubs)
+ fakes.stub_out_rate_limiting(self.stubs)
+ fakes.stub_out_auth(self.stubs)
+ self.stubs.Set(network.api.API, "get_floating_ip",
+ network_api_get_floating_ip)
+ self.stubs.Set(network.api.API, "list_floating_ips",
+ network_api_list_floating_ips)
+ self.stubs.Set(network.api.API, "allocate_floating_ip",
+ network_api_allocate)
+ self.stubs.Set(network.api.API, "release_floating_ip",
+ network_api_release)
+ self.stubs.Set(network.api.API, "associate_floating_ip",
+ network_api_associate)
+ self.stubs.Set(network.api.API, "disassociate_floating_ip",
+ network_api_disassociate)
+ self.context = context.get_admin_context()
+ self._create_floating_ip()
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ self._delete_floating_ip()
+ super(FloatingIpTest, self).tearDown()
+
+ def test_translate_floating_ip_view(self):
+ floating_ip_address = self._create_floating_ip()
+ floating_ip = db.floating_ip_get_by_address(self.context,
+ floating_ip_address)
+ view = _translate_floating_ip_view(floating_ip)
+ self.assertTrue('floating_ip' in view)
+ self.assertTrue(view['floating_ip']['id'])
+ self.assertEqual(view['floating_ip']['ip'], self.address)
+ self.assertEqual(view['floating_ip']['fixed_ip'], None)
+ self.assertEqual(view['floating_ip']['instance_id'], None)
+
+ def test_floating_ips_list(self):
+ req = webob.Request.blank('/v1.1/os-floating-ips')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ response = {'floating_ips': [{'floating_ip': {'instance_id': 11,
+ 'ip': '10.10.10.10',
+ 'fixed_ip': '10.0.0.1',
+ 'id': 1}},
+ {'floating_ip': {'instance_id': None,
+ 'ip': '10.10.10.11',
+ 'fixed_ip': None,
+ 'id': 2}}]}
+ self.assertEqual(res_dict, response)
+
+ def test_floating_ip_show(self):
+ req = webob.Request.blank('/v1.1/os-floating-ips/1')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['floating_ip']['id'], 1)
+ self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10')
+ self.assertEqual(res_dict['floating_ip']['fixed_ip'], '11.0.0.1')
+ self.assertEqual(res_dict['floating_ip']['instance_id'], None)
+
+ def test_floating_ip_allocate(self):
+ req = webob.Request.blank('/v1.1/os-floating-ips')
+ req.method = 'POST'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ ip = json.loads(res.body)['allocated']
+ expected = {
+ "id": 1,
+ "floating_ip": '10.10.10.10'}
+ self.assertEqual(ip, expected)
+
+ def test_floating_ip_release(self):
+ req = webob.Request.blank('/v1.1/os-floating-ips/1')
+ req.method = 'DELETE'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ actual = json.loads(res.body)['released']
+ expected = {
+ "id": 1,
+ "floating_ip": '10.10.10.10'}
+ self.assertEqual(actual, expected)
+
+ def test_floating_ip_associate(self):
+ body = dict(associate_address=dict(fixed_ip='1.2.3.4'))
+ req = webob.Request.blank('/v1.1/os-floating-ips/1/associate')
+ 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, 200)
+ actual = json.loads(res.body)['associated']
+ expected = {
+ "floating_ip_id": '1',
+ "floating_ip": "10.10.10.10",
+ "fixed_ip": "1.2.3.4"}
+ self.assertEqual(actual, expected)
+
+ def test_floating_ip_disassociate(self):
+ req = webob.Request.blank('/v1.1/os-floating-ips/1/disassociate')
+ req.method = 'POST'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ ip = json.loads(res.body)['disassociated']
+ expected = {
+ "floating_ip": '10.10.10.10',
+ "fixed_ip": '11.0.0.1'}
+ self.assertEqual(ip, expected)
diff --git a/nova/tests/api/openstack/extensions/test_flavors_extra_specs.py b/nova/tests/api/openstack/extensions/test_flavors_extra_specs.py
new file mode 100644
index 000000000..2c1c335b0
--- /dev/null
+++ b/nova/tests/api/openstack/extensions/test_flavors_extra_specs.py
@@ -0,0 +1,198 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 University of Southern California
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import stubout
+import unittest
+import webob
+import os.path
+
+
+from nova import flags
+from nova.api import openstack
+from nova.api.openstack import auth
+from nova.api.openstack import extensions
+from nova.tests.api.openstack import fakes
+import nova.wsgi
+
+FLAGS = flags.FLAGS
+
+
+def return_create_flavor_extra_specs(context, flavor_id, extra_specs):
+ return stub_flavor_extra_specs()
+
+
+def return_flavor_extra_specs(context, flavor_id):
+ return stub_flavor_extra_specs()
+
+
+def return_flavor_extra_specs(context, flavor_id):
+ return stub_flavor_extra_specs()
+
+
+def return_empty_flavor_extra_specs(context, flavor_id):
+ return {}
+
+
+def delete_flavor_extra_specs(context, flavor_id, key):
+ pass
+
+
+def stub_flavor_extra_specs():
+ specs = {
+ "key1": "value1",
+ "key2": "value2",
+ "key3": "value3",
+ "key4": "value4",
+ "key5": "value5"}
+ return specs
+
+
+class FlavorsExtraSpecsTest(unittest.TestCase):
+
+ def setUp(self):
+ super(FlavorsExtraSpecsTest, self).setUp()
+ FLAGS.osapi_extensions_path = os.path.join(os.path.dirname(__file__),
+ "extensions")
+ self.stubs = stubout.StubOutForTesting()
+ fakes.FakeAuthManager.auth_data = {}
+ fakes.FakeAuthDatabase.data = {}
+ fakes.stub_out_auth(self.stubs)
+ fakes.stub_out_key_pair_funcs(self.stubs)
+ self.mware = auth.AuthMiddleware(
+ extensions.ExtensionMiddleware(
+ openstack.APIRouterV11()))
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(FlavorsExtraSpecsTest, self).tearDown()
+
+ def test_index(self):
+ self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
+ return_flavor_extra_specs)
+ request = webob.Request.blank('/flavors/1/os-extra_specs')
+ res = request.get_response(self.mware)
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual('value1', res_dict['extra_specs']['key1'])
+
+ def test_index_no_data(self):
+ self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
+ return_empty_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs')
+ res = req.get_response(self.mware)
+ res_dict = json.loads(res.body)
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual(0, len(res_dict['extra_specs']))
+
+ def test_show(self):
+ self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
+ return_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/key5')
+ res = req.get_response(self.mware)
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual('value5', res_dict['key5'])
+
+ def test_show_spec_not_found(self):
+ self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
+ return_empty_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/key6')
+ res = req.get_response(self.mware)
+ res_dict = json.loads(res.body)
+ self.assertEqual(404, res.status_int)
+
+ def test_delete(self):
+ self.stubs.Set(nova.db.api, 'instance_type_extra_specs_delete',
+ delete_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/key5')
+ req.method = 'DELETE'
+ res = req.get_response(self.mware)
+ self.assertEqual(200, res.status_int)
+
+ def test_create(self):
+ self.stubs.Set(nova.db.api,
+ 'instance_type_extra_specs_update_or_create',
+ return_create_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs')
+ req.method = 'POST'
+ req.body = '{"extra_specs": {"key1": "value1"}}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(self.mware)
+ res_dict = json.loads(res.body)
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual('value1', res_dict['extra_specs']['key1'])
+
+ def test_create_empty_body(self):
+ self.stubs.Set(nova.db.api,
+ 'instance_type_extra_specs_update_or_create',
+ return_create_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs')
+ req.method = 'POST'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(self.mware)
+ self.assertEqual(400, res.status_int)
+
+ def test_update_item(self):
+ self.stubs.Set(nova.db.api,
+ 'instance_type_extra_specs_update_or_create',
+ return_create_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/key1')
+ req.method = 'PUT'
+ req.body = '{"key1": "value1"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(self.mware)
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ res_dict = json.loads(res.body)
+ self.assertEqual('value1', res_dict['key1'])
+
+ def test_update_item_empty_body(self):
+ self.stubs.Set(nova.db.api,
+ 'instance_type_extra_specs_update_or_create',
+ return_create_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/key1')
+ req.method = 'PUT'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(self.mware)
+ self.assertEqual(400, res.status_int)
+
+ def test_update_item_too_many_keys(self):
+ self.stubs.Set(nova.db.api,
+ 'instance_type_extra_specs_update_or_create',
+ return_create_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/key1')
+ req.method = 'PUT'
+ req.body = '{"key1": "value1", "key2": "value2"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(self.mware)
+ self.assertEqual(400, res.status_int)
+
+ def test_update_item_body_uri_mismatch(self):
+ self.stubs.Set(nova.db.api,
+ 'instance_type_extra_specs_update_or_create',
+ return_create_flavor_extra_specs)
+ req = webob.Request.blank('/flavors/1/os-extra_specs/bad')
+ req.method = 'PUT'
+ req.body = '{"key1": "value1"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(self.mware)
+ self.assertEqual(400, res.status_int)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index f8d158ddd..eeb96cb12 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -16,7 +16,6 @@
# under the License.
import copy
-import json
import random
import string
@@ -29,11 +28,11 @@ from glance.common import exception as glance_exc
from nova import context
from nova import exception as exc
-from nova import flags
from nova import utils
import nova.api.openstack.auth
from nova.api import openstack
from nova.api.openstack import auth
+from nova.api.openstack import extensions
from nova.api.openstack import versions
from nova.api.openstack import limits
from nova.auth.manager import User, Project
@@ -82,7 +81,8 @@ def wsgi_app(inner_app10=None, inner_app11=None):
api10 = openstack.FaultWrapper(auth.AuthMiddleware(
limits.RateLimitingMiddleware(inner_app10)))
api11 = openstack.FaultWrapper(auth.AuthMiddleware(
- limits.RateLimitingMiddleware(inner_app11)))
+ limits.RateLimitingMiddleware(
+ extensions.ExtensionMiddleware(inner_app11))))
mapper['/v1.0'] = api10
mapper['/v1.1'] = api11
mapper['/'] = openstack.FaultWrapper(versions.Versions())
@@ -140,9 +140,10 @@ def stub_out_networking(stubs):
def stub_out_compute_api_snapshot(stubs):
- def snapshot(self, context, instance_id, name):
- return dict(id='123', status='ACTIVE',
- properties=dict(instance_id='123'))
+ def snapshot(self, context, instance_id, name, extra_properties=None):
+ props = dict(instance_id=instance_id, instance_ref=instance_id)
+ props.update(extra_properties or {})
+ return dict(id='123', status='ACTIVE', name=name, properties=props)
stubs.Set(nova.compute.API, 'snapshot', snapshot)
diff --git a/nova/tests/api/openstack/test_image_metadata.py b/nova/tests/api/openstack/test_image_metadata.py
index 56be0f1cc..730af3665 100644
--- a/nova/tests/api/openstack/test_image_metadata.py
+++ b/nova/tests/api/openstack/test_image_metadata.py
@@ -19,6 +19,7 @@ import json
import stubout
import unittest
import webob
+import xml.dom.minidom as minidom
from nova import flags
@@ -37,6 +38,7 @@ class ImageMetaDataTest(unittest.TestCase):
'name': 'image1',
'deleted': False,
'container_format': None,
+ 'checksum': None,
'created_at': '2011-03-22T17:40:15',
'disk_format': None,
'updated_at': '2011-03-22T17:40:15',
@@ -52,6 +54,7 @@ class ImageMetaDataTest(unittest.TestCase):
'name': 'image2',
'deleted': False,
'container_format': None,
+ 'checksum': None,
'created_at': '2011-03-22T17:40:15',
'disk_format': None,
'updated_at': '2011-03-22T17:40:15',
@@ -67,6 +70,7 @@ class ImageMetaDataTest(unittest.TestCase):
'name': 'image3',
'deleted': False,
'container_format': None,
+ 'checksum': None,
'created_at': '2011-03-22T17:40:15',
'disk_format': None,
'updated_at': '2011-03-22T17:40:15',
@@ -103,7 +107,34 @@ class ImageMetaDataTest(unittest.TestCase):
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
- self.assertEqual('value1', res_dict['metadata']['key1'])
+ expected = self.IMAGE_FIXTURES[0]['properties']
+ self.assertEqual(len(expected), len(res_dict['metadata']))
+ for (key, value) in res_dict['metadata'].items():
+ self.assertEqual(value, res_dict['metadata'][key])
+
+ def test_index_xml(self):
+ serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
+ fixture = {
+ 'metadata': {
+ 'one': 'two',
+ 'three': 'four',
+ },
+ }
+ output = serializer.index(fixture)
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="three">
+ four
+ </meta>
+ <meta key="one">
+ two
+ </meta>
+ </metadata>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
def test_show(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
@@ -111,13 +142,32 @@ class ImageMetaDataTest(unittest.TestCase):
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
- self.assertEqual('value1', res_dict['key1'])
+ self.assertTrue('meta' in res_dict)
+ self.assertEqual(len(res_dict['meta']), 1)
+ self.assertEqual('value1', res_dict['meta']['key1'])
+
+ def test_show_xml(self):
+ serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
+ fixture = {
+ 'meta': {
+ 'one': 'two',
+ },
+ }
+ output = serializer.show(fixture)
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one">
+ two
+ </meta>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
def test_show_not_found(self):
req = webob.Request.blank('/v1.1/images/1/meta/key9')
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
- res_dict = json.loads(res.body)
self.assertEqual(404, res.status_int)
def test_create(self):
@@ -135,22 +185,79 @@ class ImageMetaDataTest(unittest.TestCase):
self.assertEqual('value2', res_dict['metadata']['key2'])
self.assertEqual(1, len(res_dict))
+ def test_create_xml(self):
+ serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
+ fixture = {
+ 'metadata': {
+ 'key9': 'value9',
+ 'key2': 'value2',
+ 'key1': 'value1',
+ },
+ }
+ output = serializer.create(fixture)
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="key2">
+ value2
+ </meta>
+ <meta key="key9">
+ value9
+ </meta>
+ <meta key="key1">
+ value1
+ </meta>
+ </metadata>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
def test_update_item(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
- req.body = '{"key1": "zz"}'
+ req.body = '{"meta": {"key1": "zz"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
res_dict = json.loads(res.body)
- self.assertEqual('zz', res_dict['key1'])
+ self.assertTrue('meta' in res_dict)
+ self.assertEqual(len(res_dict['meta']), 1)
+ self.assertEqual('zz', res_dict['meta']['key1'])
+
+ def test_update_item_bad_body(self):
+ req = webob.Request.blank('/v1.1/images/1/meta/key1')
+ req.environ['api.version'] = '1.1'
+ req.method = 'PUT'
+ req.body = '{"key1": "zz"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_update_item_xml(self):
+ serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
+ fixture = {
+ 'meta': {
+ 'one': 'two',
+ },
+ }
+ output = serializer.update(fixture)
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one">
+ two
+ </meta>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
def test_update_item_too_many_keys(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
- req.body = '{"key1": "value1", "key2": "value2"}'
+ req.body = '{"meta": {"key1": "value1", "key2": "value2"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
@@ -159,7 +266,7 @@ class ImageMetaDataTest(unittest.TestCase):
req = webob.Request.blank('/v1.1/images/1/meta/bad')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
- req.body = '{"key1": "value1"}'
+ req.body = '{"meta": {"key1": "value1"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
@@ -195,7 +302,7 @@ class ImageMetaDataTest(unittest.TestCase):
req = webob.Request.blank('/v1.1/images/3/meta/blah')
req.environ['api.version'] = '1.1'
req.method = 'PUT'
- req.body = '{"blah": "blah"}'
+ req.body = '{"meta": {"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 e4204809f..446d68e9e 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -618,7 +618,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 124,
'name': 'queued backup',
- 'serverId': 42,
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'QUEUED',
@@ -626,7 +625,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 125,
'name': 'saving backup',
- 'serverId': 42,
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'SAVING',
@@ -635,7 +633,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 126,
'name': 'active backup',
- 'serverId': 42,
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'ACTIVE'
@@ -643,7 +640,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 127,
'name': 'killed backup',
- 'serverId': 42,
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'FAILED',
@@ -689,7 +685,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 124,
'name': 'queued backup',
- 'serverRef': "http://localhost/v1.1/servers/42",
+ 'serverRef': "http://localhost:8774/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'QUEUED',
@@ -711,7 +707,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 125,
'name': 'saving backup',
- 'serverRef': "http://localhost/v1.1/servers/42",
+ 'serverRef': "http://localhost:8774/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'SAVING',
@@ -734,7 +730,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 126,
'name': 'active backup',
- 'serverRef': "http://localhost/v1.1/servers/42",
+ 'serverRef': "http://localhost:8774/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'ACTIVE',
@@ -756,7 +752,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{
'id': 127,
'name': 'killed backup',
- 'serverRef': "http://localhost/v1.1/servers/42",
+ 'serverRef': "http://localhost:8774/v1.1/servers/42",
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
'status': 'FAILED',
@@ -1002,6 +998,30 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
response = req.get_response(fakes.wsgi_app())
self.assertEqual(200, response.status_int)
+ def test_create_image_v1_1_actual_server_ref(self):
+
+ serverRef = 'http://localhost/v1.1/servers/1'
+ body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
+ req = webob.Request.blank('/v1.1/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, response.status_int)
+ result = json.loads(response.body)
+ self.assertEqual(result['image']['serverRef'], serverRef)
+
+ def test_create_image_v1_1_server_ref_bad_hostname(self):
+
+ serverRef = 'http://asdf/v1.1/servers/1'
+ body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
+ req = webob.Request.blank('/v1.1/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
def test_create_image_v1_1_xml_serialization(self):
body = dict(image=dict(serverRef='123', name='Backup 1'))
@@ -1018,7 +1038,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
<image
created="None"
id="123"
- name="None"
+ name="Backup 1"
serverRef="http://localhost/v1.1/servers/123"
status="ACTIVE"
updated="None"
@@ -1065,7 +1085,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
image_id += 1
# Backup for User 1
- backup_properties = {'instance_id': '42', 'user_id': '1'}
+ server_ref = 'http://localhost:8774/v1.1/servers/42'
+ backup_properties = {'instance_ref': server_ref, 'user_id': '1'}
for status in ('queued', 'saving', 'active', 'killed'):
add_fixture(id=image_id, name='%s backup' % status,
is_public=False, status=status,
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
index 522c7cb0e..47bd8c1e4 100644
--- a/nova/tests/integrated/integrated_helpers.py
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -171,16 +171,10 @@ class _IntegratedTestBase(test.TestCase):
self.api = self.user.openstack_api
def _start_api_service(self):
- api_service = service.ApiService.create()
- api_service.start()
-
- if not api_service:
- raise Exception("API Service was None")
-
- self.api_service = api_service
-
- host, port = api_service.get_socket_info('osapi')
- self.auth_url = 'http://%s:%s/v1.1' % (host, port)
+ osapi = service.WSGIService("osapi")
+ osapi.start()
+ self.auth_url = 'http://%s:%s/v1.1' % (osapi.host, osapi.port)
+ LOG.warn(self.auth_url)
def tearDown(self):
self.context.cleanup()
diff --git a/nova/tests/network/base.py b/nova/tests/network/base.py
index b06271c99..f65416824 100644
--- a/nova/tests/network/base.py
+++ b/nova/tests/network/base.py
@@ -18,7 +18,7 @@
"""
Base class of Unit Tests for all network models
"""
-import IPy
+import netaddr
import os
from nova import context
diff --git a/nova/tests/scheduler/test_host_filter.py b/nova/tests/scheduler/test_host_filter.py
index 10eafde08..b1892dab4 100644
--- a/nova/tests/scheduler/test_host_filter.py
+++ b/nova/tests/scheduler/test_host_filter.py
@@ -67,7 +67,18 @@ class HostFilterTestCase(test.TestCase):
flavorid=1,
swap=500,
rxtx_quota=30000,
- rxtx_cap=200)
+ rxtx_cap=200,
+ extra_specs={})
+ self.gpu_instance_type = dict(name='tiny.gpu',
+ memory_mb=50,
+ vcpus=10,
+ local_gb=500,
+ flavorid=2,
+ swap=500,
+ rxtx_quota=30000,
+ rxtx_cap=200,
+ extra_specs={'xpu_arch': 'fermi',
+ 'xpu_info': 'Tesla 2050'})
self.zone_manager = FakeZoneManager()
states = {}
@@ -75,6 +86,18 @@ class HostFilterTestCase(test.TestCase):
states['host%02d' % (x + 1)] = {'compute': self._host_caps(x)}
self.zone_manager.service_states = states
+ # Add some extra capabilities to some hosts
+ host07 = self.zone_manager.service_states['host07']['compute']
+ host07['xpu_arch'] = 'fermi'
+ host07['xpu_info'] = 'Tesla 2050'
+
+ host08 = self.zone_manager.service_states['host08']['compute']
+ host08['xpu_arch'] = 'radeon'
+
+ host09 = self.zone_manager.service_states['host09']['compute']
+ host09['xpu_arch'] = 'fermi'
+ host09['xpu_info'] = 'Tesla 2150'
+
def tearDown(self):
FLAGS.default_host_filter = self.old_flag
@@ -116,6 +139,17 @@ class HostFilterTestCase(test.TestCase):
self.assertEquals('host05', just_hosts[0])
self.assertEquals('host10', just_hosts[5])
+ def test_instance_type_filter_extra_specs(self):
+ hf = host_filter.InstanceTypeFilter()
+ # filter all hosts that can support 50 ram and 500 disk
+ name, cooked = hf.instance_type_to_filter(self.gpu_instance_type)
+ self.assertEquals('nova.scheduler.host_filter.InstanceTypeFilter',
+ name)
+ hosts = hf.filter_hosts(self.zone_manager, cooked)
+ self.assertEquals(1, len(hosts))
+ just_hosts = [host for host, caps in hosts]
+ self.assertEquals('host07', just_hosts[0])
+
def test_json_filter(self):
hf = host_filter.JsonFilter()
# filter all hosts that can support 50 ram and 500 disk
diff --git a/nova/tests/test_adminapi.py b/nova/tests/test_adminapi.py
new file mode 100644
index 000000000..ce826fd5b
--- /dev/null
+++ b/nova/tests/test_adminapi.py
@@ -0,0 +1,111 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from eventlet import greenthread
+
+from nova import context
+from nova import db
+from nova import flags
+from nova import log as logging
+from nova import rpc
+from nova import test
+from nova import utils
+from nova.auth import manager
+from nova.api.ec2 import admin
+from nova.image import fake
+
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.adminapi')
+
+
+class AdminApiTestCase(test.TestCase):
+ def setUp(self):
+ super(AdminApiTestCase, self).setUp()
+ self.flags(connection_type='fake')
+
+ self.conn = rpc.Connection.instance()
+
+ # set up our cloud
+ self.api = admin.AdminController()
+
+ # set up services
+ self.compute = self.start_service('compute')
+ self.scheduter = self.start_service('scheduler')
+ self.network = self.start_service('network')
+ self.volume = self.start_service('volume')
+ self.image_service = utils.import_object(FLAGS.image_service)
+
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('admin', 'admin', 'admin', True)
+ self.project = self.manager.create_project('proj', 'admin', 'proj')
+ self.context = context.RequestContext(user=self.user,
+ project=self.project)
+ host = self.network.get_network_host(self.context.elevated())
+
+ def fake_show(meh, context, id):
+ return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
+ 'type': 'machine', 'image_state': 'available'}}
+
+ self.stubs.Set(fake._FakeImageService, 'show', fake_show)
+ self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show)
+
+ # NOTE(vish): set up a manual wait so rpc.cast has a chance to finish
+ rpc_cast = rpc.cast
+
+ def finish_cast(*args, **kwargs):
+ rpc_cast(*args, **kwargs)
+ greenthread.sleep(0.2)
+
+ self.stubs.Set(rpc, 'cast', finish_cast)
+
+ def tearDown(self):
+ network_ref = db.project_get_network(self.context,
+ self.project.id)
+ db.network_disassociate(self.context, network_ref['id'])
+ self.manager.delete_project(self.project)
+ self.manager.delete_user(self.user)
+ super(AdminApiTestCase, self).tearDown()
+
+ def test_block_external_ips(self):
+ """Make sure provider firewall rules are created."""
+ result = self.api.block_external_addresses(self.context, '1.1.1.1/32')
+ self.api.remove_external_address_block(self.context, '1.1.1.1/32')
+ self.assertEqual('OK', result['status'])
+ self.assertEqual('Added 3 rules', result['message'])
+
+ def test_list_blocked_ips(self):
+ """Make sure we can see the external blocks that exist."""
+ self.api.block_external_addresses(self.context, '1.1.1.2/32')
+ result = self.api.describe_external_address_blocks(self.context)
+ num = len(db.provider_fw_rule_get_all(self.context))
+ self.api.remove_external_address_block(self.context, '1.1.1.2/32')
+ # we only list IP, not tcp/udp/icmp rules
+ self.assertEqual(num / 3, len(result['externalIpBlockInfo']))
+
+ def test_remove_ip_block(self):
+ """Remove ip blocks."""
+ result = self.api.block_external_addresses(self.context, '1.1.1.3/32')
+ self.assertEqual('OK', result['status'])
+ num0 = len(db.provider_fw_rule_get_all(self.context))
+ result = self.api.remove_external_address_block(self.context,
+ '1.1.1.3/32')
+ self.assertEqual('OK', result['status'])
+ self.assertEqual('Deleted 3 rules', result['message'])
+ num1 = len(db.provider_fw_rule_get_all(self.context))
+ self.assert_(num1 < num0)
diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py
index 7d00bddfe..71e0d17c9 100644
--- a/nova/tests/test_auth.py
+++ b/nova/tests/test_auth.py
@@ -25,6 +25,7 @@ from nova import log as logging
from nova import test
from nova.auth import manager
from nova.api.ec2 import cloud
+from nova.auth import fakeldap
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.auth_unittest')
@@ -369,6 +370,15 @@ class _AuthManagerBaseTestCase(test.TestCase):
class AuthManagerLdapTestCase(_AuthManagerBaseTestCase):
auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver'
+ def test_reconnect_on_server_failure(self):
+ self.manager.get_users()
+ fakeldap.server_fail = True
+ try:
+ self.assertRaises(fakeldap.SERVER_DOWN, self.manager.get_users)
+ finally:
+ fakeldap.server_fail = False
+ self.manager.get_users()
+
class AuthManagerDbTestCase(_AuthManagerBaseTestCase):
auth_driver = 'nova.auth.dbdriver.DbDriver'
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 439508b27..4d42b1fdf 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -37,6 +37,7 @@ from nova import log as logging
from nova import rpc
from nova import test
from nova import utils
+from nova.notifier import test_notifier
LOG = logging.getLogger('nova.tests.compute')
FLAGS = flags.FLAGS
@@ -62,6 +63,7 @@ class ComputeTestCase(test.TestCase):
super(ComputeTestCase, self).setUp()
self.flags(connection_type='fake',
stub_network=True,
+ notification_driver='nova.notifier.test_notifier',
network_manager='nova.network.manager.FlatManager')
self.compute = utils.import_object(FLAGS.compute_manager)
self.compute_api = compute.API()
@@ -69,6 +71,7 @@ class ComputeTestCase(test.TestCase):
self.user = self.manager.create_user('fake', 'fake', 'fake')
self.project = self.manager.create_project('fake', 'fake', 'fake')
self.context = context.RequestContext('fake', 'fake', False)
+ test_notifier.NOTIFICATIONS = []
def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}}
@@ -327,6 +330,50 @@ class ComputeTestCase(test.TestCase):
self.assert_(console)
self.compute.terminate_instance(self.context, instance_id)
+ def test_run_instance_usage_notification(self):
+ """Ensure run instance generates apropriate usage notification"""
+ instance_id = self._create_instance()
+ self.compute.run_instance(self.context, instance_id)
+ self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
+ msg = test_notifier.NOTIFICATIONS[0]
+ self.assertEquals(msg['priority'], 'INFO')
+ self.assertEquals(msg['event_type'], 'compute.instance.create')
+ payload = msg['payload']
+ self.assertEquals(payload['tenant_id'], self.project.id)
+ self.assertEquals(payload['user_id'], self.user.id)
+ self.assertEquals(payload['instance_id'], instance_id)
+ self.assertEquals(payload['instance_type'], 'm1.tiny')
+ type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
+ self.assertEquals(str(payload['instance_type_id']), str(type_id))
+ self.assertTrue('display_name' in payload)
+ self.assertTrue('created_at' in payload)
+ self.assertTrue('launched_at' in payload)
+ self.assertEquals(payload['image_ref'], '1')
+ self.compute.terminate_instance(self.context, instance_id)
+
+ def test_terminate_usage_notification(self):
+ """Ensure terminate_instance generates apropriate usage notification"""
+ instance_id = self._create_instance()
+ self.compute.run_instance(self.context, instance_id)
+ test_notifier.NOTIFICATIONS = []
+ self.compute.terminate_instance(self.context, instance_id)
+
+ self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
+ msg = test_notifier.NOTIFICATIONS[0]
+ self.assertEquals(msg['priority'], 'INFO')
+ self.assertEquals(msg['event_type'], 'compute.instance.delete')
+ payload = msg['payload']
+ self.assertEquals(payload['tenant_id'], self.project.id)
+ self.assertEquals(payload['user_id'], self.user.id)
+ self.assertEquals(payload['instance_id'], instance_id)
+ self.assertEquals(payload['instance_type'], 'm1.tiny')
+ type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
+ self.assertEquals(str(payload['instance_type_id']), str(type_id))
+ self.assertTrue('display_name' in payload)
+ self.assertTrue('created_at' in payload)
+ self.assertTrue('launched_at' in payload)
+ self.assertEquals(payload['image_ref'], '1')
+
def test_run_instance_existing(self):
"""Ensure failure when running an instance that already exists"""
instance_id = self._create_instance()
@@ -378,6 +425,36 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(self.context, instance_id)
+ def test_resize_instance_notification(self):
+ """Ensure notifications on instance migrate/resize"""
+ instance_id = self._create_instance()
+ context = self.context.elevated()
+
+ self.compute.run_instance(self.context, instance_id)
+ test_notifier.NOTIFICATIONS = []
+
+ db.instance_update(self.context, instance_id, {'host': 'foo'})
+ self.compute.prep_resize(context, instance_id, 1)
+ migration_ref = db.migration_get_by_instance_and_status(context,
+ instance_id, 'pre-migrating')
+
+ self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
+ msg = test_notifier.NOTIFICATIONS[0]
+ self.assertEquals(msg['priority'], 'INFO')
+ self.assertEquals(msg['event_type'], 'compute.instance.resize.prep')
+ payload = msg['payload']
+ self.assertEquals(payload['tenant_id'], self.project.id)
+ self.assertEquals(payload['user_id'], self.user.id)
+ self.assertEquals(payload['instance_id'], instance_id)
+ self.assertEquals(payload['instance_type'], 'm1.tiny')
+ type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
+ self.assertEquals(str(payload['instance_type_id']), str(type_id))
+ self.assertTrue('display_name' in payload)
+ self.assertTrue('created_at' in payload)
+ self.assertTrue('launched_at' in payload)
+ self.assertEquals(payload['image_ref'], '1')
+ self.compute.terminate_instance(context, instance_id)
+
def test_resize_instance(self):
"""Ensure instance can be migrated/resized"""
instance_id = self._create_instance()
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
index dcc617e25..8544019c0 100644
--- a/nova/tests/test_flat_network.py
+++ b/nova/tests/test_flat_network.py
@@ -18,7 +18,7 @@
"""
Unit Tests for flat network code
"""
-import IPy
+import netaddr
import os
import unittest
@@ -45,8 +45,8 @@ class FlatNetworkTestCase(base.NetworkTestCase):
self.context._project = self.projects[0]
self.context.project_id = self.projects[0].id
- pubnet = IPy.IP(flags.FLAGS.floating_range)
- address = str(pubnet[0])
+ pubnet = netaddr.IPRange(flags.FLAGS.floating_range)
+ address = str(list(pubnet)[0])
try:
db.floating_ip_get_by_address(context.get_admin_context(), address)
except exception.NotFound:
diff --git a/nova/tests/test_host_filter.py b/nova/tests/test_host_filter.py
index 3361c7b73..438f3e522 100644
--- a/nova/tests/test_host_filter.py
+++ b/nova/tests/test_host_filter.py
@@ -67,7 +67,8 @@ class HostFilterTestCase(test.TestCase):
flavorid=1,
swap=500,
rxtx_quota=30000,
- rxtx_cap=200)
+ rxtx_cap=200,
+ extra_specs={})
self.zone_manager = FakeZoneManager()
states = {}
diff --git a/nova/tests/test_instance_types_extra_specs.py b/nova/tests/test_instance_types_extra_specs.py
new file mode 100644
index 000000000..c26cf82ff
--- /dev/null
+++ b/nova/tests/test_instance_types_extra_specs.py
@@ -0,0 +1,165 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 University of Southern California
+# 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.
+"""
+Unit Tests for instance types extra specs code
+"""
+
+from nova import context
+from nova import db
+from nova import test
+from nova.db.sqlalchemy.session import get_session
+from nova.db.sqlalchemy import models
+
+
+class InstanceTypeExtraSpecsTestCase(test.TestCase):
+
+ def setUp(self):
+ super(InstanceTypeExtraSpecsTestCase, self).setUp()
+ self.context = context.get_admin_context()
+ values = dict(name="cg1.4xlarge",
+ memory_mb=22000,
+ vcpus=8,
+ local_gb=1690,
+ flavorid=105)
+ specs = dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus=2,
+ xpu_model="Tesla 2050")
+ values['extra_specs'] = specs
+ ref = db.api.instance_type_create(self.context,
+ values)
+ self.instance_type_id = ref.id
+
+ def tearDown(self):
+ # Remove the instance type from the database
+ db.api.instance_type_purge(context.get_admin_context(), "cg1.4xlarge")
+ super(InstanceTypeExtraSpecsTestCase, self).tearDown()
+
+ def test_instance_type_specs_get(self):
+ expected_specs = dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus="2",
+ xpu_model="Tesla 2050")
+ actual_specs = db.api.instance_type_extra_specs_get(
+ context.get_admin_context(),
+ self.instance_type_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_instance_type_extra_specs_delete(self):
+ expected_specs = dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus="2")
+ db.api.instance_type_extra_specs_delete(context.get_admin_context(),
+ self.instance_type_id,
+ "xpu_model")
+ actual_specs = db.api.instance_type_extra_specs_get(
+ context.get_admin_context(),
+ self.instance_type_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_instance_type_extra_specs_update(self):
+ expected_specs = dict(cpu_arch="x86_64",
+ cpu_model="Sandy Bridge",
+ xpu_arch="fermi",
+ xpus="2",
+ xpu_model="Tesla 2050")
+ db.api.instance_type_extra_specs_update_or_create(
+ context.get_admin_context(),
+ self.instance_type_id,
+ dict(cpu_model="Sandy Bridge"))
+ actual_specs = db.api.instance_type_extra_specs_get(
+ context.get_admin_context(),
+ self.instance_type_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_instance_type_extra_specs_create(self):
+ expected_specs = dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus="2",
+ xpu_model="Tesla 2050",
+ net_arch="ethernet",
+ net_mbps="10000")
+ db.api.instance_type_extra_specs_update_or_create(
+ context.get_admin_context(),
+ self.instance_type_id,
+ dict(net_arch="ethernet",
+ net_mbps=10000))
+ actual_specs = db.api.instance_type_extra_specs_get(
+ context.get_admin_context(),
+ self.instance_type_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_instance_type_get_by_id_with_extra_specs(self):
+ instance_type = db.api.instance_type_get_by_id(
+ context.get_admin_context(),
+ self.instance_type_id)
+ self.assertEquals(instance_type['extra_specs'],
+ dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus="2",
+ xpu_model="Tesla 2050"))
+ instance_type = db.api.instance_type_get_by_id(
+ context.get_admin_context(),
+ 5)
+ self.assertEquals(instance_type['extra_specs'], {})
+
+ def test_instance_type_get_by_name_with_extra_specs(self):
+ instance_type = db.api.instance_type_get_by_name(
+ context.get_admin_context(),
+ "cg1.4xlarge")
+ self.assertEquals(instance_type['extra_specs'],
+ dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus="2",
+ xpu_model="Tesla 2050"))
+
+ instance_type = db.api.instance_type_get_by_name(
+ context.get_admin_context(),
+ "m1.small")
+ self.assertEquals(instance_type['extra_specs'], {})
+
+ def test_instance_type_get_by_id_with_extra_specs(self):
+ instance_type = db.api.instance_type_get_by_flavor_id(
+ context.get_admin_context(),
+ 105)
+ self.assertEquals(instance_type['extra_specs'],
+ dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus="2",
+ xpu_model="Tesla 2050"))
+
+ instance_type = db.api.instance_type_get_by_flavor_id(
+ context.get_admin_context(),
+ 2)
+ self.assertEquals(instance_type['extra_specs'], {})
+
+ def test_instance_type_get_all(self):
+ specs = dict(cpu_arch="x86_64",
+ cpu_model="Nehalem",
+ xpu_arch="fermi",
+ xpus='2',
+ xpu_model="Tesla 2050")
+
+ types = db.api.instance_type_get_all(context.get_admin_context())
+
+ self.assertEquals(types['cg1.4xlarge']['extra_specs'], specs)
+ self.assertEquals(types['m1.small']['extra_specs'], {})
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 8b4183164..d12e21063 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -799,7 +799,9 @@ class IptablesFirewallTestCase(test.TestCase):
self.network = utils.import_object(FLAGS.network_manager)
class FakeLibvirtConnection(object):
- pass
+ def nwfilterDefineXML(*args, **kwargs):
+ """setup_basic_rules in nwfilter calls this."""
+ pass
self.fake_libvirt_connection = FakeLibvirtConnection()
self.fw = firewall.IptablesFirewallDriver(
get_connection=lambda: self.fake_libvirt_connection)
@@ -1035,7 +1037,6 @@ class IptablesFirewallTestCase(test.TestCase):
fakefilter.filterDefineXMLMock
self.fw.nwfilter._conn.nwfilterLookupByName =\
fakefilter.nwfilterLookupByName
-
instance_ref = self._create_instance_ref()
inst_id = instance_ref['id']
instance = db.instance_get(self.context, inst_id)
@@ -1057,6 +1058,70 @@ class IptablesFirewallTestCase(test.TestCase):
db.instance_destroy(admin_ctxt, instance_ref['id'])
+ def test_provider_firewall_rules(self):
+ # setup basic instance data
+ instance_ref = self._create_instance_ref()
+ nw_info = _create_network_info(1)
+ ip = '10.11.12.13'
+ network_ref = db.project_get_network(self.context, 'fake')
+ admin_ctxt = context.get_admin_context()
+ fixed_ip = {'address': ip, 'network_id': network_ref['id']}
+ db.fixed_ip_create(admin_ctxt, fixed_ip)
+ db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
+ 'instance_id': instance_ref['id']})
+ # FRAGILE: peeks at how the firewall names chains
+ chain_name = 'inst-%s' % instance_ref['id']
+
+ # create a firewall via setup_basic_filtering like libvirt_conn.spawn
+ # should have a chain with 0 rules
+ self.fw.setup_basic_filtering(instance_ref, network_info=nw_info)
+ self.assertTrue('provider' in self.fw.iptables.ipv4['filter'].chains)
+ rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
+ if rule.chain == 'provider']
+ self.assertEqual(0, len(rules))
+
+ # add a rule and send the update message, check for 1 rule
+ provider_fw0 = db.provider_fw_rule_create(admin_ctxt,
+ {'protocol': 'tcp',
+ 'cidr': '10.99.99.99/32',
+ 'from_port': 1,
+ 'to_port': 65535})
+ self.fw.refresh_provider_fw_rules()
+ rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
+ if rule.chain == 'provider']
+ self.assertEqual(1, len(rules))
+
+ # Add another, refresh, and make sure number of rules goes to two
+ provider_fw1 = db.provider_fw_rule_create(admin_ctxt,
+ {'protocol': 'udp',
+ 'cidr': '10.99.99.99/32',
+ 'from_port': 1,
+ 'to_port': 65535})
+ self.fw.refresh_provider_fw_rules()
+ rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
+ if rule.chain == 'provider']
+ self.assertEqual(2, len(rules))
+
+ # create the instance filter and make sure it has a jump rule
+ self.fw.prepare_instance_filter(instance_ref, network_info=nw_info)
+ self.fw.apply_instance_filter(instance_ref)
+ inst_rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
+ if rule.chain == chain_name]
+ jump_rules = [rule for rule in inst_rules if '-j' in rule.rule]
+ provjump_rules = []
+ # IptablesTable doesn't make rules unique internally
+ for rule in jump_rules:
+ if 'provider' in rule.rule and rule not in provjump_rules:
+ provjump_rules.append(rule)
+ self.assertEqual(1, len(provjump_rules))
+
+ # remove a rule from the db, cast to compute to refresh rule
+ db.provider_fw_rule_destroy(admin_ctxt, provider_fw1['id'])
+ self.fw.refresh_provider_fw_rules()
+ rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
+ if rule.chain == 'provider']
+ self.assertEqual(1, len(rules))
+
class NWFilterTestCase(test.TestCase):
def setUp(self):
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
index 77f6aaff3..9327c7129 100644
--- a/nova/tests/test_network.py
+++ b/nova/tests/test_network.py
@@ -18,7 +18,7 @@
"""
Unit Tests for network code
"""
-import IPy
+import netaddr
import os
from nova import test
@@ -164,3 +164,33 @@ class IptablesManagerTestCase(test.TestCase):
self.assertTrue('-A %s -j run_tests.py-%s' \
% (chain, chain) in new_lines,
"Built-in chain %s not wrapped" % (chain,))
+
+ def test_will_empty_chain(self):
+ self.manager.ipv4['filter'].add_chain('test-chain')
+ self.manager.ipv4['filter'].add_rule('test-chain', '-j DROP')
+ old_count = len(self.manager.ipv4['filter'].rules)
+ self.manager.ipv4['filter'].empty_chain('test-chain')
+ self.assertEqual(old_count - 1, len(self.manager.ipv4['filter'].rules))
+
+ def test_will_empty_unwrapped_chain(self):
+ self.manager.ipv4['filter'].add_chain('test-chain', wrap=False)
+ self.manager.ipv4['filter'].add_rule('test-chain', '-j DROP',
+ wrap=False)
+ old_count = len(self.manager.ipv4['filter'].rules)
+ self.manager.ipv4['filter'].empty_chain('test-chain', wrap=False)
+ self.assertEqual(old_count - 1, len(self.manager.ipv4['filter'].rules))
+
+ def test_will_not_empty_wrapped_when_unwrapped(self):
+ self.manager.ipv4['filter'].add_chain('test-chain')
+ self.manager.ipv4['filter'].add_rule('test-chain', '-j DROP')
+ old_count = len(self.manager.ipv4['filter'].rules)
+ self.manager.ipv4['filter'].empty_chain('test-chain', wrap=False)
+ self.assertEqual(old_count, len(self.manager.ipv4['filter'].rules))
+
+ def test_will_not_empty_unwrapped_when_wrapped(self):
+ self.manager.ipv4['filter'].add_chain('test-chain', wrap=False)
+ self.manager.ipv4['filter'].add_rule('test-chain', '-j DROP',
+ wrap=False)
+ old_count = len(self.manager.ipv4['filter'].rules)
+ self.manager.ipv4['filter'].empty_chain('test-chain')
+ self.assertEqual(old_count, len(self.manager.ipv4['filter'].rules))
diff --git a/nova/tests/test_objectstore.py b/nova/tests/test_objectstore.py
index c78772f27..39b4e18d7 100644
--- a/nova/tests/test_objectstore.py
+++ b/nova/tests/test_objectstore.py
@@ -70,11 +70,15 @@ class S3APITestCase(test.TestCase):
os.mkdir(FLAGS.buckets_path)
router = s3server.S3Application(FLAGS.buckets_path)
- server = wsgi.Server()
- server.start(router, FLAGS.s3_port, host=FLAGS.s3_host)
+ self.server = wsgi.Server("S3 Objectstore",
+ router,
+ host=FLAGS.s3_host,
+ port=FLAGS.s3_port)
+ self.server.start()
if not boto.config.has_section('Boto'):
boto.config.add_section('Boto')
+
boto.config.set('Boto', 'num_retries', '0')
conn = s3.S3Connection(aws_access_key_id=self.admin_user.access,
aws_secret_access_key=self.admin_user.secret,
@@ -145,4 +149,5 @@ class S3APITestCase(test.TestCase):
"""Tear down auth and test server."""
self.auth_manager.delete_user('admin')
self.auth_manager.delete_project('admin')
+ self.server.stop()
super(S3APITestCase, self).tearDown()
diff --git a/nova/tests/test_service.py b/nova/tests/test_service.py
index d1cc8bd61..f45f76b73 100644
--- a/nova/tests/test_service.py
+++ b/nova/tests/test_service.py
@@ -30,6 +30,7 @@ from nova import rpc
from nova import test
from nova import service
from nova import manager
+from nova import wsgi
from nova.compute import manager as compute_manager
FLAGS = flags.FLAGS
@@ -349,3 +350,32 @@ class ServiceTestCase(test.TestCase):
serv.stop()
db.service_destroy(ctxt, service_ref['id'])
+
+
+class TestWSGIService(test.TestCase):
+
+ def setUp(self):
+ super(TestWSGIService, self).setUp()
+ self.stubs.Set(wsgi.Loader, "load_app", mox.MockAnything())
+
+ def test_service_random_port(self):
+ test_service = service.WSGIService("test_service")
+ self.assertEquals(0, test_service.port)
+ test_service.start()
+ self.assertNotEqual(0, test_service.port)
+ test_service.stop()
+
+
+class TestLauncher(test.TestCase):
+
+ def setUp(self):
+ super(TestLauncher, self).setUp()
+ self.stubs.Set(wsgi.Loader, "load_app", mox.MockAnything())
+ self.service = service.WSGIService("test_service")
+
+ def test_launch_app(self):
+ self.assertEquals(0, self.service.port)
+ launcher = service.Launcher()
+ launcher.launch_service(self.service)
+ self.assertEquals(0, self.service.port)
+ launcher.stop()
diff --git a/nova/tests/test_vlan_network.py b/nova/tests/test_vlan_network.py
index 063b81832..a1c8ab11c 100644
--- a/nova/tests/test_vlan_network.py
+++ b/nova/tests/test_vlan_network.py
@@ -18,7 +18,7 @@
"""
Unit Tests for vlan network code
"""
-import IPy
+import netaddr
import os
from nova import context
@@ -44,8 +44,8 @@ class VlanNetworkTestCase(base.NetworkTestCase):
# TODO(vish): better way of adding floating ips
self.context._project = self.projects[0]
self.context.project_id = self.projects[0].id
- pubnet = IPy.IP(flags.FLAGS.floating_range)
- address = str(pubnet[0])
+ pubnet = netaddr.IPNetwork(flags.FLAGS.floating_range)
+ address = str(list(pubnet)[0])
try:
db.floating_ip_get_by_address(context.get_admin_context(), address)
except exception.NotFound:
diff --git a/nova/tests/test_wsgi.py b/nova/tests/test_wsgi.py
new file mode 100644
index 000000000..b71e8d418
--- /dev/null
+++ b/nova/tests/test_wsgi.py
@@ -0,0 +1,95 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for `nova.wsgi`."""
+
+import os.path
+import tempfile
+
+import unittest
+
+import nova.exception
+import nova.test
+import nova.wsgi
+
+
+class TestLoaderNothingExists(unittest.TestCase):
+ """Loader tests where os.path.exists always returns False."""
+
+ def setUp(self):
+ self._os_path_exists = os.path.exists
+ os.path.exists = lambda _: False
+
+ def test_config_not_found(self):
+ self.assertRaises(
+ nova.exception.PasteConfigNotFound,
+ nova.wsgi.Loader,
+ )
+
+ def tearDown(self):
+ os.path.exists = self._os_path_exists
+
+
+class TestLoaderNormalFilesystem(unittest.TestCase):
+ """Loader tests with normal filesystem (unmodified os.path module)."""
+
+ _paste_config = """
+[app:test_app]
+use = egg:Paste#static
+document_root = /tmp
+ """
+
+ def setUp(self):
+ self.config = tempfile.NamedTemporaryFile(mode="w+t")
+ self.config.write(self._paste_config.lstrip())
+ self.config.seek(0)
+ self.config.flush()
+ self.loader = nova.wsgi.Loader(self.config.name)
+
+ def test_config_found(self):
+ self.assertEquals(self.config.name, self.loader.config_path)
+
+ def test_app_not_found(self):
+ self.assertRaises(
+ nova.exception.PasteAppNotFound,
+ self.loader.load_app,
+ "non-existant app",
+ )
+
+ def test_app_found(self):
+ url_parser = self.loader.load_app("test_app")
+ self.assertEquals("/tmp", url_parser.directory)
+
+ def tearDown(self):
+ self.config.close()
+
+
+class TestWSGIServer(unittest.TestCase):
+ """WSGI server tests."""
+
+ def test_no_app(self):
+ server = nova.wsgi.Server("test_app", None)
+ self.assertEquals("test_app", server.name)
+
+ def test_start_random_port(self):
+ server = nova.wsgi.Server("test_random_port", None, host="127.0.0.1")
+ self.assertEqual(0, server.port)
+ server.start()
+ self.assertNotEqual(0, server.port)
+ server.stop()
+ server.wait()