diff --git a/coriolis/tests/api/v1/test_diagnostics.py b/coriolis/tests/api/v1/test_diagnostics.py new file mode 100644 index 000000000..d2ddb9b21 --- /dev/null +++ b/coriolis/tests/api/v1/test_diagnostics.py @@ -0,0 +1,38 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import diagnostics as diag +from coriolis.api.v1.views import diagnostic_view +from coriolis.diagnostics import api +from coriolis.policies import diagnostics +from coriolis.tests import test_base + + +class DiagnosticsControllerTestCase(test_base.CoriolisBaseTestCase): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(DiagnosticsControllerTestCase, self).setUp() + self.diag_api = diag.DiagnosticsController() + + @mock.patch.object(api.API, 'get') + @mock.patch.object(diagnostic_view, 'collection') + @mock.patch.object(diagnostics, 'get_diagnostics_policy_label') + def test_index( + self, + mock_get_diagnostics_policy_label, + mock_collection, + mock_get + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + + result = self.diag_api.index(mock_req) + + mock_get_diagnostics_policy_label.assert_called_once_with("get") + mock_get.assert_called_once_with(mock_context) + mock_collection.assert_called_once_with(mock_get.return_value) + self.assertEqual(result, mock_collection.return_value) diff --git a/coriolis/tests/api/v1/test_endpoint_actions.py b/coriolis/tests/api/v1/test_endpoint_actions.py new file mode 100644 index 000000000..aebabd70e --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_actions.py @@ -0,0 +1,99 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_actions +from coriolis.endpoints import api +from coriolis import exception +from coriolis.tests import test_base + +from webob import exc + + +class EndpointActionsControllerTestCase(test_base.CoriolisBaseTestCase): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointActionsControllerTestCase, self).setUp() + self.endpoint_api = endpoint_actions.EndpointActionsController() + + @mock.patch.object(api.API, 'validate_connection') + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + def test_validate_connection( + self, + mock_validate_connection + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + body = mock.sentinel.body + is_valid = True + message = 'mock_message' + mock_validate_connection.return_value = (is_valid, message) + + expected_result = { + "validate-connection": + {"valid": is_valid, "message": message} + } + result = self.endpoint_api._validate_connection( + mock_req, + id, + body + ) + + mock_validate_connection.assert_called_once_with(mock_context, id) + self.assertEqual( + expected_result, + result + ) + + @mock.patch.object(api.API, 'validate_connection') + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + def test_validate_connection_except_not_found( + self, + mock_validate_connection + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + body = mock.sentinel.body + mock_validate_connection.side_effect = exception.NotFound + + self.assertRaises( + exc.HTTPNotFound, + self.endpoint_api._validate_connection, + mock_req, + id, + body + ) + mock_validate_connection.assert_called_once_with(mock_context, id) + + @mock.patch.object(api.API, 'validate_connection') + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + def test_validate_connection_except_invalid_parameter_value( + self, + mock_validate_connection + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + body = mock.sentinel.body + mock_validate_connection.side_effect = exception.InvalidParameterValue( + "mock_err" + ) + + self.assertRaises( + exc.HTTPNotFound, + self.endpoint_api._validate_connection, + mock_req, + id, + body + ) + mock_validate_connection.assert_called_once_with(mock_context, id) diff --git a/coriolis/tests/api/v1/test_endpoint_destination_minion_pool_options.py b/coriolis/tests/api/v1/test_endpoint_destination_minion_pool_options.py new file mode 100644 index 000000000..d9289e4bc --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_destination_minion_pool_options.py @@ -0,0 +1,105 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_destination_minion_pool_options \ + as endpoint +from coriolis.api.v1.views import endpoint_options_view +from coriolis.endpoint_options import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointDestinationMinionPoolOptionsControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super( + EndpointDestinationMinionPoolOptionsControllerTestCase, + self + ).setUp() + self.minion_api = \ + endpoint.EndpointDestinationMinionPoolOptionsController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, + 'destination_minion_pool_options_collection') + @mock.patch.object(api.API, + 'get_endpoint_destination_minion_pool_options') + def test_index( + self, + mock_get_endpoint_destination_minion_pool_options, + mock_destination_minion_pool_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + options = mock.sentinel.options + mock_req.GET = { + 'env': env, + 'options': options + } + mock_decode_base64_param.side_effect = [env, options] + + expected_calls = [ + mock.call.mock_get_diagnostics_policy_label(env, is_json=True), + mock.call.mock_get_diagnostics_policy_label(options, is_json=True)] + + result = self.minion_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.has_calls(expected_calls) + (mock_get_endpoint_destination_minion_pool_options. + assert_called_once_with)( + mock_context, endpoint_id, + env=env, + option_names=options) + (mock_destination_minion_pool_options_collection. + assert_called_once_with)( + mock_get_endpoint_destination_minion_pool_options.return_value) + self.assertEqual( + mock_destination_minion_pool_options_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, + 'destination_minion_pool_options_collection') + @mock.patch.object(api.API, + 'get_endpoint_destination_minion_pool_options') + def test_index_no_env_and_options( + self, + mock_get_endpoint_destination_minion_pool_options, + mock_destination_minion_pool_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.minion_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_not_called() + (mock_get_endpoint_destination_minion_pool_options. + assert_called_once_with)( + mock_context, endpoint_id, + env={}, + option_names={}) + (mock_destination_minion_pool_options_collection. + assert_called_once_with)( + mock_get_endpoint_destination_minion_pool_options.return_value) + self.assertEqual( + mock_destination_minion_pool_options_collection.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoint_destination_options.py b/coriolis/tests/api/v1/test_endpoint_destination_options.py new file mode 100644 index 000000000..f5fdf2634 --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_destination_options.py @@ -0,0 +1,96 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_destination_options as endpoint +from coriolis.api.v1.views import endpoint_options_view +from coriolis.endpoint_options import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointDestinationOptionsControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointDestinationOptionsControllerTestCase, self).setUp() + self.endpoint_api = endpoint.EndpointDestinationOptionsController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, + 'destination_options_collection') + @mock.patch.object(api.API, + 'get_endpoint_destination_options') + def test_index( + self, + mock_get_endpoint_destination_options, + mock_destination_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + options = mock.sentinel.options + mock_req.GET = { + 'env': env, + 'options': options + } + mock_decode_base64_param.side_effect = [env, options] + + expected_calls = [ + mock.call.mock_decode_base64_param(env, is_json=True), + mock.call.mock_decode_base64_param(options, is_json=True)] + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.has_calls(expected_calls) + mock_get_endpoint_destination_options.assert_called_once_with( + mock_context, endpoint_id, + env=env, + option_names=options) + mock_destination_options_collection.assert_called_once_with( + mock_get_endpoint_destination_options.return_value) + self.assertEqual( + mock_destination_options_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, + 'destination_options_collection') + @mock.patch.object(api.API, + 'get_endpoint_destination_options') + def test_index_no_env_and_options( + self, + mock_get_endpoint_destination_options, + mock_destination_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_not_called() + mock_get_endpoint_destination_options.assert_called_once_with( + mock_context, endpoint_id, + env={}, + option_names={}) + mock_destination_options_collection.assert_called_once_with( + mock_get_endpoint_destination_options.return_value) + self.assertEqual( + mock_destination_options_collection.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoint_instances.py b/coriolis/tests/api/v1/test_endpoint_instances.py new file mode 100644 index 000000000..43ece08b6 --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_instances.py @@ -0,0 +1,168 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api import common +from coriolis.api.v1 import endpoint_instances as endpoint +from coriolis.api.v1.views import endpoint_resources_view +from coriolis.endpoint_resources import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointInstanceControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointInstanceControllerTestCase, self).setUp() + self.endpoint_api = endpoint.EndpointInstanceController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(common, 'get_paging_params') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'instances_collection') + @mock.patch.object(api.API, 'get_endpoint_instances') + def test_index( + self, + mock_get_endpoint_instances, + mock_instances_collection, + mock_decode_base64_param, + mock_get_paging_params, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + instance_name_pattern = mock.sentinel.instance_name_pattern + mock_req.GET = { + 'env': env, + 'name': instance_name_pattern + } + marker = 'mock_marker' + limit = 'mock_limit' + mock_get_paging_params.return_value = (marker, limit) + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_get_paging_params.assert_called_once_with(mock_req) + mock_decode_base64_param.assert_called_once_with(env, is_json=True) + mock_get_endpoint_instances.assert_called_once_with( + mock_context, endpoint_id, + mock_decode_base64_param.return_value, + marker, limit, instance_name_pattern) + mock_instances_collection.assert_called_once_with( + mock_get_endpoint_instances.return_value) + self.assertEqual( + mock_instances_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(common, 'get_paging_params') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'instances_collection') + @mock.patch.object(api.API, 'get_endpoint_instances') + def test_index_no_env_and_options( + self, + mock_get_endpoint_instances, + mock_instances_collection, + mock_decode_base64_param, + mock_get_paging_params, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_get_paging_params.return_value = (None, None) + mock_req.GET = {} + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_get_paging_params.assert_called_once_with(mock_req) + mock_decode_base64_param.assert_not_called() + mock_get_endpoint_instances.assert_called_once_with( + mock_context, endpoint_id, + {}, None, None, None) + mock_instances_collection.assert_called_once_with( + mock_get_endpoint_instances.return_value) + self.assertEqual( + mock_instances_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'instance_single') + @mock.patch.object(api.API, 'get_endpoint_instance') + def test_show( + self, + mock_get_endpoint_instance, + mock_instance_single, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + id = mock.sentinel.id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + mock_req.GET = { + 'env': env, + } + mock_decode_base64_param.side_effect = [id, env] + + expected_calls = [ + mock.call.mock_decode_base64_param(id), + mock.call.mock_decode_base64_param(env, is_json=True)] + + result = self.endpoint_api.show(mock_req, endpoint_id, id) + + mock_decode_base64_param.has_calls(expected_calls) + mock_get_endpoint_instance.assert_called_once_with( + mock_context, endpoint_id, + env, + id) + mock_instance_single.assert_called_once_with( + mock_get_endpoint_instance.return_value) + self.assertEqual( + mock_instance_single.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'instance_single') + @mock.patch.object(api.API, 'get_endpoint_instance') + def test_show_no_env( + self, + mock_get_endpoint_instance, + mock_instance_single, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + id = mock.sentinel.id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.endpoint_api.show(mock_req, endpoint_id, id) + + mock_decode_base64_param.assert_called_once_with(id) + mock_get_endpoint_instance.assert_called_once_with( + mock_context, endpoint_id, {}, + mock_decode_base64_param.return_value) + mock_instance_single.assert_called_once_with( + mock_get_endpoint_instance.return_value) + self.assertEqual( + mock_instance_single.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoint_networks.py b/coriolis/tests/api/v1/test_endpoint_networks.py new file mode 100644 index 000000000..4cb04d952 --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_networks.py @@ -0,0 +1,82 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_networks as endpoint +from coriolis.api.v1.views import endpoint_resources_view +from coriolis.endpoint_resources import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointNetworkControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointNetworkControllerTestCase, self).setUp() + self.endpoint_api = endpoint.EndpointNetworkController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'networks_collection') + @mock.patch.object(api.API, 'get_endpoint_networks') + def test_index( + self, + mock_get_endpoint_networks, + mock_networks_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + mock_req.GET = { + 'env': env + } + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_called_once_with(env, is_json=True) + mock_get_endpoint_networks.assert_called_once_with( + mock_context, endpoint_id, + mock_decode_base64_param.return_value) + mock_networks_collection.assert_called_once_with( + mock_get_endpoint_networks.return_value) + self.assertEqual( + mock_networks_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'networks_collection') + @mock.patch.object(api.API, 'get_endpoint_networks') + def test_index_no_env( + self, + mock_get_endpoint_networks, + mock_networks_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_not_called() + mock_get_endpoint_networks.assert_called_once_with( + mock_context, endpoint_id, {}) + mock_networks_collection.assert_called_once_with( + mock_get_endpoint_networks.return_value) + self.assertEqual( + mock_networks_collection.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoint_source_minion_pool_options.py b/coriolis/tests/api/v1/test_endpoint_source_minion_pool_options.py new file mode 100644 index 000000000..a055544d8 --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_source_minion_pool_options.py @@ -0,0 +1,101 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_source_minion_pool_options \ + as endpoint +from coriolis.api.v1.views import endpoint_options_view +from coriolis.endpoint_options import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointSourceMinionPoolOptionsControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super( + EndpointSourceMinionPoolOptionsControllerTestCase, + self + ).setUp() + self.endpoint_api = \ + endpoint.EndpointSourceMinionPoolOptionsController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, + 'source_minion_pool_options_collection') + @mock.patch.object(api.API, 'get_endpoint_source_minion_pool_options') + def test_index( + self, + mock_get_endpoint_source_minion_pool_options, + mock_source_minion_pool_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + options = mock.sentinel.options + mock_req.GET = { + 'env': env, + 'options': options + } + mock_decode_base64_param.side_effect = [env, options] + + expected_calls = [ + mock.call.mock_decode_base64_param(env, is_json=True), + mock.call.mock_decode_base64_param(options, is_json=True)] + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.has_calls(expected_calls) + (mock_get_endpoint_source_minion_pool_options. + assert_called_once_with)( + mock_context, endpoint_id, + env=env, + option_names=options) + (mock_source_minion_pool_options_collection. + assert_called_once_with)( + mock_get_endpoint_source_minion_pool_options.return_value) + self.assertEqual( + mock_source_minion_pool_options_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, + 'source_minion_pool_options_collection') + @mock.patch.object(api.API, 'get_endpoint_source_minion_pool_options') + def test_index_no_env( + self, + mock_get_endpoint_source_minion_pool_options, + mock_source_minion_pool_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_not_called() + mock_get_endpoint_source_minion_pool_options.assert_called_once_with( + mock_context, endpoint_id, + env={}, + option_names={}) + mock_source_minion_pool_options_collection.assert_called_once_with( + mock_get_endpoint_source_minion_pool_options.return_value) + self.assertEqual( + mock_source_minion_pool_options_collection.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoint_source_options.py b/coriolis/tests/api/v1/test_endpoint_source_options.py new file mode 100644 index 000000000..b9b319dbd --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_source_options.py @@ -0,0 +1,94 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_source_options as endpoint +from coriolis.api.v1.views import endpoint_options_view +from coriolis.endpoint_options import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointSourceOptionsControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointSourceOptionsControllerTestCase, self).setUp() + self.endpoint_api = endpoint.EndpointSourceOptionsController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, 'source_options_collection') + @mock.patch.object(api.API, 'get_endpoint_source_options') + def test_index( + self, + mock_get_endpoint_source_options, + mock_source_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + options = mock.sentinel.options + mock_req.GET = { + 'env': env, + 'options': options + } + mock_decode_base64_param.side_effect = [env, options] + + expected_calls = [ + mock.call.mock_decode_base64_param( + env, is_json=True), + mock.call.mock_decode_base64_param( + options, is_json=True)] + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.has_calls(expected_calls) + mock_get_endpoint_source_options.assert_called_once_with( + mock_context, endpoint_id, + env=env, + option_names=options) + mock_source_options_collection.assert_called_once_with( + mock_get_endpoint_source_options.return_value) + self.assertEqual( + mock_source_options_collection.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_options_view, 'source_options_collection') + @mock.patch.object(api.API, 'get_endpoint_source_options') + def test_index_no_env( + self, + mock_get_endpoint_source_options, + mock_source_options_collection, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_not_called() + mock_get_endpoint_source_options.assert_called_once_with( + mock_context, endpoint_id, + env={}, + option_names={}) + mock_source_options_collection.assert_called_once_with( + mock_get_endpoint_source_options.return_value) + self.assertEqual( + mock_source_options_collection.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoint_storage.py b/coriolis/tests/api/v1/test_endpoint_storage.py new file mode 100644 index 000000000..ff408dfbc --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoint_storage.py @@ -0,0 +1,82 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoint_storage as endpoint +from coriolis.api.v1.views import endpoint_resources_view +from coriolis.endpoint_resources import api +from coriolis.tests import test_base +from coriolis import utils + + +class EndpointStorageControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointStorageControllerTestCase, self).setUp() + self.endpoint_api = endpoint.EndpointStorageController() + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'storage_collection') + @mock.patch.object(api.API, 'get_endpoint_storage') + def test_index( + self, + mock_storage_collection, + mock_get_endpoint_storage, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + env = mock.sentinel.env + mock_req.GET = { + 'env': env + } + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_called_once_with(env, is_json=True) + mock_storage_collection.assert_called_once_with( + mock_context, endpoint_id, + mock_decode_base64_param.return_value) + mock_get_endpoint_storage.assert_called_once_with( + mock_storage_collection.return_value) + self.assertEqual( + mock_get_endpoint_storage.return_value, + result + ) + + @mock.patch('coriolis.policies.endpoints.ENDPOINTS_POLICY_PREFIX', + 'mock_prefix') + @mock.patch.object(utils, 'decode_base64_param') + @mock.patch.object(endpoint_resources_view, 'storage_collection') + @mock.patch.object(api.API, 'get_endpoint_storage') + def test_index_no_env( + self, + mock_storage_collection, + mock_get_endpoint_storage, + mock_decode_base64_param, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + endpoint_id = mock.sentinel.endpoint_id + mock_req.environ = {'coriolis.context': mock_context} + mock_req.GET = {} + + result = self.endpoint_api.index(mock_req, endpoint_id) + + mock_decode_base64_param.assert_not_called() + mock_storage_collection.assert_called_once_with( + mock_context, endpoint_id, {}) + mock_get_endpoint_storage.assert_called_once_with( + mock_storage_collection.return_value) + self.assertEqual( + mock_get_endpoint_storage.return_value, + result + ) diff --git a/coriolis/tests/api/v1/test_endpoints.py b/coriolis/tests/api/v1/test_endpoints.py new file mode 100644 index 000000000..25ecb9a3e --- /dev/null +++ b/coriolis/tests/api/v1/test_endpoints.py @@ -0,0 +1,306 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import endpoints +from coriolis.api.v1.views import endpoint_view +from coriolis.endpoints import api +from coriolis import exception +from coriolis.policies import endpoints as endpoint_policies +from coriolis.tests import test_base +from coriolis.tests import testutils + +from webob import exc + + +class EndpointControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(EndpointControllerTestCase, self).setUp() + self.endpoint_api = endpoints.EndpointController() + + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + @mock.patch.object(endpoint_view, 'single') + @mock.patch.object(api.API, 'get_endpoint') + def test_show( + self, + mock_get_endpoint, + mock_single, + mock_get_endpoints_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + + result = self.endpoint_api.show(mock_req, id) + + mock_get_endpoints_policy_label.assert_called_once_with("show") + mock_get_endpoint.assert_called_once_with(mock_context, id) + mock_single.assert_called_once_with( + mock_get_endpoint.return_value + ) + self.assertEqual( + mock_single.return_value, + result + ) + + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + @mock.patch.object(api.API, 'get_endpoint') + def test_show_no_endpoint( + self, + mock_get_endpoint, + mock_get_endpoints_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_get_endpoint.return_value = None + + self.assertRaises( + exc.HTTPNotFound, + self.endpoint_api.show, + mock_req, + id + ) + mock_get_endpoints_policy_label.assert_called_once_with("show") + mock_get_endpoint.assert_called_once_with(mock_context, id) + + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + @mock.patch.object(endpoint_view, 'collection') + @mock.patch.object(api.API, 'get_endpoints') + def test_index( + self, + mock_get_endpoints, + mock_collection, + mock_get_endpoints_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + + result = self.endpoint_api.index(mock_req) + + mock_get_endpoints_policy_label.assert_called_once_with("list") + mock_get_endpoints.assert_called_once_with(mock_context) + mock_collection.assert_called_once_with( + mock_get_endpoints.return_value + ) + self.assertEqual( + mock_collection.return_value, + result + ) + + def test__validate_create_body(self): + mock_body = { + 'endpoint': + { + 'name': 'mock_name', + 'type': 'mock_type', + 'connection_info': 'mock_connection_info', + } + } + endpoint = testutils.get_wrapped_function( + self.endpoint_api._validate_create_body)( + self.endpoint_api, + body=mock_body, # type: ignore + ) + self.assertEqual( + ('mock_name', 'mock_type', None, 'mock_connection_info', []), + endpoint + ) + + def test__validate_create_body_all_keys(self): + mock_body = { + 'endpoint': + { + 'name': 'mock_name', + 'type': 'mock_type', + 'description': 'mock_description', + 'connection_info': 'mock_connection_info', + 'mapped_regions': ['mapped_region_1', 'mapped_region_1'], + } + } + endpoint = testutils.get_wrapped_function( + self.endpoint_api._validate_create_body)( + self.endpoint_api, + body=mock_body, # type: ignore + ) + self.assertEqual( + ('mock_name', 'mock_type', 'mock_description', + 'mock_connection_info', ['mapped_region_1', 'mapped_region_1']), + endpoint + ) + + def test__validate_create_body_no_endpoint(self): + mock_body = {} + self.assertRaises( + KeyError, + testutils.get_wrapped_function( + self.endpoint_api._validate_create_body), + self.endpoint_api, + body=mock_body, # type: ignore + ) + + @mock.patch.object(endpoint_view, 'single') + @mock.patch.object(api.API, 'create') + @mock.patch.object(endpoints.EndpointController, '_validate_create_body') + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + def test_create( + self, + mock_get_endpoints_policy_label, + mock__validate_create_body, + mock_create, + mock_single + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + body = mock.sentinel.body + mock__validate_create_body.return_value = ( + mock.sentinel.name, + mock.sentinel.endpoint_type, + mock.sentinel.description, + mock.sentinel.connection_info, + mock.sentinel.mapped_regions + ) + + result = self.endpoint_api.create(mock_req, body) + + mock_get_endpoints_policy_label.assert_called_once_with("create") + mock_create.assert_called_once_with( + mock_context, + mock.sentinel.name, + mock.sentinel.endpoint_type, + mock.sentinel.description, + mock.sentinel.connection_info, + mock.sentinel.mapped_regions + ) + self.assertEqual( + mock_single.return_value, + result + ) + + def test__validate_update_body(self): + mock_body = { + 'endpoint': + { + 'name': 'mock_name', + 'description': 'mock_description', + 'connection_info': 'mock_connection_info', + 'mapped_regions': ['mapped_region_1', 'mapped_region_1'], + } + } + endpoint = testutils.get_wrapped_function( + self.endpoint_api._validate_update_body)( + self.endpoint_api, + body=mock_body, # type: ignore + ) + self.assertEqual( + mock_body['endpoint'], + endpoint + ) + + def test__validate_update_body_no_keys(self): + mock_body = { + 'endpoint': {} + } + endpoint = testutils.get_wrapped_function( + self.endpoint_api._validate_update_body)( + self.endpoint_api, + body=mock_body, # type: ignore + ) + self.assertEqual( + {}, + endpoint + ) + + def test__validate_update_body_no_endpoint(self): + mock_body = {} + self.assertRaises( + KeyError, + testutils.get_wrapped_function( + self.endpoint_api._validate_update_body), + self.endpoint_api, + body=mock_body, # type: ignore + ) + + @mock.patch.object(endpoint_view, 'single') + @mock.patch.object(api.API, 'update') + @mock.patch.object(endpoints.EndpointController, '_validate_update_body') + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + def test_update( + self, + mock_get_endpoints_policy_label, + mock__validate_update_body, + mock_update, + mock_single + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + body = mock.sentinel.body + + result = self.endpoint_api.update(mock_req, id, body) + + mock_get_endpoints_policy_label.assert_called_once_with("update") + mock__validate_update_body.assert_called_once_with(body) + mock_update.assert_called_once_with( + mock_context, id, + mock__validate_update_body.return_value + ) + self.assertEqual( + mock_single.return_value, + result + ) + + @mock.patch.object(api.API, 'delete') + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + def test_delete( + self, + mock_get_endpoints_policy_label, + mock_delete + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + + self.assertRaises( + exc.HTTPNoContent, + self.endpoint_api.delete, + mock_req, + id + ) + + mock_get_endpoints_policy_label.assert_called_once_with("delete") + mock_delete.assert_called_once_with(mock_context, id) + + @mock.patch.object(api.API, 'delete') + @mock.patch.object(endpoint_policies, 'get_endpoints_policy_label') + def test_delete_not_found( + self, + mock_get_endpoints_policy_label, + mock_delete + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_delete.side_effect = exception.NotFound() + + self.assertRaises( + exc.HTTPNotFound, + self.endpoint_api.delete, + mock_req, + id + ) + + mock_get_endpoints_policy_label.assert_called_once_with("delete") + mock_delete.assert_called_once_with(mock_context, id) diff --git a/coriolis/tests/api/v1/test_migration_actions.py b/coriolis/tests/api/v1/test_migration_actions.py new file mode 100644 index 000000000..0d4aab058 --- /dev/null +++ b/coriolis/tests/api/v1/test_migration_actions.py @@ -0,0 +1,124 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +from coriolis.api.v1 import migration_actions +from coriolis import exception +from coriolis.migrations import api +from coriolis.policies import migrations as migration_policies +from coriolis.tests import test_base + +from webob import exc + + +class MigrationActionsControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(MigrationActionsControllerTestCase, self).setUp() + self.migration_actions = migration_actions.MigrationActionsController() + + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch.object(api.API, 'cancel') + def test__cancel( + self, + mock_cancel, + mock_get_migrations_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_body = { + 'cancel': { + 'force': False + } + } + + self.assertRaises( + exc.HTTPNoContent, + self.migration_actions._cancel, + mock_req, + id, + mock_body + ) + + mock_get_migrations_policy_label.assert_called_once_with("cancel") + mock_cancel.assert_called_once_with(mock_context, id, False) + + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch.object(api.API, 'cancel') + def test__cancel_empty( + self, + mock_cancel, + mock_get_migrations_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_body = {'cancel': {}} + + self.assertRaises( + exc.HTTPNoContent, + self.migration_actions._cancel, + mock_req, + id, + mock_body + ) + + mock_get_migrations_policy_label.assert_called_once_with("cancel") + mock_cancel.assert_called_once_with(mock_context, id, False) + + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch.object(api.API, 'cancel') + def test__cancel_not_found( + self, + mock_cancel, + mock_get_migrations_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_body = {'cancel': {}} + mock_cancel.side_effect = exception.NotFound() + + self.assertRaises( + exc.HTTPNotFound, + self.migration_actions._cancel, + mock_req, + id, + mock_body + ) + + mock_get_migrations_policy_label.assert_called_once_with("cancel") + mock_cancel.assert_called_once_with(mock_context, id, False) + + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch.object(api.API, 'cancel') + def test__cancel_invalid_parameter_value( + self, + mock_cancel, + mock_get_migrations_policy_label, + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_body = {'cancel': {}} + mock_cancel.side_effect = exception.InvalidParameterValue("err") + + self.assertRaises( + exc.HTTPNotFound, + self.migration_actions._cancel, + mock_req, + id, + mock_body + ) + + mock_get_migrations_policy_label.assert_called_once_with("cancel") + mock_cancel.assert_called_once_with(mock_context, id, False) diff --git a/coriolis/tests/api/v1/test_migrations.py b/coriolis/tests/api/v1/test_migrations.py new file mode 100644 index 000000000..78a55a4fc --- /dev/null +++ b/coriolis/tests/api/v1/test_migrations.py @@ -0,0 +1,360 @@ +# Copyright 2023 Cloudbase Solutions Srl +# All Rights Reserved. + +from unittest import mock + +import ddt + +from coriolis.api.v1 import migrations +from coriolis.api.v1 import utils as api_utils +from coriolis.api.v1.views import migration_view +from coriolis.endpoints import api as endpoints_api +from coriolis import exception +from coriolis.migrations import api +from coriolis.policies import migrations as migration_policies +from coriolis.tests import test_base +from coriolis.tests import testutils + +from webob import exc + + +@ddt.ddt +class MigrationControllerTestCase( + test_base.CoriolisBaseTestCase +): + "Test suite for the Coriolis api v1.""" + + def setUp(self): + super(MigrationControllerTestCase, self).setUp() + self.migrations = migrations.MigrationController() + + @mock.patch.object(migration_view, 'single') + @mock.patch.object(api.API, 'get_migration') + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch('coriolis.api.v1.migrations.CONF') + def test_show( + self, + mock_conf, + mock_get_migrations_policy_label, + mock_get_migration, + mock_single + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_conf.api.include_task_info_in_migrations_api = False + + result = self.migrations.show(mock_req, id) + + self.assertEqual( + mock_single.return_value, + result + ) + + mock_get_migrations_policy_label.assert_called_once_with("show") + mock_get_migration.assert_called_once_with( + mock_context, id, include_task_info=False + ) + mock_single.assert_called_once_with(mock_get_migration.return_value) + + @mock.patch.object(api.API, 'get_migration') + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch('coriolis.api.v1.migrations.CONF') + def test_show_no_migration( + self, + mock_conf, + mock_get_migrations_policy_label, + mock_get_migration + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_conf.api.include_task_info_in_migrations_api = False + mock_get_migration.return_value = None + + self.assertRaises( + exc.HTTPNotFound, + self.migrations.show, + mock_req, + id + ) + + mock_get_migrations_policy_label.assert_called_once_with("show") + mock_get_migration.assert_called_once_with( + mock_context, id, include_task_info=False + ) + + @mock.patch.object(migration_view, 'collection') + @mock.patch.object(api.API, 'get_migrations') + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + @mock.patch.object(api_utils, '_get_show_deleted') + @mock.patch('coriolis.api.v1.migrations.CONF') + def test__list( + self, + mock_conf, + mock__get_show_deleted, + mock_get_migrations_policy_label, + mock_get_migrations, + mock_collection + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + mock_conf.api.include_task_info_in_migrations_api = False + + result = self.migrations._list(mock_req) + + self.assertEqual( + mock_collection.return_value, + result + ) + + mock__get_show_deleted.assert_called_once_with( + mock_req.GET.get.return_value) + mock_get_migrations_policy_label.assert_called_once_with("list") + mock_get_migrations.assert_called_once_with( + mock_context, + include_tasks=False, + include_task_info=False + ) + + @ddt.data( + ( + { + 'raises_value_error': False, + 'migration': + { + 'origin_endpoint_id': 'mock_origin_endpoint_id', + 'destination_endpoint_id': + 'mock_destination_endpoint_id', + 'origin_minion_pool_id': 'mock_origin_minion_pool_id', + 'destination_minion_pool_id': + 'mock_destination_minion_pool_id', + 'instance_osmorphing_minion_pool_mappings': { + 'mock_instance_1', 'mock_instance_2'}, + 'instances': {'mock_instance_1', 'mock_instance_2'}, + 'notes': 'mock_notes', + 'skip_os_morphing': False, + 'shutdown_instances': False, + 'replication_count': '2', + 'source_environment': {}, + 'network_map': {}, + 'destination_environment': + {'network_map': {}, 'storage_mappings': {}}, + 'storage_mappings': {}, + } + } + ), + ( + { + 'raises_value_error': True, + 'migration': + { + 'origin_endpoint_id': 'mock_origin_endpoint_id', + 'destination_endpoint_id': + 'mock_destination_endpoint_id', + 'origin_minion_pool_id': 'mock_origin_minion_pool_id', + 'instance_osmorphing_minion_pool_mappings': { + 'mock_instance_1', 'mock_instance_2'}, + 'instances': {'mock_instance_1', 'mock_instance_3'}, + } + } + ), + ( + { + 'raises_value_error': True, + 'migration': + { + 'origin_endpoint_id': 'mock_origin_endpoint_id', + 'destination_endpoint_id': + 'mock_destination_endpoint_id', + 'origin_minion_pool_id': 'mock_origin_minion_pool_id', + 'instance_osmorphing_minion_pool_mappings': { + 'mock_instance_1', 'mock_instance_2'}, + 'instances': {}, + 'replication_count': '12', + } + } + ) + ) + @mock.patch.object(api_utils, 'validate_storage_mappings') + @mock.patch.object(endpoints_api.API, 'validate_target_environment') + @mock.patch.object(api_utils, 'validate_network_map') + @mock.patch.object(endpoints_api.API, 'validate_source_environment') + @mock.patch.object(api_utils, 'validate_instances_list_for_transfer') + def test__validate_migration_input( + self, + data, + mock_validate_instances_list_for_transfer, + mock_validate_source_environment, + mock_validate_network_map, + mock_validate_target_environment, + mock_validate_storage_mappings + ): + raises_value_error = data.pop('raises_value_error') + mock_context = mock.Mock() + mock_validate_instances_list_for_transfer.return_value = \ + data['migration']['instances'] + + if raises_value_error: + self.assertRaises( + ValueError, + testutils.get_wrapped_function( + self.migrations._validate_migration_input), + self.migrations, + context=mock_context, + body=data + ) + mock_validate_instances_list_for_transfer.assert_called_once() + else: + testutils.get_wrapped_function( + self.migrations._validate_migration_input)( + self.migrations, + context=mock_context, # type: ignore + body=data, # type: ignore + ) + mock_validate_source_environment.assert_called_once_with( + mock_context, + data['migration']['origin_endpoint_id'], + data['migration']['source_environment'] + ) + mock_validate_network_map.assert_called_once_with( + data['migration']['network_map'] + ) + mock_validate_target_environment.assert_called_once_with( + mock_context, + data['migration']['destination_endpoint_id'], + data['migration']['destination_environment'] + ) + mock_validate_storage_mappings.assert_called_once_with( + data['migration']['storage_mappings'] + ) + mock_validate_instances_list_for_transfer.assert_called_once_with( + data['migration']['instances'], + ) + + @ddt.data( + ( + { + "expected_api_method": 'deploy_replica_instances', + "validation_expected": False, + "migration": { + "user_scripts": {"mock_user_scripts": None}, + "instances": ["mock_instance1", "mock_instance2"], + "replica_id": "mock_replica_id", + "clone_disks": True, + "force": False, + "skip_os_morphing": False, + "instance_osmorphing_minion_pool_mappings": + {"mock_mapping": "mock_value"}, + } + } + ), + ( + { + "expected_api_method": 'migrate_instances', + "validation_expected": True, + "migration": { + "user_scripts": {"mock_user_scripts": None}, + "instances": ["mock_instance1", "mock_instance2"], + "replica_id": None, + "clone_disks": True, + "force": False, + "skip_os_morphing": False, + "instance_osmorphing_minion_pool_mappings": + {"mock_mapping": "mock_value"}, + } + } + ) + ) + @mock.patch.object(migration_view, 'single') + @mock.patch.object(migrations.MigrationController, + '_validate_migration_input') + @mock.patch.object(api_utils, 'normalize_user_scripts') + @mock.patch.object(api_utils, 'validate_user_scripts') + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + def test_create( + self, + data, + mock_get_migrations_policy_label, + mock_validate_user_scripts, + mock_normalize_user_scripts, + mock__validate_migration_input, + mock_single + ): + expected_api_method = data.pop('expected_api_method') + validation_expected = data.pop('validation_expected', False) + with mock.patch.object(api.API, + expected_api_method) as mock_api_method: + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + mock__validate_migration_input.return_value = \ + (mock.sentinel.value,) * 14 + + result = self.migrations.create(mock_req, data) + + self.assertEqual( + mock_single.return_value, + result + ) + + mock_get_migrations_policy_label.assert_called_once_with("create") + mock_validate_user_scripts.assert_called_once_with( + data['migration']['user_scripts']) + mock_normalize_user_scripts.assert_called_once_with( + data['migration']['user_scripts'], + data['migration']['instances'] + ) + if validation_expected: + mock__validate_migration_input.assert_called_once_with( + mock_context, data) + mock_api_method.assert_called_once() + mock_single.assert_called_once_with(mock_api_method.return_value) + + @mock.patch.object(api.API, 'delete') + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + def test_delete( + self, + mock_get_migrations_policy_label, + mock_delete + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + + self.assertRaises( + exc.HTTPNoContent, + self.migrations.delete, + mock_req, + id + ) + + mock_get_migrations_policy_label.assert_called_once_with("delete") + mock_delete.assert_called_once_with(mock_context, id) + + @mock.patch.object(api.API, 'delete') + @mock.patch.object(migration_policies, 'get_migrations_policy_label') + def test_delete_not_found( + self, + mock_get_migrations_policy_label, + mock_delete + ): + mock_req = mock.Mock() + mock_context = mock.Mock() + mock_req.environ = {'coriolis.context': mock_context} + id = mock.sentinel.id + mock_delete.side_effect = exception.NotFound() + + self.assertRaises( + exc.HTTPNotFound, + self.migrations.delete, + mock_req, + id + ) + + mock_get_migrations_policy_label.assert_called_once_with("delete") + mock_delete.assert_called_once_with(mock_context, id)