Improve unit test coverage for dcmanager's APIs (subcloud_deploy)
Improves unit test coverage for dcmanager's subcloud_deploy API from 85% to 99%. Test plan: All of the tests were created taking into account the output of 'tox -c tox.ini -e cover' command Story: 2007082 Task: 49578 Change-Id: Ie8aa1feb9f5f1f7e9d73b76112d2f2a6db528e6a Signed-off-by: rlima <Raphael.Lima@windriver.com>
This commit is contained in:
parent
0f5d3be331
commit
5307a60a85
|
@ -20,12 +20,12 @@ import builtins
|
|||
import json
|
||||
import os
|
||||
import os.path as os_path
|
||||
import pecan
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_db import options
|
||||
from oslotest import base
|
||||
import pecan
|
||||
import sqlalchemy
|
||||
from sqlalchemy.engine import Engine
|
||||
from sqlalchemy import event
|
||||
|
@ -248,6 +248,27 @@ class DCManagerTestCase(base.BaseTestCase):
|
|||
self.mock_get_vault_load_files = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
def _mock_os_remove(self):
|
||||
"""Mock os' remove"""
|
||||
|
||||
mock_patch_object = mock.patch.object(os, 'remove')
|
||||
self.mock_os_remove = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
def _mock_os_mkdir(self):
|
||||
"""Mock os' mkdir"""
|
||||
|
||||
mock_patch_object = mock.patch.object(os, 'mkdir')
|
||||
self.mock_os_mkdir = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
def _mock_os_listdir(self):
|
||||
"""Mock os.listdir"""
|
||||
|
||||
mock_patch_object = mock.patch.object(os, 'listdir')
|
||||
self.mock_os_listdir = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
def _mock_os_path_isdir(self):
|
||||
"""Mock os' path.isdir"""
|
||||
|
||||
|
@ -262,6 +283,11 @@ class DCManagerTestCase(base.BaseTestCase):
|
|||
self.mock_builtins_open = mock_patch.start()
|
||||
self.addCleanup(mock_patch.stop)
|
||||
|
||||
def _mock_log(self, target):
|
||||
mock_patch = mock.patch.object(target, 'LOG')
|
||||
self.mock_log = 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"""
|
||||
|
||||
|
@ -290,17 +316,3 @@ class DCManagerTestCase(base.BaseTestCase):
|
|||
mock_patch = mock.patch.object(target, 'PeerMonitorManager')
|
||||
self.mock_PeerMonitor_Manager = mock_patch.start()
|
||||
self.addCleanup(mock_patch.stop)
|
||||
|
||||
def _mock_os_mkdir(self):
|
||||
"""Mock os.mkdir"""
|
||||
|
||||
mock_patch_object = mock.patch.object(os, 'mkdir')
|
||||
self.mock_os_mkdir = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
def _mock_os_listdir(self):
|
||||
"""Mock os.listdir"""
|
||||
|
||||
mock_patch_object = mock.patch.object(os, 'listdir')
|
||||
self.mock_os_listdir = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
|
|
@ -58,6 +58,7 @@ class DCManagerApiTest(base.DCManagerTestCase):
|
|||
# implementation on controllers in case the method is not specified
|
||||
self.method = self.app.put
|
||||
self.params = {}
|
||||
self.upload_files = None
|
||||
self.verb = None
|
||||
self.headers = {
|
||||
'X-Tenant-Id': utils.UUID1, 'X_ROLE': 'admin,member,reader',
|
||||
|
@ -82,8 +83,14 @@ class DCManagerApiTest(base.DCManagerTestCase):
|
|||
def _send_request(self):
|
||||
"""Send a request to a url"""
|
||||
|
||||
kwargs = {}
|
||||
|
||||
if self.upload_files:
|
||||
kwargs = {'upload_files': self.upload_files}
|
||||
|
||||
return self.method(
|
||||
self.url, headers=self.headers, params=self.params, expect_errors=True
|
||||
self.url, headers=self.headers, params=self.params,
|
||||
expect_errors=True, **kwargs
|
||||
)
|
||||
|
||||
def _assert_response(
|
||||
|
|
|
@ -14,12 +14,10 @@
|
|||
# under the License.
|
||||
#
|
||||
|
||||
import http.client
|
||||
import os
|
||||
from os import path as os_path
|
||||
|
||||
import mock
|
||||
import six
|
||||
from six.moves import http_client
|
||||
from tsconfig.tsconfig import SW_VERSION
|
||||
import webtest
|
||||
|
||||
|
@ -28,260 +26,335 @@ from dcmanager.api.controllers.v1 import subcloud_deploy
|
|||
from dcmanager.common import consts
|
||||
from dcmanager.common import phased_subcloud_deploy as psd_common
|
||||
from dcmanager.common import utils as dutils
|
||||
from dcmanager.tests.unit.api import test_root_controller as testroot
|
||||
from dcmanager.tests.base import FakeException
|
||||
from dcmanager.tests.unit.api.test_root_controller import DCManagerApiTest
|
||||
from dcmanager.tests.unit.common import fake_subcloud
|
||||
from dcmanager.tests import utils
|
||||
|
||||
FAKE_SOFTWARE_VERSION = '22.12'
|
||||
FAKE_TENANT = utils.UUID1
|
||||
FAKE_ID = "1"
|
||||
FAKE_URL = "/v1.0/subcloud-deploy"
|
||||
FAKE_HEADERS = {
|
||||
"X-Tenant-Id": FAKE_TENANT,
|
||||
"X_ROLE": "admin,member,reader",
|
||||
"X-Identity-Status": "Confirmed",
|
||||
"X-Project-Name": "admin",
|
||||
}
|
||||
|
||||
FAKE_DEPLOY_PLAYBOOK_PREFIX = consts.DEPLOY_PLAYBOOK + '_'
|
||||
FAKE_DEPLOY_OVERRIDES_PREFIX = consts.DEPLOY_OVERRIDES + '_'
|
||||
FAKE_DEPLOY_CHART_PREFIX = consts.DEPLOY_CHART + '_'
|
||||
FAKE_PRESTAGE_IMAGES_PREFIX = consts.DEPLOY_PRESTAGE + '_'
|
||||
FAKE_SOFTWARE_VERSION = "22.12"
|
||||
FAKE_DEPLOY_PLAYBOOK_FILE = 'deployment-manager.yaml'
|
||||
FAKE_DEPLOY_OVERRIDES_FILE = 'deployment-manager-overrides-subcloud.yaml'
|
||||
FAKE_DEPLOY_CHART_FILE = 'deployment-manager.tgz'
|
||||
FAKE_DEPLOY_FILES = {
|
||||
FAKE_DEPLOY_PLAYBOOK_PREFIX: FAKE_DEPLOY_PLAYBOOK_FILE,
|
||||
FAKE_DEPLOY_OVERRIDES_PREFIX: FAKE_DEPLOY_OVERRIDES_FILE,
|
||||
FAKE_DEPLOY_CHART_PREFIX: FAKE_DEPLOY_CHART_FILE,
|
||||
}
|
||||
FAKE_DEPLOY_DELETE_FILES = {
|
||||
FAKE_DEPLOY_PLAYBOOK_PREFIX:
|
||||
'/opt/platform/deploy/22.12/deployment-manager.yaml',
|
||||
FAKE_DEPLOY_OVERRIDES_PREFIX:
|
||||
'/opt/platform/deploy/22.12/deployment-manager-overrides-subcloud.yaml',
|
||||
FAKE_DEPLOY_CHART_PREFIX: '/opt/platform/deploy/22.12/deployment-manager.tgz',
|
||||
FAKE_PRESTAGE_IMAGES_PREFIX: '/opt/platform/deploy/22.12/prestage_images.yml'
|
||||
f"{consts.DEPLOY_PLAYBOOK}_": FAKE_DEPLOY_PLAYBOOK_FILE,
|
||||
f"{consts.DEPLOY_OVERRIDES}_": FAKE_DEPLOY_OVERRIDES_FILE,
|
||||
f"{consts.DEPLOY_CHART}_": FAKE_DEPLOY_CHART_FILE,
|
||||
}
|
||||
|
||||
|
||||
def get_filename_by_prefix_side_effect(dir_path, prefix):
|
||||
filename = FAKE_DEPLOY_FILES.get(prefix)
|
||||
if filename:
|
||||
return prefix + FAKE_DEPLOY_FILES.get(prefix)
|
||||
else:
|
||||
return None
|
||||
class BaseTestSubcloudDeployController(DCManagerApiTest):
|
||||
"""Base class for testing the SubcloudDeployController"""
|
||||
|
||||
|
||||
class TestSubcloudDeploy(testroot.DCManagerApiTest):
|
||||
def setUp(self):
|
||||
super(TestSubcloudDeploy, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
super().setUp()
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy(self, mock_upload_files):
|
||||
params = [("release", FAKE_SOFTWARE_VERSION)]
|
||||
fields = list()
|
||||
for opt in consts.DEPLOY_COMMON_FILE_OPTIONS:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, webtest.Upload(fake_name, fake_content)))
|
||||
mock_upload_files.return_value = True
|
||||
params += fields
|
||||
self.url = "/v1.0/subcloud-deploy"
|
||||
|
||||
with mock.patch('builtins.open',
|
||||
mock.mock_open(
|
||||
read_data=fake_subcloud.FAKE_UPGRADES_METADATA
|
||||
)):
|
||||
response = self.app.post(FAKE_URL,
|
||||
headers=FAKE_HEADERS,
|
||||
params=params)
|
||||
self._mock_os_path_isdir()
|
||||
self._mock_os_remove()
|
||||
self._mock_os_mkdir()
|
||||
self._mock_os_open()
|
||||
self._mock_os_write()
|
||||
self._mock_builtins_open()
|
||||
self._mock_get_filename_by_prefix()
|
||||
self._setup_get_filename_by_prefix()
|
||||
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
self.assertEqual(FAKE_SOFTWARE_VERSION, response.json["software_version"])
|
||||
def _mock_os_open(self):
|
||||
"""Mock os' open"""
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_without_release(self, mock_upload_files):
|
||||
fields = list()
|
||||
for opt in consts.DEPLOY_COMMON_FILE_OPTIONS:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(FAKE_URL, headers=FAKE_HEADERS, upload_files=fields)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
# Verify the active release will be returned if release doesn't present
|
||||
self.assertEqual(SW_VERSION, response.json["software_version"])
|
||||
mock_patch_object = mock.patch.object(os, 'open')
|
||||
self.mock_os_open = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_missing_chart(self, mock_upload_files):
|
||||
opts = [
|
||||
consts.DEPLOY_PLAYBOOK,
|
||||
consts.DEPLOY_OVERRIDES,
|
||||
consts.DEPLOY_PRESTAGE,
|
||||
]
|
||||
fields = list()
|
||||
for opt in opts:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(
|
||||
FAKE_URL, headers=FAKE_HEADERS, upload_files=fields, expect_errors=True
|
||||
def _mock_os_write(self):
|
||||
"""Mock os' write"""
|
||||
|
||||
mock_patch_object = mock.patch.object(os, 'write')
|
||||
self.mock_os_write = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
def _mock_get_filename_by_prefix(self):
|
||||
"""Mock dutils' get_filename_by_prefix"""
|
||||
|
||||
mock_patch_object = mock.patch.object(
|
||||
dutils, "get_filename_by_prefix"
|
||||
)
|
||||
self.assertEqual(response.status_code, http_client.BAD_REQUEST)
|
||||
self.mock_get_filename_by_prefix = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_missing_chart_prestages(self, mock_upload_files):
|
||||
opts = [consts.DEPLOY_PLAYBOOK, consts.DEPLOY_OVERRIDES]
|
||||
fields = list()
|
||||
for opt in opts:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(
|
||||
FAKE_URL, headers=FAKE_HEADERS, upload_files=fields, expect_errors=True
|
||||
)
|
||||
self.assertEqual(response.status_code, http_client.BAD_REQUEST)
|
||||
def _setup_get_filename_by_prefix(self):
|
||||
self.mock_get_filename_by_prefix.side_effect = \
|
||||
self._mock_get_filename_by_prefix_side_effect
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_missing_playbook_overrides(
|
||||
self, mock_upload_files
|
||||
def _mock_get_filename_by_prefix_side_effect(self, _, prefix):
|
||||
filename = FAKE_DEPLOY_FILES.get(prefix)
|
||||
|
||||
return f"{prefix}{filename}" if filename else None
|
||||
|
||||
def _create_fake_fields(
|
||||
self, file_options=consts.DEPLOY_COMMON_FILE_OPTIONS, is_file_upload=True
|
||||
):
|
||||
opts = [consts.DEPLOY_CHART, consts.DEPLOY_PRESTAGE]
|
||||
fields = list()
|
||||
for opt in opts:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(
|
||||
FAKE_URL, headers=FAKE_HEADERS, upload_files=fields, expect_errors=True
|
||||
)
|
||||
self.assertEqual(response.status_code, http_client.BAD_REQUEST)
|
||||
fields = []
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_missing_prestage(self, mock_upload_files):
|
||||
opts = [consts.DEPLOY_PLAYBOOK, consts.DEPLOY_OVERRIDES, consts.DEPLOY_CHART]
|
||||
fields = list()
|
||||
for opt in opts:
|
||||
fake_name = opt + "_fake"
|
||||
for file_option in file_options:
|
||||
fake_name = f"{file_option}_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(FAKE_URL, headers=FAKE_HEADERS, upload_files=fields)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_all_input(self, mock_upload_files):
|
||||
opts = [
|
||||
consts.DEPLOY_PLAYBOOK,
|
||||
consts.DEPLOY_OVERRIDES,
|
||||
consts.DEPLOY_CHART,
|
||||
consts.DEPLOY_PRESTAGE,
|
||||
]
|
||||
fields = list()
|
||||
for opt in opts:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(FAKE_URL, headers=FAKE_HEADERS, upload_files=fields)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_prestage(self, mock_upload_files):
|
||||
opts = [consts.DEPLOY_PRESTAGE]
|
||||
fields = list()
|
||||
for opt in opts:
|
||||
fake_name = opt + "_fake"
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, fake_name, fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(FAKE_URL, headers=FAKE_HEADERS, upload_files=fields)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
|
||||
@mock.patch.object(subcloud_deploy.SubcloudDeployController, "_upload_files")
|
||||
def test_post_subcloud_deploy_missing_file_name(self, mock_upload_files):
|
||||
fields = list()
|
||||
for opt in consts.DEPLOY_COMMON_FILE_OPTIONS:
|
||||
fake_content = "fake content".encode("utf-8")
|
||||
fields.append((opt, "", fake_content))
|
||||
mock_upload_files.return_value = True
|
||||
response = self.app.post(
|
||||
FAKE_URL, headers=FAKE_HEADERS, upload_files=fields, expect_errors=True
|
||||
)
|
||||
self.assertEqual(response.status_code, http_client.BAD_REQUEST)
|
||||
|
||||
@mock.patch.object(dutils, "get_filename_by_prefix")
|
||||
def test_get_subcloud_deploy_with_release(self, mock_get_filename_by_prefix):
|
||||
def get_filename_by_prefix_side_effect(dir_path, prefix):
|
||||
filename = FAKE_DEPLOY_FILES.get(prefix)
|
||||
if filename:
|
||||
return prefix + FAKE_DEPLOY_FILES.get(prefix)
|
||||
if is_file_upload:
|
||||
fields.append([file_option, webtest.Upload(fake_name, fake_content)])
|
||||
else:
|
||||
return None
|
||||
fields.append([file_option, fake_name, fake_content])
|
||||
|
||||
os.path.isdir = mock.Mock(return_value=True)
|
||||
mock_get_filename_by_prefix.side_effect = \
|
||||
get_filename_by_prefix_side_effect
|
||||
url = FAKE_URL + '/' + FAKE_SOFTWARE_VERSION
|
||||
return fields
|
||||
|
||||
with mock.patch('builtins.open',
|
||||
mock.mock_open(
|
||||
read_data=fake_subcloud.FAKE_UPGRADES_METADATA
|
||||
)):
|
||||
response = self.app.get(url, headers=FAKE_HEADERS)
|
||||
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
class TestSubcloudDeployController(BaseTestSubcloudDeployController):
|
||||
"""Test class for SubcloudDeployController"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
def test_unmapped_method(self):
|
||||
"""Test requesting an unmapped method results in success with null content"""
|
||||
|
||||
self.method = self.app.put
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(response.text, 'null')
|
||||
|
||||
|
||||
class TestSubcloudDeployPost(BaseTestSubcloudDeployController):
|
||||
"""Test class for post requests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.method = self.app.post
|
||||
self.upload_files = self._create_fake_fields(is_file_upload=False)
|
||||
|
||||
self.mock_builtins_open.side_effect = mock.mock_open(
|
||||
read_data=fake_subcloud.FAKE_UPGRADES_METADATA
|
||||
)
|
||||
|
||||
def _assert_file_open_calls(self, builtins_call_count=1, os_call_count=3):
|
||||
"""Asserts that the mock_builtins_open and os_open were called correctly
|
||||
|
||||
Depending on the file, either the builtins or the os function will be called.
|
||||
The consts.DEPLOY_COMMON_FILE_OPTIONS, which is the default variable used
|
||||
when creating the upload files, results in one call to builtins and three for
|
||||
os. That is the reason for this function's default values.
|
||||
"""
|
||||
|
||||
self.assertEqual(self.mock_builtins_open.call_count, builtins_call_count)
|
||||
self.assertEqual(self.mock_os_open.call_count, os_call_count)
|
||||
|
||||
def test_post_succeeds_with_params(self):
|
||||
"""Test post succeeds with params"""
|
||||
|
||||
self.params = [("release", FAKE_SOFTWARE_VERSION)]
|
||||
self.params += self._create_fake_fields()
|
||||
self.upload_files = None
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(FAKE_SOFTWARE_VERSION, response.json["software_version"])
|
||||
self._assert_file_open_calls(2, len(self.params) - 2)
|
||||
|
||||
def test_post_succeeds_without_release(self):
|
||||
"""Test post succeeds without release"""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
# Verify the active release will be returned if release isn't present
|
||||
self.assertEqual(SW_VERSION, response.json["software_version"])
|
||||
self._assert_file_open_calls()
|
||||
|
||||
def test_post_fails_with_missing_deploy_chart(self):
|
||||
"""Test post fails with missing deploy chart"""
|
||||
|
||||
file_options = [
|
||||
consts.DEPLOY_PLAYBOOK, consts.DEPLOY_OVERRIDES, consts.DEPLOY_PRESTAGE
|
||||
]
|
||||
self.upload_files = self._create_fake_fields(file_options, False)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
f"error: argument --{consts.DEPLOY_CHART} is required"
|
||||
)
|
||||
|
||||
def test_post_fails_with_missing_deploy_chart_and_deploy_prestage(self):
|
||||
"""Test post fails with missing deploy chart and deploy prestage"""
|
||||
|
||||
file_options = [consts.DEPLOY_PLAYBOOK, consts.DEPLOY_OVERRIDES]
|
||||
self.upload_files = self._create_fake_fields(file_options, False)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
f"error: argument --{consts.DEPLOY_CHART} is required"
|
||||
)
|
||||
|
||||
def test_post_fails_with_missing_deploy_playbook(self):
|
||||
"""Test post fails with missing deploy playbook"""
|
||||
|
||||
file_options = [
|
||||
consts.DEPLOY_CHART, consts.DEPLOY_OVERRIDES, consts.DEPLOY_PRESTAGE
|
||||
]
|
||||
self.upload_files = self._create_fake_fields(file_options, False)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
f"error: argument --{consts.DEPLOY_PLAYBOOK} is required"
|
||||
)
|
||||
|
||||
def test_post_fails_with_missing_deploy_overrides(self):
|
||||
"""Test post fails with missing deploy overrides"""
|
||||
|
||||
file_options = [
|
||||
consts.DEPLOY_PLAYBOOK, consts.DEPLOY_CHART, consts.DEPLOY_PRESTAGE
|
||||
]
|
||||
self.upload_files = self._create_fake_fields(file_options, False)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
f"error: argument --{consts.DEPLOY_OVERRIDES} is required"
|
||||
)
|
||||
|
||||
def test_post_succeeds_with_missing_deploy_prestage(self):
|
||||
"""Test post succeeds with missing deploy prestage"""
|
||||
|
||||
file_options = [
|
||||
consts.DEPLOY_PLAYBOOK, consts.DEPLOY_OVERRIDES, consts.DEPLOY_CHART
|
||||
]
|
||||
self.upload_files = self._create_fake_fields(file_options, False)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self._assert_file_open_calls(1, len(self.upload_files) - 1)
|
||||
|
||||
def test_post_succeeds_with_empty_dir_path(self):
|
||||
"""Test post succeeds with empty dir_path"""
|
||||
|
||||
self.mock_os_path_isdir.return_value = False
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self._assert_file_open_calls()
|
||||
|
||||
def test_post_succeeds_with_deploy_prestage(self):
|
||||
"""Test post succeeds with deploy prestage"""
|
||||
|
||||
file_options = [consts.DEPLOY_PRESTAGE]
|
||||
self.upload_files = self._create_fake_fields(file_options, False)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self._assert_file_open_calls(0, len(self.upload_files))
|
||||
|
||||
def test_post_fails_for_subcloud_deploy_missing_file_name(self):
|
||||
"""Test post fails when a file option has an empty name is missing"""
|
||||
|
||||
self.upload_files = self._create_fake_fields(is_file_upload=False)
|
||||
self.upload_files[0][1] = ""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
f"No {consts.DEPLOY_PLAYBOOK} file uploaded"
|
||||
)
|
||||
|
||||
def test_post_fails_with_internal_server_error(self):
|
||||
"""Test post fails with internal server error"""
|
||||
|
||||
self.mock_os_remove.side_effect = FakeException("fake file name")
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.INTERNAL_SERVER_ERROR,
|
||||
f"Failed to upload {consts.DEPLOY_PLAYBOOK} file: fake file name"
|
||||
)
|
||||
|
||||
|
||||
class TestSubcloudDeployGet(BaseTestSubcloudDeployController):
|
||||
"""Test class for get requests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.url = f"{self.url}/{FAKE_SOFTWARE_VERSION}"
|
||||
self.method = self.app.get
|
||||
|
||||
self._mock_get_filename_by_prefix()
|
||||
self._setup_get_filename_by_prefix()
|
||||
|
||||
self.mock_builtins_open.side_effect = mock.mock_open(
|
||||
read_data=fake_subcloud.FAKE_UPGRADES_METADATA
|
||||
)
|
||||
|
||||
def test_get_succeeds_with_release(self):
|
||||
"""Test get succeeds with release"""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(
|
||||
FAKE_SOFTWARE_VERSION,
|
||||
response.json["subcloud_deploy"]["software_version"],
|
||||
response.json["subcloud_deploy"]["software_version"]
|
||||
)
|
||||
self.assertEqual(
|
||||
FAKE_DEPLOY_PLAYBOOK_FILE,
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_PLAYBOOK],
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_PLAYBOOK]
|
||||
)
|
||||
self.assertEqual(
|
||||
FAKE_DEPLOY_OVERRIDES_FILE,
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_OVERRIDES],
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_OVERRIDES]
|
||||
)
|
||||
self.assertEqual(
|
||||
FAKE_DEPLOY_CHART_FILE,
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_CHART],
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_CHART]
|
||||
)
|
||||
self.assertEqual(
|
||||
None, response.json["subcloud_deploy"][consts.DEPLOY_PRESTAGE]
|
||||
)
|
||||
|
||||
@mock.patch.object(dutils, "get_filename_by_prefix")
|
||||
def test_get_subcloud_deploy_without_release(self, mock_get_filename_by_prefix):
|
||||
def get_filename_by_prefix_side_effect(dir_path, prefix):
|
||||
filename = FAKE_DEPLOY_FILES.get(prefix)
|
||||
if filename:
|
||||
return prefix + FAKE_DEPLOY_FILES.get(prefix)
|
||||
else:
|
||||
return None
|
||||
def test_get_succeeds_without_release(self):
|
||||
"""Test get succeeds without release"""
|
||||
|
||||
os.path.isdir = mock.Mock(return_value=True)
|
||||
mock_get_filename_by_prefix.side_effect = get_filename_by_prefix_side_effect
|
||||
response = self.app.get(FAKE_URL, headers=FAKE_HEADERS)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
self.mock_os_path_isdir.return_value = True
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(
|
||||
SW_VERSION, response.json["subcloud_deploy"]["software_version"]
|
||||
FAKE_SOFTWARE_VERSION,
|
||||
response.json["subcloud_deploy"]["software_version"]
|
||||
)
|
||||
self.assertEqual(
|
||||
FAKE_DEPLOY_PLAYBOOK_FILE,
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_PLAYBOOK],
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_PLAYBOOK]
|
||||
)
|
||||
self.assertEqual(
|
||||
FAKE_DEPLOY_OVERRIDES_FILE,
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_OVERRIDES],
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_OVERRIDES]
|
||||
)
|
||||
self.assertEqual(
|
||||
FAKE_DEPLOY_CHART_FILE,
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_CHART],
|
||||
response.json["subcloud_deploy"][consts.DEPLOY_CHART]
|
||||
)
|
||||
self.assertEqual(
|
||||
None, response.json["subcloud_deploy"][consts.DEPLOY_PRESTAGE]
|
||||
|
@ -295,138 +368,110 @@ class TestSubcloudDeploy(testroot.DCManagerApiTest):
|
|||
deploy_config = psd_common.get_config_file_path(
|
||||
"subcloud1", consts.DEPLOY_CONFIG
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
bootstrap_file, f"{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1.yml"
|
||||
)
|
||||
self.assertEqual(
|
||||
install_values,
|
||||
f"{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1/install_values.yml",
|
||||
f"{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1/install_values.yml"
|
||||
)
|
||||
self.assertEqual(
|
||||
deploy_config,
|
||||
f"{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_deploy_config.yml",
|
||||
f"{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_deploy_config.yml"
|
||||
)
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
def test_subcloud_deploy_delete_directory_not_found(self,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
|
||||
mock_get_sw_version.return_value = '21.12'
|
||||
url = FAKE_URL + '?prestage_images=' + \
|
||||
str(False) + '&deployment_files=' + str(False)
|
||||
mock_path_isdir.side_effect = lambda x: True \
|
||||
if x == '/opt/platform/deploy/22.12' else False
|
||||
six.assertRaisesRegex(self, webtest.app.AppError, "404 *",
|
||||
self.app.delete, url,
|
||||
headers=FAKE_HEADERS)
|
||||
class TestSubcloudDeployDelete(BaseTestSubcloudDeployController):
|
||||
"""Test class for delete requests"""
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
def test_subcloud_deploy_delete_internal_server_error(self,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
mock_get_sw_version.return_value = '22.12'
|
||||
mock_path_isdir.side_effect = lambda x: True \
|
||||
if x == '/opt/platform/deploy/22.12' else False
|
||||
six.assertRaisesRegex(self, webtest.app.AppError, "500 *",
|
||||
self.app.delete, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
self.method = self.app.delete
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||
@mock.patch.object(os, 'remove')
|
||||
def test_subcloud_deploy_delete_with_release(self, mock_os_remove,
|
||||
mock_get_filename_by_prefix,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
self._mock_log(subcloud_deploy)
|
||||
self._mock_get_sw_version()
|
||||
|
||||
mock_os_remove.return_value = None
|
||||
mock_get_sw_version.return_value = '22.12'
|
||||
self.sw_version_directory = "/opt/platform/deploy/"
|
||||
self.version = FAKE_SOFTWARE_VERSION
|
||||
|
||||
mock_get_filename_by_prefix.side_effect = \
|
||||
get_filename_by_prefix_side_effect
|
||||
mock_path_isdir.return_value = True
|
||||
url = FAKE_URL + '/' + FAKE_SOFTWARE_VERSION + \
|
||||
'?prestage_images=' + str(False) + '&deployment_files=' + str(False)
|
||||
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
self.mock_get_sw_version.return_value = self.version
|
||||
self.mock_os_path_isdir.side_effect = self._mock_os_path_isdir_side_effect
|
||||
self.mock_os_remove.return_value = None
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||
@mock.patch.object(os, 'remove')
|
||||
def test_subcloud_deploy_delete_without_release(self, mock_os_remove,
|
||||
mock_get_filename_by_prefix,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
def _mock_get_sw_version(self):
|
||||
mock_patch_object = mock.patch.object(dutils, "get_sw_version")
|
||||
self.mock_get_sw_version = mock_patch_object.start()
|
||||
self.addCleanup(mock_patch_object.stop)
|
||||
|
||||
mock_os_remove.return_value = None
|
||||
mock_get_sw_version.return_value = '22.12'
|
||||
url = FAKE_URL + '?prestage_images=' + \
|
||||
str(True) + '&deployment_files=' + str(True)
|
||||
mock_get_filename_by_prefix.side_effect = \
|
||||
get_filename_by_prefix_side_effect
|
||||
mock_path_isdir.return_value = True
|
||||
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
def _mock_os_path_isdir_side_effect(self, dir_path):
|
||||
return dir_path == f"{self.sw_version_directory}{self.version}"
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||
@mock.patch.object(os, 'remove')
|
||||
def test_subcloud_deploy_delete_deployment_files(self, mock_os_remove,
|
||||
mock_get_filename_by_prefix,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
mock_os_remove.return_value = None
|
||||
mock_get_sw_version.return_value = '22.12'
|
||||
url = FAKE_URL + '?prestage_images=' + \
|
||||
str(False) + '&deployment_files=' + str(True)
|
||||
mock_get_filename_by_prefix.side_effect = \
|
||||
get_filename_by_prefix_side_effect
|
||||
mock_path_isdir.side_effect = lambda x: True \
|
||||
if x == '/opt/platform/deploy/22.12' else False
|
||||
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
def test_delete_succeeds_with_release(self):
|
||||
"""Test delete succeeds with release"""
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||
@mock.patch.object(os, 'remove')
|
||||
def test_subcloud_deploy_delete_prestage_images(self, mock_os_remove,
|
||||
mock_get_filename_by_prefix,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
mock_os_remove.return_value = None
|
||||
mock_get_sw_version.return_value = '22.12'
|
||||
url = FAKE_URL + '?prestage_images=' + \
|
||||
str(True) + '&deployment_files=' + str(False)
|
||||
mock_get_filename_by_prefix.side_effect = \
|
||||
get_filename_by_prefix_side_effect
|
||||
mock_path_isdir.side_effect = lambda x: True \
|
||||
if x == '/opt/platform/deploy/22.12' else False
|
||||
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
self.url = f"{self.url}/{self.version}?prestage_images=False"\
|
||||
"&deployment_files=False"
|
||||
|
||||
@mock.patch.object(os_path, 'isdir')
|
||||
@mock.patch.object(dutils, 'get_sw_version')
|
||||
@mock.patch.object(dutils, 'get_filename_by_prefix')
|
||||
@mock.patch.object(os, 'remove')
|
||||
def test_subcloud_deploy_delete_with_both_parameters(self, mock_os_remove,
|
||||
mock_get_filename_by_prefix,
|
||||
mock_get_sw_version,
|
||||
mock_path_isdir):
|
||||
mock_os_remove.return_value = None
|
||||
mock_get_sw_version.return_value = '22.12'
|
||||
url = FAKE_URL + '?prestage_images=' + \
|
||||
str(True) + '&deployment_files=' + str(True)
|
||||
mock_get_filename_by_prefix.side_effect = \
|
||||
get_filename_by_prefix_side_effect
|
||||
mock_path_isdir.side_effect = lambda x: True \
|
||||
if x == '/opt/platform/deploy/22.12' else False
|
||||
response = self.app.delete(url, headers=FAKE_HEADERS)
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(self.mock_os_remove.call_count, 3)
|
||||
|
||||
def test_delete_succeeds_with_deployment_files(self):
|
||||
"""Test delete succeeds with deployment files"""
|
||||
|
||||
self.url = f"{self.url}?prestage_images=False&deployment_files=True"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(self.mock_os_remove.call_count, 3)
|
||||
|
||||
def test_delete_succeeds_with_prestage_images(self):
|
||||
"""Test delete succeeds with prestage images"""
|
||||
|
||||
self.url = f"{self.url}?prestage_images=True&deployment_files=False"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.mock_log.warning.assert_called_with("prestage_images file not present")
|
||||
|
||||
def test_delete_succeeds_with_prestage_images_and_deployment_files(self):
|
||||
"""Test delete succeeds with prestage images and deployment files"""
|
||||
|
||||
self.url = f"{self.url}?prestage_images=True&deployment_files=True"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(self.mock_os_remove.call_count, 3)
|
||||
|
||||
def test_delete_fails_with_directory_not_found(self):
|
||||
"""Test delete fails with directory not found"""
|
||||
|
||||
self.url = f"{self.url}?prestage_images=False&deployment_files=False"
|
||||
|
||||
version = "21.12"
|
||||
self.mock_get_sw_version.return_value = version
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.NOT_FOUND,
|
||||
f"Directory not found: {self.sw_version_directory}{version}"
|
||||
)
|
||||
|
||||
def test_delete_fails_with_internal_server_error(self):
|
||||
"""Test delete fails with internal server error"""
|
||||
|
||||
self.mock_os_remove.side_effect = FakeException("fake file name")
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.INTERNAL_SERVER_ERROR,
|
||||
"Failed to delete file: fake file name"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue