barbican/barbican/tests/tasks/test_resources.py

356 lines
14 KiB
Python

# Copyright (c) 2015 Rackspace, Inc.
#
# 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 unittest import mock
from oslo_utils import timeutils
from barbican import i18n as u
from barbican.model import models
from barbican.tasks import common
from barbican.tasks import resources
from barbican.tests import utils
class BaseOrderTestCase(utils.BaseTestCase, utils.MockModelRepositoryMixin):
def setUp(self):
super(BaseOrderTestCase, self).setUp()
self.requestor = 'requestor1234'
self.order = models.Order()
self.order.id = "id1"
self.order.requestor = self.requestor
self.order.type = "key"
self.meta = {'name': 'name',
'payload_content_type':
'application/octet-stream',
'algorithm': 'AES',
'bit_length': 256,
'expiration': timeutils.utcnow(),
'mode': 'CBC'}
self.order.meta = self.meta
self.external_project_id = 'keystone1234'
self.project_id = 'projectid1234'
self.project = models.Project()
self.project.id = self.project_id
self.project.external_id = self.external_project_id
self.project_repo = mock.MagicMock()
self.project_repo.get.return_value = self.project
self.setup_project_repository_mock(self.project_repo)
self.order.status = models.States.PENDING
self.order.id = 'orderid1234'
self.order.project_id = self.project_id
self.order_repo = mock.MagicMock()
self.order_repo.get.return_value = self.order
self.setup_order_repository_mock(self.order_repo)
self.setup_order_plugin_meta_repository_mock()
self.setup_order_barbican_meta_repository_mock()
self.secret = models.Secret()
self.secret_repo = mock.MagicMock()
self.secret_repo.create_from.return_value = None
self.setup_secret_repository_mock(self.secret_repo)
self.datum_repo = mock.MagicMock()
self.datum_repo.create_from.return_value = None
self.setup_encrypted_datum_repository_mock(self.datum_repo)
self.setup_kek_datum_repository_mock()
self.setup_secret_meta_repository_mock()
self.container_repo = mock.MagicMock()
self.container_repo.create_from.return_value = None
self.setup_container_repository_mock(self.container_repo)
self.container_secret_repo = mock.MagicMock()
self.container_secret_repo.create_from.return_value = None
self.setup_container_secret_repository_mock(self.container_secret_repo)
self.container = models.Container()
class WhenUsingOrderTaskHelper(BaseOrderTestCase):
def setUp(self):
super(WhenUsingOrderTaskHelper, self).setUp()
self.result = common.FollowOnProcessingStatusDTO()
self.helper = resources._OrderTaskHelper()
def test_should_retrieve_entity(self):
order_model = self.helper.retrieve_entity(
self.order.id, self.external_project_id)
self.assertEqual(self.order.id, order_model.id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
def test_should_handle_error(self):
self.helper.handle_error(self.order, 'status_code', 'reason',
ValueError())
self.assertEqual(models.States.ERROR, self.order.status)
self.assertEqual('status_code', self.order.error_status_code)
self.assertEqual('reason', self.order.error_reason)
self.order_repo.save.assert_called_once_with(self.order)
def test_should_handle_success_no_result(self):
self.helper.handle_success(self.order, None)
self.assertEqual(models.States.ACTIVE, self.order.status)
self.assertIsNone(self.order.sub_status)
self.assertIsNone(self.order.sub_status_message)
self.order_repo.save.assert_called_once_with(self.order)
def test_should_handle_success_result_no_follow_on_needed(self):
self.helper.handle_success(self.order, self.result)
self.assertEqual(models.States.ACTIVE, self.order.status)
self.assertEqual('Unknown', self.order.sub_status)
self.assertEqual('Unknown', self.order.sub_status_message)
self.order_repo.save.assert_called_once_with(self.order)
def test_should_handle_success_result_follow_on_needed(self):
self.result.retry_task = common.RetryTasks.INVOKE_SAME_TASK
self.result.status = 'status'
self.result.status_message = 'status_message'
self.helper.handle_success(self.order, self.result)
self.assertEqual(models.States.PENDING, self.order.status)
self.assertEqual('status', self.order.sub_status)
self.assertEqual('status_message', self.order.sub_status_message)
self.order_repo.save.assert_called_once_with(self.order)
def test_should_handle_success_result_large_statuses_clipped(self):
sub_status = 'z' * (models.SUB_STATUS_LENGTH + 1)
sub_status_message = 'z' * (models.SUB_STATUS_MESSAGE_LENGTH + 1)
self.result.status = sub_status
self.result.status_message = sub_status_message
self.helper.handle_success(self.order, self.result)
self.assertEqual(sub_status[:-1], self.order.sub_status)
self.assertEqual(
sub_status_message[:-1], self.order.sub_status_message)
self.order_repo.save.assert_called_once_with(self.order)
class WhenBeginningKeyTypeOrder(BaseOrderTestCase):
def setUp(self):
super(WhenBeginningKeyTypeOrder, self).setUp()
self.resource = resources.BeginTypeOrder()
@mock.patch('barbican.plugin.resources.generate_secret')
def test_should_process_key_order(self, mock_generate_secret):
mock_generate_secret.return_value = self.secret
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
self.assertEqual(self.order.status, models.States.ACTIVE)
secret_info = self.order.to_dict_fields()['meta']
mock_generate_secret.assert_called_once_with(
secret_info,
secret_info.get('payload_content_type',
'application/octet-stream'),
self.project
)
def test_should_fail_during_retrieval(self):
# Force an error during the order retrieval phase.
self.order_repo.get = mock.MagicMock(return_value=None,
side_effect=ValueError())
self.assertRaises(
ValueError,
self.resource.process,
self.order.id,
self.external_project_id,
)
# Order state doesn't change because can't retrieve it to change it.
self.assertEqual(models.States.PENDING, self.order.status)
def test_should_fail_during_processing(self):
# Force an error during the processing handler phase.
self.project_repo.get = mock.MagicMock(return_value=None,
side_effect=ValueError())
self.assertRaises(
ValueError,
self.resource.process,
self.order.id,
self.external_project_id,
)
self.assertEqual(models.States.ERROR, self.order.status)
self.assertEqual(500, self.order.error_status_code)
self.assertEqual(u._('Process TypeOrder failure seen - please contact '
'site administrator.'), self.order.error_reason)
@mock.patch('barbican.plugin.resources.generate_secret')
def test_should_fail_during_success_report_fail(self,
mock_generate_secret):
mock_generate_secret.return_value = self.secret
# Force an error during the processing handler phase.
self.order_repo.save = mock.MagicMock(return_value=None,
side_effect=ValueError())
self.assertRaises(
ValueError,
self.resource.process,
self.order.id,
self.external_project_id,
)
def test_should_fail_during_error_report_fail(self):
# Force an error during the error-report handling after
# error in processing handler phase.
# Force an error during the processing handler phase.
self.project_repo.get = mock.MagicMock(return_value=None,
side_effect=TypeError())
# Force exception in the error-reporting phase.
self.order_repo.save = mock.MagicMock(return_value=None,
side_effect=ValueError())
# Should see the original exception (TypeError) instead of the
# secondary one (ValueError).
self.assertRaises(
TypeError,
self.resource.process,
self.order.id,
self.external_project_id,
)
self.project_repo.get.assert_called_once_with(self.project_id)
self.order_repo.save.assert_called_once_with(self.order)
class WhenBeginningAsymmetricTypeOrder(BaseOrderTestCase):
def setUp(self):
super(WhenBeginningAsymmetricTypeOrder, self).setUp()
self.order.type = "asymmetric"
self.resource = resources.BeginTypeOrder()
@mock.patch('barbican.plugin.resources.generate_asymmetric_secret')
def test_should_process_asymmetric_order(self,
mock_generate_asymmetric_secret):
mock_generate_asymmetric_secret.return_value = self.container
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
self.assertEqual(self.order.status, models.States.ACTIVE)
secret_info = self.order.to_dict_fields()['meta']
mock_generate_asymmetric_secret.assert_called_once_with(
secret_info,
secret_info.get('payload_content_type',
'application/octet-stream'),
self.project
)
def test_should_fail_during_retrieval(self):
# Force an error during the order retrieval phase.
self.order_repo.get = mock.MagicMock(return_value=None,
side_effect=ValueError())
self.assertRaises(
ValueError,
self.resource.process,
self.order.id,
self.external_project_id,
)
# Order state doesn't change because can't retrieve it to change it.
self.assertEqual(models.States.PENDING, self.order.status)
def test_should_fail_during_processing(self):
# Force an error during the processing handler phase.
self.project_repo.get = mock.MagicMock(return_value=None,
side_effect=ValueError())
self.assertRaises(
ValueError,
self.resource.process,
self.order.id,
self.external_project_id,
)
self.assertEqual(models.States.ERROR, self.order.status)
self.assertEqual(500, self.order.error_status_code)
self.assertEqual(u._('Process TypeOrder failure seen - please contact '
'site administrator.'), self.order.error_reason)
@mock.patch('barbican.plugin.resources.generate_asymmetric_secret')
def test_should_fail_during_success_report_fail(self,
mock_generate_asym_secret):
mock_generate_asym_secret.return_value = self.container
# Force an error during the processing handler phase.
self.order_repo.save = mock.MagicMock(return_value=None,
side_effect=ValueError())
self.assertRaises(
ValueError,
self.resource.process,
self.order.id,
self.external_project_id,
)
def test_should_fail_during_error_report_fail(self):
# Force an error during the error-report handling after
# error in processing handler phase.
# Force an error during the processing handler phase.
self.project_repo.get = mock.MagicMock(return_value=None,
side_effect=TypeError())
# Force exception in the error-reporting phase.
self.order_repo.save = mock.MagicMock(return_value=None,
side_effect=ValueError())
# Should see the original exception (TypeError) instead of the
# secondary one (ValueError).
self.assertRaises(
TypeError,
self.resource.process,
self.order.id,
self.external_project_id,
)
self.project_repo.get.assert_called_once_with(self.project_id)
self.order_repo.save.assert_called_once_with(self.order)