From 5ba1ff9180019bfc71d4a6f44f10c2b4a85284be Mon Sep 17 00:00:00 2001 From: Andrew Laski Date: Tue, 16 Aug 2016 16:31:06 -0400 Subject: [PATCH] Add BuildRequestList object The BuildRequestList object can be used to fetch a list of pre-scheduled instances which have not been written to an instance table yet. The get_by_filters method emulates the behavior of Instance.get_by_filters and returns a BuildRequestList object with the contained BuildRequest objects sorted and filtered on the Instance object contained within. Change-Id: If3638caba2c12d4c087a854bd8cbf4f79ef9652d Partially-implements: bp add-buildrequest-obj Partially-implements: bp cells-scheduling-interaction --- nova/objects/build_request.py | 182 ++++++++ .../tests/functional/db/test_build_request.py | 418 ++++++++++++++++++ nova/tests/unit/objects/test_build_request.py | 27 ++ nova/tests/unit/objects/test_objects.py | 1 + 4 files changed, 628 insertions(+) diff --git a/nova/objects/build_request.py b/nova/objects/build_request.py index 6477d0ea47..ee355f1939 100644 --- a/nova/objects/build_request.py +++ b/nova/objects/build_request.py @@ -10,6 +10,9 @@ # License for the specific language governing permissions and limitations # under the License. +import functools +import re + from oslo_config import cfg from oslo_log import log as logging from oslo_serialization import jsonutils @@ -191,3 +194,182 @@ class BuildRequest(base.NovaObject): @base.remotable def destroy(self): self._destroy_in_db(self._context, self.instance_uuid) + + +@base.NovaObjectRegistry.register +class BuildRequestList(base.ObjectListBase, base.NovaObject): + # Version 1.0: Initial version + VERSION = '1.0' + + fields = { + 'objects': fields.ListOfObjectsField('BuildRequest'), + } + + @staticmethod + @db.api_context_manager.reader + def _get_all_from_db(context): + query = context.session.query(api_models.BuildRequest) + + if not context.is_admin: + query = query.filter_by(project_id=context.project_id) + + db_reqs = query.all() + return db_reqs + + @base.remotable_classmethod + def get_all(cls, context): + db_build_reqs = cls._get_all_from_db(context) + return base.obj_make_list(context, cls(context), objects.BuildRequest, + db_build_reqs) + + @staticmethod + def _pass_exact_filters(instance, filters): + for filter_key, filter_val in filters.items(): + if filter_key in ('metadata', 'system_metadata'): + if isinstance(filter_val, list): + for item in filter_val: + for k, v in item.items(): + if (k not in instance.metadata or + v != instance.metadata[k]): + return False + else: + for k, v in filter_val.items(): + if (k not in instance.metadata or + v != instance.metadata[k]): + return False + elif isinstance(filter_val, (list, tuple, set, frozenset)): + if not filter_val: + # Special value to indicate that nothing will match. + return None + if instance.get(filter_key, None) not in filter_val: + return False + else: + if instance.get(filter_key, None) != filter_val: + return False + + return True + + @staticmethod + def _pass_regex_filters(instance, filters): + for filter_name, filter_val in filters.items(): + try: + instance_attr = getattr(instance, filter_name) + except AttributeError: + continue + + # Sometimes the REGEX filter value is not a string + if not isinstance(filter_val, six.string_types): + filter_val = str(filter_val) + filter_re = re.compile(filter_val) + if instance_attr and not filter_re.search(str(instance_attr)): + return False + + return True + + @staticmethod + def _sort_build_requests(build_req_list, sort_keys, sort_dirs): + # build_req_list is a [] of build_reqs + sort_keys.reverse() + sort_dirs.reverse() + + def sort_attr(sort_key, build_req): + if sort_key == 'id': + # 'id' is not set on the instance yet. Use the BuildRequest + # 'id' instead. + return build_req.id + return getattr(build_req.instance, sort_key) + + for sort_key, sort_dir in zip(sort_keys, sort_dirs): + reverse = False if sort_dir.lower().startswith('asc') else True + build_req_list.sort(key=functools.partial(sort_attr, sort_key), + reverse=reverse) + return build_req_list + + @base.remotable_classmethod + def get_by_filters(cls, context, filters, limit=None, marker=None, + sort_keys=None, sort_dirs=None): + if limit == 0: + return cls(context, objects=[]) + # 'deleted' records can not be returned from here since build_requests + # are not soft deleted. + if filters.get('deleted', False): + return cls(context, objects=[]) + # 'cleaned' records won't exist as they would need to be deleted. + if filters.get('cleaned', False): + return cls(context, objects=[]) + + # Because the build_requests table stores an instance as a serialized + # versioned object it is not feasible to do the filtering and sorting + # in the database. Just get all potentially relevant records and + # process them here. It should be noted that build requests are short + # lived so there should not be a lot of results to deal with. + build_requests = cls.get_all(context) + + # Fortunately some filters do not apply here. + # 'tags' can not be applied at boot time so will not be set for an + # instance here. + # 'changes-since' works off of the updated_at field which has not yet + # been set at the point in the boot process where build_request still + # exists. So it can be ignored. + # 'deleted' and 'cleaned' are handled above. + + sort_keys, sort_dirs = db.process_sort_params(sort_keys, sort_dirs, + default_dir='desc') + + # For other filters that don't match this, we will do regexp matching + # Taken from db/sqlalchemy/api.py + exact_match_filter_names = ['project_id', 'user_id', 'image_ref', + 'vm_state', 'instance_type_id', 'uuid', + 'metadata', 'host', 'task_state', + 'system_metadata'] + exact_filters = {} + regex_filters = {} + for key, value in filters.items(): + if key in exact_match_filter_names: + exact_filters[key] = value + else: + regex_filters[key] = value + + # As much as possible this copies the logic from db/sqlalchemy/api.py + # instance_get_all_by_filters_sort. The main difference is that method + # builds a sql query and this filters in python. + filtered_build_reqs = [] + + for build_req in build_requests: + instance = build_req.instance + + filter_result = cls._pass_exact_filters(instance, exact_filters) + if filter_result is None: + # The filter condition is such that nothing will match. + # Bail early. + return cls(context, objects=[]) + if filter_result is False: + continue + + if not cls._pass_regex_filters(instance, regex_filters): + continue + + filtered_build_reqs.append(build_req) + + if (len(filtered_build_reqs) < 2) or (not sort_keys): + # No need to sort + return cls(context, objects=filtered_build_reqs) + + sorted_build_reqs = cls._sort_build_requests(filtered_build_reqs, + sort_keys, sort_dirs) + + marker_index = 0 + if marker: + for i, build_req in enumerate(sorted_build_reqs): + if build_req.instance.uuid == marker: + marker_index = i + break + len_build_reqs = len(sorted_build_reqs) + limit_index = len_build_reqs + if limit: + limit_index = marker_index + limit + if limit_index > len_build_reqs: + limit_index = len_build_reqs + + return cls(context, + objects=sorted_build_reqs[marker_index:limit_index]) diff --git a/nova/tests/functional/db/test_build_request.py b/nova/tests/functional/db/test_build_request.py index 3cddb072ea..5c00f0df2f 100644 --- a/nova/tests/functional/db/test_build_request.py +++ b/nova/tests/functional/db/test_build_request.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_serialization import jsonutils from oslo_utils import uuidutils from nova import context @@ -19,6 +20,7 @@ from nova.objects import build_request from nova import test from nova.tests import fixtures from nova.tests.unit import fake_build_request +from nova.tests.unit import fake_instance class BuildRequestTestCase(test.NoDBTestCase): @@ -82,3 +84,419 @@ class BuildRequestTestCase(test.NoDBTestCase): self.instance_uuid) db_req.destroy() self.assertRaises(exception.BuildRequestNotFound, db_req.destroy) + + +class BuildRequestListTestCase(test.NoDBTestCase): + USES_DB_SELF = True + + def setUp(self): + super(BuildRequestListTestCase, self).setUp() + # NOTE: This means that we're using a database for this test suite + # despite inheriting from NoDBTestCase + self.useFixture(fixtures.Database(database='api')) + self.project_id = 'fake-project' + self.context = context.RequestContext('fake-user', self.project_id) + + def _create_req(self, project_id=None, instance=None): + kwargs = {} + if instance: + kwargs['instance'] = jsonutils.dumps(instance.obj_to_primitive()) + args = fake_build_request.fake_db_req(**kwargs) + args.pop('id', None) + args['instance_uuid'] = uuidutils.generate_uuid() + args['project_id'] = self.project_id if not project_id else project_id + return build_request.BuildRequest._from_db_object(self.context, + build_request.BuildRequest(), + build_request.BuildRequest._create_in_db(self.context, args)) + + def test_get_all_empty(self): + req_objs = build_request.BuildRequestList.get_all(self.context) + self.assertEqual([], req_objs.objects) + + def test_get_all(self): + reqs = [self._create_req(), self._create_req()] + + req_list = build_request.BuildRequestList.get_all(self.context) + + self.assertEqual(2, len(req_list)) + for i in range(len(req_list)): + self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(reqs[i].instance, + req_list[i].instance) + + def test_get_all_filter_by_project_id(self): + reqs = [self._create_req(), self._create_req(project_id='filter')] + + req_list = build_request.BuildRequestList.get_all(self.context) + + self.assertEqual(1, len(req_list)) + self.assertEqual(reqs[0].project_id, req_list[0].project_id) + self.assertEqual(reqs[0].instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(reqs[0].instance, + req_list[0].instance) + + def test_get_all_bypass_project_id_filter_as_admin(self): + reqs = [self._create_req(), self._create_req(project_id='filter')] + + req_list = build_request.BuildRequestList.get_all( + self.context.elevated()) + + self.assertEqual(2, len(req_list)) + for i in range(len(req_list)): + self.assertEqual(reqs[i].project_id, req_list[i].project_id) + self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(reqs[i].instance, + req_list[i].instance) + + def test_get_by_filters(self): + reqs = [self._create_req(), self._create_req()] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, sort_keys=['id'], sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + for i in range(len(req_list)): + self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(reqs[i].instance, + req_list[i].instance) + + def test_get_by_filters_limit_0(self): + self._create_req() + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, limit=0) + + self.assertEqual([], req_list.objects) + + def test_get_by_filters_deleted(self): + self._create_req() + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'deleted': True}) + + self.assertEqual([], req_list.objects) + + def test_get_by_filters_cleaned(self): + self._create_req() + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'cleaned': True}) + + self.assertEqual([], req_list.objects) + + def test_get_by_filters_exact_match(self): + instance_find = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, image_ref='findme') + instance_filter = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, image_ref='filterme') + + reqs = [self._create_req(instance=instance_filter), + self._create_req(instance=instance_find)] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'image_ref': 'findme'}) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(1, len(req_list)) + self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(reqs[1].instance, + req_list[0].instance) + + def test_get_by_filters_exact_match_list(self): + instance_find = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, image_ref='findme') + instance_filter = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, image_ref='filterme') + + reqs = [self._create_req(instance=instance_filter), + self._create_req(instance=instance_find)] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'image_ref': ['findme', 'fake']}) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(1, len(req_list)) + self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(reqs[1].instance, + req_list[0].instance) + + def test_get_by_filters_exact_match_metadata(self): + instance_find = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, metadata={'foo': 'bar'}, expected_attrs='metadata') + instance_filter = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, metadata={'bar': 'baz'}, expected_attrs='metadata') + + reqs = [self._create_req(instance=instance_filter), + self._create_req(instance=instance_find)] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'metadata': {'foo': 'bar'}}) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(1, len(req_list)) + self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(reqs[1].instance, + req_list[0].instance) + + def test_get_by_filters_exact_match_metadata_list(self): + instance_find = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, metadata={'foo': 'bar', 'cat': 'meow'}, + expected_attrs='metadata') + instance_filter = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, metadata={'bar': 'baz', 'cat': 'meow'}, + expected_attrs='metadata') + + reqs = [self._create_req(instance=instance_filter), + self._create_req(instance=instance_find)] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'metadata': [{'foo': 'bar'}, {'cat': 'meow'}]}) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(1, len(req_list)) + self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(reqs[1].instance, + req_list[0].instance) + + def test_get_by_filters_regex_match_one(self): + instance_find = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, display_name='find this one') + instance_filter = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, display_name='filter this one') + + reqs = [self._create_req(instance=instance_filter), + self._create_req(instance=instance_find)] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'display_name': 'find'}) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(1, len(req_list)) + self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(reqs[1].instance, + req_list[0].instance) + + def test_get_by_filters_regex_match_both(self): + instance_find = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, display_name='find this one') + instance_filter = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, display_name='filter this one') + + reqs = [self._create_req(instance=instance_filter), + self._create_req(instance=instance_find)] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'display_name': 'this'}, sort_keys=['id'], + sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + for i in range(len(req_list)): + self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(reqs[i].instance, + req_list[i].instance) + + def test_get_by_filters_sort_asc(self): + instance_1024 = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=1024) + instance_512 = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=512) + + req_second = self._create_req(instance=instance_1024) + req_first = self._create_req(instance=instance_512) + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, sort_keys=['root_gb'], sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(req_first.instance, req_list[0].instance) + + self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid) + objects.base.obj_equal_prims(req_second.instance, req_list[1].instance) + + def test_get_by_filters_sort_desc(self): + instance_1024 = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=1024) + instance_512 = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=512) + + req_second = self._create_req(instance=instance_512) + req_first = self._create_req(instance=instance_1024) + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, sort_keys=['root_gb'], sort_dirs=['desc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(req_first.instance, req_list[0].instance) + + self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid) + objects.base.obj_equal_prims(req_second.instance, req_list[1].instance) + + def test_get_by_filters_sort_build_req_id(self): + # Create instance objects this way so that there is no 'id' set. + # The 'id' will not be populated on a BuildRequest.instance so this + # checks that sorting by 'id' uses the BuildRequest.id. + instance_1 = objects.Instance(self.context, host=None, + uuid=uuidutils.generate_uuid()) + instance_2 = objects.Instance(self.context, host=None, + uuid=uuidutils.generate_uuid()) + + req_first = self._create_req(instance=instance_2) + req_second = self._create_req(instance=instance_1) + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, sort_keys=['id'], sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(req_first.instance, req_list[0].instance) + + self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid) + objects.base.obj_equal_prims(req_second.instance, req_list[1].instance) + + def test_get_by_filters_multiple_sort_keys(self): + instance_first = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=512, image_ref='ccc') + instance_second = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=512, image_ref='bbb') + instance_third = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, root_gb=1024, image_ref='aaa') + + req_first = self._create_req(instance=instance_first) + req_third = self._create_req(instance=instance_third) + req_second = self._create_req(instance=instance_second) + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, sort_keys=['root_gb', 'image_ref'], + sort_dirs=['asc', 'desc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(3, len(req_list)) + self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid) + objects.base.obj_equal_prims(req_first.instance, req_list[0].instance) + + self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid) + objects.base.obj_equal_prims(req_second.instance, req_list[1].instance) + + self.assertEqual(req_third.instance_uuid, req_list[2].instance_uuid) + objects.base.obj_equal_prims(req_third.instance, req_list[2].instance) + + def test_get_by_filters_marker(self): + instance = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None) + + reqs = [self._create_req(), + self._create_req(instance=instance), + self._create_req()] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, marker=instance.uuid, sort_keys=['id'], + sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + for i, req in enumerate(reqs[1:]): + self.assertEqual(req.instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(req.instance, + req_list[i].instance) + + def test_get_by_filters_limit(self): + reqs = [self._create_req(), + self._create_req(), + self._create_req()] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, limit=2, sort_keys=['id'], + sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + for i, req in enumerate(reqs[:2]): + self.assertEqual(req.instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(req.instance, + req_list[i].instance) + + def test_get_by_filters_marker_limit(self): + instance = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None) + + reqs = [self._create_req(), + self._create_req(instance=instance), + self._create_req(), + self._create_req()] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, marker=instance.uuid, limit=2, + sort_keys=['id'], sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(2, len(req_list)) + for i, req in enumerate(reqs[1:3]): + self.assertEqual(req.instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(req.instance, + req_list[i].instance) + + def test_get_by_filters_marker_overlimit(self): + instance = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None) + + reqs = [self._create_req(), + self._create_req(instance=instance), + self._create_req(), + self._create_req()] + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {}, marker=instance.uuid, limit=4, + sort_keys=['id'], sort_dirs=['asc']) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(3, len(req_list)) + for i, req in enumerate(reqs[1:]): + self.assertEqual(req.instance_uuid, req_list[i].instance_uuid) + objects.base.obj_equal_prims(req.instance, + req_list[i].instance) + + def test_get_by_filters_bails_on_empty_list_check(self): + instance1 = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, image_ref='') + instance2 = fake_instance.fake_instance_obj( + self.context, objects.Instance, uuid=uuidutils.generate_uuid(), + host=None, image_ref='') + + self._create_req(instance=instance1) + self._create_req(instance=instance2) + + req_list = build_request.BuildRequestList.get_by_filters( + self.context, {'image_ref': []}) + + self.assertIsInstance(req_list, objects.BuildRequestList) + self.assertEqual(0, len(req_list)) diff --git a/nova/tests/unit/objects/test_build_request.py b/nova/tests/unit/objects/test_build_request.py index f1ac659283..687b1cef96 100644 --- a/nova/tests/unit/objects/test_build_request.py +++ b/nova/tests/unit/objects/test_build_request.py @@ -125,3 +125,30 @@ class TestBuildRequestObject(test_objects._LocalTest, class TestRemoteBuildRequestObject(test_objects._RemoteTest, _TestBuildRequestObject): pass + + +class _TestBuildRequestListObject(object): + @mock.patch.object(build_request.BuildRequestList, '_get_all_from_db') + def test_get_all(self, get_all): + fake_reqs = [fake_build_request.fake_db_req() for x in range(2)] + get_all.return_value = fake_reqs + + req_objs = build_request.BuildRequestList.get_all(self.context) + + self.assertEqual(2, len(req_objs)) + for i in range(2): + self.assertEqual(fake_reqs[i]['instance_uuid'], + req_objs[i].instance_uuid) + self.assertEqual(fake_reqs[i]['project_id'], + req_objs[i].project_id) + self.assertIsInstance(req_objs[i].instance, objects.Instance) + + +class TestBuildRequestListObject(test_objects._LocalTest, + _TestBuildRequestListObject): + pass + + +class TestRemoteBuildRequestListObject(test_objects._RemoteTest, + _TestBuildRequestListObject): + pass diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index c90a7e55a4..13078008bd 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1106,6 +1106,7 @@ object_data = { 'BlockDeviceMapping': '1.17-5e094927f1251770dcada6ab05adfcdb', 'BlockDeviceMappingList': '1.17-1e568eecb91d06d4112db9fd656de235', 'BuildRequest': '1.1-5a5ce31c2f4dcd67088342a9164d13b4', + 'BuildRequestList': '1.0-cd95608eccb89fbc702c8b52f38ec738', 'CellMapping': '1.0-7f1a7e85a22bbb7559fc730ab658b9bd', 'CellMappingList': '1.0-4ee0d9efdfd681fed822da88376e04d2', 'ComputeNode': '1.16-2436e5b836fa0306a3c4e6d9e5ddacec',