From ef8d4727e8b0b248362456398e2b42d57e026d80 Mon Sep 17 00:00:00 2001 From: Aldinson Esto Date: Tue, 2 Mar 2021 04:14:09 +0900 Subject: [PATCH] Enhancement of Fail Response Parameters - Added support for all necessary response parameters for Fail API - UT and FT assertion is also improved to be able to confirm these response params Implements: blueprint support-error-handling Spec: https://specs.openstack.org/openstack/tacker-specs/specs/wallaby/support-error-handling-based-on-ETSI-NFV.html Change-Id: I31b179a9f9703432c4e38eb29da9140311841e2f --- .../test_vnf_instance_with_user_data.py | 50 ++++++++++++++++ tacker/tests/unit/vnflcm/fakes.py | 60 ++++++++++++++++++- tacker/tests/unit/vnflcm/test_controller.py | 50 ++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) diff --git a/tacker/tests/functional/sol/vnflcm/test_vnf_instance_with_user_data.py b/tacker/tests/functional/sol/vnflcm/test_vnf_instance_with_user_data.py index 7b1e8604a..6cb19bac0 100644 --- a/tacker/tests/functional/sol/vnflcm/test_vnf_instance_with_user_data.py +++ b/tacker/tests/functional/sol/vnflcm/test_vnf_instance_with_user_data.py @@ -1300,6 +1300,7 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest): resp, _ = self._fail_op_occs(vnflcm_op_occ_id) self._wait_lcm_done('FAILED', vnf_instance_id=vnf_instance_id) self.assert_fail_vnf(resp, vnf_instance_id) + self._assert_fail_vnf_response(_) # occ-show resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id) @@ -1412,6 +1413,7 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest): resp, _ = self._fail_op_occs(vnflcm_op_occ_id) self._wait_lcm_done('FAILED', vnf_instance_id=vnf_instance_id) self.assert_fail_vnf(resp, vnf_instance_id) + self._assert_fail_vnf_response(_) # occ-show resp, op_occs_info = self._show_op_occs(vnflcm_op_occ_id) @@ -1613,3 +1615,51 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest): self.assertIsNotNone(_links.get('vnfInstance').get('href')) self.assertIsNotNone(_links.get('grant')) self.assertIsNotNone(_links.get('grant').get('href')) + + def _assert_fail_vnf_response(self, fail_response): + + # Only check parameters with cardinality = 1 + self.assertIsNotNone(fail_response.get('id')) + self.assertIsNotNone(fail_response.get('operationState')) + self.assertIsNotNone(fail_response.get('stateEnteredTime')) + self.assertIsNotNone(fail_response.get('startTime')) + self.assertIsNotNone(fail_response.get('vnfInstanceId')) + self.assertIsNotNone(fail_response.get('operation')) + self.assertIsNotNone(fail_response.get('isAutomaticInvocation')) + self.assertIsNotNone(fail_response.get('isCancelPending')) + + changed_ext_connectivity = fail_response.get( + 'changedExtConnectivity', None) + if changed_ext_connectivity is not None: + self.assertIsNotNone( + changed_ext_connectivity._get_changed_ext_connectivity('id')) + resource_handle = \ + changed_ext_connectivity._get_changed_ext_connectivity( + 'resourceHandle') + self.assertIsNotNone(resource_handle) + self.assertIsNotNone(resource_handle.get('resourceId')) + ext_link_ports = \ + changed_ext_connectivity._get_changed_ext_connectivity( + 'extLinkPorts', None) + if ext_link_ports is not None: + self.assertIsNotNone(ext_link_ports.get('id')) + ext_link_ports_resource_handle = ext_link_ports.get( + 'resourceHandle') + self.assertIsNotNone(ext_link_ports_resource_handle) + self.assertIsNotNone(ext_link_ports_resource_handle.get( + 'resourceId')) + self.assertIsNotNone(ext_link_ports.get('cpInstanceId')) + + _links = fail_response.get('_links') + self.assertIsNotNone(_links.get('self')) + self.assertIsNotNone(_links.get('self').get('href')) + self.assertIsNotNone(_links.get('vnfInstance')) + self.assertIsNotNone(_links.get('vnfInstance').get('href')) + if _links.get('retry') is not None: + self.assertIsNotNone(_links.get('retry').get('href')) + if _links.get('fail') is not None: + self.assertIsNotNone(_links.get('fail').get('href')) + if _links.get('rollback') is not None: + self.assertIsNotNone(_links.get('rollback').get('href')) + if _links.get('grant') is not None: + self.assertIsNotNone(_links.get('grant').get('href')) diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 21654bea9..b6c671163 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -908,6 +908,20 @@ def vnflcm_rollback_insta(error_point=7): def vnflcm_fail_insta(error_point=7): default_datetime = datetime.datetime( 2000, 1, 1, 1, 1, 1, tzinfo=iso8601.UTC) + ext_link_port_info = objects.ExtLinkPortInfo( + resource_handle=objects.ResourceHandle( + resource_id="109f5049-b51e-409a-9a99-d740ba5f3acb", + vim_level_resource_type="LINKPORT"), + cp_instance_id="f5c68d94-5736-4e38-ade5-c9462514f8b9", + id="1d868d02-ecd4-4402-8e6b-54e77ebdcc28") + changed_ext_connectivity_values = objects.ExtVirtualLinkInfo( + id=constants.UUID, + resource_handle=objects.ResourceHandle( + vim_connection_id=constants.UUID, + resource_id=constants.UUID, + vim_level_resource_type="OS::Neutron::Net"), + ext_link_ports=[ext_link_port_info] + ) return objects.VnfLcmOpOcc( state_entered_time=default_datetime, start_time=default_datetime, @@ -918,7 +932,51 @@ def vnflcm_fail_insta(error_point=7): operation_params='{}', error_point=error_point, id=constants.UUID, - created_at=default_datetime) + grant_id=constants.UUID, + created_at=default_datetime, + changed_ext_connectivity=[changed_ext_connectivity_values]) + + +def vnflcm_fail_check_added_params(error_point=7): + ext_link_port_info = objects.ExtLinkPortInfo( + resource_handle=objects.ResourceHandle( + resource_id="109f5049-b51e-409a-9a99-d740ba5f3acb", + vim_level_resource_type="LINKPORT"), + cp_instance_id="f5c68d94-5736-4e38-ade5-c9462514f8b9", + id="1d868d02-ecd4-4402-8e6b-54e77ebdcc28") + changed_ext_connectivity_values = objects.ExtVirtualLinkInfo( + id=constants.UUID, + resource_handle=objects.ResourceHandle( + vim_connection_id=constants.UUID, + resource_id=constants.UUID, + vim_level_resource_type="OS::Neutron::Net"), + ext_link_ports=[ext_link_port_info] + ) + changed_info_values = objects.VnfInfoModifications( + vnf_instance_name="fake_name", + vnf_instance_description="fake_vnf_instance_description", + vnfd_id="f26f181d-7891-4720-b022-b074ec1733ef", + vnf_provider="fake_vnf_provider", + vnf_product_name="fake_vnf_product_name", + vnf_software_version="fake_vnf_software_version", + vnfd_version="fake_vnfd_version") + return objects.VnfLcmOpOcc( + state_entered_time=datetime.datetime(2000, 1, 1, 1, 1, 1, + tzinfo=iso8601.UTC), + start_time=datetime.datetime(2000, 1, 1, 1, 1, 1, + tzinfo=iso8601.UTC), + vnf_instance_id=constants.UUID, + operation='INSTANTIATE', + operation_state='FAILED_TEMP', + is_automatic_invocation=False, + operation_params='{}', + error_point=error_point, + id=constants.UUID, + grant_id=constants.UUID, + created_at=datetime.datetime(2000, 1, 1, 1, 1, 1, + tzinfo=iso8601.UTC), + changed_ext_connectivity=[changed_ext_connectivity_values], + changed_info=changed_info_values) def vnflcm_rollback_active(): diff --git a/tacker/tests/unit/vnflcm/test_controller.py b/tacker/tests/unit/vnflcm/test_controller.py index a211f9035..33c41fcf1 100644 --- a/tacker/tests/unit/vnflcm/test_controller.py +++ b/tacker/tests/unit/vnflcm/test_controller.py @@ -14,6 +14,7 @@ # under the License. import codecs +import copy import ddt from http import client as http_client import json @@ -3504,3 +3505,52 @@ class TestController(base.TestCase): mock_op_occ_list.return_value = vnf_lcm_op_occ self.assertRaises( exceptions.ValidationError, self.controller.list_lcm_op_occs, req) + + @mock.patch.object(controller.VnfLcmController, + "_update_vnf_fail_status") + @mock.patch.object(objects.VnfInstance, "save") + @mock.patch.object(objects.VnfInstance, "get_by_id") + @mock.patch.object(objects.VnfLcmOpOcc, "save") + @mock.patch.object(objects.VnfLcmOpOcc, "get_by_id") + def test_fail_lcm_op_occs_changed_info_missing(self, mock_lcm_get_by_id, + mock_lcm_save, mock_vnf_get_by_id, + mock_vnf_save, mock_update): + req = fake_request.HTTPRequest.blank( + '/vnf_lcm_op_occs/%s/fail' % constants.UUID) + mock_lcm_get_by_id.return_value = \ + fakes.vnflcm_fail_insta() + + res_dict = self.controller.fail(req, constants.UUID) + ref_dict = copy.deepcopy(fakes.VNFLCMOPOCC_RESPONSE) + del ref_dict["changedInfo"] + self.assertEqual(ref_dict.keys(), res_dict.keys()) + mock_lcm_get_by_id.assert_called_once() + mock_vnf_get_by_id.assert_called_once() + + @mock.patch.object(controller.VnfLcmController, + "_update_vnf_fail_status") + @mock.patch.object(objects.VnfInstance, "save") + @mock.patch.object(objects.VnfInstance, "get_by_id") + @mock.patch.object(objects.VnfLcmOpOcc, "save") + @mock.patch.object(objects.VnfLcmOpOcc, "get_by_id") + def test_fail_lcm_op_occs_check_added_params(self, mock_lcm_get_by_id, + mock_lcm_save, mock_vnf_get_by_id, + mock_vnf_save, mock_update): + req = fake_request.HTTPRequest.blank( + '/vnf_lcm_op_occs/%s/fail' % constants.UUID) + mock_lcm_get_by_id.return_value = \ + fakes.vnflcm_fail_check_added_params() + + res_dict = self.controller.fail(req, constants.UUID) + ref_dict = fakes.VNFLCMOPOCC_RESPONSE + + self.assertEqual(ref_dict.keys(), res_dict.keys()) + self.assertEqual( + res_dict.get('changedInfo').keys(), + ref_dict.get('changedInfo').keys()) + self.assertEqual( + res_dict.get('_links').keys(), + ref_dict.get('_links').keys()) + + mock_lcm_get_by_id.assert_called_once() + mock_vnf_get_by_id.assert_called_once()