Merge "Create unit tests for root controller in dcorch"

This commit is contained in:
Zuul 2024-04-16 21:13:49 +00:00 committed by Gerrit Code Review
commit c0da5ce488
4 changed files with 275 additions and 3 deletions

View File

@ -1,5 +1,5 @@
# Copyright (c) 2015 Ericsson AB
# Copyright (c) 2024 Wind River Systems, Inc.
# Copyright (c) 2020-2024 Wind River Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,8 +14,11 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
import builtins
import mock
import pecan
from oslo_config import cfg
from oslo_db import options
from oslotest import base
@ -23,11 +26,21 @@ import sqlalchemy
from dcorch.db import api
from dcorch.db.sqlalchemy import api as db_api
from dcorch.rpc import client as rpc_client
from dcorch.tests import utils
get_engine = api.get_engine
class FakeException(Exception):
"""Exception used to throw a generic exception in the application
Using the Exception class might lead to linter errors for being too broad. In
these cases, the FakeException is used
"""
class OrchestratorTestCase(base.BaseTestCase):
"""Test case base class for all unit tests."""
@ -55,3 +68,45 @@ class OrchestratorTestCase(base.BaseTestCase):
self.setup_dummy_db()
self.addCleanup(self.reset_dummy_db)
self.ctx = utils.dummy_context()
self._mock_pecan()
def _mock_pecan(self):
"""Mock pecan's abort"""
mock_patch = mock.patch.object(pecan, 'abort', wraps=pecan.abort)
self.mock_pecan_abort = mock_patch.start()
self.addCleanup(mock_patch.stop)
def _mock_rpc_client(self):
"""Mock rpc's manager client"""
mock_patch = mock.patch.object(rpc_client, 'EngineClient')
self.mock_rpc_client = mock_patch.start()
self.addCleanup(mock_patch.stop)
def _mock_openstack_driver(self, target):
mock_patch = mock.patch.object(target, 'OpenStackDriver')
self.mock_openstack_driver = mock_patch.start()
self.addCleanup(mock_patch.stop)
def _mock_sysinv_client(self, target):
mock_patch = mock.patch.object(target, 'SysinvClient')
self.mock_sysinv_client = mock_patch.start()
self.addCleanup(mock_patch.stop)
def _mock_builtins_open(self):
"""Mock builtins' open"""
mock_patch = mock.patch.object(builtins, 'open')
self.mock_builtins_open = mock_patch.start()
self.addCleanup(mock_patch.stop)
def _assert_pecan(self, http_status, content=None, call_count=1):
"""Assert pecan was called with the correct arguments"""
self.assertEqual(self.mock_pecan_abort.call_count, call_count)
if content:
self.mock_pecan_abort.assert_called_with(http_status, content)
else:
self.mock_pecan_abort.assert_called_with(http_status)

View File

@ -0,0 +1,208 @@
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import http.client
import uuid
from oslo_config import cfg
from oslo_config import fixture as fixture_config
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
import pecan
from pecan.configuration import set_config
from pecan.testing import load_test_app
from dcorch.api import api_config
from dcorch.common import config
from dcorch.tests import base
from dcorch.tests.unit.common import constants as test_consts
config.register_options()
OPT_GROUP_NAME = 'keystone_authtoken'
cfg.CONF.import_group(OPT_GROUP_NAME, "keystonemiddleware.auth_token")
class DCOrchApiTest(base.OrchestratorTestCase):
def setUp(self):
super(DCOrchApiTest, self).setUp()
self.addCleanup(set_config, {}, overwrite=True)
api_config.test_init()
config_fixture = fixture_config.Config()
self.CONF = self.useFixture(config_fixture).conf
config_fixture.set_config_dirs([])
self.CONF.set_override('auth_strategy', 'noauth')
self.app = self._make_app()
self.url = '/'
# The put method is used as a default value, leading to the generic
# implementation on controllers in case the method is not specified
self.method = self.app.put
self.params = {}
self.verb = None
self.headers = {
'X-Tenant-Id': str(uuid.uuid4()), 'X_ROLE': 'admin,member,reader',
'X-Identity-Status': 'Confirmed', 'X-Project-Name': 'admin'
}
def _make_app(self, enable_acl=False):
self.config_fixture = {
'app': {
'root': 'dcorch.api.controllers.root.RootController',
'modules': ['dcorch.api'],
'enable_acl': enable_acl,
'errors': {
400: '/error',
'__force_dict__': True
}
},
}
return load_test_app(self.config_fixture)
def _send_request(self):
"""Send a request to a url"""
return self.method(
self.url, headers=self.headers, params=self.params, expect_errors=True
)
def _assert_response(
self, response, status_code=http.client.OK,
content_type=test_consts.APPLICATION_JSON
):
"""Assert the response for a request"""
self.assertEqual(response.status_code, status_code)
self.assertEqual(response.content_type, content_type)
def _assert_pecan_and_response(
self, response, http_status, content=None, call_count=1,
content_type=test_consts.TEXT_PLAIN
):
"""Assert the response and pecan abort for a failed request"""
self._assert_pecan(http_status, content, call_count=call_count)
self._assert_response(response, http_status, content_type)
def tearDown(self):
super(DCOrchApiTest, self).tearDown()
pecan.set_config({}, overwrite=True)
class TestRootController(DCOrchApiTest):
"""Test version listing on root URI."""
def setUp(self):
super(TestRootController, self).setUp()
self.url = '/'
self.method = self.app.get
def _test_method_returns_405(self, method, content_type=test_consts.TEXT_PLAIN):
self.method = method
response = self._send_request()
self._assert_pecan_and_response(
response, http.client.METHOD_NOT_ALLOWED, content_type=content_type
)
def test_get(self):
"""Test get request succeeds with correct versions"""
response = self._send_request()
self._assert_response(response)
json_body = jsonutils.loads(response.body)
versions = json_body.get('versions')
self.assertEqual(1, len(versions))
def test_request_id(self):
"""Test request for root returns the correct request id"""
response = self._send_request()
self._assert_response(response)
self.assertIn('x-openstack-request-id', response.headers)
self.assertTrue(
response.headers['x-openstack-request-id'].startswith('req-')
)
id_part = response.headers['x-openstack-request-id'].split('req-')[1]
self.assertTrue(uuidutils.is_uuid_like(id_part))
def test_post(self):
"""Test post request is not allowed on root"""
self._test_method_returns_405(self.app.post)
def test_put(self):
"""Test put request is not allowed on root"""
self._test_method_returns_405(self.app.put)
def test_patch(self):
"""Test patch request is not allowed on root"""
self._test_method_returns_405(self.app.patch)
def test_delete(self):
"""Test delete request is not allowed on root"""
self._test_method_returns_405(self.app.delete)
def test_head(self):
"""Test head request is not allowed on root"""
self._test_method_returns_405(
self.app.head, content_type=test_consts.TEXT_HTML
)
class TestErrors(DCOrchApiTest):
def setUp(self):
super(TestErrors, self).setUp()
cfg.CONF.set_override('admin_tenant', 'fake_tenant_id', group='cache')
def test_404(self):
self.url = '/assert_called_once'
self.method = self.app.get
response = self._send_request()
self._assert_response(
response, http.client.NOT_FOUND, content_type=test_consts.TEXT_PLAIN
)
def test_version_1_root_controller(self):
self.url = f'/v1.0/{uuidutils.generate_uuid()}/bad_method'
self.method = self.app.patch
response = self._send_request()
self._assert_pecan_and_response(response, http.client.NOT_FOUND)
class TestKeystoneAuth(DCOrchApiTest):
"""Test requests using keystone as the authentication strategy"""
def setUp(self):
super(TestKeystoneAuth, self).setUp()
cfg.CONF.set_override('auth_strategy', 'keystone')
self.method = self.app.get
def test_auth_not_enforced_for_root(self):
"""Test authentication is not enforced for root url"""
response = self._send_request()
self._assert_response(response)

View File

@ -0,0 +1,9 @@
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Content-type
TEXT_HTML = 'text/html'
TEXT_PLAIN = 'text/plain'
APPLICATION_JSON = 'application/json'