From b814f9fef3efa1bdcb7e03a9161e08721b7bc8c4 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Fri, 15 Jul 2011 17:56:27 -0700 Subject: VSA: first cut. merged with 1279 --- nova/tests/test_libvirt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index f99e1713d..36e469be3 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -242,7 +242,7 @@ class LibvirtConnTestCase(test.TestCase): return """ - + -- cgit From 9e74803d5eb8a70ba829ac0569f1cd6cd372a6f2 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Fri, 22 Jul 2011 15:14:29 -0700 Subject: Reverted volume driver part --- .../api/openstack/contrib/test_drive_types.py | 192 +++++++++++++++++ nova/tests/api/openstack/contrib/test_vsa.py | 239 +++++++++++++++++++++ nova/tests/test_drive_types.py | 146 +++++++++++++ 3 files changed, 577 insertions(+) create mode 100644 nova/tests/api/openstack/contrib/test_drive_types.py create mode 100644 nova/tests/api/openstack/contrib/test_vsa.py create mode 100644 nova/tests/test_drive_types.py (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_drive_types.py b/nova/tests/api/openstack/contrib/test_drive_types.py new file mode 100644 index 000000000..2f7d327d3 --- /dev/null +++ b/nova/tests/api/openstack/contrib/test_drive_types.py @@ -0,0 +1,192 @@ +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import stubout +import webob + +#from nova import compute +from nova.vsa import drive_types +from nova import exception +from nova import context +from nova import test +from nova import log as logging +from nova.tests.api.openstack import fakes + +from nova.api.openstack.contrib.drive_types import _drive_type_view + +LOG = logging.getLogger('nova.tests.api.openstack.drive_types') + +last_param = {} + + +def _get_default_drive_type(): + param = { + 'name': 'Test drive type', + 'type': 'SATA', + 'size_gb': 123, + 'rpm': '7200', + 'capabilities': '', + 'visible': True + } + return param + + +def _create(context, **param): + global last_param + LOG.debug(_("_create: %s"), param) + param['id'] = 123 + last_param = param + return param + + +def _delete(context, id): + global last_param + last_param = dict(id=id) + + LOG.debug(_("_delete: %s"), locals()) + + +def _get(context, id): + global last_param + last_param = dict(id=id) + + LOG.debug(_("_get: %s"), locals()) + if id != '123': + raise exception.NotFound + + dtype = _get_default_drive_type() + dtype['id'] = id + return dtype + + +def _get_all(context, visible=True): + LOG.debug(_("_get_all: %s"), locals()) + dtype = _get_default_drive_type() + dtype['id'] = 123 + return [dtype] + + +class DriveTypesApiTest(test.TestCase): + def setUp(self): + super(DriveTypesApiTest, self).setUp() + self.stubs = stubout.StubOutForTesting() + fakes.FakeAuthManager.reset_fake_data() + fakes.FakeAuthDatabase.data = {} + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + fakes.stub_out_auth(self.stubs) + self.stubs.Set(drive_types, "create", _create) + self.stubs.Set(drive_types, "delete", _delete) + self.stubs.Set(drive_types, "get", _get) + self.stubs.Set(drive_types, "get_all", _get_all) + + self.context = context.get_admin_context() + + def tearDown(self): + self.stubs.UnsetAll() + super(DriveTypesApiTest, self).tearDown() + + def test_drive_types_api_create(self): + global last_param + last_param = {} + + dtype = _get_default_drive_type() + dtype['id'] = 123 + + body = dict(drive_type=_drive_type_view(dtype)) + req = webob.Request.blank('/v1.1/zadr-drive_types') + req.method = 'POST' + req.body = json.dumps(body) + req.headers['content-type'] = 'application/json' + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + # Compare if parameters were correctly passed to stub + for k, v in last_param.iteritems(): + self.assertEqual(last_param[k], dtype[k]) + + resp_dict = json.loads(resp.body) + + # Compare response + self.assertTrue('drive_type' in resp_dict) + resp_dtype = resp_dict['drive_type'] + self.assertEqual(resp_dtype, _drive_type_view(dtype)) + + def test_drive_types_api_delete(self): + global last_param + last_param = {} + + dtype_id = 123 + req = webob.Request.blank('/v1.1/zadr-drive_types/%d' % dtype_id) + req.method = 'DELETE' + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + self.assertEqual(str(last_param['id']), str(dtype_id)) + + def test_drive_types_show(self): + global last_param + last_param = {} + + dtype_id = 123 + req = webob.Request.blank('/v1.1/zadr-drive_types/%d' % dtype_id) + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + self.assertEqual(str(last_param['id']), str(dtype_id)) + + resp_dict = json.loads(resp.body) + + # Compare response + self.assertTrue('drive_type' in resp_dict) + resp_dtype = resp_dict['drive_type'] + exp_dtype = _get_default_drive_type() + exp_dtype['id'] = dtype_id + exp_dtype_view = _drive_type_view(exp_dtype) + for k, v in exp_dtype_view.iteritems(): + self.assertEqual(str(resp_dtype[k]), str(exp_dtype_view[k])) + + def test_drive_types_show_invalid_id(self): + global last_param + last_param = {} + + dtype_id = 234 + req = webob.Request.blank('/v1.1/zadr-drive_types/%d' % dtype_id) + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 404) + self.assertEqual(str(last_param['id']), str(dtype_id)) + + def test_drive_types_index(self): + + req = webob.Request.blank('/v1.1/zadr-drive_types') + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + resp_dict = json.loads(resp.body) + + self.assertTrue('drive_types' in resp_dict) + resp_dtypes = resp_dict['drive_types'] + self.assertEqual(len(resp_dtypes), 1) + + resp_dtype = resp_dtypes.pop() + exp_dtype = _get_default_drive_type() + exp_dtype['id'] = 123 + exp_dtype_view = _drive_type_view(exp_dtype) + for k, v in exp_dtype_view.iteritems(): + self.assertEqual(str(resp_dtype[k]), str(exp_dtype_view[k])) diff --git a/nova/tests/api/openstack/contrib/test_vsa.py b/nova/tests/api/openstack/contrib/test_vsa.py new file mode 100644 index 000000000..bc0b7eaa6 --- /dev/null +++ b/nova/tests/api/openstack/contrib/test_vsa.py @@ -0,0 +1,239 @@ +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import stubout +import webob + +#from nova import compute +from nova import vsa +from nova import exception +from nova import context +from nova import test +from nova import log as logging +from nova.tests.api.openstack import fakes + +from nova.api.openstack.contrib.virtual_storage_arrays import _vsa_view + +LOG = logging.getLogger('nova.tests.api.openstack.vsa') + +last_param = {} + + +def _get_default_vsa_param(): + return { + 'display_name': 'Test_VSA_name', + 'display_description': 'Test_VSA_description', + 'vc_count': 1, + 'instance_type': 'm1.small', + 'image_name': None, + 'availability_zone': None, + 'storage': [], + 'shared': False + } + + +def stub_vsa_create(self, context, **param): + global last_param + LOG.debug(_("_create: param=%s"), param) + param['id'] = 123 + param['name'] = 'Test name' + last_param = param + return param + + +def stub_vsa_delete(self, context, vsa_id): + global last_param + last_param = dict(vsa_id=vsa_id) + + LOG.debug(_("_delete: %s"), locals()) + if vsa_id != '123': + raise exception.NotFound + + +def stub_vsa_get(self, context, vsa_id): + global last_param + last_param = dict(vsa_id=vsa_id) + + LOG.debug(_("_get: %s"), locals()) + if vsa_id != '123': + raise exception.NotFound + + param = _get_default_vsa_param() + param['id'] = vsa_id + return param + + +def stub_vsa_get_all(self, context): + LOG.debug(_("_get_all: %s"), locals()) + param = _get_default_vsa_param() + param['id'] = 123 + return [param] + + +class VSAApiTest(test.TestCase): + def setUp(self): + super(VSAApiTest, self).setUp() + self.stubs = stubout.StubOutForTesting() + fakes.FakeAuthManager.reset_fake_data() + fakes.FakeAuthDatabase.data = {} + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + fakes.stub_out_auth(self.stubs) + self.stubs.Set(vsa.api.API, "create", stub_vsa_create) + self.stubs.Set(vsa.api.API, "delete", stub_vsa_delete) + self.stubs.Set(vsa.api.API, "get", stub_vsa_get) + self.stubs.Set(vsa.api.API, "get_all", stub_vsa_get_all) + + self.context = context.get_admin_context() + + def tearDown(self): + self.stubs.UnsetAll() + super(VSAApiTest, self).tearDown() + + def test_vsa_api_create(self): + global last_param + last_param = {} + + vsa = {"displayName": "VSA Test Name", + "displayDescription": "VSA Test Desc"} + body = dict(vsa=vsa) + req = webob.Request.blank('/v1.1/zadr-vsa') + req.method = 'POST' + req.body = json.dumps(body) + req.headers['content-type'] = 'application/json' + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + # Compare if parameters were correctly passed to stub + self.assertEqual(last_param['display_name'], "VSA Test Name") + self.assertEqual(last_param['display_description'], "VSA Test Desc") + + resp_dict = json.loads(resp.body) + self.assertTrue('vsa' in resp_dict) + self.assertEqual(resp_dict['vsa']['displayName'], vsa['displayName']) + self.assertEqual(resp_dict['vsa']['displayDescription'], + vsa['displayDescription']) + + def test_vsa_api_create_no_body(self): + req = webob.Request.blank('/v1.1/zadr-vsa') + req.method = 'POST' + req.body = json.dumps({}) + req.headers['content-type'] = 'application/json' + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 422) + + def test_vsa_api_delete(self): + global last_param + last_param = {} + + vsa_id = 123 + req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req.method = 'DELETE' + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) + + def test_vsa_api_delete_invalid_id(self): + global last_param + last_param = {} + + vsa_id = 234 + req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req.method = 'DELETE' + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 404) + self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) + + def test_vsa_api_show(self): + global last_param + last_param = {} + + vsa_id = 123 + req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) + + resp_dict = json.loads(resp.body) + self.assertTrue('vsa' in resp_dict) + self.assertEqual(resp_dict['vsa']['id'], str(vsa_id)) + + def test_vsa_api_show_invalid_id(self): + global last_param + last_param = {} + + vsa_id = 234 + req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 404) + self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) + + def test_vsa_api_index(self): + req = webob.Request.blank('/v1.1/zadr-vsa') + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + resp_dict = json.loads(resp.body) + + self.assertTrue('vsaSet' in resp_dict) + resp_vsas = resp_dict['vsaSet'] + self.assertEqual(len(resp_vsas), 1) + + resp_vsa = resp_vsas.pop() + self.assertEqual(resp_vsa['id'], 123) + + def test_vsa_api_detail(self): + req = webob.Request.blank('/v1.1/zadr-vsa/detail') + req.method = 'GET' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + resp_dict = json.loads(resp.body) + + self.assertTrue('vsaSet' in resp_dict) + resp_vsas = resp_dict['vsaSet'] + self.assertEqual(len(resp_vsas), 1) + + resp_vsa = resp_vsas.pop() + self.assertEqual(resp_vsa['id'], 123) + + +class VSAVolumeDriveApiTest(test.TestCase): + def setUp(self): + super(VSAVolumeDriveApiTest, self).setUp() + self.stubs = stubout.StubOutForTesting() + fakes.FakeAuthManager.reset_fake_data() + fakes.FakeAuthDatabase.data = {} + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + fakes.stub_out_auth(self.stubs) + self.stubs.Set(vsa.api.API, "create", stub_vsa_create) + self.stubs.Set(vsa.api.API, "delete", stub_vsa_delete) + self.stubs.Set(vsa.api.API, "get", stub_vsa_get) + self.stubs.Set(vsa.api.API, "get_all", stub_vsa_get_all) + + self.context = context.get_admin_context() + + def tearDown(self): + self.stubs.UnsetAll() + super(VSAVolumeDriveApiTest, self).tearDown() diff --git a/nova/tests/test_drive_types.py b/nova/tests/test_drive_types.py new file mode 100644 index 000000000..8534bcde5 --- /dev/null +++ b/nova/tests/test_drive_types.py @@ -0,0 +1,146 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 Zadara Storage Inc. +# 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 drive types codecode +""" +import time + +from nova import context +from nova import flags +from nova import log as logging +from nova import test +from nova.vsa import drive_types + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.vsa') + + +class DriveTypesTestCase(test.TestCase): + """Test cases for driver types code""" + def setUp(self): + super(DriveTypesTestCase, self).setUp() + self.cntx = context.RequestContext(None, None) + self.cntx_admin = context.get_admin_context() + self._dtype = self._create_drive_type() + + def tearDown(self): + self._dtype = None + + def _create_drive_type(self): + """Create a volume object.""" + dtype = {} + dtype['type'] = 'SATA' + dtype['size_gb'] = 150 + dtype['rpm'] = 5000 + dtype['capabilities'] = None + dtype['visible'] = True + + LOG.debug(_("Drive Type created %s"), dtype) + return dtype + + def test_drive_type_create_delete(self): + dtype = self._dtype + prev_all_dtypes = drive_types.get_all(self.cntx_admin, False) + + new = drive_types.create(self.cntx_admin, **dtype) + for k, v in dtype.iteritems(): + self.assertEqual(v, new[k], 'one of fields doesnt match') + + new_all_dtypes = drive_types.get_all(self.cntx_admin, False) + self.assertNotEqual(len(prev_all_dtypes), + len(new_all_dtypes), + 'drive type was not created') + + drive_types.delete(self.cntx_admin, new['id']) + new_all_dtypes = drive_types.get_all(self.cntx_admin, False) + self.assertEqual(prev_all_dtypes, + new_all_dtypes, + 'drive types was not deleted') + + def test_drive_type_check_name_generation(self): + dtype = self._dtype + new = drive_types.create(self.cntx_admin, **dtype) + expected_name = FLAGS.drive_type_template_short % \ + (dtype['type'], dtype['size_gb'], dtype['rpm']) + self.assertEqual(new['name'], expected_name, + 'name was not generated correctly') + + dtype['capabilities'] = 'SEC' + new2 = drive_types.create(self.cntx_admin, **dtype) + expected_name = FLAGS.drive_type_template_long % \ + (dtype['type'], dtype['size_gb'], dtype['rpm'], + dtype['capabilities']) + self.assertEqual(new2['name'], expected_name, + 'name was not generated correctly') + + drive_types.delete(self.cntx_admin, new['id']) + drive_types.delete(self.cntx_admin, new2['id']) + + def test_drive_type_create_delete_invisible(self): + dtype = self._dtype + dtype['visible'] = False + prev_all_dtypes = drive_types.get_all(self.cntx_admin, True) + new = drive_types.create(self.cntx_admin, **dtype) + + new_all_dtypes = drive_types.get_all(self.cntx_admin, True) + self.assertEqual(prev_all_dtypes, new_all_dtypes) + + new_all_dtypes = drive_types.get_all(self.cntx_admin, False) + self.assertNotEqual(prev_all_dtypes, new_all_dtypes) + + drive_types.delete(self.cntx_admin, new['id']) + + def test_drive_type_rename_update(self): + dtype = self._dtype + dtype['capabilities'] = None + + new = drive_types.create(self.cntx_admin, **dtype) + for k, v in dtype.iteritems(): + self.assertEqual(v, new[k], 'one of fields doesnt match') + + new_name = 'NEW_DRIVE_NAME' + new = drive_types.rename(self.cntx_admin, new['name'], new_name) + self.assertEqual(new['name'], new_name) + + new = drive_types.rename(self.cntx_admin, new_name) + expected_name = FLAGS.drive_type_template_short % \ + (dtype['type'], dtype['size_gb'], dtype['rpm']) + self.assertEqual(new['name'], expected_name) + + changes = {'rpm': 7200} + new = drive_types.update(self.cntx_admin, new['id'], **changes) + for k, v in changes.iteritems(): + self.assertEqual(v, new[k], 'one of fields doesnt match') + + drive_types.delete(self.cntx_admin, new['id']) + + def test_drive_type_get(self): + dtype = self._dtype + new = drive_types.create(self.cntx_admin, **dtype) + + new2 = drive_types.get(self.cntx_admin, new['id']) + for k, v in new2.iteritems(): + self.assertEqual(str(new[k]), str(new2[k]), + 'one of fields doesnt match') + + new2 = drive_types.get_by_name(self.cntx_admin, new['name']) + for k, v in new.iteritems(): + self.assertEqual(str(new[k]), str(new2[k]), + 'one of fields doesnt match') + + drive_types.delete(self.cntx_admin, new['id']) -- cgit From 61781dae931ced36db0f2735da474d0bd38a53cf Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Fri, 22 Jul 2011 20:25:32 -0700 Subject: more unittest changes --- nova/tests/api/openstack/contrib/test_vsa.py | 238 +++++++++++++++++++++++++-- 1 file changed, 220 insertions(+), 18 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_vsa.py b/nova/tests/api/openstack/contrib/test_vsa.py index bc0b7eaa6..c3150fa9c 100644 --- a/nova/tests/api/openstack/contrib/test_vsa.py +++ b/nova/tests/api/openstack/contrib/test_vsa.py @@ -15,18 +15,26 @@ import json import stubout +import unittest import webob -#from nova import compute -from nova import vsa + from nova import exception +from nova import flags +from nova import vsa +from nova import db +from nova import volume from nova import context from nova import test from nova import log as logging +from nova.api import openstack from nova.tests.api.openstack import fakes +import nova.wsgi from nova.api.openstack.contrib.virtual_storage_arrays import _vsa_view +FLAGS = flags.FLAGS + LOG = logging.getLogger('nova.tests.api.openstack.vsa') last_param = {} @@ -103,7 +111,7 @@ class VSAApiTest(test.TestCase): self.stubs.UnsetAll() super(VSAApiTest, self).tearDown() - def test_vsa_api_create(self): + def test_vsa_create(self): global last_param last_param = {} @@ -128,7 +136,7 @@ class VSAApiTest(test.TestCase): self.assertEqual(resp_dict['vsa']['displayDescription'], vsa['displayDescription']) - def test_vsa_api_create_no_body(self): + def test_vsa_create_no_body(self): req = webob.Request.blank('/v1.1/zadr-vsa') req.method = 'POST' req.body = json.dumps({}) @@ -137,7 +145,7 @@ class VSAApiTest(test.TestCase): resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 422) - def test_vsa_api_delete(self): + def test_vsa_delete(self): global last_param last_param = {} @@ -149,7 +157,7 @@ class VSAApiTest(test.TestCase): self.assertEqual(resp.status_int, 200) self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) - def test_vsa_api_delete_invalid_id(self): + def test_vsa_delete_invalid_id(self): global last_param last_param = {} @@ -161,7 +169,7 @@ class VSAApiTest(test.TestCase): self.assertEqual(resp.status_int, 404) self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) - def test_vsa_api_show(self): + def test_vsa_show(self): global last_param last_param = {} @@ -176,7 +184,7 @@ class VSAApiTest(test.TestCase): self.assertTrue('vsa' in resp_dict) self.assertEqual(resp_dict['vsa']['id'], str(vsa_id)) - def test_vsa_api_show_invalid_id(self): + def test_vsa_show_invalid_id(self): global last_param last_param = {} @@ -187,7 +195,7 @@ class VSAApiTest(test.TestCase): self.assertEqual(resp.status_int, 404) self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) - def test_vsa_api_index(self): + def test_vsa_index(self): req = webob.Request.blank('/v1.1/zadr-vsa') req.method = 'GET' resp = req.get_response(fakes.wsgi_app()) @@ -202,7 +210,7 @@ class VSAApiTest(test.TestCase): resp_vsa = resp_vsas.pop() self.assertEqual(resp_vsa['id'], 123) - def test_vsa_api_detail(self): + def test_vsa_detail(self): req = webob.Request.blank('/v1.1/zadr-vsa/detail') req.method = 'GET' resp = req.get_response(fakes.wsgi_app()) @@ -218,22 +226,216 @@ class VSAApiTest(test.TestCase): self.assertEqual(resp_vsa['id'], 123) -class VSAVolumeDriveApiTest(test.TestCase): - def setUp(self): - super(VSAVolumeDriveApiTest, self).setUp() +def _get_default_volume_param(): + return { + 'id': 123, + 'status': 'available', + 'size': 100, + 'availability_zone': 'nova', + 'created_at': None, + 'attach_status': 'detached', + 'display_name': 'Default vol name', + 'display_description': 'Default vol description', + 'from_vsa_id': None, + 'to_vsa_id': None, + } + + +def stub_volume_create(self, context, size, snapshot_id, name, description, + **param): + LOG.debug(_("_create: param=%s"), size) + vol = _get_default_volume_param() + for k, v in param.iteritems(): + vol[k] = v + vol['size'] = size + vol['display_name'] = name + vol['display_description'] = description + return vol + + +def stub_volume_update(self, context, **param): + LOG.debug(_("_volume_update: param=%s"), param) + pass + + +def stub_volume_delete(self, context, **param): + LOG.debug(_("_volume_delete: param=%s"), param) + pass + + +def stub_volume_get(self, context, volume_id): + LOG.debug(_("_volume_get: volume_id=%s"), volume_id) + vol = _get_default_volume_param() + vol['id'] = volume_id + if volume_id == '234': + vol['from_vsa_id'] = 123 + if volume_id == '345': + vol['to_vsa_id'] = 123 + return vol + + +def stub_volume_get_notfound(self, context, volume_id): + raise exception.NotFound + + +def stub_volume_get_all_by_vsa(self, context, vsa_id, direction): + vol = stub_volume_get(self, context, '123') + vol['%s_vsa_id' % direction] = vsa_id + return [vol] + + +def return_vsa(context, vsa_id): + return {'id': vsa_id} + + +class VSAVolumeApiTest(test.TestCase): + + def setUp(self, test_obj=None, test_objs=None): + super(VSAVolumeApiTest, self).setUp() self.stubs = stubout.StubOutForTesting() fakes.FakeAuthManager.reset_fake_data() fakes.FakeAuthDatabase.data = {} fakes.stub_out_networking(self.stubs) fakes.stub_out_rate_limiting(self.stubs) fakes.stub_out_auth(self.stubs) - self.stubs.Set(vsa.api.API, "create", stub_vsa_create) - self.stubs.Set(vsa.api.API, "delete", stub_vsa_delete) - self.stubs.Set(vsa.api.API, "get", stub_vsa_get) - self.stubs.Set(vsa.api.API, "get_all", stub_vsa_get_all) + self.stubs.Set(nova.db.api, 'vsa_get', return_vsa) + + self.stubs.Set(volume.api.API, "create", stub_volume_create) + self.stubs.Set(volume.api.API, "update", stub_volume_update) + self.stubs.Set(volume.api.API, "delete", stub_volume_delete) + self.stubs.Set(volume.api.API, "get_all_by_vsa", + stub_volume_get_all_by_vsa) + self.stubs.Set(volume.api.API, "get", stub_volume_get) self.context = context.get_admin_context() + self.test_obj = test_obj if test_obj else "volume" + self.test_objs = test_objs if test_objs else "volumes" + + def tearDown(self): + self.stubs.UnsetAll() + super(VSAVolumeApiTest, self).tearDown() + + def test_vsa_volume_create(self): + vol = {"size": 100, + "displayName": "VSA Volume Test Name", + "displayDescription": "VSA Volume Test Desc"} + body = {self.test_obj: vol} + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s' % self.test_objs) + req.method = 'POST' + req.body = json.dumps(body) + req.headers['content-type'] = 'application/json' + resp = req.get_response(fakes.wsgi_app()) + + if self.test_obj == "volume": + self.assertEqual(resp.status_int, 200) + + resp_dict = json.loads(resp.body) + self.assertTrue(self.test_obj in resp_dict) + self.assertEqual(resp_dict[self.test_obj]['size'], + vol['size']) + self.assertEqual(resp_dict[self.test_obj]['displayName'], + vol['displayName']) + self.assertEqual(resp_dict[self.test_obj]['displayDescription'], + vol['displayDescription']) + else: + self.assertEqual(resp.status_int, 400) + + def test_vsa_volume_create_no_body(self): + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s' % self.test_objs) + req.method = 'POST' + req.body = json.dumps({}) + req.headers['content-type'] = 'application/json' + + resp = req.get_response(fakes.wsgi_app()) + if self.test_obj == "volume": + self.assertEqual(resp.status_int, 422) + else: + self.assertEqual(resp.status_int, 400) + + def test_vsa_volume_index(self): + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s' % self.test_objs) + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + def test_vsa_volume_detail(self): + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/detail' % \ + self.test_objs) + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + def test_vsa_volume_show(self): + obj_num = 234 if self.test_objs == "volumes" else 345 + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ + (self.test_objs, obj_num)) + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + + def test_vsa_volume_show_no_vsa_assignment(self): + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + (self.test_objs)) + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 400) + + def test_vsa_volume_show_no_volume(self): + self.stubs.Set(volume.api.API, "get", stub_volume_get_notfound) + + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + (self.test_objs)) + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 404) + + def test_vsa_volume_update(self): + obj_num = 234 if self.test_objs == "volumes" else 345 + update = {"status": "available"} + body = {self.test_obj: update} + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ + (self.test_objs, obj_num)) + req.method = 'PUT' + req.body = json.dumps(body) + req.headers['content-type'] = 'application/json' + + resp = req.get_response(fakes.wsgi_app()) + if self.test_obj == "volume": + self.assertEqual(resp.status_int, 202) + else: + self.assertEqual(resp.status_int, 400) + + def test_vsa_volume_delete(self): + obj_num = 234 if self.test_objs == "volumes" else 345 + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ + (self.test_objs, obj_num)) + req.method = 'DELETE' + resp = req.get_response(fakes.wsgi_app()) + if self.test_obj == "volume": + self.assertEqual(resp.status_int, 202) + else: + self.assertEqual(resp.status_int, 400) + + def test_vsa_volume_delete_no_vsa_assignment(self): + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + (self.test_objs)) + req.method = 'DELETE' + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 400) + + def test_vsa_volume_delete_no_volume(self): + self.stubs.Set(volume.api.API, "get", stub_volume_get_notfound) + + req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + (self.test_objs)) + req.method = 'DELETE' + resp = req.get_response(fakes.wsgi_app()) + if self.test_obj == "volume": + self.assertEqual(resp.status_int, 404) + else: + self.assertEqual(resp.status_int, 400) + + +class VSADriveApiTest(VSAVolumeApiTest): + def setUp(self): + super(VSADriveApiTest, self).setUp(test_obj="drive", + test_objs="drives") def tearDown(self): self.stubs.UnsetAll() - super(VSAVolumeDriveApiTest, self).tearDown() + super(VSADriveApiTest, self).tearDown() -- cgit From fb755ae05b0b6a7b3701614c8d702e8a24ff380c Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Sun, 24 Jul 2011 00:07:00 -0700 Subject: some cosmetic changes. Prior to merge proposal --- nova/tests/test_vsa.py | 185 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 nova/tests/test_vsa.py (limited to 'nova/tests') diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py new file mode 100644 index 000000000..859fe3325 --- /dev/null +++ b/nova/tests/test_vsa.py @@ -0,0 +1,185 @@ +# 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 stubout +import base64 + +from xml.etree import ElementTree +from xml.etree.ElementTree import Element, SubElement + +from nova import exception +from nova import flags +from nova import vsa +from nova import db +from nova import context +from nova import test +from nova import log as logging +import nova.image.fake + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.vsa') + + +def fake_drive_type_get_by_name(context, name): + drive_type = { + 'id': 1, + 'name': name, + 'type': name.split('_')[0], + 'size_gb': int(name.split('_')[1]), + 'rpm': name.split('_')[2], + 'capabilities': '', + 'visible': True} + return drive_type + + +class VsaTestCase(test.TestCase): + + def setUp(self): + super(VsaTestCase, self).setUp() + self.stubs = stubout.StubOutForTesting() + self.vsa_api = vsa.API() + + self.context_non_admin = context.RequestContext(None, None) + self.context = context.get_admin_context() + + def fake_show_by_name(meh, context, name): + if name == 'wrong_image_name': + LOG.debug(_("Test: Emulate wrong VSA name. Raise")) + raise exception.ImageNotFound + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} + + self.stubs.Set(nova.image.fake._FakeImageService, 'show_by_name', + fake_show_by_name) + + def tearDown(self): + self.stubs.UnsetAll() + super(VsaTestCase, self).tearDown() + + def test_vsa_create_delete_defaults(self): + param = {'display_name': 'VSA name test'} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['display_name'], param['display_name']) + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_create_delete_check_in_db(self): + vsa_list1 = self.vsa_api.get_all(self.context) + vsa_ref = self.vsa_api.create(self.context) + vsa_list2 = self.vsa_api.get_all(self.context) + self.assertEqual(len(vsa_list2), len(vsa_list1) + 1) + + self.vsa_api.delete(self.context, vsa_ref['id']) + vsa_list3 = self.vsa_api.get_all(self.context) + self.assertEqual(len(vsa_list3), len(vsa_list2) - 1) + + def test_vsa_create_delete_high_vc_count(self): + param = {'vc_count': FLAGS.max_vcs_in_vsa + 1} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['vc_count'], FLAGS.max_vcs_in_vsa) + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_create_wrong_image_name(self): + param = {'image_name': 'wrong_image_name'} + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context, **param) + + def test_vsa_create_db_error(self): + + def fake_vsa_create(context, options): + LOG.debug(_("Test: Emulate DB error. Raise")) + raise exception.Error + + self.stubs.Set(nova.db.api, 'vsa_create', fake_vsa_create) + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context) + + def test_vsa_create_wrong_storage_params(self): + vsa_list1 = self.vsa_api.get_all(self.context) + param = {'storage': [{'stub': 1}]} + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context, **param) + vsa_list2 = self.vsa_api.get_all(self.context) + self.assertEqual(len(vsa_list2), len(vsa_list1) + 1) + + param = {'storage': [{'drive_name': 'wrong name'}]} + self.assertRaises(exception.ApiError, + self.vsa_api.create, self.context, **param) + + def test_vsa_create_with_storage(self, multi_vol_creation=True): + """Test creation of VSA with BE storage""" + + FLAGS.vsa_multi_vol_creation = multi_vol_creation + + self.stubs.Set(nova.vsa.drive_types, 'get_by_name', + fake_drive_type_get_by_name) + + param = {'storage': [{'drive_name': 'SATA_500_7200', + 'num_drives': 3}]} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['vol_count'], 3) + self.vsa_api.delete(self.context, vsa_ref['id']) + + param = {'storage': [{'drive_name': 'SATA_500_7200', + 'num_drives': 3}], + 'shared': True} + vsa_ref = self.vsa_api.create(self.context, **param) + self.assertEqual(vsa_ref['vol_count'], 15) + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_create_with_storage_single_volumes(self): + self.test_vsa_create_with_storage(multi_vol_creation=False) + + def test_vsa_update(self): + vsa_ref = self.vsa_api.create(self.context) + + param = {'vc_count': FLAGS.max_vcs_in_vsa + 1} + vsa_ref = self.vsa_api.update(self.context, vsa_ref['id'], **param) + self.assertEqual(vsa_ref['vc_count'], FLAGS.max_vcs_in_vsa) + + param = {'vc_count': 2} + vsa_ref = self.vsa_api.update(self.context, vsa_ref['id'], **param) + self.assertEqual(vsa_ref['vc_count'], 2) + + self.vsa_api.delete(self.context, vsa_ref['id']) + + def test_vsa_generate_user_data(self): + self.stubs.Set(nova.vsa.drive_types, 'get_by_name', + fake_drive_type_get_by_name) + + FLAGS.vsa_multi_vol_creation = False + param = {'display_name': 'VSA name test', + 'display_description': 'VSA desc test', + 'vc_count': 2, + 'storage': [{'drive_name': 'SATA_500_7200', + 'num_drives': 3}]} + vsa_ref = self.vsa_api.create(self.context, **param) + volumes = db.volume_get_all_assigned_to_vsa(self.context, + vsa_ref['id']) + + user_data = self.vsa_api.generate_user_data(self.context, + vsa_ref, + volumes) + user_data = base64.b64decode(user_data) + + LOG.debug(_("Test: user_data = %s"), user_data) + + elem = ElementTree.fromstring(user_data) + self.assertEqual(elem.findtext('name'), + param['display_name']) + self.assertEqual(elem.findtext('description'), + param['display_description']) + self.assertEqual(elem.findtext('vc_count'), + str(param['vc_count'])) + + self.vsa_api.delete(self.context, vsa_ref['id']) -- cgit From c500eac4589e9cb22e5e71b900164a151290ec03 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Mon, 25 Jul 2011 16:26:23 -0700 Subject: some cleanup. VSA flag status changes. returned some files --- nova/tests/api/openstack/contrib/test_vsa.py | 4 +++- nova/tests/test_drive_types.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_vsa.py b/nova/tests/api/openstack/contrib/test_vsa.py index c3150fa9c..3c9136e14 100644 --- a/nova/tests/api/openstack/contrib/test_vsa.py +++ b/nova/tests/api/openstack/contrib/test_vsa.py @@ -234,6 +234,7 @@ def _get_default_volume_param(): 'availability_zone': 'nova', 'created_at': None, 'attach_status': 'detached', + 'name': 'vol name', 'display_name': 'Default vol name', 'display_description': 'Default vol description', 'from_vsa_id': None, @@ -386,7 +387,8 @@ class VSAVolumeApiTest(test.TestCase): def test_vsa_volume_update(self): obj_num = 234 if self.test_objs == "volumes" else 345 - update = {"status": "available"} + update = {"status": "available", + "displayName": "Test Display name"} body = {self.test_obj: update} req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ (self.test_objs, obj_num)) diff --git a/nova/tests/test_drive_types.py b/nova/tests/test_drive_types.py index 8534bcde5..e91c41321 100644 --- a/nova/tests/test_drive_types.py +++ b/nova/tests/test_drive_types.py @@ -1,6 +1,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2011 Zadara Storage Inc. +# Copyright (c) 2011 OpenStack LLC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may -- cgit From a72f2e29e2a35791a1c53f4f606948572ab52280 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Tue, 26 Jul 2011 13:25:34 -0700 Subject: VSA volume creation/deletion changes --- nova/tests/test_vsa.py | 5 +- nova/tests/test_vsa_volumes.py | 108 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 nova/tests/test_vsa_volumes.py (limited to 'nova/tests') diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py index 859fe3325..8e4d58960 100644 --- a/nova/tests/test_vsa.py +++ b/nova/tests/test_vsa.py @@ -60,8 +60,9 @@ class VsaTestCase(test.TestCase): raise exception.ImageNotFound return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} - self.stubs.Set(nova.image.fake._FakeImageService, 'show_by_name', - fake_show_by_name) + self.stubs.Set(nova.image.fake._FakeImageService, + 'show_by_name', + fake_show_by_name) def tearDown(self): self.stubs.UnsetAll() diff --git a/nova/tests/test_vsa_volumes.py b/nova/tests/test_vsa_volumes.py new file mode 100644 index 000000000..0facd3b1b --- /dev/null +++ b/nova/tests/test_vsa_volumes.py @@ -0,0 +1,108 @@ +# 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 stubout + +from nova import exception +from nova import flags +from nova import vsa +from nova import volume +from nova import db +from nova import context +from nova import test +from nova import log as logging +import nova.image.fake + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.vsa.volumes') + + +def _default_volume_param(): + return { + 'size': 1, + 'snapshot_id': None, + 'name': 'Test volume name', + 'description': 'Test volume desc name' + } + + +class VsaVolumesTestCase(test.TestCase): + + def setUp(self): + super(VsaVolumesTestCase, self).setUp() + self.stubs = stubout.StubOutForTesting() + self.vsa_api = vsa.API() + self.volume_api = volume.API() + + self.context_non_admin = context.RequestContext(None, None) + self.context = context.get_admin_context() + + def fake_show_by_name(meh, context, name): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} + + self.stubs.Set(nova.image.fake._FakeImageService, + 'show_by_name', + fake_show_by_name) + + param = {'display_name': 'VSA name test'} + vsa_ref = self.vsa_api.create(self.context, **param) + self.vsa_id = vsa_ref['id'] + + def tearDown(self): + self.vsa_api.delete(self.context, self.vsa_id) + self.stubs.UnsetAll() + super(VsaVolumesTestCase, self).tearDown() + + def test_vsa_volume_create_delete(self): + """ Check if volume properly created and deleted. """ + vols1 = self.volume_api.get_all_by_vsa(self.context, + self.vsa_id, "from") + volume_param = _default_volume_param() + volume_param['from_vsa_id'] = self.vsa_id + volume_ref = self.volume_api.create(self.context, **volume_param) + + self.assertEqual(volume_ref['display_name'], + volume_param['name']) + self.assertEqual(volume_ref['display_description'], + volume_param['description']) + self.assertEqual(volume_ref['size'], + volume_param['size']) + self.assertEqual(volume_ref['status'], + 'available') + + vols2 = self.volume_api.get_all_by_vsa(self.context, + self.vsa_id, "from") + self.assertEqual(len(vols1) + 1, len(vols2)) + + self.volume_api.delete(self.context, volume_ref['id']) + vols3 = self.volume_api.get_all_by_vsa(self.context, + self.vsa_id, "from") + self.assertEqual(len(vols3) + 1, len(vols2)) + + def test_vsa_volume_delete_nonavail_volume(self): + """ Check volume deleton in different states. """ + volume_param = _default_volume_param() + volume_param['from_vsa_id'] = self.vsa_id + volume_ref = self.volume_api.create(self.context, **volume_param) + + self.volume_api.update(self.context, + volume_ref['id'], {'status': 'in-use'}) + self.assertRaises(exception.ApiError, + self.volume_api.delete, + self.context, volume_ref['id']) + + self.volume_api.update(self.context, + volume_ref['id'], {'status': 'error'}) + self.volume_api.delete(self.context, volume_ref['id']) -- cgit From 336b2703ef90fcd7b422434434c9967880b97204 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Tue, 26 Jul 2011 13:28:23 -0700 Subject: pep8 compliance --- nova/tests/test_vsa_volumes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_vsa_volumes.py b/nova/tests/test_vsa_volumes.py index 0facd3b1b..e1d4cd756 100644 --- a/nova/tests/test_vsa_volumes.py +++ b/nova/tests/test_vsa_volumes.py @@ -67,7 +67,7 @@ class VsaVolumesTestCase(test.TestCase): def test_vsa_volume_create_delete(self): """ Check if volume properly created and deleted. """ - vols1 = self.volume_api.get_all_by_vsa(self.context, + vols1 = self.volume_api.get_all_by_vsa(self.context, self.vsa_id, "from") volume_param = _default_volume_param() volume_param['from_vsa_id'] = self.vsa_id @@ -82,7 +82,7 @@ class VsaVolumesTestCase(test.TestCase): self.assertEqual(volume_ref['status'], 'available') - vols2 = self.volume_api.get_all_by_vsa(self.context, + vols2 = self.volume_api.get_all_by_vsa(self.context, self.vsa_id, "from") self.assertEqual(len(vols1) + 1, len(vols2)) @@ -90,7 +90,7 @@ class VsaVolumesTestCase(test.TestCase): vols3 = self.volume_api.get_all_by_vsa(self.context, self.vsa_id, "from") self.assertEqual(len(vols3) + 1, len(vols2)) - + def test_vsa_volume_delete_nonavail_volume(self): """ Check volume deleton in different states. """ volume_param = _default_volume_param() -- cgit From 401de172b86a13010885e70bc78351e72a7dfde3 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Wed, 27 Jul 2011 22:49:16 -0700 Subject: prior to nova-1336 merge --- nova/tests/api/openstack/test_extensions.py | 7 +- nova/tests/scheduler/test_vsa_scheduler.py | 616 ++++++++++++++++++++++++++++ nova/tests/test_vsa.py | 2 + nova/tests/test_vsa_volumes.py | 23 +- 4 files changed, 644 insertions(+), 4 deletions(-) create mode 100644 nova/tests/scheduler/test_vsa_scheduler.py (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index d459c694f..2febe50e5 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -97,8 +97,9 @@ class ExtensionControllerTest(unittest.TestCase): data = json.loads(response.body) names = [x['name'] for x in data['extensions']] names.sort() - self.assertEqual(names, ["FlavorExtraSpecs", "Floating_ips", - "Fox In Socks", "Hosts", "Multinic", "Volumes"]) + self.assertEqual(names, ["DriveTypes", "FlavorExtraSpecs", + "Floating_ips", "Fox In Socks", "Hosts", "Multinic", "VSAs", + "Volumes"]) # Make sure that at least Fox in Sox is correct. (fox_ext,) = [ @@ -145,7 +146,7 @@ class ExtensionControllerTest(unittest.TestCase): # Make sure we have all the extensions. exts = root.findall('{0}extension'.format(NS)) - self.assertEqual(len(exts), 6) + self.assertEqual(len(exts), 8) # Make sure that at least Fox in Sox is correct. (fox_ext,) = [x for x in exts if x.get('alias') == 'FOXNSOX'] diff --git a/nova/tests/scheduler/test_vsa_scheduler.py b/nova/tests/scheduler/test_vsa_scheduler.py new file mode 100644 index 000000000..697ad3842 --- /dev/null +++ b/nova/tests/scheduler/test_vsa_scheduler.py @@ -0,0 +1,616 @@ +# 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 stubout + +import nova +from nova import exception +from nova import flags +from nova import db +from nova import context +from nova import test +from nova import utils +from nova import log as logging + +from nova.scheduler import vsa as vsa_sched +from nova.scheduler import driver + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.scheduler.vsa') + +scheduled_volumes = [] +scheduled_volume = {} +global_volume = {} + + +class FakeVsaLeastUsedScheduler( + vsa_sched.VsaSchedulerLeastUsedHost): + # No need to stub anything at the moment + pass + + +class FakeVsaMostAvailCapacityScheduler( + vsa_sched.VsaSchedulerMostAvailCapacity): + # No need to stub anything at the moment + pass + + +class VsaSchedulerTestCase(test.TestCase): + + def _get_vol_creation_request(self, num_vols, drive_ix, size=0): + volume_params = [] + for i in range(num_vols): + drive_type = {'id': i, + 'name': 'name_' + str(drive_ix), + 'type': 'type_' + str(drive_ix), + 'size_gb': 1 + 100 * (drive_ix)} + volume = {'size': size, + 'snapshot_id': None, + 'name': 'vol_' + str(i), + 'description': None, + 'drive_ref': drive_type} + volume_params.append(volume) + + return {'num_volumes': len(volume_params), + 'vsa_id': 123, + 'volumes': volume_params} + + def _generate_default_service_states(self): + service_states = {} + for i in range(self.host_num): + host = {} + hostname = 'host_' + str(i) + if hostname in self.exclude_host_list: + continue + + host['volume'] = {'timestamp': utils.utcnow(), + 'drive_qos_info': {}} + + for j in range(self.drive_type_start_ix, + self.drive_type_start_ix + self.drive_type_num): + dtype = {} + dtype['Name'] = 'name_' + str(j) + dtype['DriveType'] = 'type_' + str(j) + dtype['TotalDrives'] = 2 * (self.init_num_drives + i) + dtype['DriveCapacity'] = vsa_sched.GB_TO_BYTES(1 + 100 * j) + dtype['TotalCapacity'] = dtype['TotalDrives'] * \ + dtype['DriveCapacity'] + dtype['AvailableCapacity'] = (dtype['TotalDrives'] - i) * \ + dtype['DriveCapacity'] + dtype['DriveRpm'] = 7200 + dtype['DifCapable'] = 0 + dtype['SedCapable'] = 0 + dtype['PartitionDrive'] = { + 'PartitionSize': 0, + 'NumOccupiedPartitions': 0, + 'NumFreePartitions': 0} + dtype['FullDrive'] = { + 'NumFreeDrives': dtype['TotalDrives'] - i, + 'NumOccupiedDrives': i} + host['volume']['drive_qos_info'][dtype['Name']] = dtype + + service_states[hostname] = host + + return service_states + + def _print_service_states(self): + for host, host_val in self.service_states.iteritems(): + LOG.info(_("Host %s"), host) + total_used = 0 + total_available = 0 + qos = host_val['volume']['drive_qos_info'] + + for k, d in qos.iteritems(): + LOG.info("\t%s: type %s: drives (used %2d, total %2d) "\ + "size %3d, total %4d, used %4d, avail %d", + k, d['DriveType'], + d['FullDrive']['NumOccupiedDrives'], d['TotalDrives'], + vsa_sched.BYTES_TO_GB(d['DriveCapacity']), + vsa_sched.BYTES_TO_GB(d['TotalCapacity']), + vsa_sched.BYTES_TO_GB(d['TotalCapacity'] - \ + d['AvailableCapacity']), + vsa_sched.BYTES_TO_GB(d['AvailableCapacity'])) + + total_used += vsa_sched.BYTES_TO_GB(d['TotalCapacity'] - \ + d['AvailableCapacity']) + total_available += vsa_sched.BYTES_TO_GB( + d['AvailableCapacity']) + LOG.info("Host %s: used %d, avail %d", + host, total_used, total_available) + + def _set_service_states(self, host_num, + drive_type_start_ix, drive_type_num, + init_num_drives=10, + exclude_host_list=[]): + self.host_num = host_num + self.drive_type_start_ix = drive_type_start_ix + self.drive_type_num = drive_type_num + self.exclude_host_list = exclude_host_list + self.init_num_drives = init_num_drives + self.service_states = self._generate_default_service_states() + + def _get_service_states(self): + return self.service_states + + def _fake_get_service_states(self): + return self._get_service_states() + + def _fake_provision_volume(self, context, vol, vsa_id, availability_zone): + global scheduled_volumes + scheduled_volumes.append(dict(vol=vol, + vsa_id=vsa_id, + az=availability_zone)) + name = vol['name'] + host = vol['host'] + LOG.debug(_("Test: provision vol %(name)s on host %(host)s"), + locals()) + LOG.debug(_("\t vol=%(vol)s"), locals()) + pass + + def _fake_vsa_update(self, context, vsa_id, values): + LOG.debug(_("Test: VSA update request: vsa_id=%(vsa_id)s "\ + "values=%(values)s"), locals()) + pass + + def _fake_volume_create(self, context, options): + LOG.debug(_("Test: Volume create: %s"), options) + options['id'] = 123 + global global_volume + global_volume = options + return options + + def _fake_volume_get(self, context, volume_id): + LOG.debug(_("Test: Volume get request: id=%(volume_id)s"), locals()) + global global_volume + global_volume['id'] = volume_id + global_volume['availability_zone'] = None + return global_volume + + def _fake_volume_update(self, context, volume_id, values): + LOG.debug(_("Test: Volume update request: id=%(volume_id)s "\ + "values=%(values)s"), locals()) + global scheduled_volume + scheduled_volume = {'id': volume_id, 'host': values['host']} + pass + + def _fake_service_get_by_args(self, context, host, binary): + return "service" + + def _fake_service_is_up_True(self, service): + return True + + def _fake_service_is_up_False(self, service): + return False + + def setUp(self, sched_class=None): + super(VsaSchedulerTestCase, self).setUp() + self.stubs = stubout.StubOutForTesting() + self.context_non_admin = context.RequestContext(None, None) + self.context = context.get_admin_context() + + if sched_class is None: + self.sched = FakeVsaLeastUsedScheduler() + else: + self.sched = sched_class + + self.host_num = 10 + self.drive_type_num = 5 + + self.stubs.Set(self.sched, + '_get_service_states', self._fake_get_service_states) + self.stubs.Set(self.sched, + '_provision_volume', self._fake_provision_volume) + self.stubs.Set(nova.db, 'vsa_update', self._fake_vsa_update) + + self.stubs.Set(nova.db, 'volume_get', self._fake_volume_get) + self.stubs.Set(nova.db, 'volume_update', self._fake_volume_update) + + def tearDown(self): + self.stubs.UnsetAll() + super(VsaSchedulerTestCase, self).tearDown() + + def test_vsa_sched_create_volumes_simple(self): + global scheduled_volumes + scheduled_volumes = [] + self._set_service_states(host_num=10, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=10, + exclude_host_list=['host_1', 'host_3']) + prev = self._generate_default_service_states() + request_spec = self._get_vol_creation_request(num_vols=3, drive_ix=2) + + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + + self.assertEqual(len(scheduled_volumes), 3) + self.assertEqual(scheduled_volumes[0]['vol']['host'], 'host_0') + self.assertEqual(scheduled_volumes[1]['vol']['host'], 'host_2') + self.assertEqual(scheduled_volumes[2]['vol']['host'], 'host_4') + + cur = self._get_service_states() + for host in ['host_0', 'host_2', 'host_4']: + cur_dtype = cur[host]['volume']['drive_qos_info']['name_2'] + prev_dtype = prev[host]['volume']['drive_qos_info']['name_2'] + self.assertEqual(cur_dtype['DriveType'], prev_dtype['DriveType']) + self.assertEqual(cur_dtype['FullDrive']['NumFreeDrives'], + prev_dtype['FullDrive']['NumFreeDrives'] - 1) + self.assertEqual(cur_dtype['FullDrive']['NumOccupiedDrives'], + prev_dtype['FullDrive']['NumOccupiedDrives'] + 1) + + def test_vsa_sched_no_drive_type(self): + self._set_service_states(host_num=10, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=1) + request_spec = self._get_vol_creation_request(num_vols=1, drive_ix=6) + self.assertRaises(driver.WillNotSchedule, + self.sched.schedule_create_volumes, + self.context, + request_spec, + availability_zone=None) + + def test_vsa_sched_no_enough_drives(self): + global scheduled_volumes + scheduled_volumes = [] + + self._set_service_states(host_num=3, + drive_type_start_ix=0, + drive_type_num=1, + init_num_drives=0) + prev = self._generate_default_service_states() + request_spec = self._get_vol_creation_request(num_vols=3, drive_ix=0) + + self.assertRaises(driver.WillNotSchedule, + self.sched.schedule_create_volumes, + self.context, + request_spec, + availability_zone=None) + + # check that everything was returned back + cur = self._get_service_states() + for k, v in prev.iteritems(): + self.assertEqual(prev[k]['volume']['drive_qos_info'], + cur[k]['volume']['drive_qos_info']) + + def test_vsa_sched_wrong_topic(self): + self._set_service_states(host_num=1, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=1) + states = self._get_service_states() + new_states = {} + new_states['host_0'] = {'compute': states['host_0']['volume']} + self.service_states = new_states + request_spec = self._get_vol_creation_request(num_vols=1, drive_ix=0) + + self.assertRaises(driver.WillNotSchedule, + self.sched.schedule_create_volumes, + self.context, + request_spec, + availability_zone=None) + + def test_vsa_sched_provision_volume(self): + global global_volume + global_volume = {} + self._set_service_states(host_num=1, + drive_type_start_ix=0, + drive_type_num=1, + init_num_drives=1) + request_spec = self._get_vol_creation_request(num_vols=1, drive_ix=0) + + self.stubs.UnsetAll() + self.stubs.Set(self.sched, + '_get_service_states', self._fake_get_service_states) + self.stubs.Set(nova.db, 'volume_create', self._fake_volume_create) + + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + + self.assertEqual(request_spec['volumes'][0]['name'], + global_volume['display_name']) + + def test_vsa_sched_no_free_drives(self): + self._set_service_states(host_num=1, + drive_type_start_ix=0, + drive_type_num=1, + init_num_drives=1) + request_spec = self._get_vol_creation_request(num_vols=1, drive_ix=0) + + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + + cur = self._get_service_states() + cur_dtype = cur['host_0']['volume']['drive_qos_info']['name_0'] + self.assertEqual(cur_dtype['FullDrive']['NumFreeDrives'], 1) + + new_request = self._get_vol_creation_request(num_vols=1, drive_ix=0) + + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + self._print_service_states() + + self.assertRaises(driver.WillNotSchedule, + self.sched.schedule_create_volumes, + self.context, + new_request, + availability_zone=None) + + def test_vsa_sched_forced_host(self): + global scheduled_volumes + scheduled_volumes = [] + + self._set_service_states(host_num=10, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=10) + + request_spec = self._get_vol_creation_request(num_vols=3, drive_ix=2) + + self.assertRaises(exception.HostBinaryNotFound, + self.sched.schedule_create_volumes, + self.context, + request_spec, + availability_zone="nova:host_5") + + self.stubs.Set(nova.db, + 'service_get_by_args', self._fake_service_get_by_args) + self.stubs.Set(self.sched, + 'service_is_up', self._fake_service_is_up_False) + + self.assertRaises(driver.WillNotSchedule, + self.sched.schedule_create_volumes, + self.context, + request_spec, + availability_zone="nova:host_5") + + self.stubs.Set(self.sched, + 'service_is_up', self._fake_service_is_up_True) + + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone="nova:host_5") + + self.assertEqual(len(scheduled_volumes), 3) + self.assertEqual(scheduled_volumes[0]['vol']['host'], 'host_5') + self.assertEqual(scheduled_volumes[1]['vol']['host'], 'host_5') + self.assertEqual(scheduled_volumes[2]['vol']['host'], 'host_5') + + def test_vsa_sched_create_volumes_partition(self): + global scheduled_volumes + scheduled_volumes = [] + self._set_service_states(host_num=5, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=1, + exclude_host_list=['host_0', 'host_2']) + prev = self._generate_default_service_states() + request_spec = self._get_vol_creation_request(num_vols=3, + drive_ix=3, + size=50) + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + + self.assertEqual(len(scheduled_volumes), 3) + self.assertEqual(scheduled_volumes[0]['vol']['host'], 'host_1') + self.assertEqual(scheduled_volumes[1]['vol']['host'], 'host_3') + self.assertEqual(scheduled_volumes[2]['vol']['host'], 'host_4') + + cur = self._get_service_states() + for host in ['host_1', 'host_3', 'host_4']: + cur_dtype = cur[host]['volume']['drive_qos_info']['name_3'] + prev_dtype = prev[host]['volume']['drive_qos_info']['name_3'] + + self.assertEqual(cur_dtype['DriveType'], prev_dtype['DriveType']) + self.assertEqual(cur_dtype['FullDrive']['NumFreeDrives'], + prev_dtype['FullDrive']['NumFreeDrives'] - 1) + self.assertEqual(cur_dtype['FullDrive']['NumOccupiedDrives'], + prev_dtype['FullDrive']['NumOccupiedDrives'] + 1) + + self.assertEqual(prev_dtype['PartitionDrive'] + ['NumOccupiedPartitions'], 0) + self.assertEqual(cur_dtype['PartitionDrive'] + ['NumOccupiedPartitions'], 1) + self.assertEqual(cur_dtype['PartitionDrive'] + ['NumFreePartitions'], 5) + + self.assertEqual(prev_dtype['PartitionDrive'] + ['NumFreePartitions'], 0) + self.assertEqual(prev_dtype['PartitionDrive'] + ['PartitionSize'], 0) + + def test_vsa_sched_create_single_volume_az(self): + global scheduled_volume + scheduled_volume = {} + + def _fake_volume_get_az(context, volume_id): + LOG.debug(_("Test: Volume get: id=%(volume_id)s"), locals()) + return {'id': volume_id, 'availability_zone': 'nova:host_3'} + + self.stubs.Set(nova.db, 'volume_get', _fake_volume_get_az) + self.stubs.Set(nova.db, + 'service_get_by_args', self._fake_service_get_by_args) + self.stubs.Set(self.sched, + 'service_is_up', self._fake_service_is_up_True) + + host = self.sched.schedule_create_volume(self.context, + 123, availability_zone=None) + + self.assertEqual(host, 'host_3') + self.assertEqual(scheduled_volume['id'], 123) + self.assertEqual(scheduled_volume['host'], 'host_3') + + def test_vsa_sched_create_single_non_vsa_volume(self): + global scheduled_volume + scheduled_volume = {} + + global global_volume + global_volume = {} + global_volume['drive_type'] = None + + self.assertRaises(driver.NoValidHost, + self.sched.schedule_create_volume, + self.context, + 123, + availability_zone=None) + + def test_vsa_sched_create_single_volume(self): + global scheduled_volume + scheduled_volume = {} + self._set_service_states(host_num=10, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=10, + exclude_host_list=['host_0', 'host_1']) + prev = self._generate_default_service_states() + + global global_volume + global_volume = {} + + drive_ix = 2 + drive_type = {'id': drive_ix, + 'name': 'name_' + str(drive_ix), + 'type': 'type_' + str(drive_ix), + 'size_gb': 1 + 100 * (drive_ix)} + + global_volume['drive_type'] = drive_type + global_volume['size'] = 0 + + host = self.sched.schedule_create_volume(self.context, + 123, availability_zone=None) + + self.assertEqual(host, 'host_2') + self.assertEqual(scheduled_volume['id'], 123) + self.assertEqual(scheduled_volume['host'], 'host_2') + + +class VsaSchedulerTestCaseMostAvail(VsaSchedulerTestCase): + + def setUp(self): + super(VsaSchedulerTestCaseMostAvail, self).setUp( + FakeVsaMostAvailCapacityScheduler()) + + def tearDown(self): + self.stubs.UnsetAll() + super(VsaSchedulerTestCaseMostAvail, self).tearDown() + + def test_vsa_sched_create_single_volume(self): + global scheduled_volume + scheduled_volume = {} + self._set_service_states(host_num=10, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=10, + exclude_host_list=['host_0', 'host_1']) + prev = self._generate_default_service_states() + + global global_volume + global_volume = {} + + drive_ix = 2 + drive_type = {'id': drive_ix, + 'name': 'name_' + str(drive_ix), + 'type': 'type_' + str(drive_ix), + 'size_gb': 1 + 100 * (drive_ix)} + + global_volume['drive_type'] = drive_type + global_volume['size'] = 0 + + host = self.sched.schedule_create_volume(self.context, + 123, availability_zone=None) + + self.assertEqual(host, 'host_9') + self.assertEqual(scheduled_volume['id'], 123) + self.assertEqual(scheduled_volume['host'], 'host_9') + + def test_vsa_sched_create_volumes_simple(self): + global scheduled_volumes + scheduled_volumes = [] + self._set_service_states(host_num=10, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=10, + exclude_host_list=['host_1', 'host_3']) + prev = self._generate_default_service_states() + request_spec = self._get_vol_creation_request(num_vols=3, drive_ix=2) + + self._print_service_states() + + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + + self.assertEqual(len(scheduled_volumes), 3) + self.assertEqual(scheduled_volumes[0]['vol']['host'], 'host_9') + self.assertEqual(scheduled_volumes[1]['vol']['host'], 'host_8') + self.assertEqual(scheduled_volumes[2]['vol']['host'], 'host_7') + + cur = self._get_service_states() + for host in ['host_9', 'host_8', 'host_7']: + cur_dtype = cur[host]['volume']['drive_qos_info']['name_2'] + prev_dtype = prev[host]['volume']['drive_qos_info']['name_2'] + self.assertEqual(cur_dtype['DriveType'], prev_dtype['DriveType']) + self.assertEqual(cur_dtype['FullDrive']['NumFreeDrives'], + prev_dtype['FullDrive']['NumFreeDrives'] - 1) + self.assertEqual(cur_dtype['FullDrive']['NumOccupiedDrives'], + prev_dtype['FullDrive']['NumOccupiedDrives'] + 1) + + def test_vsa_sched_create_volumes_partition(self): + global scheduled_volumes + scheduled_volumes = [] + self._set_service_states(host_num=5, + drive_type_start_ix=0, + drive_type_num=5, + init_num_drives=1, + exclude_host_list=['host_0', 'host_2']) + prev = self._generate_default_service_states() + request_spec = self._get_vol_creation_request(num_vols=3, + drive_ix=3, + size=50) + self.sched.schedule_create_volumes(self.context, + request_spec, + availability_zone=None) + + self.assertEqual(len(scheduled_volumes), 3) + self.assertEqual(scheduled_volumes[0]['vol']['host'], 'host_4') + self.assertEqual(scheduled_volumes[1]['vol']['host'], 'host_3') + self.assertEqual(scheduled_volumes[2]['vol']['host'], 'host_1') + + cur = self._get_service_states() + for host in ['host_1', 'host_3', 'host_4']: + cur_dtype = cur[host]['volume']['drive_qos_info']['name_3'] + prev_dtype = prev[host]['volume']['drive_qos_info']['name_3'] + + self.assertEqual(cur_dtype['DriveType'], prev_dtype['DriveType']) + self.assertEqual(cur_dtype['FullDrive']['NumFreeDrives'], + prev_dtype['FullDrive']['NumFreeDrives'] - 1) + self.assertEqual(cur_dtype['FullDrive']['NumOccupiedDrives'], + prev_dtype['FullDrive']['NumOccupiedDrives'] + 1) + + self.assertEqual(prev_dtype['PartitionDrive'] + ['NumOccupiedPartitions'], 0) + self.assertEqual(cur_dtype['PartitionDrive'] + ['NumOccupiedPartitions'], 1) + self.assertEqual(cur_dtype['PartitionDrive'] + ['NumFreePartitions'], 5) + self.assertEqual(prev_dtype['PartitionDrive'] + ['NumFreePartitions'], 0) + self.assertEqual(prev_dtype['PartitionDrive'] + ['PartitionSize'], 0) diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py index 8e4d58960..cff23a800 100644 --- a/nova/tests/test_vsa.py +++ b/nova/tests/test_vsa.py @@ -22,6 +22,7 @@ from xml.etree.ElementTree import Element, SubElement from nova import exception from nova import flags from nova import vsa +from nova import volume from nova import db from nova import context from nova import test @@ -50,6 +51,7 @@ class VsaTestCase(test.TestCase): super(VsaTestCase, self).setUp() self.stubs = stubout.StubOutForTesting() self.vsa_api = vsa.API() + self.volume_api = volume.API() self.context_non_admin = context.RequestContext(None, None) self.context = context.get_admin_context() diff --git a/nova/tests/test_vsa_volumes.py b/nova/tests/test_vsa_volumes.py index e1d4cd756..d451a4377 100644 --- a/nova/tests/test_vsa_volumes.py +++ b/nova/tests/test_vsa_volumes.py @@ -61,7 +61,8 @@ class VsaVolumesTestCase(test.TestCase): self.vsa_id = vsa_ref['id'] def tearDown(self): - self.vsa_api.delete(self.context, self.vsa_id) + if self.vsa_id: + self.vsa_api.delete(self.context, self.vsa_id) self.stubs.UnsetAll() super(VsaVolumesTestCase, self).tearDown() @@ -106,3 +107,23 @@ class VsaVolumesTestCase(test.TestCase): self.volume_api.update(self.context, volume_ref['id'], {'status': 'error'}) self.volume_api.delete(self.context, volume_ref['id']) + + def test_vsa_volume_delete_vsa_with_volumes(self): + """ Check volume deleton in different states. """ + + vols1 = self.volume_api.get_all_by_vsa(self.context, + self.vsa_id, "from") + for i in range(3): + volume_param = _default_volume_param() + volume_param['from_vsa_id'] = self.vsa_id + volume_ref = self.volume_api.create(self.context, **volume_param) + + vols2 = self.volume_api.get_all_by_vsa(self.context, + self.vsa_id, "from") + self.assertEqual(len(vols1) + 3, len(vols2)) + + self.vsa_api.delete(self.context, self.vsa_id) + + vols3 = self.volume_api.get_all_by_vsa(self.context, + self.vsa_id, "from") + self.assertEqual(len(vols1), len(vols3)) -- cgit From 57b8f976f18b1f45de16ef8e87a6e215c009d228 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Thu, 11 Aug 2011 12:04:03 -0700 Subject: moved vsa_id to metadata. Added search my meta --- nova/tests/test_compute.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 80f7ff489..661acc980 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1320,6 +1320,69 @@ class ComputeTestCase(test.TestCase): db.instance_destroy(c, instance_id2) db.instance_destroy(c, instance_id3) + def test_get_all_by_metadata(self): + """Test searching instances by metadata""" + + c = context.get_admin_context() + instance_id0 = self._create_instance() + instance_id1 = self._create_instance({ + 'metadata': {'key1': 'value1'}}) + instance_id2 = self._create_instance({ + 'metadata': {'key2': 'value2'}}) + instance_id3 = self._create_instance({ + 'metadata': {'key3': 'value3'}}) + instance_id4 = self._create_instance({ + 'metadata': {'key3': 'value3', + 'key4': 'value4'}}) + + # get all instances + instances = self.compute_api.get_all(c, + search_opts={'metadata': {}}) + self.assertEqual(len(instances), 5) + + # wrong key/value combination + instances = self.compute_api.get_all(c, + search_opts={'metadata': {'key1': 'value3'}}) + self.assertEqual(len(instances), 0) + + # non-existing keys + instances = self.compute_api.get_all(c, + search_opts={'metadata': {'key5': 'value1'}}) + self.assertEqual(len(instances), 0) + + # find existing instance + instances = self.compute_api.get_all(c, + search_opts={'metadata': {'key2': 'value2'}}) + self.assertEqual(len(instances), 1) + self.assertEqual(instances[0].id, instance_id2) + + instances = self.compute_api.get_all(c, + search_opts={'metadata': {'key3': 'value3'}}) + self.assertEqual(len(instances), 2) + instance_ids = [instance.id for instance in instances] + self.assertTrue(instance_id3 in instance_ids) + self.assertTrue(instance_id4 in instance_ids) + + # multiple criterias as a dict + instances = self.compute_api.get_all(c, + search_opts={'metadata': {'key3': 'value3', + 'key4': 'value4'}}) + self.assertEqual(len(instances), 1) + self.assertEqual(instances[0].id, instance_id4) + + # multiple criterias as a list + instances = self.compute_api.get_all(c, + search_opts={'metadata': [{'key4': 'value4'}, + {'key3': 'value3'}]}) + self.assertEqual(len(instances), 1) + self.assertEqual(instances[0].id, instance_id4) + + db.instance_destroy(c, instance_id0) + db.instance_destroy(c, instance_id1) + db.instance_destroy(c, instance_id2) + db.instance_destroy(c, instance_id3) + db.instance_destroy(c, instance_id4) + @staticmethod def _parse_db_block_device_mapping(bdm_ref): attr_list = ('delete_on_termination', 'device_name', 'no_device', -- cgit From cabf9cc8f29ad8c99971c434516e1b911f07f32f Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Wed, 17 Aug 2011 16:27:12 -0700 Subject: nova-manage VSA print & forced update_cap changes; fixed bug with report capabilities; added IP address to VSA APIs; added instances to APIs --- nova/tests/api/openstack/contrib/test_vsa.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_vsa.py b/nova/tests/api/openstack/contrib/test_vsa.py index 3c9136e14..a9b76b0ff 100644 --- a/nova/tests/api/openstack/contrib/test_vsa.py +++ b/nova/tests/api/openstack/contrib/test_vsa.py @@ -46,6 +46,7 @@ def _get_default_vsa_param(): 'display_description': 'Test_VSA_description', 'vc_count': 1, 'instance_type': 'm1.small', + 'instance_type_id': 5, 'image_name': None, 'availability_zone': None, 'storage': [], @@ -58,6 +59,7 @@ def stub_vsa_create(self, context, **param): LOG.debug(_("_create: param=%s"), param) param['id'] = 123 param['name'] = 'Test name' + param['instance_type_id'] = 5 last_param = param return param -- cgit From cab13dbfd652d1fcf9443e796e50f7eb374fc3fc Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 18 Aug 2011 12:34:01 -0400 Subject: Updated a number of items to pave the way for new states. --- nova/tests/scheduler/test_scheduler.py | 13 +++++++++---- nova/tests/test_compute.py | 29 +++++++++++++++-------------- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 158df2a27..1b5e131c9 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -40,6 +40,7 @@ from nova.scheduler import driver from nova.scheduler import manager from nova.scheduler import multi from nova.compute import power_state +from nova.compute import vm_state FLAGS = flags.FLAGS @@ -94,6 +95,9 @@ class SchedulerTestCase(test.TestCase): inst['vcpus'] = kwargs.get('vcpus', 1) inst['memory_mb'] = kwargs.get('memory_mb', 10) inst['local_gb'] = kwargs.get('local_gb', 20) + inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) + inst['task_state'] = kwargs.get('task_state', None) return db.instance_create(ctxt, inst) def test_fallback(self): @@ -271,8 +275,9 @@ class SimpleDriverTestCase(test.TestCase): inst['memory_mb'] = kwargs.get('memory_mb', 20) inst['local_gb'] = kwargs.get('local_gb', 30) inst['launched_on'] = kwargs.get('launghed_on', 'dummy') - inst['state_description'] = kwargs.get('state_description', 'running') - inst['state'] = kwargs.get('state', power_state.RUNNING) + inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['task_state'] = kwargs.get('task_state', None) + inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) return db.instance_create(self.context, inst)['id'] def _create_volume(self): @@ -664,14 +669,14 @@ class SimpleDriverTestCase(test.TestCase): block_migration=False) i_ref = db.instance_get(self.context, instance_id) - self.assertTrue(i_ref['state_description'] == 'migrating') + self.assertTrue(i_ref['vm_state'] == vm_state.MIGRATE) db.instance_destroy(self.context, instance_id) db.volume_destroy(self.context, v_ref['id']) def test_live_migration_src_check_instance_not_running(self): """The instance given by instance_id is not running.""" - instance_id = self._create_instance(state_description='migrating') + instance_id = self._create_instance(power_state=power_state.NOSTATE) i_ref = db.instance_get(self.context, instance_id) try: diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index e2fa3b140..f310eaff6 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -23,6 +23,7 @@ from nova import compute from nova.compute import instance_types from nova.compute import manager as compute_manager from nova.compute import power_state +from nova.compute import vm_state from nova import context from nova import db from nova.db.sqlalchemy import models @@ -747,8 +748,8 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'state_description': 'running', - 'state': power_state.RUNNING, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + 'task_state': None, 'host': i_ref['host']}) for v in i_ref['volumes']: dbmock.volume_update(c, v['id'], {'status': 'in-use'}) @@ -779,8 +780,8 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'state_description': 'running', - 'state': power_state.RUNNING, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + 'task_state': None, 'host': i_ref['host']}) self.compute.db = dbmock @@ -825,8 +826,8 @@ class ComputeTestCase(test.TestCase): c = context.get_admin_context() instance_id = self._create_instance() i_ref = db.instance_get(c, instance_id) - db.instance_update(c, i_ref['id'], {'state_description': 'migrating', - 'state': power_state.PAUSED}) + db.instance_update(c, i_ref['id'], {'vm_state': vm_state.MIGRATE, + 'power_state': power_state.PAUSED}) v_ref = db.volume_create(c, {'size': 1, 'instance_id': instance_id}) fix_addr = db.fixed_ip_create(c, {'address': '1.1.1.1', 'instance_id': instance_id}) @@ -887,7 +888,7 @@ 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), 1) - self.assertEqual(power_state.SHUTOFF, instances[0]['state']) + self.assertEqual(power_state.NOSTATE, instances[0]['power_state']) def test_get_all_by_name_regexp(self): """Test searching instances by name (display_name)""" @@ -1307,25 +1308,25 @@ class ComputeTestCase(test.TestCase): """Test searching instances by state""" c = context.get_admin_context() - instance_id1 = self._create_instance({'state': power_state.SHUTDOWN}) + instance_id1 = self._create_instance({'power_state': power_state.SHUTDOWN}) instance_id2 = self._create_instance({ 'id': 2, - 'state': power_state.RUNNING}) + 'power_state': power_state.RUNNING}) instance_id3 = self._create_instance({ 'id': 10, - 'state': power_state.RUNNING}) + 'power_state': power_state.RUNNING}) instances = self.compute_api.get_all(c, - search_opts={'state': power_state.SUSPENDED}) + search_opts={'power_state': power_state.SUSPENDED}) self.assertEqual(len(instances), 0) instances = self.compute_api.get_all(c, - search_opts={'state': power_state.SHUTDOWN}) + search_opts={'power_state': power_state.SHUTDOWN}) self.assertEqual(len(instances), 1) self.assertEqual(instances[0].id, instance_id1) instances = self.compute_api.get_all(c, - search_opts={'state': power_state.RUNNING}) + search_opts={'power_state': power_state.RUNNING}) self.assertEqual(len(instances), 2) instance_ids = [instance.id for instance in instances] self.assertTrue(instance_id2 in instance_ids) @@ -1333,7 +1334,7 @@ class ComputeTestCase(test.TestCase): # Test passing a list as search arg instances = self.compute_api.get_all(c, - search_opts={'state': [power_state.SHUTDOWN, + search_opts={'power_state': [power_state.SHUTDOWN, power_state.RUNNING]}) self.assertEqual(len(instances), 3) -- cgit From f4f0ce95946962be73cfc509b24fd000fc931198 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Thu, 18 Aug 2011 16:46:16 -0700 Subject: tests pass --- nova/tests/api/openstack/test_servers.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index a510d7d97..e374abb6b 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -335,6 +335,8 @@ class ServersTest(test.TestCase): "name": "server1", "status": "BUILD", "hostId": '', + "key_name": '', + "security_group": '', "image": { "id": "10", "links": [ @@ -497,6 +499,8 @@ class ServersTest(test.TestCase): "name": "server1", "status": "ACTIVE", "hostId": '', + "key_name": '', + "security_group": '', "image": { "id": "10", "links": [ @@ -588,6 +592,8 @@ class ServersTest(test.TestCase): "name": "server1", "status": "ACTIVE", "hostId": '', + "key_name": '', + "security_group": '', "image": { "id": "10", "links": [ @@ -3094,6 +3100,8 @@ class ServersViewBuilderV11Test(test.TestCase): "name": "test_server", "status": "BUILD", "hostId": '', + "key_name": '', + "security_group": '', "image": { "id": "5", "links": [ @@ -3145,6 +3153,8 @@ class ServersViewBuilderV11Test(test.TestCase): "name": "test_server", "status": "ACTIVE", "hostId": '', + "key_name": '', + "security_group": '', "image": { "id": "5", "links": [ @@ -3200,6 +3210,8 @@ class ServersViewBuilderV11Test(test.TestCase): "name": "test_server", "status": "BUILD", "hostId": '', + "key_name": '', + "security_group": '', "image": { "id": "5", "links": [ @@ -3265,6 +3277,8 @@ class ServerXMLSerializationTest(test.TestCase): "name": "test_server", "status": "BUILD", "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "key_name": '', + "security_group": '', "image": { "id": "5", "links": [ -- cgit From 203309693fc2dd648b9d4b211686228557728c89 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Thu, 18 Aug 2011 19:05:40 -0700 Subject: remove security groups, improve exception handling, add tests --- nova/tests/api/openstack/test_servers.py | 42 ++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index e374abb6b..139820c09 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -336,7 +336,6 @@ class ServersTest(test.TestCase): "status": "BUILD", "hostId": '', "key_name": '', - "security_group": '', "image": { "id": "10", "links": [ @@ -500,7 +499,6 @@ class ServersTest(test.TestCase): "status": "ACTIVE", "hostId": '', "key_name": '', - "security_group": '', "image": { "id": "10", "links": [ @@ -593,7 +591,6 @@ class ServersTest(test.TestCase): "status": "ACTIVE", "hostId": '', "key_name": '', - "security_group": '', "image": { "id": "10", "links": [ @@ -1643,6 +1640,41 @@ class ServersTest(test.TestCase): self.assertEqual(expected_flavor, server['flavor']) self.assertEqual(expected_image, server['image']) + def test_create_instance_v1_1_invalid_key_name(self): + self._setup_for_create_instance() + + image_href = 'http://localhost/v1.1/images/2' + flavor_ref = 'http://localhost/flavors/3' + body = dict(server=dict( + name='server_test', imageRef=image_href, flavorRef=flavor_ref, + key_name='nonexistentkey')) + 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_create_instance_v1_1_valid_key_name(self): + self._setup_for_create_instance() + + def key_pair_get(context, user_id, key_name): + return dict(name='mykey', public_key='public_key') + + self.stubs.Set(nova.db, 'key_pair_get', key_pair_get) + + image_href = 'http://localhost/v1.1/images/2' + flavor_ref = 'http://localhost/flavors/3' + body = dict(server=dict( + name='server_test', imageRef=image_href, flavorRef=flavor_ref, + key_name='mykey')) + 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, 202) + def test_create_instance_v1_1_invalid_flavor_href(self): self._setup_for_create_instance() @@ -3101,7 +3133,6 @@ class ServersViewBuilderV11Test(test.TestCase): "status": "BUILD", "hostId": '', "key_name": '', - "security_group": '', "image": { "id": "5", "links": [ @@ -3154,7 +3185,6 @@ class ServersViewBuilderV11Test(test.TestCase): "status": "ACTIVE", "hostId": '', "key_name": '', - "security_group": '', "image": { "id": "5", "links": [ @@ -3211,7 +3241,6 @@ class ServersViewBuilderV11Test(test.TestCase): "status": "BUILD", "hostId": '', "key_name": '', - "security_group": '', "image": { "id": "5", "links": [ @@ -3278,7 +3307,6 @@ class ServerXMLSerializationTest(test.TestCase): "status": "BUILD", "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', "key_name": '', - "security_group": '', "image": { "id": "5", "links": [ -- cgit From 1ab7b11a439cef8b48621355467d5fb460d9b2e2 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Thu, 18 Aug 2011 22:52:45 -0700 Subject: add key_name/data support to server stub --- nova/tests/api/openstack/test_servers.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 139820c09..605b3fee3 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -145,7 +145,7 @@ def instance_addresses(context, instance_id): def stub_instance(id, user_id='fake', project_id='fake', private_address=None, public_addresses=None, host=None, power_state=0, reservation_id="", uuid=FAKE_UUID, image_ref="10", - flavor_id="1", interfaces=None, name=None): + flavor_id="1", interfaces=None, name=None, key_name=''): metadata = [] metadata.append(InstanceMetadata(key='seq', value=id)) @@ -160,6 +160,11 @@ def stub_instance(id, user_id='fake', project_id='fake', private_address=None, if host is not None: host = str(host) + if key_name: + key_data = 'FAKE' + else: + key_data = '' + # ReservationID isn't sent back, hack it in there. server_name = name or "server%s" % id if reservation_id != "": @@ -176,8 +181,8 @@ def stub_instance(id, user_id='fake', project_id='fake', private_address=None, "kernel_id": "", "ramdisk_id": "", "launch_index": 0, - "key_name": "", - "key_data": "", + "key_name": key_name, + "key_data": key_data, "state": power_state, "state_description": "", "memory_mb": 0, -- cgit From 3bd386cdba53f6a54a29e510c0f9eecf9b9ea7d9 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 19 Aug 2011 15:13:40 -0400 Subject: vm_state --> vm_states --- nova/tests/scheduler/test_scheduler.py | 2 +- nova/tests/test_compute.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 1b5e131c9..629019eaf 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -40,7 +40,7 @@ from nova.scheduler import driver from nova.scheduler import manager from nova.scheduler import multi from nova.compute import power_state -from nova.compute import vm_state +from nova.compute import vm_states FLAGS = flags.FLAGS diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 188398924..ca1bbc69f 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -23,7 +23,7 @@ from nova import compute from nova.compute import instance_types from nova.compute import manager as compute_manager from nova.compute import power_state -from nova.compute import vm_state +from nova.compute import vm_states from nova import context from nova import db from nova.db.sqlalchemy import models @@ -748,7 +748,7 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_states.ACTIVE, 'task_state': None, 'host': i_ref['host']}) for v in i_ref['volumes']: @@ -780,7 +780,7 @@ class ComputeTestCase(test.TestCase): 'block_migration': False, 'disk': None}}).\ AndRaise(rpc.RemoteError('', '', '')) - dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_state.ACTIVE, + dbmock.instance_update(c, i_ref['id'], {'vm_state': vm_states.ACTIVE, 'task_state': None, 'host': i_ref['host']}) @@ -826,7 +826,7 @@ class ComputeTestCase(test.TestCase): c = context.get_admin_context() instance_id = self._create_instance() i_ref = db.instance_get(c, instance_id) - db.instance_update(c, i_ref['id'], {'vm_state': vm_state.MIGRATE, + db.instance_update(c, i_ref['id'], {'vm_state': vm_states.MIGRATE, 'power_state': power_state.PAUSED}) v_ref = db.volume_create(c, {'size': 1, 'instance_id': instance_id}) fix_addr = db.fixed_ip_create(c, {'address': '1.1.1.1', -- cgit From c4e77b67a74cb0828bb9a7ccbedcaa1baeb6188d Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Fri, 19 Aug 2011 18:34:34 -0400 Subject: Lots of modifications surrounding the OSAPI to remove any mention of dealing with power states and exclusively using vm_states and task_state modules. Currently there are still a number of tests failing, but this is a stopping place for today. --- nova/tests/api/openstack/test_server_actions.py | 28 ++++--- nova/tests/api/openstack/test_servers.py | 102 +++++++++++++++--------- nova/tests/integrated/test_servers.py | 27 ++++--- nova/tests/vmwareapi/db_fakes.py | 5 +- 4 files changed, 101 insertions(+), 61 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 80a27e30f..6f8be0f47 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -12,7 +12,8 @@ from nova import utils from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types -from nova.compute import power_state +from nova.compute import vm_states +from nova.compute import task_state import nova.db.api from nova import test from nova.tests.api.openstack import common @@ -30,17 +31,18 @@ def instance_update(context, instance_id, kwargs): return _get_instance() -def return_server_with_power_state(power_state): +def return_server_with_state(vm_state, task_state=None): def _return_server(context, id): instance = _get_instance() - instance['state'] = power_state + instance['vm_state'] = vm_state + instance['task_state'] = task_state return instance return _return_server -def return_server_with_uuid_and_power_state(power_state): +def return_server_with_uuid_and_state(vm_state, task_state=None): def _return_server(context, id): - return return_server_with_power_state(power_state) + return return_server_with_state(vm_state, task_state) return _return_server @@ -68,8 +70,8 @@ def _get_instance(): "launch_index": 0, "key_name": "", "key_data": "", - "state": 0, - "state_description": "", + "vm_state": vm_states.ACTIVE, + "task_state": None, "memory_mb": 0, "vcpus": 0, "local_gb": 0, @@ -164,11 +166,11 @@ class ServerActionsTest(test.TestCase): }, } - state = power_state.BUILDING - new_return_server = return_server_with_power_state(state) + state = vm_states.BUILD + new_return_server = return_server_with_state(state) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) self.stubs.Set(nova.db, 'instance_get_by_uuid', - return_server_with_uuid_and_power_state(state)) + return_server_with_uuid_and_state(state)) req = webob.Request.blank('/v1.0/servers/1/action') req.method = 'POST' @@ -627,11 +629,11 @@ class ServerActionsTestV11(test.TestCase): }, } - state = power_state.BUILDING - new_return_server = return_server_with_power_state(state) + state = vm_states.BUILD + new_return_server = return_server_with_state(state) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) self.stubs.Set(nova.db, 'instance_get_by_uuid', - return_server_with_uuid_and_power_state(state)) + return_server_with_uuid_and_state(state)) req = webob.Request.blank('/v1.1/servers/1/action') req.method = 'POST' diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 437620854..b500c514e 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -34,7 +34,8 @@ from nova.api.openstack import servers from nova.api.openstack import wsgi import nova.compute.api from nova.compute import instance_types -from nova.compute import power_state +from nova.compute import task_state +from nova.compute import vm_states import nova.db.api import nova.scheduler.api from nova.db.sqlalchemy.models import Instance @@ -86,15 +87,18 @@ def return_server_with_addresses(private, public): return _return_server -def return_server_with_power_state(power_state): +def return_server_with_state(vm_state, task_state=None): def _return_server(context, id): - return stub_instance(id, power_state=power_state) + return stub_instance(id, vm_state=vm_state, task_state=task_state) return _return_server -def return_server_with_uuid_and_power_state(power_state): +def return_server_with_uuid_and_state(vm_state, task_state): def _return_server(context, id): - return stub_instance(id, uuid=FAKE_UUID, power_state=power_state) + return stub_instance(id, + uuid=FAKE_UUID, + vm_state=vm_state, + task_state=task_state) return _return_server @@ -143,7 +147,8 @@ def instance_addresses(context, instance_id): def stub_instance(id, user_id='fake', project_id='fake', private_address=None, - public_addresses=None, host=None, power_state=0, + public_addresses=None, host=None, + vm_state=None, task_state=None, reservation_id="", uuid=FAKE_UUID, image_ref="10", flavor_id="1", interfaces=None, name=None): metadata = [] @@ -178,8 +183,8 @@ def stub_instance(id, user_id='fake', project_id='fake', private_address=None, "launch_index": 0, "key_name": "", "key_data": "", - "state": power_state, - "state_description": "", + "vm_state": vm_state or vm_states.BUILD, + "task_state": task_state, "memory_mb": 0, "vcpus": 0, "local_gb": 0, @@ -481,7 +486,7 @@ class ServersTest(test.TestCase): }, ] new_return_server = return_server_with_attributes( - interfaces=interfaces, power_state=1) + interfaces=interfaces, vm_state=vm_states.ACTIVE) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) req = webob.Request.blank('/v1.1/servers/1') @@ -571,8 +576,8 @@ class ServersTest(test.TestCase): }, ] new_return_server = return_server_with_attributes( - interfaces=interfaces, power_state=1, image_ref=image_ref, - flavor_id=flavor_id) + interfaces=interfaces, vm_state=vm_states.ACTIVE, + image_ref=image_ref, flavor_id=flavor_id) self.stubs.Set(nova.db.api, 'instance_get', new_return_server) req = webob.Request.blank('/v1.1/servers/1') @@ -1169,9 +1174,8 @@ class ServersTest(test.TestCase): def test_get_servers_allows_status_v1_1(self): def fake_get_all(compute_self, context, search_opts=None): self.assertNotEqual(search_opts, None) - self.assertTrue('state' in search_opts) - self.assertEqual(set(search_opts['state']), - set([power_state.RUNNING, power_state.BLOCKED])) + self.assertTrue('vm_state' in search_opts) + self.assertEqual(search_opts['vm_state'], vm_states.ACTIVE) return [stub_instance(100)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) @@ -1188,13 +1192,9 @@ class ServersTest(test.TestCase): def test_get_servers_invalid_status_v1_1(self): """Test getting servers by invalid status""" - self.flags(allow_admin_api=False) - req = webob.Request.blank('/v1.1/servers?status=running') res = req.get_response(fakes.wsgi_app()) - # The following assert will fail if either of the asserts in - # fake_get_all() fail self.assertEqual(res.status_int, 400) self.assertTrue(res.body.find('Invalid server status') > -1) @@ -1632,6 +1632,7 @@ class ServersTest(test.TestCase): server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual(1, server['id']) + self.assertEqual("BUILD", server["status"]) self.assertEqual(0, server['progress']) self.assertEqual('server_test', server['name']) self.assertEqual(expected_flavor, server['flavor']) @@ -2165,23 +2166,52 @@ class ServersTest(test.TestCase): self.assertEqual(res.status_int, 204) self.assertEqual(self.server_delete_called, True) - def test_shutdown_status(self): - new_server = return_server_with_power_state(power_state.SHUTDOWN) - self.stubs.Set(nova.db.api, 'instance_get', new_server) - 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) +class TestServerStatus(test.TestCase): + + def _get_with_state(self, vm_state, task_state=None): + new_server = return_server_with_state(vm_state, task_state) 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') + request = webob.Request.blank('/v1.0/servers/1') + response = request.get_response(fakes.wsgi_app()) + self.assertEqual(response.status_int, 200) + return json.loads(response.body) + + def test_active(self): + response = self._get_with_state(vm_states.ACTIVE) + self.assertEqual(response['server']['status'], 'ACTIVE') + + def test_reboot(self): + response = self._get_with_state(vm_states.REBOOT) + self.assertEqual(response['server']['status'], 'REBOOT') + + def test_hard_reboot(self): + response = self._get_with_state(vm_states.HARD_REBOOT) + self.assertEqual(response['server']['status'], 'HARD_REBOOT') + + def test_rebuild(self): + response = self._get_with_state(vm_states.REBUILD) + self.assertEqual(response['server']['status'], 'REBUILD') + + def test_rebuild_error(self): + response = self._get_with_state(vm_states.ERROR) + self.assertEqual(response['server']['status'], 'ERROR') + + def test_resize(self): + response = self._get_with_state(vm_states.RESIZE) + self.assertEqual(response['server']['status'], 'RESIZE') + + def test_verify_resize(self): + response = self._get_with_state(vm_states.VERIFY_RESIZE) + self.assertEqual(response['server']['status'], 'VERIFY_RESIZE') + + def test_password_update(self): + response = self._get_with_state(vm_states.ACTIVE, task_state.PASSWORD) + self.assertEqual(response['server']['status'], 'PASSWORD') + + def test_stopped(self): + response = self._get_with_state(vm_states.STOP) + self.assertEqual(response['server']['status'], 'STOPPED') class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): @@ -3018,8 +3048,8 @@ class ServersViewBuilderV11Test(test.TestCase): "launch_index": 0, "key_name": "", "key_data": "", - "state": 0, - "state_description": "", + "vm_state": vm_states.BUILD, + "task_state": None, "memory_mb": 0, "vcpus": 0, "local_gb": 0, @@ -3132,7 +3162,7 @@ class ServersViewBuilderV11Test(test.TestCase): def test_build_server_detail_active_status(self): #set the power state of the instance to running - self.instance['state'] = 1 + self.instance['vm_state'] = vm_states.ACTIVE image_bookmark = "http://localhost/images/5" flavor_bookmark = "http://localhost/flavors/1" expected_server = { diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index 725f6d529..deeb3d008 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -28,6 +28,17 @@ LOG = logging.getLogger('nova.tests.integrated') class ServersTest(integrated_helpers._IntegratedTestBase): + def _wait_for_creation(self, server): + retries = 0 + while server['status'] == 'BUILD': + time.sleep(1) + server = self.api.get_server(server['id']) + print server + retries = retries + 1 + if retries > 8: + break + return server + def test_get_servers(self): """Simple check that listing servers works.""" servers = self.api.get_servers() @@ -36,7 +47,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_delete_server(self): """Creates and deletes a server.""" - + self.flags(stub_network=True) # Create server # Build the server data gradually, checking errors along the way @@ -91,19 +102,11 @@ class ServersTest(integrated_helpers._IntegratedTestBase): server_ids = [server['id'] for server in servers] self.assertTrue(created_server_id in server_ids) - # Wait (briefly) for creation - retries = 0 - while found_server['status'] == 'build': - LOG.debug("found server: %s" % found_server) - time.sleep(1) - found_server = self.api.get_server(created_server_id) - retries = retries + 1 - if retries > 5: - break + found_server = self._wait_for_creation(found_server) # It should be available... # TODO(justinsb): Mock doesn't yet do this... - #self.assertEqual('available', found_server['status']) + self.assertEqual('ACTIVE', found_server['status']) servers = self.api.get_servers(detail=True) for server in servers: self.assertTrue("image" in server) @@ -190,6 +193,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertTrue(created_server['id']) created_server_id = created_server['id'] + created_server = self._wait_for_creation(created_server) + # rebuild the server with metadata post = {} post['rebuild'] = { diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index afd672c7a..dd38420ce 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -23,6 +23,8 @@ import time from nova import db from nova import utils +from nova.compute import task_state +from nova.compute import vm_states def stub_out_db_instance_api(stubs): @@ -64,7 +66,8 @@ def stub_out_db_instance_api(stubs): 'image_ref': values['image_ref'], 'kernel_id': values['kernel_id'], 'ramdisk_id': values['ramdisk_id'], - 'state_description': 'scheduling', + 'vm_state': vm_states.BUILD, + 'task_state': task_state.SCHEDULE, 'user_id': values['user_id'], 'project_id': values['project_id'], 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), -- cgit From f82d2d309a0f826522854fe331d1c53b8c6d6879 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 09:54:33 -0400 Subject: Ec2 API updates. --- nova/tests/test_cloud.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 0793784f8..cce9514ec 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -1163,7 +1163,7 @@ class CloudTestCase(test.TestCase): self.compute = self.start_service('compute') def _wait_for_state(self, ctxt, instance_id, predicate): - """Wait for an stopping instance to be a given state""" + """Wait for a stopped instance to be a given state""" id = ec2utils.ec2_id_to_id(instance_id) while True: info = self.cloud.compute_api.get(context=ctxt, instance_id=id) @@ -1174,12 +1174,12 @@ class CloudTestCase(test.TestCase): def _wait_for_running(self, instance_id): def is_running(info): - return info['state_description'] == 'running' + return info['vm_state'] == 'running' self._wait_for_state(self.context, instance_id, is_running) def _wait_for_stopped(self, instance_id): def is_stopped(info): - return info['state_description'] == 'stopped' + return info['vm_state'] == 'stopped' self._wait_for_state(self.context, instance_id, is_stopped) def _wait_for_terminate(self, instance_id): @@ -1562,7 +1562,7 @@ class CloudTestCase(test.TestCase): 'id': 0, 'root_device_name': '/dev/sdh', 'security_groups': [{'name': 'fake0'}, {'name': 'fake1'}], - 'state_description': 'stopping', + 'vm_state': 'stopped', 'instance_type': {'name': 'fake_type'}, 'kernel_id': 1, 'ramdisk_id': 2, -- cgit From 44aea954e5efa7d94d8333ddbf54dab6464018a0 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 10:01:13 -0400 Subject: Renamed task_state to task_states... --- nova/tests/api/openstack/test_server_actions.py | 1 - nova/tests/vmwareapi/db_fakes.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 6f8be0f47..011f83773 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -13,7 +13,6 @@ from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types from nova.compute import vm_states -from nova.compute import task_state import nova.db.api from nova import test from nova.tests.api.openstack import common diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index dd38420ce..b046071c7 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -23,7 +23,7 @@ import time from nova import db from nova import utils -from nova.compute import task_state +from nova.compute import task_states from nova.compute import vm_states @@ -67,7 +67,7 @@ def stub_out_db_instance_api(stubs): 'kernel_id': values['kernel_id'], 'ramdisk_id': values['ramdisk_id'], 'vm_state': vm_states.BUILD, - 'task_state': task_state.SCHEDULE, + 'task_state': task_states.SCHEDULE, 'user_id': values['user_id'], 'project_id': values['project_id'], 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), -- cgit From c2736787be23d0893e2d4aebcc2cad6fdc5c2bd1 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 22 Aug 2011 11:57:42 -0400 Subject: Fix scheduler and integrated tests. --- nova/tests/integrated/test_servers.py | 11 +++++++++-- nova/tests/scheduler/test_scheduler.py | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index deeb3d008..0e3a6eefb 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -35,7 +35,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): server = self.api.get_server(server['id']) print server retries = retries + 1 - if retries > 8: + if retries > 5: break return server @@ -48,8 +48,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_delete_server(self): """Creates and deletes a server.""" self.flags(stub_network=True) - # Create server + # Create server # Build the server data gradually, checking errors along the way server = {} good_server = self._build_minimal_create_server_request() @@ -184,6 +184,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_rebuild_server(self): """Rebuild a server.""" + self.flags(stub_network=True) # create a server with initially has no metadata server = self._build_minimal_create_server_request() @@ -216,6 +217,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_rebuild_server_with_metadata(self): """Rebuild a server with metadata.""" + self.flags(stub_network=True) # create a server with initially has no metadata server = self._build_minimal_create_server_request() @@ -225,6 +227,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertTrue(created_server['id']) created_server_id = created_server['id'] + created_server = self._wait_for_creation(created_server) + # rebuild the server with metadata post = {} post['rebuild'] = { @@ -252,6 +256,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): def test_create_and_rebuild_server_with_metadata_removal(self): """Rebuild a server with metadata.""" + self.flags(stub_network=True) # create a server with initially has no metadata server = self._build_minimal_create_server_request() @@ -268,6 +273,8 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertTrue(created_server['id']) created_server_id = created_server['id'] + created_server = self._wait_for_creation(created_server) + # rebuild the server with metadata post = {} post['rebuild'] = { diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 629019eaf..a1281ae73 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -95,7 +95,7 @@ class SchedulerTestCase(test.TestCase): inst['vcpus'] = kwargs.get('vcpus', 1) inst['memory_mb'] = kwargs.get('memory_mb', 10) inst['local_gb'] = kwargs.get('local_gb', 20) - inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['vm_state'] = kwargs.get('vm_state', vm_states.ACTIVE) inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) inst['task_state'] = kwargs.get('task_state', None) return db.instance_create(ctxt, inst) @@ -275,7 +275,7 @@ class SimpleDriverTestCase(test.TestCase): inst['memory_mb'] = kwargs.get('memory_mb', 20) inst['local_gb'] = kwargs.get('local_gb', 30) inst['launched_on'] = kwargs.get('launghed_on', 'dummy') - inst['vm_state'] = kwargs.get('vm_state', vm_state.ACTIVE) + inst['vm_state'] = kwargs.get('vm_state', vm_states.ACTIVE) inst['task_state'] = kwargs.get('task_state', None) inst['power_state'] = kwargs.get('power_state', power_state.RUNNING) return db.instance_create(self.context, inst)['id'] @@ -669,7 +669,7 @@ class SimpleDriverTestCase(test.TestCase): block_migration=False) i_ref = db.instance_get(self.context, instance_id) - self.assertTrue(i_ref['vm_state'] == vm_state.MIGRATE) + self.assertTrue(i_ref['vm_state'] == vm_states.MIGRATE) db.instance_destroy(self.context, instance_id) db.volume_destroy(self.context, v_ref['id']) -- cgit From d60f813201df345507ce0aca7bed0f8b719aabfe Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 22 Aug 2011 11:59:08 -0400 Subject: Fixes/updates to make test_cloud pass. --- nova/tests/test_cloud.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index cce9514ec..4d148f39e 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -38,6 +38,7 @@ from nova import test from nova import utils from nova.api.ec2 import cloud from nova.api.ec2 import ec2utils +from nova.compute import vm_states from nova.image import fake @@ -1174,12 +1175,12 @@ class CloudTestCase(test.TestCase): def _wait_for_running(self, instance_id): def is_running(info): - return info['vm_state'] == 'running' + return info['vm_state'] == vm_states.ACTIVE self._wait_for_state(self.context, instance_id, is_running) def _wait_for_stopped(self, instance_id): def is_stopped(info): - return info['vm_state'] == 'stopped' + return info['vm_state'] == vm_states.STOP self._wait_for_state(self.context, instance_id, is_stopped) def _wait_for_terminate(self, instance_id): @@ -1562,7 +1563,7 @@ class CloudTestCase(test.TestCase): 'id': 0, 'root_device_name': '/dev/sdh', 'security_groups': [{'name': 'fake0'}, {'name': 'fake1'}], - 'vm_state': 'stopped', + 'vm_state': vm_states.STOP, 'instance_type': {'name': 'fake_type'}, 'kernel_id': 1, 'ramdisk_id': 2, -- cgit From ea3684d2a2e60f19bdea6b3117be613103a605dc Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 22 Aug 2011 13:16:48 -0400 Subject: Fixes for a number of tests. --- nova/tests/vmwareapi/db_fakes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index b046071c7..b56956f96 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -67,7 +67,7 @@ def stub_out_db_instance_api(stubs): 'kernel_id': values['kernel_id'], 'ramdisk_id': values['ramdisk_id'], 'vm_state': vm_states.BUILD, - 'task_state': task_states.SCHEDULE, + 'task_state': task_states.SCHEDULING, 'user_id': values['user_id'], 'project_id': values['project_id'], 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), -- cgit From 7726b3d763a136347f2324e630f0a3cdc60a045b Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 22 Aug 2011 14:08:03 -0700 Subject: Simple usage extension for nova. Uses db to calculate tenant_usage for specified time periods. Methods: index: return a list of tenant_usages, with option of incuding detailed server_usage show: returns a specific tenant_usage object tenant_usage object: tenant_usage.total_memory_mb_usage: sum of memory_mb * hours for all instances in tenant for this period tenant_usage.total_local_gb_usage: sum of local_gb * hours for all instances in tenant for this period tenant_usage.total_vcpus_usage: sum of vcpus * hours for all instances in tenant for this period tenant_usage.total_hours: sum of all instance hours for this period tenant_usage.server_usages: A detailed list of server_usages, which describe the usage of a specific server For larger instances db tables, indexes on instance.launched_at and instance.terminated_at should significantly help performance. --- .../openstack/contrib/test_simple_tenant_usage.py | 189 +++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 nova/tests/api/openstack/contrib/test_simple_tenant_usage.py (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py new file mode 100644 index 000000000..d20e36aaf --- /dev/null +++ b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py @@ -0,0 +1,189 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# 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 datetime +import json +import webob + +from nova import context +from nova import db +from nova import flags +from nova import test +from nova.compute import instance_types +from nova.db.sqlalchemy import models +from nova.db.sqlalchemy import session +from nova.tests.api.openstack import fakes +from webob import exc + +from nova.api.openstack.contrib import simple_tenant_usage + + +FLAGS = flags.FLAGS + +SERVERS = 5 +TENANTS = 2 +HOURS = 24 +LOCAL_GB = 10 +MEMORY_MB = 1024 +VCPUS = 2 +STOP = datetime.datetime.utcnow() +START = STOP - datetime.timedelta(hours=HOURS) + + +def fake_get_session(): + class FakeFetcher(object): + def fetchall(fetcher_self): + # return 10 rows, 2 tenants, 5 servers each, each run for 1 day + return [get_fake_db_row(START, + STOP, + x, + "faketenant_%s" % (x / SERVERS)) + for x in xrange(TENANTS * SERVERS)] + + class FakeConn(object): + def execute(self, query): + return FakeFetcher() + + class FakeSession(object): + def connection(self): + return FakeConn() + + return FakeSession() + + +def fake_instance_type_get(context, instance_type_id): + return {'id': 1, + 'vcpus': VCPUS, + 'local_gb': LOCAL_GB, + 'memory_mb': MEMORY_MB, + 'name': + 'fakeflavor'} + + +def get_fake_db_row(start, end, instance_id, tenant_id): + return [instance_id, + '1', + tenant_id, + 'fakeuser', + 'name', + 'state', + 1, + start, + None] + + +class SimpleTenantUsageTest(test.TestCase): + def setUp(self): + super(SimpleTenantUsageTest, self).setUp() + self.stubs.Set(session, "get_session", + fake_get_session) + self.stubs.Set(db, "instance_type_get", + fake_instance_type_get) + self.admin_context = context.RequestContext('fakeadmin_0', + 'faketenant_0', + is_admin=True) + self.user_context = context.RequestContext('fakeadmin_0', + 'faketenant_0', + is_admin=False) + self.alt_user_context = context.RequestContext('fakeadmin_0', + 'faketenant_1', + is_admin=False) + FLAGS.allow_admin_api = True + + def test_verify_db_fields_exist_in_instance_model(self): + for field in simple_tenant_usage.INSTANCE_FIELDS: + self.assertTrue(field in models.Instance.__table__.columns) + + def test_verify_index(self): + req = webob.Request.blank( + '/v1.1/os-simple-tenant-usage?start=%s&end=%s' % + (START.isoformat(), STOP.isoformat())) + req.method = "GET" + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app( + fake_auth_context=self.admin_context)) + + self.assertEqual(res.status_int, 200) + res_dict = json.loads(res.body) + usages = res_dict['tenant_usages'] + for i in xrange(TENANTS): + self.assertEqual(int(usages[i]['total_hours']), + SERVERS * HOURS) + self.assertEqual(int(usages[i]['total_local_gb_usage']), + SERVERS * LOCAL_GB * HOURS) + self.assertEqual(int(usages[i]['total_memory_mb_usage']), + SERVERS * MEMORY_MB * HOURS) + self.assertEqual(int(usages[i]['total_vcpus_usage']), + SERVERS * VCPUS * HOURS) + self.assertFalse(usages[i].get('server_usages')) + + def test_verify_detailed_index(self): + req = webob.Request.blank( + '/v1.1/os-simple-tenant-usage?detailed=1&start=%s&end=%s' % + (START.isoformat(), STOP.isoformat())) + req.method = "GET" + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app( + fake_auth_context=self.admin_context)) + self.assertEqual(res.status_int, 200) + res_dict = json.loads(res.body) + usages = res_dict['tenant_usages'] + for i in xrange(TENANTS): + servers = usages[i]['server_usages'] + for j in xrange(SERVERS): + self.assertEqual(int(servers[j]['hours']), HOURS) + + def test_verify_index_fails_for_nonadmin(self): + req = webob.Request.blank( + '/v1.1/os-simple-tenant-usage?detailed=1&start=%s&end=%s' % + (START.isoformat(), STOP.isoformat())) + req.method = "GET" + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 403) + + def test_verify_show(self): + req = webob.Request.blank( + '/v1.1/os-simple-tenant-usage/faketenant_0?start=%s&end=%s' % + (START.isoformat(), STOP.isoformat())) + req.method = "GET" + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app( + fake_auth_context=self.user_context)) + self.assertEqual(res.status_int, 200) + res_dict = json.loads(res.body) + + usage = res_dict['tenant_usage'] + servers = usage['server_usages'] + self.assertEqual(len(usage['server_usages']), SERVERS) + for j in xrange(SERVERS): + self.assertEqual(int(servers[j]['hours']), HOURS) + + def test_verify_show_cant_view_other_tenant(self): + req = webob.Request.blank( + '/v1.1/os-simple-tenant-usage/faketenant_0?start=%s&end=%s' % + (START.isoformat(), STOP.isoformat())) + req.method = "GET" + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app( + fake_auth_context=self.alt_user_context)) + self.assertEqual(res.status_int, 403) -- cgit From 2fbaac5e07b558d7829253915523f073b07e24d4 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 23 Aug 2011 10:57:47 -0400 Subject: PEP8 fixes --- nova/tests/test_compute.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 2cf694d2c..11e1fd540 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1308,14 +1308,17 @@ class ComputeTestCase(test.TestCase): """Test searching instances by state""" c = context.get_admin_context() - instance_id1 = self._create_instance({'power_state': power_state.SHUTDOWN}) + instance_id1 = self._create_instance({ + 'power_state': power_state.SHUTDOWN, + }) instance_id2 = self._create_instance({ - 'id': 2, - 'power_state': power_state.RUNNING}) + 'id': 2, + 'power_state': power_state.RUNNING, + }) instance_id3 = self._create_instance({ - 'id': 10, - 'power_state': power_state.RUNNING}) - + 'id': 10, + 'power_state': power_state.RUNNING, + }) instances = self.compute_api.get_all(c, search_opts={'power_state': power_state.SUSPENDED}) self.assertEqual(len(instances), 0) -- cgit From 5f1380bfc69913f6aeb2a64e3501f77973493bc3 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 18:14:13 -0400 Subject: Added fix for parallel build test. --- nova/tests/api/openstack/test_server_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 0cbbe271d..eae74e75e 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -35,7 +35,7 @@ def return_server_with_attributes(**kwargs): return _return_server -def return_server_with_state(vm_state, task_state=None) +def return_server_with_state(vm_state, task_state=None): return return_server_with_attributes(vm_state=vm_state, task_state=task_state) -- cgit From 6c4329f846685ee54c5265e5cc56e58e6fbd55e9 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 24 Aug 2011 18:25:21 -0400 Subject: stub_instance fix from merge conflict --- nova/tests/api/openstack/test_server_actions.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index eae74e75e..6fb21fad3 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -46,7 +46,8 @@ def return_server_with_uuid_and_state(vm_state, task_state=None): return _return_server -def stub_instance(id, metadata=None, image_ref="10", flavor_id="1", name=None): +def stub_instance(id, metadata=None, image_ref="10", flavor_id="1", + name=None, vm_state=None, task_state=None): if metadata is not None: metadata_items = [{'key':k, 'value':v} for k, v in metadata.items()] else: @@ -67,8 +68,8 @@ def stub_instance(id, metadata=None, image_ref="10", flavor_id="1", name=None): "launch_index": 0, "key_name": "", "key_data": "", - "vm_state": vm_states.ACTIVE, - "task_state": None, + "vm_state": vm_state or vm_states.ACTIVE, + "task_state": task_state, "memory_mb": 0, "vcpus": 0, "local_gb": 0, -- cgit From 48cd9689de31e408c792052747f714a9dbe1f8f7 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Wed, 24 Aug 2011 15:51:29 -0700 Subject: added virtio flag; associate address for VSA; cosmetic changes. Prior to volume_types merge --- nova/tests/test_drive_types.py | 59 +++++++++++++++++++++--------------------- nova/tests/test_vsa.py | 2 +- 2 files changed, 30 insertions(+), 31 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_drive_types.py b/nova/tests/test_drive_types.py index e91c41321..b52e6705b 100644 --- a/nova/tests/test_drive_types.py +++ b/nova/tests/test_drive_types.py @@ -2,7 +2,6 @@ # Copyright (c) 2011 Zadara Storage Inc. # Copyright (c) 2011 OpenStack LLC. -# All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -28,21 +27,21 @@ from nova import test from nova.vsa import drive_types FLAGS = flags.FLAGS -LOG = logging.getLogger('nova.tests.vsa') +LOG = logging.getLogger('nova.tests.test_drive_types') class DriveTypesTestCase(test.TestCase): """Test cases for driver types code""" def setUp(self): super(DriveTypesTestCase, self).setUp() - self.cntx = context.RequestContext(None, None) - self.cntx_admin = context.get_admin_context() - self._dtype = self._create_drive_type() + self.ctxt = context.RequestContext(None, None) + self.ctxt_admin = context.get_admin_context() + self._dtype = self._create_default_drive_type() def tearDown(self): self._dtype = None - def _create_drive_type(self): + def _create_default_drive_type(self): """Create a volume object.""" dtype = {} dtype['type'] = 'SATA' @@ -51,97 +50,97 @@ class DriveTypesTestCase(test.TestCase): dtype['capabilities'] = None dtype['visible'] = True - LOG.debug(_("Drive Type created %s"), dtype) + LOG.debug(_("Default values for Drive Type: %s"), dtype) return dtype def test_drive_type_create_delete(self): dtype = self._dtype - prev_all_dtypes = drive_types.get_all(self.cntx_admin, False) + prev_all_dtypes = drive_types.get_all(self.ctxt_admin, False) - new = drive_types.create(self.cntx_admin, **dtype) + new = drive_types.create(self.ctxt_admin, **dtype) for k, v in dtype.iteritems(): self.assertEqual(v, new[k], 'one of fields doesnt match') - new_all_dtypes = drive_types.get_all(self.cntx_admin, False) + new_all_dtypes = drive_types.get_all(self.ctxt_admin, False) self.assertNotEqual(len(prev_all_dtypes), len(new_all_dtypes), 'drive type was not created') - drive_types.delete(self.cntx_admin, new['id']) - new_all_dtypes = drive_types.get_all(self.cntx_admin, False) + drive_types.delete(self.ctxt_admin, new['id']) + new_all_dtypes = drive_types.get_all(self.ctxt_admin, False) self.assertEqual(prev_all_dtypes, new_all_dtypes, 'drive types was not deleted') def test_drive_type_check_name_generation(self): dtype = self._dtype - new = drive_types.create(self.cntx_admin, **dtype) + new = drive_types.create(self.ctxt_admin, **dtype) expected_name = FLAGS.drive_type_template_short % \ (dtype['type'], dtype['size_gb'], dtype['rpm']) self.assertEqual(new['name'], expected_name, 'name was not generated correctly') dtype['capabilities'] = 'SEC' - new2 = drive_types.create(self.cntx_admin, **dtype) + new2 = drive_types.create(self.ctxt_admin, **dtype) expected_name = FLAGS.drive_type_template_long % \ (dtype['type'], dtype['size_gb'], dtype['rpm'], dtype['capabilities']) self.assertEqual(new2['name'], expected_name, 'name was not generated correctly') - drive_types.delete(self.cntx_admin, new['id']) - drive_types.delete(self.cntx_admin, new2['id']) + drive_types.delete(self.ctxt_admin, new['id']) + drive_types.delete(self.ctxt_admin, new2['id']) def test_drive_type_create_delete_invisible(self): dtype = self._dtype dtype['visible'] = False - prev_all_dtypes = drive_types.get_all(self.cntx_admin, True) - new = drive_types.create(self.cntx_admin, **dtype) + prev_all_dtypes = drive_types.get_all(self.ctxt_admin, True) + new = drive_types.create(self.ctxt_admin, **dtype) - new_all_dtypes = drive_types.get_all(self.cntx_admin, True) + new_all_dtypes = drive_types.get_all(self.ctxt_admin, True) self.assertEqual(prev_all_dtypes, new_all_dtypes) - new_all_dtypes = drive_types.get_all(self.cntx_admin, False) + new_all_dtypes = drive_types.get_all(self.ctxt_admin, False) self.assertNotEqual(prev_all_dtypes, new_all_dtypes) - drive_types.delete(self.cntx_admin, new['id']) + drive_types.delete(self.ctxt_admin, new['id']) def test_drive_type_rename_update(self): dtype = self._dtype dtype['capabilities'] = None - new = drive_types.create(self.cntx_admin, **dtype) + new = drive_types.create(self.ctxt_admin, **dtype) for k, v in dtype.iteritems(): self.assertEqual(v, new[k], 'one of fields doesnt match') new_name = 'NEW_DRIVE_NAME' - new = drive_types.rename(self.cntx_admin, new['name'], new_name) + new = drive_types.rename(self.ctxt_admin, new['name'], new_name) self.assertEqual(new['name'], new_name) - new = drive_types.rename(self.cntx_admin, new_name) + new = drive_types.rename(self.ctxt_admin, new_name) expected_name = FLAGS.drive_type_template_short % \ (dtype['type'], dtype['size_gb'], dtype['rpm']) self.assertEqual(new['name'], expected_name) changes = {'rpm': 7200} - new = drive_types.update(self.cntx_admin, new['id'], **changes) + new = drive_types.update(self.ctxt_admin, new['id'], **changes) for k, v in changes.iteritems(): self.assertEqual(v, new[k], 'one of fields doesnt match') - drive_types.delete(self.cntx_admin, new['id']) + drive_types.delete(self.ctxt_admin, new['id']) def test_drive_type_get(self): dtype = self._dtype - new = drive_types.create(self.cntx_admin, **dtype) + new = drive_types.create(self.ctxt_admin, **dtype) - new2 = drive_types.get(self.cntx_admin, new['id']) + new2 = drive_types.get(self.ctxt_admin, new['id']) for k, v in new2.iteritems(): self.assertEqual(str(new[k]), str(new2[k]), 'one of fields doesnt match') - new2 = drive_types.get_by_name(self.cntx_admin, new['name']) + new2 = drive_types.get_by_name(self.ctxt_admin, new['name']) for k, v in new.iteritems(): self.assertEqual(str(new[k]), str(new2[k]), 'one of fields doesnt match') - drive_types.delete(self.cntx_admin, new['id']) + drive_types.delete(self.ctxt_admin, new['id']) diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py index cff23a800..726939744 100644 --- a/nova/tests/test_vsa.py +++ b/nova/tests/test_vsa.py @@ -113,7 +113,7 @@ class VsaTestCase(test.TestCase): self.assertRaises(exception.ApiError, self.vsa_api.create, self.context, **param) vsa_list2 = self.vsa_api.get_all(self.context) - self.assertEqual(len(vsa_list2), len(vsa_list1) + 1) + self.assertEqual(len(vsa_list2), len(vsa_list1)) param = {'storage': [{'drive_name': 'wrong name'}]} self.assertRaises(exception.ApiError, -- cgit From f0fcc4ba61b4658b1e28bd69cfcf395cc408496a Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 09:04:04 -0400 Subject: Another attempt at fixing hanging test. --- nova/tests/test_xenapi.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 2f0559366..061e9ffea 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -24,6 +24,8 @@ import re import stubout import ast +eventlet.monkey_patch() + from nova import db from nova import context from nova import flags -- cgit From 0e3986e71f4bbc848e81f18d6c3e6ad33ab3684c Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 11:12:53 -0400 Subject: Removed invalid test. --- nova/tests/api/openstack/test_server_actions.py | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 6fb21fad3..b9ef41465 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -244,19 +244,6 @@ class ServerActionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 500) - def test_resized_server_has_correct_status(self): - req = self.webreq('/1', 'GET') - - def fake_migration_get(*args): - return {} - - self.stubs.Set(nova.db, 'migration_get_by_instance_and_status', - fake_migration_get) - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - body = json.loads(res.body) - self.assertEqual(body['server']['status'], 'RESIZE-CONFIRM') - def test_confirm_resize_server(self): req = self.webreq('/1/action', 'POST', dict(confirmResize=None)) -- cgit From 2cf0b67e08e1608bd717ffadd41d5029db2b4a3a Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Thu, 25 Aug 2011 21:56:45 +0000 Subject: Fix glance image authorization check now that glance can do authorization checks on its own; use correct image service when looking for ramdisk, etc.; fix a couple of PEP8 errors --- nova/tests/test_ipv6.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index 04c1b5598..e1ba4aafb 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -48,7 +48,7 @@ class IPv6RFC2462TestCase(test.TestCase): def test_to_global_with_bad_prefix(self): bad_prefix = '82' self.assertRaises(TypeError, ipv6.to_global, - bad_prefix, + bad_prefix, '2001:db8::216:3eff:fe33:4455', 'test') -- cgit From 63b26178407423524390b2a47425b6953c910e00 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 25 Aug 2011 18:00:32 -0400 Subject: Test fixup after last review feedback commit. --- nova/tests/api/openstack/test_servers.py | 11 ++++------- nova/tests/test_cloud.py | 2 +- nova/tests/test_xenapi.py | 2 -- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 3905e4f7a..f75263c45 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2488,11 +2488,6 @@ class TestServerStatus(test.TestCase): task_states.REBOOTING) self.assertEqual(response['server']['status'], 'REBOOT') - def test_hard_reboot(self): - response = self._get_with_state(vm_states.ACTIVE, - task_states.HARD_REBOOTING) - self.assertEqual(response['server']['status'], 'HARD_REBOOT') - def test_rebuild(self): response = self._get_with_state(vm_states.REBUILDING) self.assertEqual(response['server']['status'], 'REBUILD') @@ -2506,11 +2501,13 @@ class TestServerStatus(test.TestCase): self.assertEqual(response['server']['status'], 'RESIZE') def test_verify_resize(self): - response = self._get_with_state(vm_states.VERIFY_RESIZE) + response = self._get_with_state(vm_states.ACTIVE, + task_states.RESIZE_VERIFY) self.assertEqual(response['server']['status'], 'VERIFY_RESIZE') def test_password_update(self): - response = self._get_with_state(vm_states.ACTIVE, task_states.PASSWORD) + response = self._get_with_state(vm_states.ACTIVE, + task_states.UPDATING_PASSWORD) self.assertEqual(response['server']['status'], 'PASSWORD') def test_stopped(self): diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 9d58b7341..9deb5c011 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -1611,7 +1611,7 @@ class CloudTestCase(test.TestCase): self.assertEqual(groupSet, expected_groupSet) self.assertEqual(get_attribute('instanceInitiatedShutdownBehavior'), {'instance_id': 'i-12345678', - 'instanceInitiatedShutdownBehavior': 'stop'}) + 'instanceInitiatedShutdownBehavior': 'stopped'}) self.assertEqual(get_attribute('instanceType'), {'instance_id': 'i-12345678', 'instanceType': 'fake_type'}) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 061e9ffea..2f0559366 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -24,8 +24,6 @@ import re import stubout import ast -eventlet.monkey_patch() - from nova import db from nova import context from nova import flags -- cgit From 4834b920e3186712ab56e65a88c2e8c838d16f9c Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Thu, 25 Aug 2011 18:38:35 -0700 Subject: VSA code redesign. Drive types completely replaced by Volume types --- .../api/openstack/contrib/test_drive_types.py | 192 --------------------- nova/tests/api/openstack/contrib/test_vsa.py | 79 +++++---- nova/tests/api/openstack/test_extensions.py | 3 +- nova/tests/scheduler/test_vsa_scheduler.py | 68 +++++--- nova/tests/test_drive_types.py | 146 ---------------- nova/tests/test_vsa.py | 49 +++--- nova/tests/test_vsa_volumes.py | 77 +++++---- nova/tests/test_xenapi.py | 1 + 8 files changed, 156 insertions(+), 459 deletions(-) delete mode 100644 nova/tests/api/openstack/contrib/test_drive_types.py delete mode 100644 nova/tests/test_drive_types.py (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_drive_types.py b/nova/tests/api/openstack/contrib/test_drive_types.py deleted file mode 100644 index 2f7d327d3..000000000 --- a/nova/tests/api/openstack/contrib/test_drive_types.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json -import stubout -import webob - -#from nova import compute -from nova.vsa import drive_types -from nova import exception -from nova import context -from nova import test -from nova import log as logging -from nova.tests.api.openstack import fakes - -from nova.api.openstack.contrib.drive_types import _drive_type_view - -LOG = logging.getLogger('nova.tests.api.openstack.drive_types') - -last_param = {} - - -def _get_default_drive_type(): - param = { - 'name': 'Test drive type', - 'type': 'SATA', - 'size_gb': 123, - 'rpm': '7200', - 'capabilities': '', - 'visible': True - } - return param - - -def _create(context, **param): - global last_param - LOG.debug(_("_create: %s"), param) - param['id'] = 123 - last_param = param - return param - - -def _delete(context, id): - global last_param - last_param = dict(id=id) - - LOG.debug(_("_delete: %s"), locals()) - - -def _get(context, id): - global last_param - last_param = dict(id=id) - - LOG.debug(_("_get: %s"), locals()) - if id != '123': - raise exception.NotFound - - dtype = _get_default_drive_type() - dtype['id'] = id - return dtype - - -def _get_all(context, visible=True): - LOG.debug(_("_get_all: %s"), locals()) - dtype = _get_default_drive_type() - dtype['id'] = 123 - return [dtype] - - -class DriveTypesApiTest(test.TestCase): - def setUp(self): - super(DriveTypesApiTest, self).setUp() - self.stubs = stubout.StubOutForTesting() - fakes.FakeAuthManager.reset_fake_data() - fakes.FakeAuthDatabase.data = {} - fakes.stub_out_networking(self.stubs) - fakes.stub_out_rate_limiting(self.stubs) - fakes.stub_out_auth(self.stubs) - self.stubs.Set(drive_types, "create", _create) - self.stubs.Set(drive_types, "delete", _delete) - self.stubs.Set(drive_types, "get", _get) - self.stubs.Set(drive_types, "get_all", _get_all) - - self.context = context.get_admin_context() - - def tearDown(self): - self.stubs.UnsetAll() - super(DriveTypesApiTest, self).tearDown() - - def test_drive_types_api_create(self): - global last_param - last_param = {} - - dtype = _get_default_drive_type() - dtype['id'] = 123 - - body = dict(drive_type=_drive_type_view(dtype)) - req = webob.Request.blank('/v1.1/zadr-drive_types') - req.method = 'POST' - req.body = json.dumps(body) - req.headers['content-type'] = 'application/json' - - resp = req.get_response(fakes.wsgi_app()) - self.assertEqual(resp.status_int, 200) - - # Compare if parameters were correctly passed to stub - for k, v in last_param.iteritems(): - self.assertEqual(last_param[k], dtype[k]) - - resp_dict = json.loads(resp.body) - - # Compare response - self.assertTrue('drive_type' in resp_dict) - resp_dtype = resp_dict['drive_type'] - self.assertEqual(resp_dtype, _drive_type_view(dtype)) - - def test_drive_types_api_delete(self): - global last_param - last_param = {} - - dtype_id = 123 - req = webob.Request.blank('/v1.1/zadr-drive_types/%d' % dtype_id) - req.method = 'DELETE' - - resp = req.get_response(fakes.wsgi_app()) - self.assertEqual(resp.status_int, 200) - self.assertEqual(str(last_param['id']), str(dtype_id)) - - def test_drive_types_show(self): - global last_param - last_param = {} - - dtype_id = 123 - req = webob.Request.blank('/v1.1/zadr-drive_types/%d' % dtype_id) - req.method = 'GET' - resp = req.get_response(fakes.wsgi_app()) - self.assertEqual(resp.status_int, 200) - self.assertEqual(str(last_param['id']), str(dtype_id)) - - resp_dict = json.loads(resp.body) - - # Compare response - self.assertTrue('drive_type' in resp_dict) - resp_dtype = resp_dict['drive_type'] - exp_dtype = _get_default_drive_type() - exp_dtype['id'] = dtype_id - exp_dtype_view = _drive_type_view(exp_dtype) - for k, v in exp_dtype_view.iteritems(): - self.assertEqual(str(resp_dtype[k]), str(exp_dtype_view[k])) - - def test_drive_types_show_invalid_id(self): - global last_param - last_param = {} - - dtype_id = 234 - req = webob.Request.blank('/v1.1/zadr-drive_types/%d' % dtype_id) - req.method = 'GET' - resp = req.get_response(fakes.wsgi_app()) - self.assertEqual(resp.status_int, 404) - self.assertEqual(str(last_param['id']), str(dtype_id)) - - def test_drive_types_index(self): - - req = webob.Request.blank('/v1.1/zadr-drive_types') - req.method = 'GET' - resp = req.get_response(fakes.wsgi_app()) - self.assertEqual(resp.status_int, 200) - - resp_dict = json.loads(resp.body) - - self.assertTrue('drive_types' in resp_dict) - resp_dtypes = resp_dict['drive_types'] - self.assertEqual(len(resp_dtypes), 1) - - resp_dtype = resp_dtypes.pop() - exp_dtype = _get_default_drive_type() - exp_dtype['id'] = 123 - exp_dtype_view = _drive_type_view(exp_dtype) - for k, v in exp_dtype_view.iteritems(): - self.assertEqual(str(resp_dtype[k]), str(exp_dtype_view[k])) diff --git a/nova/tests/api/openstack/contrib/test_vsa.py b/nova/tests/api/openstack/contrib/test_vsa.py index a9b76b0ff..311b6cb8d 100644 --- a/nova/tests/api/openstack/contrib/test_vsa.py +++ b/nova/tests/api/openstack/contrib/test_vsa.py @@ -18,15 +18,14 @@ import stubout import unittest import webob - +from nova import context +from nova import db from nova import exception from nova import flags -from nova import vsa -from nova import db -from nova import volume -from nova import context -from nova import test from nova import log as logging +from nova import test +from nova import volume +from nova import vsa from nova.api import openstack from nova.tests.api.openstack import fakes import nova.wsgi @@ -120,7 +119,7 @@ class VSAApiTest(test.TestCase): vsa = {"displayName": "VSA Test Name", "displayDescription": "VSA Test Desc"} body = dict(vsa=vsa) - req = webob.Request.blank('/v1.1/zadr-vsa') + req = webob.Request.blank('/v1.1/777/zadr-vsa') req.method = 'POST' req.body = json.dumps(body) req.headers['content-type'] = 'application/json' @@ -139,7 +138,7 @@ class VSAApiTest(test.TestCase): vsa['displayDescription']) def test_vsa_create_no_body(self): - req = webob.Request.blank('/v1.1/zadr-vsa') + req = webob.Request.blank('/v1.1/777/zadr-vsa') req.method = 'POST' req.body = json.dumps({}) req.headers['content-type'] = 'application/json' @@ -152,7 +151,7 @@ class VSAApiTest(test.TestCase): last_param = {} vsa_id = 123 - req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req = webob.Request.blank('/v1.1/777/zadr-vsa/%d' % vsa_id) req.method = 'DELETE' resp = req.get_response(fakes.wsgi_app()) @@ -164,7 +163,7 @@ class VSAApiTest(test.TestCase): last_param = {} vsa_id = 234 - req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req = webob.Request.blank('/v1.1/777/zadr-vsa/%d' % vsa_id) req.method = 'DELETE' resp = req.get_response(fakes.wsgi_app()) @@ -176,7 +175,7 @@ class VSAApiTest(test.TestCase): last_param = {} vsa_id = 123 - req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req = webob.Request.blank('/v1.1/777/zadr-vsa/%d' % vsa_id) req.method = 'GET' resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) @@ -191,14 +190,14 @@ class VSAApiTest(test.TestCase): last_param = {} vsa_id = 234 - req = webob.Request.blank('/v1.1/zadr-vsa/%d' % vsa_id) + req = webob.Request.blank('/v1.1/777/zadr-vsa/%d' % vsa_id) req.method = 'GET' resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 404) self.assertEqual(str(last_param['vsa_id']), str(vsa_id)) def test_vsa_index(self): - req = webob.Request.blank('/v1.1/zadr-vsa') + req = webob.Request.blank('/v1.1/777/zadr-vsa') req.method = 'GET' resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) @@ -213,7 +212,7 @@ class VSAApiTest(test.TestCase): self.assertEqual(resp_vsa['id'], 123) def test_vsa_detail(self): - req = webob.Request.blank('/v1.1/zadr-vsa/detail') + req = webob.Request.blank('/v1.1/777/zadr-vsa/detail') req.method = 'GET' resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) @@ -239,17 +238,21 @@ def _get_default_volume_param(): 'name': 'vol name', 'display_name': 'Default vol name', 'display_description': 'Default vol description', - 'from_vsa_id': None, - 'to_vsa_id': None, + 'volume_type_id': 1, + 'volume_metadata': [], } +def stub_get_vsa_volume_type(self, context): + return {'id': 1, + 'name': 'VSA volume type', + 'extra_specs': {'type': 'vsa_volume'}} + + def stub_volume_create(self, context, size, snapshot_id, name, description, **param): LOG.debug(_("_create: param=%s"), size) vol = _get_default_volume_param() - for k, v in param.iteritems(): - vol[k] = v vol['size'] = size vol['display_name'] = name vol['display_description'] = description @@ -270,10 +273,10 @@ def stub_volume_get(self, context, volume_id): LOG.debug(_("_volume_get: volume_id=%s"), volume_id) vol = _get_default_volume_param() vol['id'] = volume_id - if volume_id == '234': - vol['from_vsa_id'] = 123 + meta = {'key': 'from_vsa_id', 'value': '123'} if volume_id == '345': - vol['to_vsa_id'] = 123 + meta = {'key': 'to_vsa_id', 'value': '123'} + vol['volume_metadata'].append(meta) return vol @@ -281,9 +284,9 @@ def stub_volume_get_notfound(self, context, volume_id): raise exception.NotFound -def stub_volume_get_all_by_vsa(self, context, vsa_id, direction): +def stub_volume_get_all(self, context, search_opts): vol = stub_volume_get(self, context, '123') - vol['%s_vsa_id' % direction] = vsa_id + vol['metadata'] = search_opts['metadata'] return [vol] @@ -302,13 +305,13 @@ class VSAVolumeApiTest(test.TestCase): fakes.stub_out_rate_limiting(self.stubs) fakes.stub_out_auth(self.stubs) self.stubs.Set(nova.db.api, 'vsa_get', return_vsa) + self.stubs.Set(vsa.api.API, "get_vsa_volume_type", + stub_get_vsa_volume_type) - self.stubs.Set(volume.api.API, "create", stub_volume_create) self.stubs.Set(volume.api.API, "update", stub_volume_update) self.stubs.Set(volume.api.API, "delete", stub_volume_delete) - self.stubs.Set(volume.api.API, "get_all_by_vsa", - stub_volume_get_all_by_vsa) self.stubs.Set(volume.api.API, "get", stub_volume_get) + self.stubs.Set(volume.api.API, "get_all", stub_volume_get_all) self.context = context.get_admin_context() self.test_obj = test_obj if test_obj else "volume" @@ -319,11 +322,13 @@ class VSAVolumeApiTest(test.TestCase): super(VSAVolumeApiTest, self).tearDown() def test_vsa_volume_create(self): + self.stubs.Set(volume.api.API, "create", stub_volume_create) + vol = {"size": 100, "displayName": "VSA Volume Test Name", "displayDescription": "VSA Volume Test Desc"} body = {self.test_obj: vol} - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s' % self.test_objs) + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s' % self.test_objs) req.method = 'POST' req.body = json.dumps(body) req.headers['content-type'] = 'application/json' @@ -344,7 +349,7 @@ class VSAVolumeApiTest(test.TestCase): self.assertEqual(resp.status_int, 400) def test_vsa_volume_create_no_body(self): - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s' % self.test_objs) + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s' % self.test_objs) req.method = 'POST' req.body = json.dumps({}) req.headers['content-type'] = 'application/json' @@ -356,25 +361,25 @@ class VSAVolumeApiTest(test.TestCase): self.assertEqual(resp.status_int, 400) def test_vsa_volume_index(self): - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s' % self.test_objs) + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s' % self.test_objs) resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) def test_vsa_volume_detail(self): - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/detail' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s/detail' % \ self.test_objs) resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) def test_vsa_volume_show(self): obj_num = 234 if self.test_objs == "volumes" else 345 - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s/%s' % \ (self.test_objs, obj_num)) resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) def test_vsa_volume_show_no_vsa_assignment(self): - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/4/%s/333' % \ (self.test_objs)) resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 400) @@ -382,7 +387,7 @@ class VSAVolumeApiTest(test.TestCase): def test_vsa_volume_show_no_volume(self): self.stubs.Set(volume.api.API, "get", stub_volume_get_notfound) - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s/333' % \ (self.test_objs)) resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 404) @@ -392,7 +397,7 @@ class VSAVolumeApiTest(test.TestCase): update = {"status": "available", "displayName": "Test Display name"} body = {self.test_obj: update} - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s/%s' % \ (self.test_objs, obj_num)) req.method = 'PUT' req.body = json.dumps(body) @@ -406,7 +411,7 @@ class VSAVolumeApiTest(test.TestCase): def test_vsa_volume_delete(self): obj_num = 234 if self.test_objs == "volumes" else 345 - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/%s' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s/%s' % \ (self.test_objs, obj_num)) req.method = 'DELETE' resp = req.get_response(fakes.wsgi_app()) @@ -416,7 +421,7 @@ class VSAVolumeApiTest(test.TestCase): self.assertEqual(resp.status_int, 400) def test_vsa_volume_delete_no_vsa_assignment(self): - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/4/%s/333' % \ (self.test_objs)) req.method = 'DELETE' resp = req.get_response(fakes.wsgi_app()) @@ -425,7 +430,7 @@ class VSAVolumeApiTest(test.TestCase): def test_vsa_volume_delete_no_volume(self): self.stubs.Set(volume.api.API, "get", stub_volume_get_notfound) - req = webob.Request.blank('/v1.1/zadr-vsa/123/%s/333' % \ + req = webob.Request.blank('/v1.1/777/zadr-vsa/123/%s/333' % \ (self.test_objs)) req.method = 'DELETE' resp = req.get_response(fakes.wsgi_app()) diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index 6e9cae38d..05267d8fb 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -85,7 +85,6 @@ class ExtensionControllerTest(test.TestCase): ext_path = os.path.join(os.path.dirname(__file__), "extensions") self.flags(osapi_extensions_path=ext_path) self.ext_list = [ - "DriveTypes", "Createserverext", "FlavorExtraSpecs", "Floating_ips", @@ -96,8 +95,8 @@ class ExtensionControllerTest(test.TestCase): "Quotas", "Rescue", "SecurityGroups", - "VirtualInterfaces", "VSAs", + "VirtualInterfaces", "Volumes", "VolumeTypes", ] diff --git a/nova/tests/scheduler/test_vsa_scheduler.py b/nova/tests/scheduler/test_vsa_scheduler.py index 697ad3842..309db96a2 100644 --- a/nova/tests/scheduler/test_vsa_scheduler.py +++ b/nova/tests/scheduler/test_vsa_scheduler.py @@ -16,13 +16,15 @@ import stubout import nova + +from nova import context +from nova import db from nova import exception from nova import flags -from nova import db -from nova import context +from nova import log as logging from nova import test from nova import utils -from nova import log as logging +from nova.volume import volume_types from nova.scheduler import vsa as vsa_sched from nova.scheduler import driver @@ -52,15 +54,26 @@ class VsaSchedulerTestCase(test.TestCase): def _get_vol_creation_request(self, num_vols, drive_ix, size=0): volume_params = [] for i in range(num_vols): - drive_type = {'id': i, - 'name': 'name_' + str(drive_ix), - 'type': 'type_' + str(drive_ix), - 'size_gb': 1 + 100 * (drive_ix)} + + name = 'name_' + str(i) + try: + volume_types.create(self.context, name, + extra_specs={'type': 'vsa_drive', + 'drive_name': name, + 'drive_type': 'type_' + str(drive_ix), + 'drive_size': 1 + 100 * (drive_ix)}) + self.created_types_lst.append(name) + except exception.ApiError: + # type is already created + pass + + volume_type = volume_types.get_volume_type_by_name(self.context, + name) volume = {'size': size, 'snapshot_id': None, 'name': 'vol_' + str(i), 'description': None, - 'drive_ref': drive_type} + 'volume_type_id': volume_type['id']} volume_params.append(volume) return {'num_volumes': len(volume_params), @@ -217,7 +230,12 @@ class VsaSchedulerTestCase(test.TestCase): self.stubs.Set(nova.db, 'volume_get', self._fake_volume_get) self.stubs.Set(nova.db, 'volume_update', self._fake_volume_update) + self.created_types_lst = [] + def tearDown(self): + for name in self.created_types_lst: + volume_types.purge(self.context, name) + self.stubs.UnsetAll() super(VsaSchedulerTestCase, self).tearDown() @@ -463,7 +481,7 @@ class VsaSchedulerTestCase(test.TestCase): global global_volume global_volume = {} - global_volume['drive_type'] = None + global_volume['volume_type_id'] = None self.assertRaises(driver.NoValidHost, self.sched.schedule_create_volume, @@ -485,12 +503,16 @@ class VsaSchedulerTestCase(test.TestCase): global_volume = {} drive_ix = 2 - drive_type = {'id': drive_ix, - 'name': 'name_' + str(drive_ix), - 'type': 'type_' + str(drive_ix), - 'size_gb': 1 + 100 * (drive_ix)} - - global_volume['drive_type'] = drive_type + name = 'name_' + str(drive_ix) + volume_types.create(self.context, name, + extra_specs={'type': 'vsa_drive', + 'drive_name': name, + 'drive_type': 'type_' + str(drive_ix), + 'drive_size': 1 + 100 * (drive_ix)}) + self.created_types_lst.append(name) + volume_type = volume_types.get_volume_type_by_name(self.context, name) + + global_volume['volume_type_id'] = volume_type['id'] global_volume['size'] = 0 host = self.sched.schedule_create_volume(self.context, @@ -525,12 +547,16 @@ class VsaSchedulerTestCaseMostAvail(VsaSchedulerTestCase): global_volume = {} drive_ix = 2 - drive_type = {'id': drive_ix, - 'name': 'name_' + str(drive_ix), - 'type': 'type_' + str(drive_ix), - 'size_gb': 1 + 100 * (drive_ix)} - - global_volume['drive_type'] = drive_type + name = 'name_' + str(drive_ix) + volume_types.create(self.context, name, + extra_specs={'type': 'vsa_drive', + 'drive_name': name, + 'drive_type': 'type_' + str(drive_ix), + 'drive_size': 1 + 100 * (drive_ix)}) + self.created_types_lst.append(name) + volume_type = volume_types.get_volume_type_by_name(self.context, name) + + global_volume['volume_type_id'] = volume_type['id'] global_volume['size'] = 0 host = self.sched.schedule_create_volume(self.context, diff --git a/nova/tests/test_drive_types.py b/nova/tests/test_drive_types.py deleted file mode 100644 index b52e6705b..000000000 --- a/nova/tests/test_drive_types.py +++ /dev/null @@ -1,146 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 Zadara Storage Inc. -# 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. - -""" -Unit Tests for drive types codecode -""" -import time - -from nova import context -from nova import flags -from nova import log as logging -from nova import test -from nova.vsa import drive_types - -FLAGS = flags.FLAGS -LOG = logging.getLogger('nova.tests.test_drive_types') - - -class DriveTypesTestCase(test.TestCase): - """Test cases for driver types code""" - def setUp(self): - super(DriveTypesTestCase, self).setUp() - self.ctxt = context.RequestContext(None, None) - self.ctxt_admin = context.get_admin_context() - self._dtype = self._create_default_drive_type() - - def tearDown(self): - self._dtype = None - - def _create_default_drive_type(self): - """Create a volume object.""" - dtype = {} - dtype['type'] = 'SATA' - dtype['size_gb'] = 150 - dtype['rpm'] = 5000 - dtype['capabilities'] = None - dtype['visible'] = True - - LOG.debug(_("Default values for Drive Type: %s"), dtype) - return dtype - - def test_drive_type_create_delete(self): - dtype = self._dtype - prev_all_dtypes = drive_types.get_all(self.ctxt_admin, False) - - new = drive_types.create(self.ctxt_admin, **dtype) - for k, v in dtype.iteritems(): - self.assertEqual(v, new[k], 'one of fields doesnt match') - - new_all_dtypes = drive_types.get_all(self.ctxt_admin, False) - self.assertNotEqual(len(prev_all_dtypes), - len(new_all_dtypes), - 'drive type was not created') - - drive_types.delete(self.ctxt_admin, new['id']) - new_all_dtypes = drive_types.get_all(self.ctxt_admin, False) - self.assertEqual(prev_all_dtypes, - new_all_dtypes, - 'drive types was not deleted') - - def test_drive_type_check_name_generation(self): - dtype = self._dtype - new = drive_types.create(self.ctxt_admin, **dtype) - expected_name = FLAGS.drive_type_template_short % \ - (dtype['type'], dtype['size_gb'], dtype['rpm']) - self.assertEqual(new['name'], expected_name, - 'name was not generated correctly') - - dtype['capabilities'] = 'SEC' - new2 = drive_types.create(self.ctxt_admin, **dtype) - expected_name = FLAGS.drive_type_template_long % \ - (dtype['type'], dtype['size_gb'], dtype['rpm'], - dtype['capabilities']) - self.assertEqual(new2['name'], expected_name, - 'name was not generated correctly') - - drive_types.delete(self.ctxt_admin, new['id']) - drive_types.delete(self.ctxt_admin, new2['id']) - - def test_drive_type_create_delete_invisible(self): - dtype = self._dtype - dtype['visible'] = False - prev_all_dtypes = drive_types.get_all(self.ctxt_admin, True) - new = drive_types.create(self.ctxt_admin, **dtype) - - new_all_dtypes = drive_types.get_all(self.ctxt_admin, True) - self.assertEqual(prev_all_dtypes, new_all_dtypes) - - new_all_dtypes = drive_types.get_all(self.ctxt_admin, False) - self.assertNotEqual(prev_all_dtypes, new_all_dtypes) - - drive_types.delete(self.ctxt_admin, new['id']) - - def test_drive_type_rename_update(self): - dtype = self._dtype - dtype['capabilities'] = None - - new = drive_types.create(self.ctxt_admin, **dtype) - for k, v in dtype.iteritems(): - self.assertEqual(v, new[k], 'one of fields doesnt match') - - new_name = 'NEW_DRIVE_NAME' - new = drive_types.rename(self.ctxt_admin, new['name'], new_name) - self.assertEqual(new['name'], new_name) - - new = drive_types.rename(self.ctxt_admin, new_name) - expected_name = FLAGS.drive_type_template_short % \ - (dtype['type'], dtype['size_gb'], dtype['rpm']) - self.assertEqual(new['name'], expected_name) - - changes = {'rpm': 7200} - new = drive_types.update(self.ctxt_admin, new['id'], **changes) - for k, v in changes.iteritems(): - self.assertEqual(v, new[k], 'one of fields doesnt match') - - drive_types.delete(self.ctxt_admin, new['id']) - - def test_drive_type_get(self): - dtype = self._dtype - new = drive_types.create(self.ctxt_admin, **dtype) - - new2 = drive_types.get(self.ctxt_admin, new['id']) - for k, v in new2.iteritems(): - self.assertEqual(str(new[k]), str(new2[k]), - 'one of fields doesnt match') - - new2 = drive_types.get_by_name(self.ctxt_admin, new['name']) - for k, v in new.iteritems(): - self.assertEqual(str(new[k]), str(new2[k]), - 'one of fields doesnt match') - - drive_types.delete(self.ctxt_admin, new['id']) diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py index 726939744..300a4d71c 100644 --- a/nova/tests/test_vsa.py +++ b/nova/tests/test_vsa.py @@ -13,38 +13,29 @@ # License for the specific language governing permissions and limitations # under the License. -import stubout import base64 +import stubout from xml.etree import ElementTree from xml.etree.ElementTree import Element, SubElement +from nova import context +from nova import db from nova import exception from nova import flags +from nova import log as logging +from nova import test from nova import vsa from nova import volume -from nova import db -from nova import context -from nova import test -from nova import log as logging +from nova.volume import volume_types +from nova.vsa import utils as vsa_utils + import nova.image.fake FLAGS = flags.FLAGS LOG = logging.getLogger('nova.tests.vsa') -def fake_drive_type_get_by_name(context, name): - drive_type = { - 'id': 1, - 'name': name, - 'type': name.split('_')[0], - 'size_gb': int(name.split('_')[1]), - 'rpm': name.split('_')[2], - 'capabilities': '', - 'visible': True} - return drive_type - - class VsaTestCase(test.TestCase): def setUp(self): @@ -53,9 +44,20 @@ class VsaTestCase(test.TestCase): self.vsa_api = vsa.API() self.volume_api = volume.API() + FLAGS.quota_volumes = 100 + FLAGS.quota_gigabytes = 10000 + self.context_non_admin = context.RequestContext(None, None) self.context = context.get_admin_context() + volume_types.create(self.context, + 'SATA_500_7200', + extra_specs={'type': 'vsa_drive', + 'drive_name': 'SATA_500_7200', + 'drive_type': 'SATA', + 'drive_size': '500', + 'drive_rpm': '7200'}) + def fake_show_by_name(meh, context, name): if name == 'wrong_image_name': LOG.debug(_("Test: Emulate wrong VSA name. Raise")) @@ -124,9 +126,6 @@ class VsaTestCase(test.TestCase): FLAGS.vsa_multi_vol_creation = multi_vol_creation - self.stubs.Set(nova.vsa.drive_types, 'get_by_name', - fake_drive_type_get_by_name) - param = {'storage': [{'drive_name': 'SATA_500_7200', 'num_drives': 3}]} vsa_ref = self.vsa_api.create(self.context, **param) @@ -157,8 +156,6 @@ class VsaTestCase(test.TestCase): self.vsa_api.delete(self.context, vsa_ref['id']) def test_vsa_generate_user_data(self): - self.stubs.Set(nova.vsa.drive_types, 'get_by_name', - fake_drive_type_get_by_name) FLAGS.vsa_multi_vol_creation = False param = {'display_name': 'VSA name test', @@ -167,12 +164,10 @@ class VsaTestCase(test.TestCase): 'storage': [{'drive_name': 'SATA_500_7200', 'num_drives': 3}]} vsa_ref = self.vsa_api.create(self.context, **param) - volumes = db.volume_get_all_assigned_to_vsa(self.context, - vsa_ref['id']) + volumes = self.vsa_api.get_all_vsa_drives(self.context, + vsa_ref['id']) - user_data = self.vsa_api.generate_user_data(self.context, - vsa_ref, - volumes) + user_data = vsa_utils.generate_user_data(vsa_ref, volumes) user_data = base64.b64decode(user_data) LOG.debug(_("Test: user_data = %s"), user_data) diff --git a/nova/tests/test_vsa_volumes.py b/nova/tests/test_vsa_volumes.py index d451a4377..43173d86a 100644 --- a/nova/tests/test_vsa_volumes.py +++ b/nova/tests/test_vsa_volumes.py @@ -29,15 +29,6 @@ FLAGS = flags.FLAGS LOG = logging.getLogger('nova.tests.vsa.volumes') -def _default_volume_param(): - return { - 'size': 1, - 'snapshot_id': None, - 'name': 'Test volume name', - 'description': 'Test volume desc name' - } - - class VsaVolumesTestCase(test.TestCase): def setUp(self): @@ -49,6 +40,8 @@ class VsaVolumesTestCase(test.TestCase): self.context_non_admin = context.RequestContext(None, None) self.context = context.get_admin_context() + self.default_vol_type = self.vsa_api.get_vsa_volume_type(self.context) + def fake_show_by_name(meh, context, name): return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} @@ -66,12 +59,23 @@ class VsaVolumesTestCase(test.TestCase): self.stubs.UnsetAll() super(VsaVolumesTestCase, self).tearDown() + def _default_volume_param(self): + return { + 'size': 1, + 'snapshot_id': None, + 'name': 'Test volume name', + 'description': 'Test volume desc name', + 'volume_type': self.default_vol_type, + 'metadata': {'from_vsa_id': self.vsa_id} + } + + def _get_all_volumes_by_vsa(self): + return self.volume_api.get_all(self.context, + search_opts={'metadata': {"from_vsa_id": str(self.vsa_id)}}) + def test_vsa_volume_create_delete(self): """ Check if volume properly created and deleted. """ - vols1 = self.volume_api.get_all_by_vsa(self.context, - self.vsa_id, "from") - volume_param = _default_volume_param() - volume_param['from_vsa_id'] = self.vsa_id + volume_param = self._default_volume_param() volume_ref = self.volume_api.create(self.context, **volume_param) self.assertEqual(volume_ref['display_name'], @@ -81,21 +85,34 @@ class VsaVolumesTestCase(test.TestCase): self.assertEqual(volume_ref['size'], volume_param['size']) self.assertEqual(volume_ref['status'], - 'available') + 'creating') - vols2 = self.volume_api.get_all_by_vsa(self.context, - self.vsa_id, "from") - self.assertEqual(len(vols1) + 1, len(vols2)) + vols2 = self._get_all_volumes_by_vsa() + self.assertEqual(1, len(vols2)) + volume_ref = vols2[0] + self.assertEqual(volume_ref['display_name'], + volume_param['name']) + self.assertEqual(volume_ref['display_description'], + volume_param['description']) + self.assertEqual(volume_ref['size'], + volume_param['size']) + self.assertEqual(volume_ref['status'], + 'creating') + + self.volume_api.update(self.context, + volume_ref['id'], {'status': 'available'}) self.volume_api.delete(self.context, volume_ref['id']) - vols3 = self.volume_api.get_all_by_vsa(self.context, - self.vsa_id, "from") - self.assertEqual(len(vols3) + 1, len(vols2)) + + vols3 = self._get_all_volumes_by_vsa() + self.assertEqual(1, len(vols2)) + volume_ref = vols3[0] + self.assertEqual(volume_ref['status'], + 'deleting') def test_vsa_volume_delete_nonavail_volume(self): """ Check volume deleton in different states. """ - volume_param = _default_volume_param() - volume_param['from_vsa_id'] = self.vsa_id + volume_param = self._default_volume_param() volume_ref = self.volume_api.create(self.context, **volume_param) self.volume_api.update(self.context, @@ -104,26 +121,18 @@ class VsaVolumesTestCase(test.TestCase): self.volume_api.delete, self.context, volume_ref['id']) - self.volume_api.update(self.context, - volume_ref['id'], {'status': 'error'}) - self.volume_api.delete(self.context, volume_ref['id']) - def test_vsa_volume_delete_vsa_with_volumes(self): """ Check volume deleton in different states. """ - vols1 = self.volume_api.get_all_by_vsa(self.context, - self.vsa_id, "from") + vols1 = self._get_all_volumes_by_vsa() for i in range(3): - volume_param = _default_volume_param() - volume_param['from_vsa_id'] = self.vsa_id + volume_param = self._default_volume_param() volume_ref = self.volume_api.create(self.context, **volume_param) - vols2 = self.volume_api.get_all_by_vsa(self.context, - self.vsa_id, "from") + vols2 = self._get_all_volumes_by_vsa() self.assertEqual(len(vols1) + 3, len(vols2)) self.vsa_api.delete(self.context, self.vsa_id) - vols3 = self.volume_api.get_all_by_vsa(self.context, - self.vsa_id, "from") + vols3 = self._get_all_volumes_by_vsa() self.assertEqual(len(vols1), len(vols3)) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 2f0559366..6d1958401 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -203,6 +203,7 @@ class XenAPIVMTestCase(test.TestCase): self.context = context.RequestContext(self.user_id, self.project_id) self.conn = xenapi_conn.get_connection(False) + @test.skip_test("Skip this test meanwhile") def test_parallel_builds(self): stubs.stubout_loopingcall_delay(self.stubs) -- cgit From 59e9adb8e2ef39474a04ead76975a1fc3f913550 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Thu, 25 Aug 2011 19:09:50 -0700 Subject: cosmetic cleanup --- nova/tests/scheduler/test_vsa_scheduler.py | 1 - nova/tests/test_vsa.py | 1 - nova/tests/test_vsa_volumes.py | 2 -- nova/tests/test_xenapi.py | 1 - 4 files changed, 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/scheduler/test_vsa_scheduler.py b/nova/tests/scheduler/test_vsa_scheduler.py index 309db96a2..37964f00d 100644 --- a/nova/tests/scheduler/test_vsa_scheduler.py +++ b/nova/tests/scheduler/test_vsa_scheduler.py @@ -210,7 +210,6 @@ class VsaSchedulerTestCase(test.TestCase): def setUp(self, sched_class=None): super(VsaSchedulerTestCase, self).setUp() self.stubs = stubout.StubOutForTesting() - self.context_non_admin = context.RequestContext(None, None) self.context = context.get_admin_context() if sched_class is None: diff --git a/nova/tests/test_vsa.py b/nova/tests/test_vsa.py index 300a4d71c..3d2d2de13 100644 --- a/nova/tests/test_vsa.py +++ b/nova/tests/test_vsa.py @@ -47,7 +47,6 @@ class VsaTestCase(test.TestCase): FLAGS.quota_volumes = 100 FLAGS.quota_gigabytes = 10000 - self.context_non_admin = context.RequestContext(None, None) self.context = context.get_admin_context() volume_types.create(self.context, diff --git a/nova/tests/test_vsa_volumes.py b/nova/tests/test_vsa_volumes.py index 43173d86a..b7cd4e840 100644 --- a/nova/tests/test_vsa_volumes.py +++ b/nova/tests/test_vsa_volumes.py @@ -36,8 +36,6 @@ class VsaVolumesTestCase(test.TestCase): self.stubs = stubout.StubOutForTesting() self.vsa_api = vsa.API() self.volume_api = volume.API() - - self.context_non_admin = context.RequestContext(None, None) self.context = context.get_admin_context() self.default_vol_type = self.vsa_api.get_vsa_volume_type(self.context) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 6d1958401..2f0559366 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -203,7 +203,6 @@ class XenAPIVMTestCase(test.TestCase): self.context = context.RequestContext(self.user_id, self.project_id) self.conn = xenapi_conn.get_connection(False) - @test.skip_test("Skip this test meanwhile") def test_parallel_builds(self): stubs.stubout_loopingcall_delay(self.stubs) -- cgit From 5dc7956eed749c33b6cfaaaf122e829feec62ea9 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 26 Aug 2011 09:54:53 -0400 Subject: Update compute API and manager so that the image_ref is set before spawning the rebuilt instance. Fixes issue where rebuild didn't actually change the image_id. --- nova/tests/integrated/test_servers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index c2f800689..b9382038a 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -193,7 +193,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): # rebuild the server with metadata post = {} post['rebuild'] = { - "imageRef": "https://localhost/v1.1/32278/images/2", + "imageRef": "https://localhost/v1.1/32278/images/3", "name": "blah", } @@ -205,6 +205,7 @@ class ServersTest(integrated_helpers._IntegratedTestBase): self.assertEqual(created_server_id, found_server['id']) self.assertEqual({}, found_server.get('metadata')) self.assertEqual('blah', found_server.get('name')) + self.assertEqual('3', found_server.get('image')['id']) # Cleanup self._delete_server(created_server_id) -- cgit From 400427ab786779109d49b27eda2fe9e246503dd6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 26 Aug 2011 16:17:40 -0700 Subject: use db layer for aggregation --- .../openstack/contrib/test_simple_tenant_usage.py | 77 +++++++++------------- 1 file changed, 30 insertions(+), 47 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py index d20e36aaf..2bd619820 100644 --- a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py +++ b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py @@ -23,13 +23,8 @@ from nova import context from nova import db from nova import flags from nova import test -from nova.compute import instance_types -from nova.db.sqlalchemy import models -from nova.db.sqlalchemy import session from nova.tests.api.openstack import fakes -from webob import exc -from nova.api.openstack.contrib import simple_tenant_usage FLAGS = flags.FLAGS @@ -44,27 +39,6 @@ STOP = datetime.datetime.utcnow() START = STOP - datetime.timedelta(hours=HOURS) -def fake_get_session(): - class FakeFetcher(object): - def fetchall(fetcher_self): - # return 10 rows, 2 tenants, 5 servers each, each run for 1 day - return [get_fake_db_row(START, - STOP, - x, - "faketenant_%s" % (x / SERVERS)) - for x in xrange(TENANTS * SERVERS)] - - class FakeConn(object): - def execute(self, query): - return FakeFetcher() - - class FakeSession(object): - def connection(self): - return FakeConn() - - return FakeSession() - - def fake_instance_type_get(context, instance_type_id): return {'id': 1, 'vcpus': VCPUS, @@ -74,25 +48,32 @@ def fake_instance_type_get(context, instance_type_id): 'fakeflavor'} -def get_fake_db_row(start, end, instance_id, tenant_id): - return [instance_id, - '1', - tenant_id, - 'fakeuser', - 'name', - 'state', - 1, - start, - None] +def get_fake_db_instance(start, end, instance_id, tenant_id): + return {'id': instance_id, + 'image_ref': '1', + 'project_id': tenant_id, + 'user_id': 'fakeuser', + 'display_name': 'name', + 'state_description': 'state', + 'instance_type_id': 1, + 'launched_at': start, + 'terminated_at': end} + +def fake_instance_get_active_by_window(context, begin, end, project_id, fast): + return [get_fake_db_instance(START, + STOP, + x, + "faketenant_%s" % (x / SERVERS)) + for x in xrange(TENANTS * SERVERS)] class SimpleTenantUsageTest(test.TestCase): def setUp(self): super(SimpleTenantUsageTest, self).setUp() - self.stubs.Set(session, "get_session", - fake_get_session) self.stubs.Set(db, "instance_type_get", fake_instance_type_get) + self.stubs.Set(db, "instance_get_active_by_window", + fake_instance_get_active_by_window) self.admin_context = context.RequestContext('fakeadmin_0', 'faketenant_0', is_admin=True) @@ -104,13 +85,9 @@ class SimpleTenantUsageTest(test.TestCase): is_admin=False) FLAGS.allow_admin_api = True - def test_verify_db_fields_exist_in_instance_model(self): - for field in simple_tenant_usage.INSTANCE_FIELDS: - self.assertTrue(field in models.Instance.__table__.columns) - def test_verify_index(self): req = webob.Request.blank( - '/v1.1/os-simple-tenant-usage?start=%s&end=%s' % + '/v1.1/123/os-simple-tenant-usage?start=%s&end=%s' % (START.isoformat(), STOP.isoformat())) req.method = "GET" req.headers["content-type"] = "application/json" @@ -121,6 +98,8 @@ class SimpleTenantUsageTest(test.TestCase): self.assertEqual(res.status_int, 200) res_dict = json.loads(res.body) usages = res_dict['tenant_usages'] + from nova import log as logging + logging.warn(usages) for i in xrange(TENANTS): self.assertEqual(int(usages[i]['total_hours']), SERVERS * HOURS) @@ -134,7 +113,8 @@ class SimpleTenantUsageTest(test.TestCase): def test_verify_detailed_index(self): req = webob.Request.blank( - '/v1.1/os-simple-tenant-usage?detailed=1&start=%s&end=%s' % + '/v1.1/123/os-simple-tenant-usage?' + 'detailed=1&start=%s&end=%s' % (START.isoformat(), STOP.isoformat())) req.method = "GET" req.headers["content-type"] = "application/json" @@ -151,7 +131,8 @@ class SimpleTenantUsageTest(test.TestCase): def test_verify_index_fails_for_nonadmin(self): req = webob.Request.blank( - '/v1.1/os-simple-tenant-usage?detailed=1&start=%s&end=%s' % + '/v1.1/123/os-simple-tenant-usage?' + 'detailed=1&start=%s&end=%s' % (START.isoformat(), STOP.isoformat())) req.method = "GET" req.headers["content-type"] = "application/json" @@ -161,7 +142,8 @@ class SimpleTenantUsageTest(test.TestCase): def test_verify_show(self): req = webob.Request.blank( - '/v1.1/os-simple-tenant-usage/faketenant_0?start=%s&end=%s' % + '/v1.1/faketenant_0/os-simple-tenant-usage/' + 'faketenant_0?start=%s&end=%s' % (START.isoformat(), STOP.isoformat())) req.method = "GET" req.headers["content-type"] = "application/json" @@ -179,7 +161,8 @@ class SimpleTenantUsageTest(test.TestCase): def test_verify_show_cant_view_other_tenant(self): req = webob.Request.blank( - '/v1.1/os-simple-tenant-usage/faketenant_0?start=%s&end=%s' % + '/v1.1/faketenant_1/os-simple-tenant-usage/' + 'faketenant_0?start=%s&end=%s' % (START.isoformat(), STOP.isoformat())) req.method = "GET" req.headers["content-type"] = "application/json" -- cgit From 470b9dc73c5e27ef8716436fe22e9f32dbdffd28 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 26 Aug 2011 17:40:22 -0700 Subject: add tests to verify NotFound exceptions are wrapped with the proper ids --- nova/tests/api/ec2/__init__.py | 19 +++++ nova/tests/api/ec2/test_middleware.py | 130 ++++++++++++++++++++++++++++++++++ nova/tests/test_cloud.py | 7 -- nova/tests/test_middleware.py | 85 ---------------------- 4 files changed, 149 insertions(+), 92 deletions(-) create mode 100644 nova/tests/api/ec2/__init__.py create mode 100644 nova/tests/api/ec2/test_middleware.py delete mode 100644 nova/tests/test_middleware.py (limited to 'nova/tests') diff --git a/nova/tests/api/ec2/__init__.py b/nova/tests/api/ec2/__init__.py new file mode 100644 index 000000000..6dab802f2 --- /dev/null +++ b/nova/tests/api/ec2/__init__.py @@ -0,0 +1,19 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# 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. + +# NOTE(vish): this forces the fixtures from tests/__init.py:setup() to work +from nova.tests import * diff --git a/nova/tests/api/ec2/test_middleware.py b/nova/tests/api/ec2/test_middleware.py new file mode 100644 index 000000000..295f6c4ea --- /dev/null +++ b/nova/tests/api/ec2/test_middleware.py @@ -0,0 +1,130 @@ +# 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. + +import webob +import webob.dec +import webob.exc + +from nova.api import ec2 +from nova import context +from nova import exception +from nova import flags +from nova import test +from nova import utils + +from xml.etree.ElementTree import fromstring as xml_to_tree + +FLAGS = flags.FLAGS + + +@webob.dec.wsgify +def conditional_forbid(req): + """Helper wsgi app returns 403 if param 'die' is 1.""" + if 'die' in req.params and req.params['die'] == '1': + raise webob.exc.HTTPForbidden() + return 'OK' + + +class LockoutTestCase(test.TestCase): + """Test case for the Lockout middleware.""" + def setUp(self): # pylint: disable=C0103 + super(LockoutTestCase, self).setUp() + utils.set_time_override() + self.lockout = ec2.Lockout(conditional_forbid) + + def tearDown(self): # pylint: disable=C0103 + utils.clear_time_override() + super(LockoutTestCase, self).tearDown() + + def _send_bad_attempts(self, access_key, num_attempts=1): + """Fail x.""" + for i in xrange(num_attempts): + req = webob.Request.blank('/?AWSAccessKeyId=%s&die=1' % access_key) + self.assertEqual(req.get_response(self.lockout).status_int, 403) + + def _is_locked_out(self, access_key): + """Sends a test request to see if key is locked out.""" + req = webob.Request.blank('/?AWSAccessKeyId=%s' % access_key) + return (req.get_response(self.lockout).status_int == 403) + + def test_lockout(self): + self._send_bad_attempts('test', FLAGS.lockout_attempts) + self.assertTrue(self._is_locked_out('test')) + + def test_timeout(self): + self._send_bad_attempts('test', FLAGS.lockout_attempts) + self.assertTrue(self._is_locked_out('test')) + utils.advance_time_seconds(FLAGS.lockout_minutes * 60) + self.assertFalse(self._is_locked_out('test')) + + def test_multiple_keys(self): + self._send_bad_attempts('test1', FLAGS.lockout_attempts) + self.assertTrue(self._is_locked_out('test1')) + self.assertFalse(self._is_locked_out('test2')) + utils.advance_time_seconds(FLAGS.lockout_minutes * 60) + self.assertFalse(self._is_locked_out('test1')) + self.assertFalse(self._is_locked_out('test2')) + + def test_window_timeout(self): + self._send_bad_attempts('test', FLAGS.lockout_attempts - 1) + self.assertFalse(self._is_locked_out('test')) + utils.advance_time_seconds(FLAGS.lockout_window * 60) + self._send_bad_attempts('test', FLAGS.lockout_attempts - 1) + self.assertFalse(self._is_locked_out('test')) + + +class ExecutorTestCase(test.TestCase): + def setUp(self): + super(ExecutorTestCase, self).setUp() + self.executor = ec2.Executor() + + def _execute(self, invoke): + class Fake(object): + pass + fake_ec2_request = Fake() + fake_ec2_request.invoke = invoke + + fake_wsgi_request = Fake() + + fake_wsgi_request.environ = { + 'nova.context': context.get_admin_context(), + 'ec2.request': fake_ec2_request, + } + return self.executor(fake_wsgi_request) + + def _extract_message(self, result): + tree = xml_to_tree(result.body) + return tree.findall('./Errors')[0].find('Error/Message').text + + def test_instance_not_found(self): + def not_found(context): + raise exception.InstanceNotFound(instance_id=5) + result = self._execute(not_found) + self.assertIn('i-00000005', self._extract_message(result)) + + def test_snapshot_not_found(self): + def not_found(context): + raise exception.SnapshotNotFound(snapshot_id=5) + result = self._execute(not_found) + self.assertIn('snap-00000005', self._extract_message(result)) + + def test_volume_not_found(self): + def not_found(context): + raise exception.VolumeNotFound(volume_id=5) + result = self._execute(not_found) + self.assertIn('vol-00000005', self._extract_message(result)) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 0793784f8..1bf12a06f 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -86,13 +86,6 @@ class CloudTestCase(test.TestCase): self.stubs.Set(rpc, 'cast', finish_cast) - def tearDown(self): - networks = db.project_get_networks(self.context, self.project_id, - associate=False) - for network in networks: - db.network_disassociate(self.context, network['id']) - super(CloudTestCase, self).tearDown() - def _create_key(self, name): # NOTE(vish): create depends on pool, so just call helper directly return cloud._gen_key(self.context, self.context.user_id, name) diff --git a/nova/tests/test_middleware.py b/nova/tests/test_middleware.py deleted file mode 100644 index 40d117c45..000000000 --- a/nova/tests/test_middleware.py +++ /dev/null @@ -1,85 +0,0 @@ -# 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. - -import webob -import webob.dec -import webob.exc - -from nova.api import ec2 -from nova import flags -from nova import test -from nova import utils - - -FLAGS = flags.FLAGS - - -@webob.dec.wsgify -def conditional_forbid(req): - """Helper wsgi app returns 403 if param 'die' is 1.""" - if 'die' in req.params and req.params['die'] == '1': - raise webob.exc.HTTPForbidden() - return 'OK' - - -class LockoutTestCase(test.TestCase): - """Test case for the Lockout middleware.""" - def setUp(self): # pylint: disable=C0103 - super(LockoutTestCase, self).setUp() - utils.set_time_override() - self.lockout = ec2.Lockout(conditional_forbid) - - def tearDown(self): # pylint: disable=C0103 - utils.clear_time_override() - super(LockoutTestCase, self).tearDown() - - def _send_bad_attempts(self, access_key, num_attempts=1): - """Fail x.""" - for i in xrange(num_attempts): - req = webob.Request.blank('/?AWSAccessKeyId=%s&die=1' % access_key) - self.assertEqual(req.get_response(self.lockout).status_int, 403) - - def _is_locked_out(self, access_key): - """Sends a test request to see if key is locked out.""" - req = webob.Request.blank('/?AWSAccessKeyId=%s' % access_key) - return (req.get_response(self.lockout).status_int == 403) - - def test_lockout(self): - self._send_bad_attempts('test', FLAGS.lockout_attempts) - self.assertTrue(self._is_locked_out('test')) - - def test_timeout(self): - self._send_bad_attempts('test', FLAGS.lockout_attempts) - self.assertTrue(self._is_locked_out('test')) - utils.advance_time_seconds(FLAGS.lockout_minutes * 60) - self.assertFalse(self._is_locked_out('test')) - - def test_multiple_keys(self): - self._send_bad_attempts('test1', FLAGS.lockout_attempts) - self.assertTrue(self._is_locked_out('test1')) - self.assertFalse(self._is_locked_out('test2')) - utils.advance_time_seconds(FLAGS.lockout_minutes * 60) - self.assertFalse(self._is_locked_out('test1')) - self.assertFalse(self._is_locked_out('test2')) - - def test_window_timeout(self): - self._send_bad_attempts('test', FLAGS.lockout_attempts - 1) - self.assertFalse(self._is_locked_out('test')) - utils.advance_time_seconds(FLAGS.lockout_window * 60) - self._send_bad_attempts('test', FLAGS.lockout_attempts - 1) - self.assertFalse(self._is_locked_out('test')) -- cgit From 19cb3672f2849fe659173631f7f81ed489f1ea7e Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Fri, 26 Aug 2011 17:46:47 -0700 Subject: v1.0 of server create injects first users keypair --- nova/tests/api/openstack/test_servers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index bb531f462..c54bead49 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1761,7 +1761,7 @@ class ServersTest(test.TestCase): body = dict(server=dict( name='server_test', imageRef=image_href, flavorRef=flavor_ref, key_name='nonexistentkey')) - req = webob.Request.blank('/v1.1/servers') + req = webob.Request.blank('/v1.1/fake/servers') req.method = 'POST' req.body = json.dumps(body) req.headers["content-type"] = "application/json" @@ -1781,7 +1781,7 @@ class ServersTest(test.TestCase): body = dict(server=dict( name='server_test', imageRef=image_href, flavorRef=flavor_ref, key_name='mykey')) - req = webob.Request.blank('/v1.1/servers') + req = webob.Request.blank('/v1.1/fake/servers') req.method = 'POST' req.body = json.dumps(body) req.headers["content-type"] = "application/json" @@ -3793,6 +3793,7 @@ class ServersViewBuilderV11Test(test.TestCase): "created": "2010-10-10T12:00:00Z", "progress": 0, "name": "test_server", + "key_name": "", "status": "BUILD", "hostId": '', "image": { @@ -3848,6 +3849,7 @@ class ServersViewBuilderV11Test(test.TestCase): "created": "2010-10-10T12:00:00Z", "progress": 0, "name": "test_server", + "key_name": "", "status": "BUILD", "hostId": '', "image": { -- cgit From 75c7c841379341c63598850e4676f2146d63334a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Sun, 28 Aug 2011 16:17:17 +0530 Subject: Bug #835964: pep8 violations in IPv6 code Fix pep8 violations. --- nova/tests/test_ipv6.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index 04c1b5598..e1ba4aafb 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -48,7 +48,7 @@ class IPv6RFC2462TestCase(test.TestCase): def test_to_global_with_bad_prefix(self): bad_prefix = '82' self.assertRaises(TypeError, ipv6.to_global, - bad_prefix, + bad_prefix, '2001:db8::216:3eff:fe33:4455', 'test') -- cgit From 17c0a1aad98effa4554a9083b35185f2d430d81f Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Sun, 28 Aug 2011 23:40:09 +0530 Subject: In the XenAPI simulator, set VM.domid, when creating the instance initially, and when starting the VM. This shows up in the logs for Bug #831599, but this fix doesn't actually fix the hang. --- nova/tests/xenapi/stubs.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index a6a1febd6..d309cfb88 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -18,6 +18,8 @@ import eventlet import json +import random + from nova.virt import xenapi_conn from nova.virt.xenapi import fake from nova.virt.xenapi import volume_utils @@ -191,6 +193,7 @@ class FakeSessionForVMTests(fake.SessionBase): vm['power_state'] = 'Running' vm['is_a_template'] = False vm['is_control_domain'] = False + vm['domid'] = random.randrange(0, 1 << 16) def VM_snapshot(self, session_ref, vm_ref, label): status = "Running" @@ -290,6 +293,7 @@ class FakeSessionForMigrationTests(fake.SessionBase): vm['power_state'] = 'Running' vm['is_a_template'] = False vm['is_control_domain'] = False + vm['domid'] = random.randrange(0, 1 << 16) def stub_out_migration_methods(stubs): -- cgit From c35086ca2d2ac1a519442217bf89c0572b28053b Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 29 Aug 2011 00:41:14 +0530 Subject: Start domid's at 1, not 0, to avoid any confusion with dom0. --- nova/tests/xenapi/stubs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index d309cfb88..647a4c1df 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -193,7 +193,7 @@ class FakeSessionForVMTests(fake.SessionBase): vm['power_state'] = 'Running' vm['is_a_template'] = False vm['is_control_domain'] = False - vm['domid'] = random.randrange(0, 1 << 16) + vm['domid'] = random.randrange(1, 1 << 16) def VM_snapshot(self, session_ref, vm_ref, label): status = "Running" @@ -293,7 +293,7 @@ class FakeSessionForMigrationTests(fake.SessionBase): vm['power_state'] = 'Running' vm['is_a_template'] = False vm['is_control_domain'] = False - vm['domid'] = random.randrange(0, 1 << 16) + vm['domid'] = random.randrange(1, 1 << 16) def stub_out_migration_methods(stubs): -- cgit From 32943729861ba4ad562e899a55af77b7974af8db Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Sun, 28 Aug 2011 18:17:21 -0700 Subject: fix test_rpc and kombu stuff --- nova/tests/test_rpc.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_rpc.py b/nova/tests/test_rpc.py index ba9c0a859..2b9922491 100644 --- a/nova/tests/test_rpc.py +++ b/nova/tests/test_rpc.py @@ -33,13 +33,17 @@ class RpcTestCase(test.TestCase): super(RpcTestCase, self).setUp() self.conn = rpc.create_connection(True) self.receiver = TestReceiver() - self.consumer = rpc.create_consumer(self.conn, - 'test', - self.receiver, - False) - self.consumer.attach_to_eventlet() + rpc.create_consumer(self.conn, + 'test', + self.receiver, + False) + self.conn.consume_in_thread() self.context = context.get_admin_context() + def tearDown(self): + self.conn.close() + super(RpcTestCase, self).tearDown() + def test_call_succeed(self): value = 42 result = rpc.call(self.context, 'test', {"method": "echo", @@ -139,16 +143,17 @@ class RpcTestCase(test.TestCase): nested = Nested() conn = rpc.create_connection(True) - consumer = rpc.create_consumer(conn, - 'nested', - nested, - False) - consumer.attach_to_eventlet() + rpc.create_consumer(conn, + 'nested', + nested, + False) + conn.consume_in_thread() value = 42 result = rpc.call(self.context, 'nested', {"method": "echo", "args": {"queue": "test", "value": value}}) + conn.close() self.assertEqual(value, result) -- cgit From da11af2893719677a9113ce391d37b0dada6585c Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Sun, 28 Aug 2011 18:19:41 -0700 Subject: fix nova/tests/test_test.py --- nova/tests/test_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_test.py b/nova/tests/test_test.py index 64f11fa45..6075abbb0 100644 --- a/nova/tests/test_test.py +++ b/nova/tests/test_test.py @@ -40,6 +40,6 @@ class IsolationTestCase(test.TestCase): connection = rpc.create_connection(new=True) proxy = NeverCalled() - consumer = rpc.create_consumer(connection, 'compute', - proxy, fanout=False) - consumer.attach_to_eventlet() + rpc.create_consumer(connection, 'compute', + proxy, fanout=False) + connection.consume_in_thread() -- cgit From 6fbb35d596f670d6dcdda2486a12fc09ef9be853 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Sun, 28 Aug 2011 19:22:53 -0700 Subject: add carrot/kombu tests... small thread fix for kombu --- nova/tests/test_rpc_amqp.py | 88 -------------- nova/tests/test_rpc_carrot.py | 202 ++++++++++++++++++++++++++++++++ nova/tests/test_rpc_kombu.py | 266 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 468 insertions(+), 88 deletions(-) delete mode 100644 nova/tests/test_rpc_amqp.py create mode 100644 nova/tests/test_rpc_carrot.py create mode 100644 nova/tests/test_rpc_kombu.py (limited to 'nova/tests') diff --git a/nova/tests/test_rpc_amqp.py b/nova/tests/test_rpc_amqp.py deleted file mode 100644 index 2215a908b..000000000 --- a/nova/tests/test_rpc_amqp.py +++ /dev/null @@ -1,88 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2010 Openstack, LLC. -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Tests For RPC AMQP. -""" - -from nova import context -from nova import log as logging -from nova import rpc -from nova.rpc import amqp -from nova import test - - -LOG = logging.getLogger('nova.tests.rpc') - - -class RpcAMQPTestCase(test.TestCase): - def setUp(self): - super(RpcAMQPTestCase, self).setUp() - self.conn = rpc.create_connection(True) - self.receiver = TestReceiver() - self.consumer = rpc.create_consumer(self.conn, - 'test', - self.receiver, - False) - self.consumer.attach_to_eventlet() - self.context = context.get_admin_context() - - def test_connectionpool_single(self): - """Test that ConnectionPool recycles a single connection.""" - conn1 = amqp.ConnectionPool.get() - amqp.ConnectionPool.put(conn1) - conn2 = amqp.ConnectionPool.get() - amqp.ConnectionPool.put(conn2) - self.assertEqual(conn1, conn2) - - -class TestReceiver(object): - """Simple Proxy class so the consumer has methods to call. - - Uses static methods because we aren't actually storing any state. - - """ - - @staticmethod - def echo(context, value): - """Simply returns whatever value is sent in.""" - LOG.debug(_("Received %s"), value) - return value - - @staticmethod - def context(context, value): - """Returns dictionary version of context.""" - LOG.debug(_("Received %s"), context) - return context.to_dict() - - @staticmethod - def echo_three_times(context, value): - context.reply(value) - context.reply(value + 1) - context.reply(value + 2) - - @staticmethod - def echo_three_times_yield(context, value): - yield value - yield value + 1 - yield value + 2 - - @staticmethod - def fail(context, value): - """Raises an exception with the value sent in.""" - raise Exception(value) diff --git a/nova/tests/test_rpc_carrot.py b/nova/tests/test_rpc_carrot.py new file mode 100644 index 000000000..cf84980ab --- /dev/null +++ b/nova/tests/test_rpc_carrot.py @@ -0,0 +1,202 @@ +# 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. +""" +Unit Tests for remote procedure calls using queue +""" + +from nova import context +from nova import log as logging +from nova.rpc import impl_carrot as rpc +from nova import test + + +LOG = logging.getLogger('nova.tests.rpc') + + +class RpcCarrotTestCase(test.TestCase): + def setUp(self): + super(RpcCarrotTestCase, self).setUp() + self.conn = rpc.create_connection(True) + self.receiver = TestReceiver() + rpc.create_consumer(self.conn, + 'test', + self.receiver, + False) + self.conn.consume_in_thread() + self.context = context.get_admin_context() + + def tearDown(self): + self.conn.close() + super(RpcCarrotTestCase, self).tearDown() + + def test_connectionpool_single(self): + """Test that ConnectionPool recycles a single connection.""" + conn1 = rpc.ConnectionPool.get() + rpc.ConnectionPool.put(conn1) + conn2 = rpc.ConnectionPool.get() + rpc.ConnectionPool.put(conn2) + self.assertEqual(conn1, conn2) + + def test_call_succeed(self): + value = 42 + result = rpc.call(self.context, 'test', {"method": "echo", + "args": {"value": value}}) + self.assertEqual(value, result) + + def test_call_succeed_despite_multiple_returns(self): + value = 42 + result = rpc.call(self.context, 'test', {"method": "echo_three_times", + "args": {"value": value}}) + self.assertEqual(value + 2, result) + + def test_call_succeed_despite_multiple_returns_yield(self): + value = 42 + result = rpc.call(self.context, 'test', + {"method": "echo_three_times_yield", + "args": {"value": value}}) + self.assertEqual(value + 2, result) + + def test_multicall_succeed_once(self): + value = 42 + result = rpc.multicall(self.context, + 'test', + {"method": "echo", + "args": {"value": value}}) + for i, x in enumerate(result): + if i > 0: + self.fail('should only receive one response') + self.assertEqual(value + i, x) + + def test_multicall_succeed_three_times(self): + value = 42 + result = rpc.multicall(self.context, + 'test', + {"method": "echo_three_times", + "args": {"value": value}}) + for i, x in enumerate(result): + self.assertEqual(value + i, x) + + def test_multicall_succeed_three_times_yield(self): + value = 42 + result = rpc.multicall(self.context, + 'test', + {"method": "echo_three_times_yield", + "args": {"value": value}}) + for i, x in enumerate(result): + self.assertEqual(value + i, x) + + def test_context_passed(self): + """Makes sure a context is passed through rpc call.""" + value = 42 + result = rpc.call(self.context, + 'test', {"method": "context", + "args": {"value": value}}) + self.assertEqual(self.context.to_dict(), result) + + def test_call_exception(self): + """Test that exception gets passed back properly. + + rpc.call returns a RemoteError object. The value of the + exception is converted to a string, so we convert it back + to an int in the test. + + """ + value = 42 + self.assertRaises(rpc.RemoteError, + rpc.call, + self.context, + 'test', + {"method": "fail", + "args": {"value": value}}) + try: + rpc.call(self.context, + 'test', + {"method": "fail", + "args": {"value": value}}) + self.fail("should have thrown rpc.RemoteError") + except rpc.RemoteError as exc: + self.assertEqual(int(exc.value), value) + + def test_nested_calls(self): + """Test that we can do an rpc.call inside another call.""" + class Nested(object): + @staticmethod + def echo(context, queue, value): + """Calls echo in the passed queue""" + LOG.debug(_("Nested received %(queue)s, %(value)s") + % locals()) + # TODO: so, it will replay the context and use the same REQID? + # that's bizarre. + ret = rpc.call(context, + queue, + {"method": "echo", + "args": {"value": value}}) + LOG.debug(_("Nested return %s"), ret) + return value + + nested = Nested() + conn = rpc.create_connection(True) + rpc.create_consumer(conn, + 'nested', + nested, + False) + conn.consume_in_thread() + value = 42 + result = rpc.call(self.context, + 'nested', {"method": "echo", + "args": {"queue": "test", + "value": value}}) + conn.close() + self.assertEqual(value, result) + + +class TestReceiver(object): + """Simple Proxy class so the consumer has methods to call. + + Uses static methods because we aren't actually storing any state. + + """ + + @staticmethod + def echo(context, value): + """Simply returns whatever value is sent in.""" + LOG.debug(_("Received %s"), value) + return value + + @staticmethod + def context(context, value): + """Returns dictionary version of context.""" + LOG.debug(_("Received %s"), context) + return context.to_dict() + + @staticmethod + def echo_three_times(context, value): + context.reply(value) + context.reply(value + 1) + context.reply(value + 2) + + @staticmethod + def echo_three_times_yield(context, value): + yield value + yield value + 1 + yield value + 2 + + @staticmethod + def fail(context, value): + """Raises an exception with the value sent in.""" + raise Exception(value) diff --git a/nova/tests/test_rpc_kombu.py b/nova/tests/test_rpc_kombu.py new file mode 100644 index 000000000..457dfdeca --- /dev/null +++ b/nova/tests/test_rpc_kombu.py @@ -0,0 +1,266 @@ +# 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. +""" +Unit Tests for remote procedure calls using queue +""" + +from nova import context +from nova import log as logging +from nova.rpc import impl_kombu as rpc +from nova import test + + +LOG = logging.getLogger('nova.tests.rpc') + + +class RpcKombuTestCase(test.TestCase): + def setUp(self): + super(RpcKombuTestCase, self).setUp() + self.conn = rpc.create_connection() + self.receiver = TestReceiver() + rpc.create_consumer(self.conn, + 'test', + self.receiver, + False) + self.conn.consume_in_thread() + self.context = context.get_admin_context() + + def tearDown(self): + self.conn.close() + super(RpcKombuTestCase, self).tearDown() + + def test_reusing_connection(self): + """Test that reusing a connection returns same one.""" + conn_context = rpc.create_connection(new=False) + conn1 = conn_context.connection + conn_context.close() + conn_context = rpc.create_connection(new=False) + conn2 = conn_context.connection + conn_context.close() + self.assertEqual(conn1, conn2) + + def test_topic_send_receive(self): + """Test sending to a topic exchange/queue""" + + conn = rpc.create_connection() + message = 'topic test message' + + self.received_message = None + + def _callback(message): + self.received_message = message + + conn.declare_topic_consumer('a_topic', _callback) + conn.topic_send('a_topic', message) + conn.consume(limit=1) + conn.close() + + self.assertEqual(self.received_message, message) + + def test_direct_send_receive(self): + """Test sending to a direct exchange/queue""" + conn = rpc.create_connection() + message = 'direct test message' + + self.received_message = None + + def _callback(message): + self.received_message = message + + conn.declare_direct_consumer('a_direct', _callback) + conn.direct_send('a_direct', message) + conn.consume(limit=1) + conn.close() + + self.assertEqual(self.received_message, message) + + @test.skip_test("kombu memory transport seems buggy with fanout queues " + "as this test passes when you use rabbit (fake_rabbit=False)") + def test_fanout_send_receive(self): + """Test sending to a fanout exchange and consuming from 2 queues""" + + conn = rpc.create_connection() + conn2 = rpc.create_connection() + message = 'fanout test message' + + self.received_message = None + + def _callback(message): + self.received_message = message + + conn.declare_fanout_consumer('a_fanout', _callback) + conn2.declare_fanout_consumer('a_fanout', _callback) + conn.fanout_send('a_fanout', message) + + conn.consume(limit=1) + conn.close() + self.assertEqual(self.received_message, message) + + self.received_message = None + conn2.consume(limit=1) + conn2.close() + self.assertEqual(self.received_message, message) + + def test_call_succeed(self): + value = 42 + result = rpc.call(self.context, 'test', {"method": "echo", + "args": {"value": value}}) + self.assertEqual(value, result) + + def test_call_succeed_despite_multiple_returns(self): + value = 42 + result = rpc.call(self.context, 'test', {"method": "echo_three_times", + "args": {"value": value}}) + self.assertEqual(value + 2, result) + + def test_call_succeed_despite_multiple_returns_yield(self): + value = 42 + result = rpc.call(self.context, 'test', + {"method": "echo_three_times_yield", + "args": {"value": value}}) + self.assertEqual(value + 2, result) + + def test_multicall_succeed_once(self): + value = 42 + result = rpc.multicall(self.context, + 'test', + {"method": "echo", + "args": {"value": value}}) + for i, x in enumerate(result): + if i > 0: + self.fail('should only receive one response') + self.assertEqual(value + i, x) + + def test_multicall_succeed_three_times(self): + value = 42 + result = rpc.multicall(self.context, + 'test', + {"method": "echo_three_times", + "args": {"value": value}}) + for i, x in enumerate(result): + self.assertEqual(value + i, x) + + def test_multicall_succeed_three_times_yield(self): + value = 42 + result = rpc.multicall(self.context, + 'test', + {"method": "echo_three_times_yield", + "args": {"value": value}}) + for i, x in enumerate(result): + self.assertEqual(value + i, x) + + def test_context_passed(self): + """Makes sure a context is passed through rpc call.""" + value = 42 + result = rpc.call(self.context, + 'test', {"method": "context", + "args": {"value": value}}) + self.assertEqual(self.context.to_dict(), result) + + def test_call_exception(self): + """Test that exception gets passed back properly. + + rpc.call returns a RemoteError object. The value of the + exception is converted to a string, so we convert it back + to an int in the test. + + """ + value = 42 + self.assertRaises(rpc.RemoteError, + rpc.call, + self.context, + 'test', + {"method": "fail", + "args": {"value": value}}) + try: + rpc.call(self.context, + 'test', + {"method": "fail", + "args": {"value": value}}) + self.fail("should have thrown rpc.RemoteError") + except rpc.RemoteError as exc: + self.assertEqual(int(exc.value), value) + + def test_nested_calls(self): + """Test that we can do an rpc.call inside another call.""" + class Nested(object): + @staticmethod + def echo(context, queue, value): + """Calls echo in the passed queue""" + LOG.debug(_("Nested received %(queue)s, %(value)s") + % locals()) + # TODO: so, it will replay the context and use the same REQID? + # that's bizarre. + ret = rpc.call(context, + queue, + {"method": "echo", + "args": {"value": value}}) + LOG.debug(_("Nested return %s"), ret) + return value + + nested = Nested() + conn = rpc.create_connection(True) + rpc.create_consumer(conn, + 'nested', + nested, + False) + conn.consume_in_thread() + value = 42 + result = rpc.call(self.context, + 'nested', {"method": "echo", + "args": {"queue": "test", + "value": value}}) + conn.close() + self.assertEqual(value, result) + + +class TestReceiver(object): + """Simple Proxy class so the consumer has methods to call. + + Uses static methods because we aren't actually storing any state. + + """ + + @staticmethod + def echo(context, value): + """Simply returns whatever value is sent in.""" + LOG.debug(_("Received %s"), value) + return value + + @staticmethod + def context(context, value): + """Returns dictionary version of context.""" + LOG.debug(_("Received %s"), context) + return context.to_dict() + + @staticmethod + def echo_three_times(context, value): + context.reply(value) + context.reply(value + 1) + context.reply(value + 2) + + @staticmethod + def echo_three_times_yield(context, value): + yield value + yield value + 1 + yield value + 2 + + @staticmethod + def fail(context, value): + """Raises an exception with the value sent in.""" + raise Exception(value) -- cgit From 53f796e0cfcec9d5c56dca86ee3c185625917dca Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Sun, 28 Aug 2011 19:27:49 -0700 Subject: remove unused rpc connections in test_cloud and test_adminapi --- nova/tests/test_adminapi.py | 2 -- nova/tests/test_cloud.py | 2 -- 2 files changed, 4 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_adminapi.py b/nova/tests/test_adminapi.py index 06cc498ac..aaa633adc 100644 --- a/nova/tests/test_adminapi.py +++ b/nova/tests/test_adminapi.py @@ -38,8 +38,6 @@ class AdminApiTestCase(test.TestCase): super(AdminApiTestCase, self).setUp() self.flags(connection_type='fake') - self.conn = rpc.create_connection() - # set up our cloud self.api = admin.AdminController() diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 0793784f8..14ab64f33 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -51,8 +51,6 @@ class CloudTestCase(test.TestCase): self.flags(connection_type='fake', stub_network=True) - self.conn = rpc.create_connection() - # set up our cloud self.cloud = cloud.CloudController() -- cgit From 0972d9188b0b73fa357f75896ab3bebda9a2a9de Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 29 Aug 2011 10:13:39 -0400 Subject: Removed test_parallel_builds --- nova/tests/test_xenapi.py | 37 ------------------------------------- 1 file changed, 37 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 2f0559366..45dad3516 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -16,7 +16,6 @@ """Test suite for XenAPI.""" -import eventlet import functools import json import os @@ -203,42 +202,6 @@ class XenAPIVMTestCase(test.TestCase): self.context = context.RequestContext(self.user_id, self.project_id) 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_ref': 1, - 'kernel_id': 2, - 'ramdisk_id': 3, - 'instance_type_id': '3', # m1.large - 'os_type': 'linux', - 'architecture': 'x86-64'} - network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, - {'broadcast': '192.168.0.255', - 'dns': ['192.168.0.1'], - 'gateway': '192.168.0.1', - 'gateway6': 'dead:beef::1', - 'ip6s': [{'enabled': '1', - 'ip': 'dead:beef::dcad:beff:feef:0', - 'netmask': '64'}], - 'ips': [{'enabled': '1', - 'ip': '192.168.0.100', - 'netmask': '255.255.255.0'}], - 'label': 'fake', - 'mac': 'DE:AD:BE:EF:00:00', - 'rxtx_cap': 3})] - instance = db.instance_create(self.context, values) - self.conn.spawn(self.context, instance, network_info) - - 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, []) -- cgit From ee15f2a58217d522e23d811db4958e2e9b2338d6 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Mon, 29 Aug 2011 14:36:12 -0700 Subject: ditched rpc.create_consumer(conn) interface... instead you now do conn.create_consumer(.. --- nova/tests/test_rpc.py | 10 ++-------- nova/tests/test_rpc_carrot.py | 10 ++-------- nova/tests/test_rpc_kombu.py | 10 ++-------- nova/tests/test_test.py | 3 +-- 4 files changed, 7 insertions(+), 26 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_rpc.py b/nova/tests/test_rpc.py index 2b9922491..ba91ea3b2 100644 --- a/nova/tests/test_rpc.py +++ b/nova/tests/test_rpc.py @@ -33,10 +33,7 @@ class RpcTestCase(test.TestCase): super(RpcTestCase, self).setUp() self.conn = rpc.create_connection(True) self.receiver = TestReceiver() - rpc.create_consumer(self.conn, - 'test', - self.receiver, - False) + self.conn.create_consumer('test', self.receiver, False) self.conn.consume_in_thread() self.context = context.get_admin_context() @@ -143,10 +140,7 @@ class RpcTestCase(test.TestCase): nested = Nested() conn = rpc.create_connection(True) - rpc.create_consumer(conn, - 'nested', - nested, - False) + conn.create_consumer('nested', nested, False) conn.consume_in_thread() value = 42 result = rpc.call(self.context, diff --git a/nova/tests/test_rpc_carrot.py b/nova/tests/test_rpc_carrot.py index cf84980ab..ff704ecf8 100644 --- a/nova/tests/test_rpc_carrot.py +++ b/nova/tests/test_rpc_carrot.py @@ -33,10 +33,7 @@ class RpcCarrotTestCase(test.TestCase): super(RpcCarrotTestCase, self).setUp() self.conn = rpc.create_connection(True) self.receiver = TestReceiver() - rpc.create_consumer(self.conn, - 'test', - self.receiver, - False) + self.conn.create_consumer('test', self.receiver, False) self.conn.consume_in_thread() self.context = context.get_admin_context() @@ -151,10 +148,7 @@ class RpcCarrotTestCase(test.TestCase): nested = Nested() conn = rpc.create_connection(True) - rpc.create_consumer(conn, - 'nested', - nested, - False) + conn.create_consumer('nested', nested, False) conn.consume_in_thread() value = 42 result = rpc.call(self.context, diff --git a/nova/tests/test_rpc_kombu.py b/nova/tests/test_rpc_kombu.py index 457dfdeca..7db88ecd0 100644 --- a/nova/tests/test_rpc_kombu.py +++ b/nova/tests/test_rpc_kombu.py @@ -33,10 +33,7 @@ class RpcKombuTestCase(test.TestCase): super(RpcKombuTestCase, self).setUp() self.conn = rpc.create_connection() self.receiver = TestReceiver() - rpc.create_consumer(self.conn, - 'test', - self.receiver, - False) + self.conn.create_consumer('test', self.receiver, False) self.conn.consume_in_thread() self.context = context.get_admin_context() @@ -215,10 +212,7 @@ class RpcKombuTestCase(test.TestCase): nested = Nested() conn = rpc.create_connection(True) - rpc.create_consumer(conn, - 'nested', - nested, - False) + conn.create_consumer('nested', nested, False) conn.consume_in_thread() value = 42 result = rpc.call(self.context, diff --git a/nova/tests/test_test.py b/nova/tests/test_test.py index 6075abbb0..3482ff6a0 100644 --- a/nova/tests/test_test.py +++ b/nova/tests/test_test.py @@ -40,6 +40,5 @@ class IsolationTestCase(test.TestCase): connection = rpc.create_connection(new=True) proxy = NeverCalled() - rpc.create_consumer(connection, 'compute', - proxy, fanout=False) + connection.create_consumer('compute', proxy, fanout=False) connection.consume_in_thread() -- cgit From a16efa7b94a15040657b961b0fd29a4d2720ef21 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Mon, 29 Aug 2011 14:54:20 -0700 Subject: created nova/tests/test_rpc_common.py which contains a rpc test base class so we can share tests between the rpc implementations --- nova/tests/test_rpc.py | 157 +---------------------------------- nova/tests/test_rpc_carrot.py | 169 ++----------------------------------- nova/tests/test_rpc_common.py | 188 ++++++++++++++++++++++++++++++++++++++++++ nova/tests/test_rpc_kombu.py | 172 +++----------------------------------- 4 files changed, 211 insertions(+), 475 deletions(-) create mode 100644 nova/tests/test_rpc_common.py (limited to 'nova/tests') diff --git a/nova/tests/test_rpc.py b/nova/tests/test_rpc.py index ba91ea3b2..6b4454747 100644 --- a/nova/tests/test_rpc.py +++ b/nova/tests/test_rpc.py @@ -22,167 +22,16 @@ Unit Tests for remote procedure calls using queue from nova import context from nova import log as logging from nova import rpc -from nova import test +from nova.tests import test_rpc_common LOG = logging.getLogger('nova.tests.rpc') -class RpcTestCase(test.TestCase): +class RpcTestCase(test_rpc_common._BaseRpcTestCase): def setUp(self): + self.rpc = rpc super(RpcTestCase, self).setUp() - self.conn = rpc.create_connection(True) - self.receiver = TestReceiver() - self.conn.create_consumer('test', self.receiver, False) - self.conn.consume_in_thread() - self.context = context.get_admin_context() def tearDown(self): - self.conn.close() super(RpcTestCase, self).tearDown() - - def test_call_succeed(self): - value = 42 - result = rpc.call(self.context, 'test', {"method": "echo", - "args": {"value": value}}) - self.assertEqual(value, result) - - def test_call_succeed_despite_multiple_returns(self): - value = 42 - result = rpc.call(self.context, 'test', {"method": "echo_three_times", - "args": {"value": value}}) - self.assertEqual(value + 2, result) - - def test_call_succeed_despite_multiple_returns_yield(self): - value = 42 - result = rpc.call(self.context, 'test', - {"method": "echo_three_times_yield", - "args": {"value": value}}) - self.assertEqual(value + 2, result) - - def test_multicall_succeed_once(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo", - "args": {"value": value}}) - for i, x in enumerate(result): - if i > 0: - self.fail('should only receive one response') - self.assertEqual(value + i, x) - - def test_multicall_succeed_three_times(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo_three_times", - "args": {"value": value}}) - for i, x in enumerate(result): - self.assertEqual(value + i, x) - - def test_multicall_succeed_three_times_yield(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo_three_times_yield", - "args": {"value": value}}) - for i, x in enumerate(result): - self.assertEqual(value + i, x) - - def test_context_passed(self): - """Makes sure a context is passed through rpc call.""" - value = 42 - result = rpc.call(self.context, - 'test', {"method": "context", - "args": {"value": value}}) - self.assertEqual(self.context.to_dict(), result) - - def test_call_exception(self): - """Test that exception gets passed back properly. - - rpc.call returns a RemoteError object. The value of the - exception is converted to a string, so we convert it back - to an int in the test. - - """ - value = 42 - self.assertRaises(rpc.RemoteError, - rpc.call, - self.context, - 'test', - {"method": "fail", - "args": {"value": value}}) - try: - rpc.call(self.context, - 'test', - {"method": "fail", - "args": {"value": value}}) - self.fail("should have thrown rpc.RemoteError") - except rpc.RemoteError as exc: - self.assertEqual(int(exc.value), value) - - def test_nested_calls(self): - """Test that we can do an rpc.call inside another call.""" - class Nested(object): - @staticmethod - def echo(context, queue, value): - """Calls echo in the passed queue""" - LOG.debug(_("Nested received %(queue)s, %(value)s") - % locals()) - # TODO: so, it will replay the context and use the same REQID? - # that's bizarre. - ret = rpc.call(context, - queue, - {"method": "echo", - "args": {"value": value}}) - LOG.debug(_("Nested return %s"), ret) - return value - - nested = Nested() - conn = rpc.create_connection(True) - conn.create_consumer('nested', nested, False) - conn.consume_in_thread() - value = 42 - result = rpc.call(self.context, - 'nested', {"method": "echo", - "args": {"queue": "test", - "value": value}}) - conn.close() - self.assertEqual(value, result) - - -class TestReceiver(object): - """Simple Proxy class so the consumer has methods to call. - - Uses static methods because we aren't actually storing any state. - - """ - - @staticmethod - def echo(context, value): - """Simply returns whatever value is sent in.""" - LOG.debug(_("Received %s"), value) - return value - - @staticmethod - def context(context, value): - """Returns dictionary version of context.""" - LOG.debug(_("Received %s"), context) - return context.to_dict() - - @staticmethod - def echo_three_times(context, value): - context.reply(value) - context.reply(value + 1) - context.reply(value + 2) - - @staticmethod - def echo_three_times_yield(context, value): - yield value - yield value + 1 - yield value + 2 - - @staticmethod - def fail(context, value): - """Raises an exception with the value sent in.""" - raise Exception(value) diff --git a/nova/tests/test_rpc_carrot.py b/nova/tests/test_rpc_carrot.py index ff704ecf8..57cdebf4f 100644 --- a/nova/tests/test_rpc_carrot.py +++ b/nova/tests/test_rpc_carrot.py @@ -16,181 +16,30 @@ # License for the specific language governing permissions and limitations # under the License. """ -Unit Tests for remote procedure calls using queue +Unit Tests for remote procedure calls using carrot """ from nova import context from nova import log as logging -from nova.rpc import impl_carrot as rpc -from nova import test +from nova.rpc import impl_carrot +from nova.tests import test_rpc_common LOG = logging.getLogger('nova.tests.rpc') -class RpcCarrotTestCase(test.TestCase): +class RpcCarrotTestCase(test_rpc_common._BaseRpcTestCase): def setUp(self): + self.rpc = impl_carrot super(RpcCarrotTestCase, self).setUp() - self.conn = rpc.create_connection(True) - self.receiver = TestReceiver() - self.conn.create_consumer('test', self.receiver, False) - self.conn.consume_in_thread() - self.context = context.get_admin_context() def tearDown(self): - self.conn.close() super(RpcCarrotTestCase, self).tearDown() def test_connectionpool_single(self): """Test that ConnectionPool recycles a single connection.""" - conn1 = rpc.ConnectionPool.get() - rpc.ConnectionPool.put(conn1) - conn2 = rpc.ConnectionPool.get() - rpc.ConnectionPool.put(conn2) + conn1 = self.rpc.ConnectionPool.get() + self.rpc.ConnectionPool.put(conn1) + conn2 = self.rpc.ConnectionPool.get() + self.rpc.ConnectionPool.put(conn2) self.assertEqual(conn1, conn2) - - def test_call_succeed(self): - value = 42 - result = rpc.call(self.context, 'test', {"method": "echo", - "args": {"value": value}}) - self.assertEqual(value, result) - - def test_call_succeed_despite_multiple_returns(self): - value = 42 - result = rpc.call(self.context, 'test', {"method": "echo_three_times", - "args": {"value": value}}) - self.assertEqual(value + 2, result) - - def test_call_succeed_despite_multiple_returns_yield(self): - value = 42 - result = rpc.call(self.context, 'test', - {"method": "echo_three_times_yield", - "args": {"value": value}}) - self.assertEqual(value + 2, result) - - def test_multicall_succeed_once(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo", - "args": {"value": value}}) - for i, x in enumerate(result): - if i > 0: - self.fail('should only receive one response') - self.assertEqual(value + i, x) - - def test_multicall_succeed_three_times(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo_three_times", - "args": {"value": value}}) - for i, x in enumerate(result): - self.assertEqual(value + i, x) - - def test_multicall_succeed_three_times_yield(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo_three_times_yield", - "args": {"value": value}}) - for i, x in enumerate(result): - self.assertEqual(value + i, x) - - def test_context_passed(self): - """Makes sure a context is passed through rpc call.""" - value = 42 - result = rpc.call(self.context, - 'test', {"method": "context", - "args": {"value": value}}) - self.assertEqual(self.context.to_dict(), result) - - def test_call_exception(self): - """Test that exception gets passed back properly. - - rpc.call returns a RemoteError object. The value of the - exception is converted to a string, so we convert it back - to an int in the test. - - """ - value = 42 - self.assertRaises(rpc.RemoteError, - rpc.call, - self.context, - 'test', - {"method": "fail", - "args": {"value": value}}) - try: - rpc.call(self.context, - 'test', - {"method": "fail", - "args": {"value": value}}) - self.fail("should have thrown rpc.RemoteError") - except rpc.RemoteError as exc: - self.assertEqual(int(exc.value), value) - - def test_nested_calls(self): - """Test that we can do an rpc.call inside another call.""" - class Nested(object): - @staticmethod - def echo(context, queue, value): - """Calls echo in the passed queue""" - LOG.debug(_("Nested received %(queue)s, %(value)s") - % locals()) - # TODO: so, it will replay the context and use the same REQID? - # that's bizarre. - ret = rpc.call(context, - queue, - {"method": "echo", - "args": {"value": value}}) - LOG.debug(_("Nested return %s"), ret) - return value - - nested = Nested() - conn = rpc.create_connection(True) - conn.create_consumer('nested', nested, False) - conn.consume_in_thread() - value = 42 - result = rpc.call(self.context, - 'nested', {"method": "echo", - "args": {"queue": "test", - "value": value}}) - conn.close() - self.assertEqual(value, result) - - -class TestReceiver(object): - """Simple Proxy class so the consumer has methods to call. - - Uses static methods because we aren't actually storing any state. - - """ - - @staticmethod - def echo(context, value): - """Simply returns whatever value is sent in.""" - LOG.debug(_("Received %s"), value) - return value - - @staticmethod - def context(context, value): - """Returns dictionary version of context.""" - LOG.debug(_("Received %s"), context) - return context.to_dict() - - @staticmethod - def echo_three_times(context, value): - context.reply(value) - context.reply(value + 1) - context.reply(value + 2) - - @staticmethod - def echo_three_times_yield(context, value): - yield value - yield value + 1 - yield value + 2 - - @staticmethod - def fail(context, value): - """Raises an exception with the value sent in.""" - raise Exception(value) diff --git a/nova/tests/test_rpc_common.py b/nova/tests/test_rpc_common.py new file mode 100644 index 000000000..b922be1df --- /dev/null +++ b/nova/tests/test_rpc_common.py @@ -0,0 +1,188 @@ +# 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. +""" +Unit Tests for remote procedure calls shared between all implementations +""" + +from nova import context +from nova import log as logging +from nova.rpc.common import RemoteError +from nova import test + + +LOG = logging.getLogger('nova.tests.rpc') + + +class _BaseRpcTestCase(test.TestCase): + def setUp(self): + super(_BaseRpcTestCase, self).setUp() + self.conn = self.rpc.create_connection(True) + self.receiver = TestReceiver() + self.conn.create_consumer('test', self.receiver, False) + self.conn.consume_in_thread() + self.context = context.get_admin_context() + + def tearDown(self): + self.conn.close() + super(_BaseRpcTestCase, self).tearDown() + + def test_call_succeed(self): + value = 42 + result = self.rpc.call(self.context, 'test', {"method": "echo", + "args": {"value": value}}) + self.assertEqual(value, result) + + def test_call_succeed_despite_multiple_returns(self): + value = 42 + result = self.rpc.call(self.context, 'test', {"method": "echo_three_times", + "args": {"value": value}}) + self.assertEqual(value + 2, result) + + def test_call_succeed_despite_multiple_returns_yield(self): + value = 42 + result = self.rpc.call(self.context, 'test', + {"method": "echo_three_times_yield", + "args": {"value": value}}) + self.assertEqual(value + 2, result) + + def test_multicall_succeed_once(self): + value = 42 + result = self.rpc.multicall(self.context, + 'test', + {"method": "echo", + "args": {"value": value}}) + for i, x in enumerate(result): + if i > 0: + self.fail('should only receive one response') + self.assertEqual(value + i, x) + + def test_multicall_succeed_three_times(self): + value = 42 + result = self.rpc.multicall(self.context, + 'test', + {"method": "echo_three_times", + "args": {"value": value}}) + for i, x in enumerate(result): + self.assertEqual(value + i, x) + + def test_multicall_succeed_three_times_yield(self): + value = 42 + result = self.rpc.multicall(self.context, + 'test', + {"method": "echo_three_times_yield", + "args": {"value": value}}) + for i, x in enumerate(result): + self.assertEqual(value + i, x) + + def test_context_passed(self): + """Makes sure a context is passed through rpc call.""" + value = 42 + result = self.rpc.call(self.context, + 'test', {"method": "context", + "args": {"value": value}}) + self.assertEqual(self.context.to_dict(), result) + + def test_call_exception(self): + """Test that exception gets passed back properly. + + rpc.call returns a RemoteError object. The value of the + exception is converted to a string, so we convert it back + to an int in the test. + + """ + value = 42 + self.assertRaises(RemoteError, + self.rpc.call, + self.context, + 'test', + {"method": "fail", + "args": {"value": value}}) + try: + self.rpc.call(self.context, + 'test', + {"method": "fail", + "args": {"value": value}}) + self.fail("should have thrown RemoteError") + except RemoteError as exc: + self.assertEqual(int(exc.value), value) + + def test_nested_calls(self): + """Test that we can do an rpc.call inside another call.""" + class Nested(object): + @staticmethod + def echo(context, queue, value): + """Calls echo in the passed queue""" + LOG.debug(_("Nested received %(queue)s, %(value)s") + % locals()) + # TODO: so, it will replay the context and use the same REQID? + # that's bizarre. + ret = self.rpc.call(context, + queue, + {"method": "echo", + "args": {"value": value}}) + LOG.debug(_("Nested return %s"), ret) + return value + + nested = Nested() + conn = self.rpc.create_connection(True) + conn.create_consumer('nested', nested, False) + conn.consume_in_thread() + value = 42 + result = self.rpc.call(self.context, + 'nested', {"method": "echo", + "args": {"queue": "test", + "value": value}}) + conn.close() + self.assertEqual(value, result) + + +class TestReceiver(object): + """Simple Proxy class so the consumer has methods to call. + + Uses static methods because we aren't actually storing any state. + + """ + + @staticmethod + def echo(context, value): + """Simply returns whatever value is sent in.""" + LOG.debug(_("Received %s"), value) + return value + + @staticmethod + def context(context, value): + """Returns dictionary version of context.""" + LOG.debug(_("Received %s"), context) + return context.to_dict() + + @staticmethod + def echo_three_times(context, value): + context.reply(value) + context.reply(value + 1) + context.reply(value + 2) + + @staticmethod + def echo_three_times_yield(context, value): + yield value + yield value + 1 + yield value + 2 + + @staticmethod + def fail(context, value): + """Raises an exception with the value sent in.""" + raise Exception(value) diff --git a/nova/tests/test_rpc_kombu.py b/nova/tests/test_rpc_kombu.py index 7db88ecd0..101ed14af 100644 --- a/nova/tests/test_rpc_kombu.py +++ b/nova/tests/test_rpc_kombu.py @@ -16,37 +16,33 @@ # License for the specific language governing permissions and limitations # under the License. """ -Unit Tests for remote procedure calls using queue +Unit Tests for remote procedure calls using kombu """ from nova import context from nova import log as logging -from nova.rpc import impl_kombu as rpc from nova import test +from nova.rpc import impl_kombu +from nova.tests import test_rpc_common LOG = logging.getLogger('nova.tests.rpc') -class RpcKombuTestCase(test.TestCase): +class RpcKombuTestCase(test_rpc_common._BaseRpcTestCase): def setUp(self): + self.rpc = impl_kombu super(RpcKombuTestCase, self).setUp() - self.conn = rpc.create_connection() - self.receiver = TestReceiver() - self.conn.create_consumer('test', self.receiver, False) - self.conn.consume_in_thread() - self.context = context.get_admin_context() def tearDown(self): - self.conn.close() super(RpcKombuTestCase, self).tearDown() def test_reusing_connection(self): """Test that reusing a connection returns same one.""" - conn_context = rpc.create_connection(new=False) + conn_context = self.rpc.create_connection(new=False) conn1 = conn_context.connection conn_context.close() - conn_context = rpc.create_connection(new=False) + conn_context = self.rpc.create_connection(new=False) conn2 = conn_context.connection conn_context.close() self.assertEqual(conn1, conn2) @@ -54,7 +50,7 @@ class RpcKombuTestCase(test.TestCase): def test_topic_send_receive(self): """Test sending to a topic exchange/queue""" - conn = rpc.create_connection() + conn = self.rpc.create_connection() message = 'topic test message' self.received_message = None @@ -71,7 +67,7 @@ class RpcKombuTestCase(test.TestCase): def test_direct_send_receive(self): """Test sending to a direct exchange/queue""" - conn = rpc.create_connection() + conn = self.rpc.create_connection() message = 'direct test message' self.received_message = None @@ -91,8 +87,8 @@ class RpcKombuTestCase(test.TestCase): def test_fanout_send_receive(self): """Test sending to a fanout exchange and consuming from 2 queues""" - conn = rpc.create_connection() - conn2 = rpc.create_connection() + conn = self.rpc.create_connection() + conn2 = self.rpc.create_connection() message = 'fanout test message' self.received_message = None @@ -112,149 +108,3 @@ class RpcKombuTestCase(test.TestCase): conn2.consume(limit=1) conn2.close() self.assertEqual(self.received_message, message) - - def test_call_succeed(self): - value = 42 - result = rpc.call(self.context, 'test', {"method": "echo", - "args": {"value": value}}) - self.assertEqual(value, result) - - def test_call_succeed_despite_multiple_returns(self): - value = 42 - result = rpc.call(self.context, 'test', {"method": "echo_three_times", - "args": {"value": value}}) - self.assertEqual(value + 2, result) - - def test_call_succeed_despite_multiple_returns_yield(self): - value = 42 - result = rpc.call(self.context, 'test', - {"method": "echo_three_times_yield", - "args": {"value": value}}) - self.assertEqual(value + 2, result) - - def test_multicall_succeed_once(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo", - "args": {"value": value}}) - for i, x in enumerate(result): - if i > 0: - self.fail('should only receive one response') - self.assertEqual(value + i, x) - - def test_multicall_succeed_three_times(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo_three_times", - "args": {"value": value}}) - for i, x in enumerate(result): - self.assertEqual(value + i, x) - - def test_multicall_succeed_three_times_yield(self): - value = 42 - result = rpc.multicall(self.context, - 'test', - {"method": "echo_three_times_yield", - "args": {"value": value}}) - for i, x in enumerate(result): - self.assertEqual(value + i, x) - - def test_context_passed(self): - """Makes sure a context is passed through rpc call.""" - value = 42 - result = rpc.call(self.context, - 'test', {"method": "context", - "args": {"value": value}}) - self.assertEqual(self.context.to_dict(), result) - - def test_call_exception(self): - """Test that exception gets passed back properly. - - rpc.call returns a RemoteError object. The value of the - exception is converted to a string, so we convert it back - to an int in the test. - - """ - value = 42 - self.assertRaises(rpc.RemoteError, - rpc.call, - self.context, - 'test', - {"method": "fail", - "args": {"value": value}}) - try: - rpc.call(self.context, - 'test', - {"method": "fail", - "args": {"value": value}}) - self.fail("should have thrown rpc.RemoteError") - except rpc.RemoteError as exc: - self.assertEqual(int(exc.value), value) - - def test_nested_calls(self): - """Test that we can do an rpc.call inside another call.""" - class Nested(object): - @staticmethod - def echo(context, queue, value): - """Calls echo in the passed queue""" - LOG.debug(_("Nested received %(queue)s, %(value)s") - % locals()) - # TODO: so, it will replay the context and use the same REQID? - # that's bizarre. - ret = rpc.call(context, - queue, - {"method": "echo", - "args": {"value": value}}) - LOG.debug(_("Nested return %s"), ret) - return value - - nested = Nested() - conn = rpc.create_connection(True) - conn.create_consumer('nested', nested, False) - conn.consume_in_thread() - value = 42 - result = rpc.call(self.context, - 'nested', {"method": "echo", - "args": {"queue": "test", - "value": value}}) - conn.close() - self.assertEqual(value, result) - - -class TestReceiver(object): - """Simple Proxy class so the consumer has methods to call. - - Uses static methods because we aren't actually storing any state. - - """ - - @staticmethod - def echo(context, value): - """Simply returns whatever value is sent in.""" - LOG.debug(_("Received %s"), value) - return value - - @staticmethod - def context(context, value): - """Returns dictionary version of context.""" - LOG.debug(_("Received %s"), context) - return context.to_dict() - - @staticmethod - def echo_three_times(context, value): - context.reply(value) - context.reply(value + 1) - context.reply(value + 2) - - @staticmethod - def echo_three_times_yield(context, value): - yield value - yield value + 1 - yield value + 2 - - @staticmethod - def fail(context, value): - """Raises an exception with the value sent in.""" - raise Exception(value) -- cgit From 345afb31678a1f94fcca6d63a4ab506e537c3a9c Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Mon, 29 Aug 2011 15:25:54 -0700 Subject: pep8 fix for test_rpc_common.py --- nova/tests/test_rpc_common.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_rpc_common.py b/nova/tests/test_rpc_common.py index b922be1df..4ab4e8a0e 100644 --- a/nova/tests/test_rpc_common.py +++ b/nova/tests/test_rpc_common.py @@ -49,8 +49,9 @@ class _BaseRpcTestCase(test.TestCase): def test_call_succeed_despite_multiple_returns(self): value = 42 - result = self.rpc.call(self.context, 'test', {"method": "echo_three_times", - "args": {"value": value}}) + result = self.rpc.call(self.context, 'test', + {"method": "echo_three_times", + "args": {"value": value}}) self.assertEqual(value + 2, result) def test_call_succeed_despite_multiple_returns_yield(self): -- cgit From ebd47b7cb397f33c1e7c9f32dd5b77f7fd5d6642 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 29 Aug 2011 22:27:28 -0400 Subject: Update RequestContext so that it correctly sets self.is_admin from the roles array. Additionally add a bit of code to ignore case as well. Resolves issues when accessing admin API's w/ Keystone. --- nova/tests/test_context.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 nova/tests/test_context.py (limited to 'nova/tests') diff --git a/nova/tests/test_context.py b/nova/tests/test_context.py new file mode 100644 index 000000000..b2507fa59 --- /dev/null +++ b/nova/tests/test_context.py @@ -0,0 +1,33 @@ +# 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. + +from nova import context +from nova import test + + +class ContextTestCase(test.TestCase): + + def test_request_context_sets_is_admin(self): + ctxt = context.RequestContext('111', + '222', + roles=['admin', 'weasel']) + self.assertEquals(ctxt.is_admin, True) + + def test_request_context_sets_is_admin_upcase(self): + ctxt = context.RequestContext('111', + '222', + roles=['Admin', 'weasel']) + self.assertEquals(ctxt.is_admin, True) -- cgit From a635027ddbeb73dfad8bbf2890f67cb1ed7511bf Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 30 Aug 2011 00:03:39 -0700 Subject: disassociate floating ips before re-associating, and prevent re-association of already associated floating ips in manager --- .../api/openstack/contrib/test_floating_ips.py | 68 ++++++++++++++++++++-- nova/tests/test_network.py | 16 +++++ 2 files changed, 79 insertions(+), 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py index 568faf867..c14c29bf3 100644 --- a/nova/tests/api/openstack/contrib/test_floating_ips.py +++ b/nova/tests/api/openstack/contrib/test_floating_ips.py @@ -23,6 +23,7 @@ from nova import db from nova import test from nova import network from nova.tests.api.openstack import fakes +from nova.tests.api.openstack import test_servers from nova.api.openstack.contrib.floating_ips import FloatingIPController @@ -60,10 +61,38 @@ def compute_api_associate(self, context, instance_id, floating_ip): pass +def network_api_associate(self, context, floating_ip, fixed_ip): + pass + + def network_api_disassociate(self, context, floating_address): pass +def network_get_instance_nw_info(self, context, instance): + info = { + 'label': 'fake', + 'gateway': 'fake', + 'dhcp_server': 'fake', + 'broadcast': 'fake', + 'mac': 'fake', + 'vif_uuid': 'fake', + 'rxtx_cap': 'fake', + 'dns': [], + 'ips': [{'ip': '10.0.0.1'}], + 'should_create_bridge': False, + 'should_create_vlan': False} + + return [['ignore', info]] + + +def fake_instance_get(context, instance_id): + return { + "id": 1, + "user_id": 'fakeuser', + "project_id": '123'} + + class FloatingIpTest(test.TestCase): address = "10.10.10.10" @@ -79,9 +108,6 @@ class FloatingIpTest(test.TestCase): def setUp(self): super(FloatingIpTest, self).setUp() - self.controller = FloatingIPController() - fakes.stub_out_networking(self.stubs) - fakes.stub_out_rate_limiting(self.stubs) self.stubs.Set(network.api.API, "get_floating_ip", network_api_get_floating_ip) self.stubs.Set(network.api.API, "get_floating_ip_by_ip", @@ -92,10 +118,13 @@ class FloatingIpTest(test.TestCase): network_api_allocate) self.stubs.Set(network.api.API, "release_floating_ip", network_api_release) - self.stubs.Set(compute.api.API, "associate_floating_ip", - compute_api_associate) self.stubs.Set(network.api.API, "disassociate_floating_ip", network_api_disassociate) + self.stubs.Set(network.api.API, "get_instance_nw_info", + network_get_instance_nw_info) + self.stubs.Set(db.api, 'instance_get', + fake_instance_get) + self.context = context.get_admin_context() self._create_floating_ip() @@ -165,6 +194,8 @@ class FloatingIpTest(test.TestCase): self.assertEqual(res.status_int, 202) def test_add_floating_ip_to_instance(self): + self.stubs.Set(network.api.API, "associate_floating_ip", + network_api_associate) body = dict(addFloatingIp=dict(address='11.0.0.1')) req = webob.Request.blank('/v1.1/123/servers/test_inst/action') req.method = "POST" @@ -174,6 +205,33 @@ class FloatingIpTest(test.TestCase): resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 202) + def test_add_associated_floating_ip_to_instance(self): + def fake_fixed_ip_get_by_address(ctx, address, session=None): + return {'address': address, 'network': {'multi_host': None, + 'host': 'fake'}} + + self.disassociated = False + + def fake_network_api_disassociate(local_self, ctx, floating_address): + self.disassociated = True + + db.floating_ip_update(self.context, self.address, {'project_id': '123', + 'fixed_ip_id': 1}) + self.stubs.Set(network.api.API, "disassociate_floating_ip", + fake_network_api_disassociate) + self.stubs.Set(db.api, "fixed_ip_get_by_address", + fake_fixed_ip_get_by_address) + + body = dict(addFloatingIp=dict(address=self.address)) + req = webob.Request.blank('/v1.1/123/servers/test_inst/action') + req.method = "POST" + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 202) + self.assertTrue(self.disassociated) + def test_remove_floating_ip_from_instance(self): body = dict(removeFloatingIp=dict(address='11.0.0.1')) req = webob.Request.blank('/v1.1/123/servers/test_inst/action') diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py index 0b8539442..25ff940f0 100644 --- a/nova/tests/test_network.py +++ b/nova/tests/test_network.py @@ -371,6 +371,22 @@ class VlanNetworkTestCase(test.TestCase): self.mox.ReplayAll() self.network.validate_networks(self.context, requested_networks) + def test_cant_associate_associated_floating_ip(self): + ctxt = context.RequestContext('testuser', 'testproject', + is_admin=False) + + def fake_floating_ip_get_by_address(context, address): + return {'address': '10.10.10.10', + 'fixed_ip': {'address': '10.0.0.1'}} + self.stubs.Set(self.network.db, 'floating_ip_get_by_address', + fake_floating_ip_get_by_address) + + self.assertRaises(exception.FloatingIpAlreadyInUse, + self.network.associate_floating_ip, + ctxt, + mox.IgnoreArg(), + mox.IgnoreArg()) + class CommonNetworkTestCase(test.TestCase): -- cgit From 1155b734164eb5856d68c926f7bf64a37ae4a3a4 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 30 Aug 2011 11:13:25 -0400 Subject: supporting changes-since --- nova/tests/api/openstack/test_servers.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 3559e6de5..9036d6552 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1257,6 +1257,30 @@ class ServersTest(test.TestCase): self.assertEqual(len(servers), 1) self.assertEqual(servers[0]['id'], 100) + def test_get_servers_allows_changes_since_v1_1(self): + def fake_get_all(compute_self, context, search_opts=None): + self.assertNotEqual(search_opts, None) + self.assertTrue('changes-since' in search_opts) + changes_since = datetime.datetime(2011, 1, 24, 17, 8, 1) + self.assertEqual(search_opts['changes-since'], changes_since) + return [stub_instance(100)] + + self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) + + params = 'changes-since=2011-01-24T17:08:01Z' + req = webob.Request.blank('/v1.1/fake/servers?%s' % params) + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) + servers = json.loads(res.body)['servers'] + self.assertEqual(len(servers), 1) + self.assertEqual(servers[0]['id'], 100) + + def test_get_servers_allows_changes_since_bad_value_v1_1(self): + params = 'changes-since=asdf' + req = webob.Request.blank('/v1.1/fake/servers?%s' % params) + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 400) + def test_get_servers_unknown_or_admin_options1(self): """Test getting servers by admin-only or unknown options. This tests when admin_api is off. Make sure the admin and -- cgit From a127747db0ab3405a768e8f680a2eb94ae8ce314 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 30 Aug 2011 11:44:19 -0400 Subject: adding an assert --- nova/tests/api/openstack/test_servers.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 9036d6552..5f1ca466a 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1263,6 +1263,7 @@ class ServersTest(test.TestCase): self.assertTrue('changes-since' in search_opts) changes_since = datetime.datetime(2011, 1, 24, 17, 8, 1) self.assertEqual(search_opts['changes-since'], changes_since) + self.assertTrue('deleted' not in search_opts) return [stub_instance(100)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) -- cgit From dcf5970dd9bed27201c593d7d053970a632e5eee Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 30 Aug 2011 12:01:18 -0700 Subject: make two functions instead of fast flag and add compute api commands instead of hitting db directly --- nova/tests/api/openstack/contrib/test_simple_tenant_usage.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py index 2bd619820..de0a6d779 100644 --- a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py +++ b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py @@ -20,9 +20,9 @@ import json import webob from nova import context -from nova import db from nova import flags from nova import test +from nova.compute import api from nova.tests.api.openstack import fakes @@ -39,7 +39,7 @@ STOP = datetime.datetime.utcnow() START = STOP - datetime.timedelta(hours=HOURS) -def fake_instance_type_get(context, instance_type_id): +def fake_instance_type_get(self, context, instance_type_id): return {'id': 1, 'vcpus': VCPUS, 'local_gb': LOCAL_GB, @@ -59,7 +59,7 @@ def get_fake_db_instance(start, end, instance_id, tenant_id): 'launched_at': start, 'terminated_at': end} -def fake_instance_get_active_by_window(context, begin, end, project_id, fast): +def fake_instance_get_active_by_window(self, context, begin, end, project_id): return [get_fake_db_instance(START, STOP, x, @@ -70,9 +70,9 @@ def fake_instance_get_active_by_window(context, begin, end, project_id, fast): class SimpleTenantUsageTest(test.TestCase): def setUp(self): super(SimpleTenantUsageTest, self).setUp() - self.stubs.Set(db, "instance_type_get", + self.stubs.Set(api.API, "get_instance_type", fake_instance_type_get) - self.stubs.Set(db, "instance_get_active_by_window", + self.stubs.Set(api.API, "get_active_by_window", fake_instance_get_active_by_window) self.admin_context = context.RequestContext('fakeadmin_0', 'faketenant_0', -- cgit From 2fcc6da8ba528c5169f7394d57f90ccd2754a23c Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 30 Aug 2011 12:14:25 -0700 Subject: pep8, fix fakes --- nova/tests/api/openstack/contrib/test_createserverext.py | 2 ++ nova/tests/api/openstack/contrib/test_simple_tenant_usage.py | 2 +- nova/tests/api/openstack/test_servers.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_createserverext.py b/nova/tests/api/openstack/contrib/test_createserverext.py index e5eed14fe..f6d9ba784 100644 --- a/nova/tests/api/openstack/contrib/test_createserverext.py +++ b/nova/tests/api/openstack/contrib/test_createserverext.py @@ -23,6 +23,7 @@ from xml.dom import minidom import stubout import webob +from nova import db from nova import exception from nova import flags from nova import test @@ -76,6 +77,7 @@ class CreateserverextTest(test.TestCase): def __init__(self): self.injected_files = None self.networks = None + self.db = db def create(self, *args, **kwargs): if 'injected_files' in kwargs: diff --git a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py index de0a6d779..2430b9d51 100644 --- a/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py +++ b/nova/tests/api/openstack/contrib/test_simple_tenant_usage.py @@ -26,7 +26,6 @@ from nova.compute import api from nova.tests.api.openstack import fakes - FLAGS = flags.FLAGS SERVERS = 5 @@ -59,6 +58,7 @@ def get_fake_db_instance(start, end, instance_id, tenant_id): 'launched_at': start, 'terminated_at': end} + def fake_instance_get_active_by_window(self, context, begin, end, project_id): return [get_fake_db_instance(START, STOP, diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 3559e6de5..d065f48b6 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3229,6 +3229,7 @@ class TestServerInstanceCreation(test.TestCase): def __init__(self): self.injected_files = None self.networks = None + self.db = db def create(self, *args, **kwargs): if 'injected_files' in kwargs: -- cgit From 5cf27b5a338f7821f82c91df5889159b56fa0bb6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 30 Aug 2011 12:41:30 -0700 Subject: fix remaining tests --- .../api/openstack/contrib/test_security_groups.py | 72 +++++++++++----------- nova/tests/api/openstack/test_extensions.py | 1 + nova/tests/api/openstack/test_server_actions.py | 2 +- 3 files changed, 38 insertions(+), 37 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_security_groups.py b/nova/tests/api/openstack/contrib/test_security_groups.py index bc1536911..0816a6312 100644 --- a/nova/tests/api/openstack/contrib/test_security_groups.py +++ b/nova/tests/api/openstack/contrib/test_security_groups.py @@ -360,7 +360,7 @@ class TestSecurityGroups(test.TestCase): def test_associate_by_invalid_server_id(self): body = dict(addSecurityGroup=dict(name='test')) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) req = webob.Request.blank('/v1.1/123/servers/invalid/action') req.headers['Content-Type'] = 'application/json' @@ -372,7 +372,7 @@ class TestSecurityGroups(test.TestCase): def test_associate_without_body(self): req = webob.Request.blank('/v1.1/123/servers/1/action') body = dict(addSecurityGroup=None) - self.stubs.Set(nova.db, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'instance_get', return_server) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = json.dumps(body) @@ -382,7 +382,7 @@ class TestSecurityGroups(test.TestCase): def test_associate_no_security_group_name(self): req = webob.Request.blank('/v1.1/123/servers/1/action') body = dict(addSecurityGroup=dict()) - self.stubs.Set(nova.db, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'instance_get', return_server) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = json.dumps(body) @@ -392,7 +392,7 @@ class TestSecurityGroups(test.TestCase): def test_associate_security_group_name_with_whitespaces(self): req = webob.Request.blank('/v1.1/123/servers/1/action') body = dict(addSecurityGroup=dict(name=" ")) - self.stubs.Set(nova.db, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'instance_get', return_server) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = json.dumps(body) @@ -400,9 +400,9 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 400) def test_associate_non_existing_instance(self): - self.stubs.Set(nova.db, 'instance_get', return_server_nonexistant) + self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant) body = dict(addSecurityGroup=dict(name="test")) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) req = webob.Request.blank('/v1.1/123/servers/10000/action') req.headers['Content-Type'] = 'application/json' @@ -412,8 +412,8 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 404) def test_associate_non_running_instance(self): - self.stubs.Set(nova.db, 'instance_get', return_non_running_server) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'instance_get', return_non_running_server) + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group_without_instances) body = dict(addSecurityGroup=dict(name="test")) req = webob.Request.blank('/v1.1/123/servers/1/action') @@ -424,8 +424,8 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 400) def test_associate_already_associated_security_group_to_instance(self): - self.stubs.Set(nova.db, 'instance_get', return_server) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) body = dict(addSecurityGroup=dict(name="test")) req = webob.Request.blank('/v1.1/123/servers/1/action') @@ -436,12 +436,12 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 400) def test_associate(self): - self.stubs.Set(nova.db, 'instance_get', return_server) - self.mox.StubOutWithMock(nova.db, 'instance_add_security_group') - nova.db.instance_add_security_group(mox.IgnoreArg(), + self.stubs.Set(nova.db.api, 'instance_get', return_server) + self.mox.StubOutWithMock(nova.db.api, 'instance_add_security_group') + nova.db.api.instance_add_security_group(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group_without_instances) self.mox.ReplayAll() @@ -454,12 +454,12 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 202) def test_associate_xml(self): - self.stubs.Set(nova.db, 'instance_get', return_server) - self.mox.StubOutWithMock(nova.db, 'instance_add_security_group') - nova.db.instance_add_security_group(mox.IgnoreArg(), + self.stubs.Set(nova.db.api, 'instance_get', return_server) + self.mox.StubOutWithMock(nova.db.api, 'instance_add_security_group') + nova.db.api.instance_add_security_group(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group_without_instances) self.mox.ReplayAll() @@ -483,7 +483,7 @@ class TestSecurityGroups(test.TestCase): def test_disassociate_by_invalid_server_id(self): body = dict(removeSecurityGroup=dict(name='test')) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) req = webob.Request.blank('/v1.1/123/servers/invalid/action') req.headers['Content-Type'] = 'application/json' @@ -495,7 +495,7 @@ class TestSecurityGroups(test.TestCase): def test_disassociate_without_body(self): req = webob.Request.blank('/v1.1/123/servers/1/action') body = dict(removeSecurityGroup=None) - self.stubs.Set(nova.db, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'instance_get', return_server) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = json.dumps(body) @@ -505,7 +505,7 @@ class TestSecurityGroups(test.TestCase): def test_disassociate_no_security_group_name(self): req = webob.Request.blank('/v1.1/123/servers/1/action') body = dict(removeSecurityGroup=dict()) - self.stubs.Set(nova.db, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'instance_get', return_server) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = json.dumps(body) @@ -515,7 +515,7 @@ class TestSecurityGroups(test.TestCase): def test_disassociate_security_group_name_with_whitespaces(self): req = webob.Request.blank('/v1.1/123/servers/1/action') body = dict(removeSecurityGroup=dict(name=" ")) - self.stubs.Set(nova.db, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'instance_get', return_server) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = json.dumps(body) @@ -523,9 +523,9 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 400) def test_disassociate_non_existing_instance(self): - self.stubs.Set(nova.db, 'instance_get', return_server_nonexistant) + self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant) body = dict(removeSecurityGroup=dict(name="test")) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) req = webob.Request.blank('/v1.1/123/servers/10000/action') req.headers['Content-Type'] = 'application/json' @@ -535,8 +535,8 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 404) def test_disassociate_non_running_instance(self): - self.stubs.Set(nova.db, 'instance_get', return_non_running_server) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'instance_get', return_non_running_server) + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) body = dict(removeSecurityGroup=dict(name="test")) req = webob.Request.blank('/v1.1/123/servers/1/action') @@ -547,8 +547,8 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 400) def test_disassociate_already_associated_security_group_to_instance(self): - self.stubs.Set(nova.db, 'instance_get', return_server) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'instance_get', return_server) + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group_without_instances) body = dict(removeSecurityGroup=dict(name="test")) req = webob.Request.blank('/v1.1/123/servers/1/action') @@ -559,12 +559,12 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 400) def test_disassociate(self): - self.stubs.Set(nova.db, 'instance_get', return_server) - self.mox.StubOutWithMock(nova.db, 'instance_remove_security_group') - nova.db.instance_remove_security_group(mox.IgnoreArg(), + self.stubs.Set(nova.db.api, 'instance_get', return_server) + self.mox.StubOutWithMock(nova.db.api, 'instance_remove_security_group') + nova.db.api.instance_remove_security_group(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) self.mox.ReplayAll() @@ -577,12 +577,12 @@ class TestSecurityGroups(test.TestCase): self.assertEquals(response.status_int, 202) def test_disassociate_xml(self): - self.stubs.Set(nova.db, 'instance_get', return_server) - self.mox.StubOutWithMock(nova.db, 'instance_remove_security_group') - nova.db.instance_remove_security_group(mox.IgnoreArg(), + self.stubs.Set(nova.db.api, 'instance_get', return_server) + self.mox.StubOutWithMock(nova.db.api, 'instance_remove_security_group') + nova.db.api.instance_remove_security_group(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) - self.stubs.Set(nova.db, 'security_group_get_by_name', + self.stubs.Set(nova.db.api, 'security_group_get_by_name', return_security_group) self.mox.ReplayAll() diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index 05267d8fb..31443242b 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -95,6 +95,7 @@ class ExtensionControllerTest(test.TestCase): "Quotas", "Rescue", "SecurityGroups", + "SimpleTenantUsage", "VSAs", "VirtualInterfaces", "Volumes", diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 3dfdeb79c..c9c33abbd 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -248,7 +248,7 @@ class ServerActionsTest(test.TestCase): def fake_migration_get(*args): return {} - self.stubs.Set(nova.db, 'migration_get_by_instance_and_status', + self.stubs.Set(nova.db.api, 'migration_get_by_instance_and_status', fake_migration_get) res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) -- cgit From e326acf46748904704dd97f511927559dc2480f2 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Tue, 30 Aug 2011 15:05:39 -0700 Subject: Fix for LP Bug #837534 --- .../api/openstack/contrib/test_createserverext.py | 46 +++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_createserverext.py b/nova/tests/api/openstack/contrib/test_createserverext.py index e5eed14fe..65c7c1682 100644 --- a/nova/tests/api/openstack/contrib/test_createserverext.py +++ b/nova/tests/api/openstack/contrib/test_createserverext.py @@ -37,7 +37,8 @@ import nova.image.fake import nova.rpc from nova.tests.api.openstack import fakes - +from nova import log as logging +LOG = logging.getLogger('nova.api.openstack.test') FLAGS = flags.FLAGS FLAGS.verbose = True @@ -76,6 +77,7 @@ class CreateserverextTest(test.TestCase): def __init__(self): self.injected_files = None self.networks = None + self.user_data = None def create(self, *args, **kwargs): if 'injected_files' in kwargs: @@ -87,6 +89,10 @@ class CreateserverextTest(test.TestCase): self.networks = kwargs['requested_networks'] else: self.networks = None + + if 'user_data' in kwargs: + self.user_data = kwargs['user_data'] + return [{'id': '1234', 'display_name': 'fakeinstance', 'uuid': FAKE_UUID, 'created_at': "", @@ -119,6 +125,14 @@ class CreateserverextTest(test.TestCase): server['networks'] = network_list return {'server': server} + def _create_user_data_request_dict(self, user_data): + server = {} + server['name'] = 'new-server-test' + server['imageRef'] = 1 + server['flavorRef'] = 1 + server['user_data'] = user_data + return {'server': server} + def _get_create_request_json(self, body_dict): req = webob.Request.blank('/v1.1/123/os-create-server-ext') req.headers['Content-Type'] = 'application/json' @@ -178,6 +192,13 @@ class CreateserverextTest(test.TestCase): self._run_create_instance_with_mock_compute_api(request) return request, response, compute_api.networks + def _create_instance_with_user_data_json(self, networks): + body_dict = self._create_user_data_request_dict(networks) + request = self._get_create_request_json(body_dict) + compute_api, response = \ + self._run_create_instance_with_mock_compute_api(request) + return request, response, compute_api.user_data + def _create_instance_with_networks_xml(self, networks): body_dict = self._create_networks_request_dict(networks) request = self._get_create_request_xml(body_dict) @@ -188,6 +209,7 @@ class CreateserverextTest(test.TestCase): def test_create_instance_with_no_networks(self): request, response, networks = \ self._create_instance_with_networks_json(networks=None) + LOG.debug(response) self.assertEquals(response.status_int, 202) self.assertEquals(networks, None) @@ -304,3 +326,25 @@ class CreateserverextTest(test.TestCase): self.assertEquals(response.status_int, 202) self.assertEquals(compute_api.networks, [('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', None)]) + + def test_create_instance_with_userdata(self): + user_data_contents = '#!/bin/bash\necho "Oh no!"\n' + user_data_contents = base64.b64encode(user_data_contents) + request, response, user_data = \ + self._create_instance_with_user_data_json(user_data_contents) + self.assertEquals(response.status_int, 202) + self.assertEquals(user_data, user_data_contents) + + def test_create_instance_with_userdata_none(self): + user_data_contents = None + request, response, user_data = \ + self._create_instance_with_user_data_json(user_data_contents) + self.assertEquals(response.status_int, 202) + self.assertEquals(user_data, user_data_contents) + + def test_create_instance_with_userdata_with_non_b64_content(self): + user_data_contents = '#!/bin/bash\necho "Oh no!"\n' + request, response, user_data = \ + self._create_instance_with_user_data_json(user_data_contents) + self.assertEquals(response.status_int, 400) + self.assertEquals(user_data, None) -- cgit From 476101d81cf81e6035b44e2257c1bcd8e958043a Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Tue, 30 Aug 2011 15:09:08 -0700 Subject: Removed debug messages --- nova/tests/api/openstack/contrib/test_createserverext.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_createserverext.py b/nova/tests/api/openstack/contrib/test_createserverext.py index 65c7c1682..d8a5c9e55 100644 --- a/nova/tests/api/openstack/contrib/test_createserverext.py +++ b/nova/tests/api/openstack/contrib/test_createserverext.py @@ -37,8 +37,7 @@ import nova.image.fake import nova.rpc from nova.tests.api.openstack import fakes -from nova import log as logging -LOG = logging.getLogger('nova.api.openstack.test') + FLAGS = flags.FLAGS FLAGS.verbose = True @@ -209,7 +208,6 @@ class CreateserverextTest(test.TestCase): def test_create_instance_with_no_networks(self): request, response, networks = \ self._create_instance_with_networks_json(networks=None) - LOG.debug(response) self.assertEquals(response.status_int, 202) self.assertEquals(networks, None) -- cgit From 66aa9a6306cde5db2039daaf11a8422619560a33 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 30 Aug 2011 20:45:51 -0700 Subject: fix FloatingIpAlreadyInUse to use correct string pattern, convert ApiErrors to 400 responses --- .../api/openstack/contrib/test_floating_ips.py | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py index c14c29bf3..08148278d 100644 --- a/nova/tests/api/openstack/contrib/test_floating_ips.py +++ b/nova/tests/api/openstack/contrib/test_floating_ips.py @@ -205,6 +205,38 @@ class FloatingIpTest(test.TestCase): resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 202) + def test_associate_floating_ip_to_instance_wrong_project_id(self): + def fake_fixed_ip_get_by_address(ctx, address, session=None): + return {'address': address, 'network': {'multi_host': None, + 'host': 'fake'}} + self.stubs.Set(db.api, "fixed_ip_get_by_address", + fake_fixed_ip_get_by_address) + db.floating_ip_update(self.context, self.address, {'project_id': 'bad', + 'fixed_ip_id': 1}) + body = dict(addFloatingIp=dict(address=self.address)) + req = webob.Request.blank('/v1.1/123/servers/test_inst/action') + req.method = "POST" + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 400) + + def test_associate_floating_ip_to_instance_no_project_id(self): + def fake_fixed_ip_get_by_address(ctx, address, session=None): + return {'address': address, 'network': {'multi_host': None, + 'host': 'fake'}} + self.stubs.Set(db.api, "fixed_ip_get_by_address", + fake_fixed_ip_get_by_address) + db.floating_ip_update(self.context, self.address, {'project_id': None, + 'fixed_ip_id': 1}) + body = dict(addFloatingIp=dict(address=self.address)) + req = webob.Request.blank('/v1.1/123/servers/test_inst/action') + req.method = "POST" + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 400) + def test_add_associated_floating_ip_to_instance(self): def fake_fixed_ip_get_by_address(ctx, address, session=None): return {'address': address, 'network': {'multi_host': None, -- cgit From 1477b8c33374db1166c6c67ff68e03c94f3436a5 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 30 Aug 2011 21:16:26 -0700 Subject: add test to verify 400 response when out of addresses --- nova/tests/api/openstack/contrib/test_floating_ips.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py index 08148278d..fc10f2f6c 100644 --- a/nova/tests/api/openstack/contrib/test_floating_ips.py +++ b/nova/tests/api/openstack/contrib/test_floating_ips.py @@ -20,8 +20,9 @@ import webob from nova import compute from nova import context from nova import db -from nova import test from nova import network +from nova import rpc +from nova import test from nova.tests.api.openstack import fakes from nova.tests.api.openstack import test_servers @@ -114,8 +115,6 @@ class FloatingIpTest(test.TestCase): 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, "disassociate_floating_ip", @@ -172,7 +171,20 @@ class FloatingIpTest(test.TestCase): self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10') self.assertEqual(res_dict['floating_ip']['instance_id'], None) + def test_floating_ip_allocate_no_free_ips(self): + def fake_call(*args, **kwargs): + raise(rpc.RemoteError('NoMoreFloatingIps', '', '')) + + self.stubs.Set(rpc, "call", fake_call) + req = webob.Request.blank('/v1.1/123/os-floating-ips') + req.method = 'POST' + req.headers['Content-Type'] = 'application/json' + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 400) + def test_floating_ip_allocate(self): + self.stubs.Set(network.api.API, "allocate_floating_ip", + network_api_allocate) req = webob.Request.blank('/v1.1/123/os-floating-ips') req.method = 'POST' req.headers['Content-Type'] = 'application/json' -- cgit From c9758dd4832c167562baefad5dcc88f2a1a19b73 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 31 Aug 2011 12:51:16 -0700 Subject: fix keypairs stubs --- nova/tests/api/openstack/fakes.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index a095dd90a..a4a90e6da 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -107,11 +107,18 @@ def stub_out_key_pair_funcs(stubs, have_key_pair=True): def key_pair(context, user_id): return [dict(name='key', public_key='public_key')] + def one_key_pair(context, user_id, name): + if name == 'key': + return dict(name='key', public_key='public_key') + else: + raise exc.KeypairNotFound(user_id=user_id, name=name) + def no_key_pair(context, user_id): return [] if have_key_pair: stubs.Set(nova.db, 'key_pair_get_all_by_user', key_pair) + stubs.Set(nova.db, 'key_pair_get', one_key_pair) else: stubs.Set(nova.db, 'key_pair_get_all_by_user', no_key_pair) -- cgit From a87a0bba9c7b046b36ee80bc033df5499cca35e1 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 31 Aug 2011 17:05:01 -0400 Subject: adding support for limiting in image service; updating tests with fixture ids and marker support --- nova/tests/image/test_glance.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index 0ff508ffa..5df25df37 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -38,7 +38,16 @@ class StubGlanceClient(object): return self.images[image_id] def get_images_detailed(self, filters=None, marker=None, limit=None): - return self.images.itervalues() + images = self.images.values() + if marker is None: + index = 0 + else: + for index, image in enumerate(images): + if image['id'] == marker: + index += 1 + break + # default to a page size of 3 to ensure we flex the pagination code + return images[index:index + 3] def get_image(self, image_id): return self.images[image_id], [] @@ -86,23 +95,23 @@ class TestGlanceImageServiceProperties(BaseGlanceTest): """Ensure attributes which aren't BASE_IMAGE_ATTRS are stored in the properties dict """ - fixtures = {'image1': {'name': 'image1', 'is_public': True, + fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True, 'foo': 'bar', 'properties': {'prop1': 'propvalue1'}}} self.client.images = fixtures image_meta = self.service.show(self.context, 'image1') - expected = {'name': 'image1', 'is_public': True, + expected = {'id': '1', 'name': 'image1', 'is_public': True, 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} self.assertEqual(image_meta, expected) def test_detail_passes_through_to_client(self): - fixtures = {'image1': {'name': 'image1', 'is_public': True, + fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True, 'foo': 'bar', 'properties': {'prop1': 'propvalue1'}}} self.client.images = fixtures image_meta = self.service.detail(self.context) - expected = [{'name': 'image1', 'is_public': True, + expected = [{'id': '1', 'name': 'image1', 'is_public': True, 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}}] self.assertEqual(image_meta, expected) @@ -166,6 +175,7 @@ class TestGetterDateTimeNoneTests(BaseGlanceTest): def _make_datetime_fixtures(self): fixtures = { 'image1': { + 'id': '1', 'name': 'image1', 'is_public': True, 'created_at': self.NOW_GLANCE_FORMAT, @@ -173,6 +183,7 @@ class TestGetterDateTimeNoneTests(BaseGlanceTest): 'deleted_at': self.NOW_GLANCE_FORMAT, }, 'image2': { + 'id': '2', 'name': 'image2', 'is_public': True, 'created_at': self.NOW_GLANCE_OLD_FORMAT, @@ -183,13 +194,17 @@ class TestGetterDateTimeNoneTests(BaseGlanceTest): return fixtures def _make_none_datetime_fixtures(self): - fixtures = {'image1': {'name': 'image1', 'is_public': True, + fixtures = {'image1': {'id': '1', + 'name': 'image1', + 'is_public': True, 'updated_at': None, 'deleted_at': None}} return fixtures def _make_blank_datetime_fixtures(self): - fixtures = {'image1': {'name': 'image1', 'is_public': True, + fixtures = {'image1': {'id': '1', + 'name': 'image1', + 'is_public': True, 'updated_at': '', 'deleted_at': ''}} return fixtures -- cgit From 642c9ceb1bae9fa5ba008cb69c47f449ea173c3a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 31 Aug 2011 15:24:29 -0700 Subject: expect key_name attribute in 1.1 --- nova/tests/api/openstack/test_servers.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index c54bead49..78c872a28 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3630,6 +3630,7 @@ class ServersViewBuilderV11Test(test.TestCase): "id": 1, "uuid": self.instance['uuid'], "name": "test_server", + "key_name": '', "links": [ { "rel": "self", @@ -3653,6 +3654,7 @@ class ServersViewBuilderV11Test(test.TestCase): "id": 1, "uuid": self.instance['uuid'], "name": "test_server", + "key_name": '', "config_drive": None, "links": [ { -- cgit From bd917feb287a3d0e8f2f9f9c60b716c7f599f4ff Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 31 Aug 2011 16:13:55 -0700 Subject: remove extra test --- nova/tests/api/openstack/test_server_actions.py | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 0c5fab41e..b9ef41465 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -244,19 +244,6 @@ class ServerActionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 500) - def test_resized_server_has_correct_status(self): - req = self.webreq('/1', 'GET') - - def fake_migration_get(*args): - return {} - - self.stubs.Set(nova.db.api, 'migration_get_by_instance_and_status', - fake_migration_get) - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - body = json.loads(res.body) - self.assertEqual(body['server']['status'], 'RESIZE-CONFIRM') - def test_confirm_resize_server(self): req = self.webreq('/1/action', 'POST', dict(confirmResize=None)) -- cgit From fdf076a04e001b897d01b2a8c4a9e3c980ea8f94 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 31 Aug 2011 21:34:10 -0700 Subject: fix for lp838583 - return instance_id for associated floating_ips, add test --- .../api/openstack/contrib/test_floating_ips.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py index fc10f2f6c..642f2b841 100644 --- a/nova/tests/api/openstack/contrib/test_floating_ips.py +++ b/nova/tests/api/openstack/contrib/test_floating_ips.py @@ -38,14 +38,13 @@ def network_api_get_floating_ip(self, context, id): def network_api_get_floating_ip_by_ip(self, context, address): return {'id': 1, 'address': '10.10.10.10', - 'fixed_ip': {'address': '11.0.0.1'}} + 'fixed_ip': {'address': '10.0.0.1', 'instance_id': 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'}}, + 'fixed_ip': {'address': '10.0.0.1', 'instance_id': 1}}, {'id': 2, 'address': '10.10.10.11'}] @@ -152,7 +151,7 @@ class FloatingIpTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) res_dict = json.loads(res.body) - response = {'floating_ips': [{'instance_id': 11, + response = {'floating_ips': [{'instance_id': 1, 'ip': '10.10.10.10', 'fixed_ip': '10.0.0.1', 'id': 1}, @@ -171,6 +170,20 @@ class FloatingIpTest(test.TestCase): self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10') self.assertEqual(res_dict['floating_ip']['instance_id'], None) + def test_show_associated_floating_ip(self): + def get_floating_ip(self, context, id): + return {'id': 1, 'address': '10.10.10.10', + 'fixed_ip': {'address': '10.0.0.1', 'instance_id': 1}} + self.stubs.Set(network.api.API, "get_floating_ip", get_floating_ip) + + req = webob.Request.blank('/v1.1/123/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']['instance_id'], 1) + def test_floating_ip_allocate_no_free_ips(self): def fake_call(*args, **kwargs): raise(rpc.RemoteError('NoMoreFloatingIps', '', '')) -- cgit From dd5eeafbfe1013fd9acdb119933cb5bf986706e6 Mon Sep 17 00:00:00 2001 From: Christopher MacGown Date: Thu, 1 Sep 2011 12:05:21 -0700 Subject: Adds test for image.glance.GlanceImageService._is_image_available --- nova/tests/image/test_glance.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index 0ff508ffa..81a54346e 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -20,6 +20,7 @@ import datetime import unittest from nova import context +from nova import exception from nova import test from nova.image import glance @@ -96,6 +97,31 @@ class TestGlanceImageServiceProperties(BaseGlanceTest): 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} self.assertEqual(image_meta, expected) + def test_show_raises_when_no_authtoken_in_the_context(self): + fixtures = {'image1': {'name': 'image1', 'is_public': False, + 'foo': 'bar', + 'properties': {'prop1': 'propvalue1'}}} + self.client.images = fixtures + self.context.auth_token = False + + expected = {'name': 'image1', 'is_public': True, + 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} + self.assertRaises(exception.ImageNotFound, + self.service.show, self.context, 'image1') + + def test_show_passes_through_to_client_with_authtoken_in_context(self): + fixtures = {'image1': {'name': 'image1', 'is_public': False, + 'foo': 'bar', + 'properties': {'prop1': 'propvalue1'}}} + self.client.images = fixtures + self.context.auth_token = True + + expected = {'name': 'image1', 'is_public': False, + 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} + + image_meta = self.service.show(self.context, 'image1') + self.assertEqual(image_meta, expected) + def test_detail_passes_through_to_client(self): fixtures = {'image1': {'name': 'image1', 'is_public': True, 'foo': 'bar', -- cgit From 59be9be68c0fd9b33b72257b8a1eb8c357ce9217 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 1 Sep 2011 12:22:32 -0700 Subject: remove extra references to state_description --- nova/tests/test_libvirt.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 6a213b4f0..8c6775b29 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -34,6 +34,7 @@ from nova import test from nova import utils from nova.api.ec2 import cloud from nova.compute import power_state +from nova.compute import vm_states from nova.virt.libvirt import connection from nova.virt.libvirt import firewall @@ -674,8 +675,9 @@ class LibvirtConnTestCase(test.TestCase): # Preparing data self.compute = utils.import_object(FLAGS.compute_manager) - instance_dict = {'host': 'fake', 'state': power_state.RUNNING, - 'state_description': 'running'} + instance_dict = {'host': 'fake', + 'power_state': power_state.RUNNING, + 'vm_state': vm_states.ACTIVE} instance_ref = db.instance_create(self.context, self.test_instance) instance_ref = db.instance_update(self.context, instance_ref['id'], instance_dict) @@ -713,8 +715,8 @@ class LibvirtConnTestCase(test.TestCase): self.compute.rollback_live_migration) instance_ref = db.instance_get(self.context, instance_ref['id']) - self.assertTrue(instance_ref['state_description'] == 'running') - self.assertTrue(instance_ref['state'] == power_state.RUNNING) + self.assertTrue(instance_ref['vm_state'] == vm_states.ACTIVE) + self.assertTrue(instance_ref['power_state'] == power_state.RUNNING) volume_ref = db.volume_get(self.context, volume_ref['id']) self.assertTrue(volume_ref['status'] == 'in-use') -- cgit