[LYN-4288] Adding error page if resource mapping tool has invalid setup (#1219)
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
"""
|
||||||
|
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||||
|
its licensors.
|
||||||
|
|
||||||
|
For complete copyright and license terms please see the LICENSE at the root of this
|
||||||
|
distribution (the "License"). All use of this software is governed by the License,
|
||||||
|
or, if provided, by the license below or the license accompanying this file. Do not
|
||||||
|
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PySide2.QtCore import (QCoreApplication, QObject)
|
||||||
|
|
||||||
|
from manager.view_manager import ViewManager
|
||||||
|
from view.error_page import ErrorPage
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorController(QObject):
|
||||||
|
"""
|
||||||
|
ErrorPage Controller
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super(ErrorController, self).__init__()
|
||||||
|
# Initialize manager references
|
||||||
|
self._view_manager: ViewManager = ViewManager.get_instance()
|
||||||
|
# Initialize view references
|
||||||
|
self._error_page: ErrorPage = self._view_manager.get_error_page()
|
||||||
|
|
||||||
|
def _ok(self) -> None:
|
||||||
|
QCoreApplication.instance().quit()
|
||||||
|
|
||||||
|
def setup(self) -> None:
|
||||||
|
self._error_page.ok_button.clicked.connect(self._ok)
|
||||||
@@ -48,11 +48,15 @@ class ConfigurationManager(object):
|
|||||||
def configuration(self, new_configuration: ConfigurationManager) -> None:
|
def configuration(self, new_configuration: ConfigurationManager) -> None:
|
||||||
self._configuration = new_configuration
|
self._configuration = new_configuration
|
||||||
|
|
||||||
def setup(self, config_path: str) -> bool:
|
def setup(self, profile_name: str, config_path: str) -> bool:
|
||||||
result: bool = True
|
result: bool = True
|
||||||
logger.info("Setting up default configuration ...")
|
logger.debug("Setting up default configuration ...")
|
||||||
try:
|
try:
|
||||||
normalized_config_path: str = file_utils.normalize_file_path(config_path);
|
logger.debug("Setting up boto3 default session ...")
|
||||||
|
aws_utils.setup_default_session(profile_name)
|
||||||
|
|
||||||
|
logger.debug("Setting up config directory and files ...")
|
||||||
|
normalized_config_path: str = file_utils.normalize_file_path(config_path)
|
||||||
if normalized_config_path:
|
if normalized_config_path:
|
||||||
self._configuration.config_directory = normalized_config_path
|
self._configuration.config_directory = normalized_config_path
|
||||||
else:
|
else:
|
||||||
@@ -61,6 +65,7 @@ class ConfigurationManager(object):
|
|||||||
file_utils.find_files_with_suffix_under_directory(self._configuration.config_directory,
|
file_utils.find_files_with_suffix_under_directory(self._configuration.config_directory,
|
||||||
constants.RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX)
|
constants.RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX)
|
||||||
|
|
||||||
|
logger.debug("Setting up aws account id and region ...")
|
||||||
self._configuration.account_id = aws_utils.get_default_account_id()
|
self._configuration.account_id = aws_utils.get_default_account_id()
|
||||||
self._configuration.region = aws_utils.get_default_region()
|
self._configuration.region = aws_utils.get_default_region()
|
||||||
except (RuntimeError, FileNotFoundError) as e:
|
except (RuntimeError, FileNotFoundError) as e:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from controller.error_controller import ErrorController
|
||||||
from controller.import_resources_controller import ImportResourcesController
|
from controller.import_resources_controller import ImportResourcesController
|
||||||
from controller.view_edit_controller import ViewEditController
|
from controller.view_edit_controller import ViewEditController
|
||||||
from model import error_messages
|
from model import error_messages
|
||||||
@@ -33,8 +34,9 @@ class ControllerManager(object):
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
if ControllerManager.__instance is None:
|
if ControllerManager.__instance is None:
|
||||||
self._view_edit_controller: ViewEditController = ViewEditController()
|
self._error_controller: ErrorController = None
|
||||||
self._import_resources_controller: ImportResourcesController = ImportResourcesController()
|
self._view_edit_controller: ViewEditController = None
|
||||||
|
self._import_resources_controller: ImportResourcesController = None
|
||||||
ControllerManager.__instance = self
|
ControllerManager.__instance = self
|
||||||
else:
|
else:
|
||||||
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ControllerManager"))
|
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ControllerManager"))
|
||||||
@@ -47,9 +49,17 @@ class ControllerManager(object):
|
|||||||
def view_edit_controller(self) -> ViewEditController:
|
def view_edit_controller(self) -> ViewEditController:
|
||||||
return self._view_edit_controller
|
return self._view_edit_controller
|
||||||
|
|
||||||
def setup(self) -> None:
|
def setup(self, setup_error: bool) -> None:
|
||||||
logger.info("Setting up ViewEdit and ImportResource controllers ...")
|
if setup_error:
|
||||||
self._view_edit_controller.setup()
|
logger.debug("Setting up Error controllers ...")
|
||||||
self._import_resources_controller.setup()
|
self._error_controller = ErrorController()
|
||||||
self._import_resources_controller.add_import_resources_sender.connect(
|
self._error_controller.setup()
|
||||||
self._view_edit_controller.add_import_resources_receiver)
|
else:
|
||||||
|
logger.debug("Setting up ViewEdit and ImportResource controllers ...")
|
||||||
|
self._view_edit_controller = ViewEditController()
|
||||||
|
self._import_resources_controller = ImportResourcesController()
|
||||||
|
|
||||||
|
self._view_edit_controller.setup()
|
||||||
|
self._import_resources_controller.setup()
|
||||||
|
self._import_resources_controller.add_import_resources_sender.connect(
|
||||||
|
self._view_edit_controller.add_import_resources_receiver)
|
||||||
|
|||||||
@@ -37,10 +37,13 @@ class ThreadManager(object):
|
|||||||
else:
|
else:
|
||||||
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ThreadManager"))
|
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ThreadManager"))
|
||||||
|
|
||||||
def setup(self, thread_count: int = 1) -> None:
|
def setup(self, setup_error: bool, thread_count: int = 1) -> None:
|
||||||
# Based on prototype use case, we just need 1 thread
|
if setup_error:
|
||||||
logger.info(f"Setting up thread pool with MaxThreadCount={thread_count} ...")
|
logger.debug("Skip thread pool creation, as there is major setup error.")
|
||||||
self._thread_pool.setMaxThreadCount(thread_count)
|
else:
|
||||||
|
# Based on prototype use case, we just need 1 thread
|
||||||
|
logger.debug(f"Setting up thread pool with MaxThreadCount={thread_count} ...")
|
||||||
|
self._thread_pool.setMaxThreadCount(thread_count)
|
||||||
|
|
||||||
"""Reserves a thread and uses it to run runnable worker, unless this thread will make
|
"""Reserves a thread and uses it to run runnable worker, unless this thread will make
|
||||||
the current thread count exceed max thread count. In that case, runnable is added to a run queue instead."""
|
the current thread count exceed max thread count. In that case, runnable is added to a run queue instead."""
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from PySide2.QtGui import QIcon
|
|||||||
from PySide2.QtWidgets import (QMainWindow, QStackedWidget, QWidget)
|
from PySide2.QtWidgets import (QMainWindow, QStackedWidget, QWidget)
|
||||||
|
|
||||||
from model import (error_messages, view_size_constants)
|
from model import (error_messages, view_size_constants)
|
||||||
|
from view.error_page import ErrorPage
|
||||||
from view.import_resources_page import ImportResourcesPage
|
from view.import_resources_page import ImportResourcesPage
|
||||||
from view.view_edit_page import ViewEditPage
|
from view.view_edit_page import ViewEditPage
|
||||||
|
|
||||||
@@ -27,6 +28,10 @@ class ViewManagerConstants(object):
|
|||||||
IMPORT_RESOURCES_PAGE_INDEX: int = 1
|
IMPORT_RESOURCES_PAGE_INDEX: int = 1
|
||||||
|
|
||||||
|
|
||||||
|
# Error page will be a single page
|
||||||
|
ERROR_PAGE_INDEX: int = 0
|
||||||
|
|
||||||
|
|
||||||
class ViewManager(object):
|
class ViewManager(object):
|
||||||
"""
|
"""
|
||||||
View manager maintains the main stacked pages for this tool, which
|
View manager maintains the main stacked pages for this tool, which
|
||||||
@@ -58,21 +63,32 @@ class ViewManager(object):
|
|||||||
ViewManager.__instance = self
|
ViewManager.__instance = self
|
||||||
else:
|
else:
|
||||||
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ViewManager"))
|
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ViewManager"))
|
||||||
|
|
||||||
|
def get_error_page(self) -> QWidget:
|
||||||
|
return self._resource_mapping_stacked_pages.widget(ERROR_PAGE_INDEX)
|
||||||
|
|
||||||
def get_view_edit_page(self) -> QWidget:
|
def get_view_edit_page(self) -> QWidget:
|
||||||
return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||||
|
|
||||||
def get_import_resources_page(self) -> QWidget:
|
def get_import_resources_page(self) -> QWidget:
|
||||||
return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.IMPORT_RESOURCES_PAGE_INDEX)
|
return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.IMPORT_RESOURCES_PAGE_INDEX)
|
||||||
|
|
||||||
def setup(self) -> None:
|
def setup(self, setup_error: bool) -> None:
|
||||||
logger.debug("Setting up ViewEdit and ImportResources view pages ...")
|
if setup_error:
|
||||||
self._resource_mapping_stacked_pages.addWidget(ViewEditPage())
|
logger.debug("Setting up Error view pages ...")
|
||||||
self._resource_mapping_stacked_pages.addWidget(ImportResourcesPage())
|
self._resource_mapping_stacked_pages.addWidget(ErrorPage())
|
||||||
|
self._main_window.adjustSize() # fit error page size
|
||||||
|
else:
|
||||||
|
logger.debug("Setting up ViewEdit and ImportResources view pages ...")
|
||||||
|
self._resource_mapping_stacked_pages.addWidget(ViewEditPage())
|
||||||
|
self._resource_mapping_stacked_pages.addWidget(ImportResourcesPage())
|
||||||
|
|
||||||
def show(self) -> None:
|
def show(self, setup_error: bool) -> None:
|
||||||
"""Show up the tool view by setting default page index and showing main widget"""
|
"""Show up the tool view by setting default page index and showing main widget"""
|
||||||
self._resource_mapping_stacked_pages.setCurrentIndex(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
if setup_error:
|
||||||
|
self._resource_mapping_stacked_pages.setCurrentIndex(ERROR_PAGE_INDEX)
|
||||||
|
else:
|
||||||
|
self._resource_mapping_stacked_pages.setCurrentIndex(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||||
self._main_window.show()
|
self._main_window.show()
|
||||||
|
|
||||||
def switch_to_view_edit_page(self) -> None:
|
def switch_to_view_edit_page(self) -> None:
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
ERROR_PAGE_TOOL_SETUP_ERROR_MESSAGE: str = \
|
||||||
|
"AWS credentials are missing or invalid. See " \
|
||||||
|
"<a href=\"https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-core/configuring-credentials/\">"\
|
||||||
|
"<span style=\"color:#4A90E2;\">documentation</span></a> for details." \
|
||||||
|
"<br>Check log file under Gems/AWSCore/Code/Tool/ResourceMappingTool for further information."
|
||||||
|
|
||||||
VIEW_EDIT_PAGE_SAVING_FAILED_WITH_INVALID_ROW_ERROR_MESSAGE: str = \
|
VIEW_EDIT_PAGE_SAVING_FAILED_WITH_INVALID_ROW_ERROR_MESSAGE: str = \
|
||||||
"Row {} have errors. Please correct errors or delete the row to proceed."
|
"Row {} have errors. Please correct errors or delete the row to proceed."
|
||||||
VIEW_EDIT_PAGE_READ_FROM_JSON_FAILED_WITH_UNEXPECTED_FILE_ERROR_MESSAGE: str = \
|
VIEW_EDIT_PAGE_READ_FROM_JSON_FAILED_WITH_UNEXPECTED_FILE_ERROR_MESSAGE: str = \
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
|
|
||||||
NOTIFICATION_LOADING_MESSAGE: str = "Loading..."
|
NOTIFICATION_LOADING_MESSAGE: str = "Loading..."
|
||||||
|
|
||||||
|
ERROR_PAGE_OK_TEXT: str = "OK"
|
||||||
|
|
||||||
VIEW_EDIT_PAGE_CONFIG_FILE_TEXT: str = "Config File"
|
VIEW_EDIT_PAGE_CONFIG_FILE_TEXT: str = "Config File"
|
||||||
VIEW_EDIT_PAGE_CONFIG_LOCATION_TEXT: str = "Config Location:"
|
VIEW_EDIT_PAGE_CONFIG_LOCATION_TEXT: str = "Config Location:"
|
||||||
VIEW_EDIT_PAGE_ADD_ROW_TEXT: str = "Add Row"
|
VIEW_EDIT_PAGE_ADD_ROW_TEXT: str = "Add Row"
|
||||||
|
|||||||
@@ -17,6 +17,18 @@ MAIN_PAGE_LAYOUT_MARGIN_TOPBOTTOM: int = 15
|
|||||||
|
|
||||||
INTERACTION_COMPONENT_HEIGHT: int = 25
|
INTERACTION_COMPONENT_HEIGHT: int = 25
|
||||||
|
|
||||||
|
"""error page related constants"""
|
||||||
|
ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT: int = 10
|
||||||
|
ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM: int = 10
|
||||||
|
|
||||||
|
ERROR_PAGE_MAIN_WINDOW_WIDTH: int = 600
|
||||||
|
ERROR_PAGE_MAIN_WINDOW_HEIGHT: int = 145
|
||||||
|
|
||||||
|
ERROR_PAGE_NOTIFICATION_AREA_HEIGHT: int = 100
|
||||||
|
ERROR_PAGE_FOOTER_AREA_HEIGHT: int = 45
|
||||||
|
|
||||||
|
OK_BUTTON_WIDTH: int = 90
|
||||||
|
|
||||||
"""view edit page related constants"""
|
"""view edit page related constants"""
|
||||||
VIEW_EDIT_PAGE_HEADER_AREA_HEIGHT: int = 65
|
VIEW_EDIT_PAGE_HEADER_AREA_HEIGHT: int = 65
|
||||||
VIEW_EDIT_PAGE_CENTER_AREA_HEIGHT: int = 500
|
VIEW_EDIT_PAGE_CENTER_AREA_HEIGHT: int = 500
|
||||||
|
|||||||
@@ -73,32 +73,22 @@ if __name__ == "__main__":
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.warning("Failed to load style sheet for resource mapping tool")
|
logger.warning("Failed to load style sheet for resource mapping tool")
|
||||||
|
|
||||||
logger.info("Initializing boto3 default session ...")
|
|
||||||
try:
|
|
||||||
aws_utils.setup_default_session(arguments.profile)
|
|
||||||
except RuntimeError as error:
|
|
||||||
logger.error(error)
|
|
||||||
environment_utils.cleanup_qt_environment()
|
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
logger.info("Initializing configuration manager ...")
|
logger.info("Initializing configuration manager ...")
|
||||||
configuration_manager: ConfigurationManager = ConfigurationManager()
|
configuration_manager: ConfigurationManager = ConfigurationManager()
|
||||||
if not configuration_manager.setup(arguments.config_path):
|
configuration_error: bool = not configuration_manager.setup(arguments.profile, arguments.config_path)
|
||||||
environment_utils.cleanup_qt_environment()
|
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
logger.info("Initializing thread manager ...")
|
logger.info("Initializing thread manager ...")
|
||||||
thread_manager: ThreadManager = ThreadManager()
|
thread_manager: ThreadManager = ThreadManager()
|
||||||
thread_manager.setup()
|
thread_manager.setup(configuration_error)
|
||||||
|
|
||||||
logger.info("Initializing view manager ...")
|
logger.info("Initializing view manager ...")
|
||||||
view_manager: ViewManager = ViewManager()
|
view_manager: ViewManager = ViewManager()
|
||||||
view_manager.setup()
|
view_manager.setup(configuration_error)
|
||||||
|
|
||||||
logger.info("Initializing controller manager ...")
|
logger.info("Initializing controller manager ...")
|
||||||
controller_manager: ControllerManager = ControllerManager()
|
controller_manager: ControllerManager = ControllerManager()
|
||||||
controller_manager.setup()
|
controller_manager.setup(configuration_error)
|
||||||
|
|
||||||
view_manager.show()
|
view_manager.show(configuration_error)
|
||||||
|
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|||||||
@@ -368,3 +368,18 @@ QFrame#NotificationFrame
|
|||||||
margin: 4px;
|
margin: 4px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFrame#ErrorPage
|
||||||
|
{
|
||||||
|
background-color: #2d2d2d;
|
||||||
|
border: 1px solid #4A90E2;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFrame#ErrorPage QLabel#NotificationIcon
|
||||||
|
{
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|||||||
+11
-4
@@ -33,6 +33,7 @@ class TestConfigurationManager(TestCase):
|
|||||||
def test_get_instance_raise_exception(self) -> None:
|
def test_get_instance_raise_exception(self) -> None:
|
||||||
self.assertRaises(Exception, ConfigurationManager)
|
self.assertRaises(Exception, ConfigurationManager)
|
||||||
|
|
||||||
|
@patch("utils.aws_utils.setup_default_session")
|
||||||
@patch("utils.aws_utils.get_default_region", return_value=_expected_region)
|
@patch("utils.aws_utils.get_default_region", return_value=_expected_region)
|
||||||
@patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id)
|
@patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id)
|
||||||
@patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files)
|
@patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files)
|
||||||
@@ -42,8 +43,10 @@ class TestConfigurationManager(TestCase):
|
|||||||
mock_check_path_exists: MagicMock,
|
mock_check_path_exists: MagicMock,
|
||||||
mock_find_files_with_suffix_under_directory: MagicMock,
|
mock_find_files_with_suffix_under_directory: MagicMock,
|
||||||
mock_get_default_account_id: MagicMock,
|
mock_get_default_account_id: MagicMock,
|
||||||
mock_get_default_region: MagicMock) -> None:
|
mock_get_default_region: MagicMock,
|
||||||
TestConfigurationManager._expected_configuration_manager.setup("")
|
mock_setup_default_session: MagicMock) -> None:
|
||||||
|
TestConfigurationManager._expected_configuration_manager.setup("", "")
|
||||||
|
mock_setup_default_session.assert_called_once()
|
||||||
mock_get_current_directory_path.assert_called_once()
|
mock_get_current_directory_path.assert_called_once()
|
||||||
mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path)
|
mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path)
|
||||||
mock_find_files_with_suffix_under_directory.assert_called_once_with(
|
mock_find_files_with_suffix_under_directory.assert_called_once_with(
|
||||||
@@ -59,6 +62,7 @@ class TestConfigurationManager(TestCase):
|
|||||||
assert TestConfigurationManager._expected_configuration_manager.configuration.region == \
|
assert TestConfigurationManager._expected_configuration_manager.configuration.region == \
|
||||||
TestConfigurationManager._expected_region
|
TestConfigurationManager._expected_region
|
||||||
|
|
||||||
|
@patch("utils.aws_utils.setup_default_session")
|
||||||
@patch("utils.aws_utils.get_default_region", return_value=_expected_region)
|
@patch("utils.aws_utils.get_default_region", return_value=_expected_region)
|
||||||
@patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id)
|
@patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id)
|
||||||
@patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files)
|
@patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files)
|
||||||
@@ -68,8 +72,11 @@ class TestConfigurationManager(TestCase):
|
|||||||
mock_check_path_exists: MagicMock,
|
mock_check_path_exists: MagicMock,
|
||||||
mock_find_files_with_suffix_under_directory: MagicMock,
|
mock_find_files_with_suffix_under_directory: MagicMock,
|
||||||
mock_get_default_account_id: MagicMock,
|
mock_get_default_account_id: MagicMock,
|
||||||
mock_get_default_region: MagicMock) -> None:
|
mock_get_default_region: MagicMock,
|
||||||
TestConfigurationManager._expected_configuration_manager.setup(TestConfigurationManager._expected_directory_path)
|
mock_setup_default_session: MagicMock) -> None:
|
||||||
|
TestConfigurationManager._expected_configuration_manager.setup(
|
||||||
|
"", TestConfigurationManager._expected_directory_path)
|
||||||
|
mock_setup_default_session.assert_called_once()
|
||||||
mock_normalize_file_path.assert_called_once()
|
mock_normalize_file_path.assert_called_once()
|
||||||
mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path)
|
mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path)
|
||||||
mock_find_files_with_suffix_under_directory.assert_called_once_with(
|
mock_find_files_with_suffix_under_directory.assert_called_once_with(
|
||||||
|
|||||||
+10
-1
@@ -25,6 +25,9 @@ class TestControllerManager(TestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls) -> None:
|
def setUpClass(cls) -> None:
|
||||||
|
error_controller_patcher: patch = patch("manager.controller_manager.ErrorController")
|
||||||
|
cls._mock_error_controller = error_controller_patcher.start()
|
||||||
|
|
||||||
import_resources_controller_patcher: patch = patch("manager.controller_manager.ImportResourcesController")
|
import_resources_controller_patcher: patch = patch("manager.controller_manager.ImportResourcesController")
|
||||||
cls._mock_import_resources_controller = import_resources_controller_patcher.start()
|
cls._mock_import_resources_controller = import_resources_controller_patcher.start()
|
||||||
|
|
||||||
@@ -52,8 +55,14 @@ class TestControllerManager(TestCase):
|
|||||||
mocked_import_resources_controller: MagicMock = \
|
mocked_import_resources_controller: MagicMock = \
|
||||||
TestControllerManager._mock_import_resources_controller.return_value
|
TestControllerManager._mock_import_resources_controller.return_value
|
||||||
|
|
||||||
TestControllerManager._expected_controller_manager.setup()
|
TestControllerManager._expected_controller_manager.setup(False)
|
||||||
mocked_view_edit_controller.setup.assert_called_once()
|
mocked_view_edit_controller.setup.assert_called_once()
|
||||||
mocked_import_resources_controller.setup.assert_called_once()
|
mocked_import_resources_controller.setup.assert_called_once()
|
||||||
mocked_import_resources_controller.add_import_resources_sender.connect.assert_called_once_with(
|
mocked_import_resources_controller.add_import_resources_sender.connect.assert_called_once_with(
|
||||||
mocked_view_edit_controller.add_import_resources_receiver)
|
mocked_view_edit_controller.add_import_resources_receiver)
|
||||||
|
|
||||||
|
def test_setup_error_controller_setup_gets_invoked(self) -> None:
|
||||||
|
mocked_error_controller: MagicMock = TestControllerManager._mock_error_controller.return_value
|
||||||
|
|
||||||
|
TestControllerManager._expected_controller_manager.setup(True)
|
||||||
|
mocked_error_controller.setup.assert_called_once()
|
||||||
|
|||||||
+7
-1
@@ -45,9 +45,15 @@ class TestThreadManager(TestCase):
|
|||||||
def test_setup_thread_pool_setup_with_expected_configuration(self) -> None:
|
def test_setup_thread_pool_setup_with_expected_configuration(self) -> None:
|
||||||
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
||||||
|
|
||||||
TestThreadManager._expected_thread_manager.setup()
|
TestThreadManager._expected_thread_manager.setup(False)
|
||||||
mocked_thread_pool.setMaxThreadCount.assert_called_once_with(1)
|
mocked_thread_pool.setMaxThreadCount.assert_called_once_with(1)
|
||||||
|
|
||||||
|
def test_setup_thread_pool_skip_setup(self) -> None:
|
||||||
|
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
||||||
|
|
||||||
|
TestThreadManager._expected_thread_manager.setup(True)
|
||||||
|
mocked_thread_pool.setMaxThreadCount.asset_not_called()
|
||||||
|
|
||||||
def test_start_thread_pool_start_expected_worker(self) -> None:
|
def test_start_thread_pool_start_expected_worker(self) -> None:
|
||||||
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
||||||
expected_mocked_worker: MagicMock = MagicMock()
|
expected_mocked_worker: MagicMock = MagicMock()
|
||||||
|
|||||||
+32
-3
@@ -13,13 +13,14 @@ from typing import List
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import (call, MagicMock, patch)
|
from unittest.mock import (call, MagicMock, patch)
|
||||||
|
|
||||||
from manager.view_manager import (ViewManager, ViewManagerConstants)
|
from manager.view_manager import (ERROR_PAGE_INDEX, ViewManager, ViewManagerConstants)
|
||||||
|
|
||||||
|
|
||||||
class TestViewManager(TestCase):
|
class TestViewManager(TestCase):
|
||||||
"""
|
"""
|
||||||
ViewManager unit test cases
|
ViewManager unit test cases
|
||||||
"""
|
"""
|
||||||
|
_mock_error_page: MagicMock
|
||||||
_mock_import_resources_page: MagicMock
|
_mock_import_resources_page: MagicMock
|
||||||
_mock_view_edit_page: MagicMock
|
_mock_view_edit_page: MagicMock
|
||||||
_mock_main_window: MagicMock
|
_mock_main_window: MagicMock
|
||||||
@@ -28,6 +29,9 @@ class TestViewManager(TestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls) -> None:
|
def setUpClass(cls) -> None:
|
||||||
|
error_page_patcher: patch = patch("manager.view_manager.ErrorPage")
|
||||||
|
cls._mock_error_page = error_page_patcher.start()
|
||||||
|
|
||||||
import_resources_page_patcher: patch = patch("manager.view_manager.ImportResourcesPage")
|
import_resources_page_patcher: patch = patch("manager.view_manager.ImportResourcesPage")
|
||||||
cls._mock_import_resources_page = import_resources_page_patcher.start()
|
cls._mock_import_resources_page = import_resources_page_patcher.start()
|
||||||
|
|
||||||
@@ -60,6 +64,15 @@ class TestViewManager(TestCase):
|
|||||||
def test_get_instance_raise_exception(self) -> None:
|
def test_get_instance_raise_exception(self) -> None:
|
||||||
self.assertRaises(Exception, ViewManager)
|
self.assertRaises(Exception, ViewManager)
|
||||||
|
|
||||||
|
def test_get_error_page_return_expected_page(self) -> None:
|
||||||
|
expected_page: MagicMock = TestViewManager._mock_error_page.return_value
|
||||||
|
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||||
|
mocked_stacked_pages.widget.return_value = expected_page
|
||||||
|
|
||||||
|
actual_page: MagicMock = TestViewManager._expected_view_manager.get_error_page()
|
||||||
|
mocked_stacked_pages.widget.assert_called_once_with(ERROR_PAGE_INDEX)
|
||||||
|
assert actual_page == expected_page
|
||||||
|
|
||||||
def test_get_import_resources_page_return_expected_page(self) -> None:
|
def test_get_import_resources_page_return_expected_page(self) -> None:
|
||||||
expected_page: MagicMock = TestViewManager._mock_import_resources_page.return_value
|
expected_page: MagicMock = TestViewManager._mock_import_resources_page.return_value
|
||||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||||
@@ -83,18 +96,34 @@ class TestViewManager(TestCase):
|
|||||||
mocked_import_resources_page: MagicMock = TestViewManager._mock_import_resources_page.return_value
|
mocked_import_resources_page: MagicMock = TestViewManager._mock_import_resources_page.return_value
|
||||||
mocked_view_edit_page: MagicMock = TestViewManager._mock_view_edit_page.return_value
|
mocked_view_edit_page: MagicMock = TestViewManager._mock_view_edit_page.return_value
|
||||||
|
|
||||||
TestViewManager._expected_view_manager.setup()
|
TestViewManager._expected_view_manager.setup(False)
|
||||||
mocked_calls: List[call] = [call(mocked_view_edit_page), call(mocked_import_resources_page)]
|
mocked_calls: List[call] = [call(mocked_view_edit_page), call(mocked_import_resources_page)]
|
||||||
mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls)
|
mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls)
|
||||||
|
|
||||||
|
def test_setup_error_page_only(self) -> None:
|
||||||
|
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||||
|
mocked_error_page: MagicMock = TestViewManager._mock_error_page.return_value
|
||||||
|
|
||||||
|
TestViewManager._expected_view_manager.setup(True)
|
||||||
|
mocked_calls: List[call] = [call(mocked_error_page)]
|
||||||
|
mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls)
|
||||||
|
|
||||||
def test_show_stacked_pages_show_with_expected_index(self) -> None:
|
def test_show_stacked_pages_show_with_expected_index(self) -> None:
|
||||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||||
mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value
|
mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value
|
||||||
|
|
||||||
TestViewManager._expected_view_manager.show()
|
TestViewManager._expected_view_manager.show(False)
|
||||||
mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||||
mocked_main_window.show.assert_called_once()
|
mocked_main_window.show.assert_called_once()
|
||||||
|
|
||||||
|
def test_show_stacked_pages_show_error_plage(self) -> None:
|
||||||
|
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||||
|
mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value
|
||||||
|
|
||||||
|
TestViewManager._expected_view_manager.show(True)
|
||||||
|
mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ERROR_PAGE_INDEX)
|
||||||
|
mocked_main_window.show.assert_called_once()
|
||||||
|
|
||||||
def test_switch_to_view_edit_page_stacked_pages_switch_to_expected_index(self) -> None:
|
def test_switch_to_view_edit_page_stacked_pages_switch_to_expected_index(self) -> None:
|
||||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ class NotificationFrame(QFrame):
|
|||||||
self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
|
self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
|
||||||
|
|
||||||
icon_label: QLabel = QLabel(self)
|
icon_label: QLabel = QLabel(self)
|
||||||
|
icon_label.setObjectName("NotificationIcon")
|
||||||
icon_label.setPixmap(pixmap)
|
icon_label.setPixmap(pixmap)
|
||||||
|
|
||||||
self._title_label: QLabel = QLabel(title, self)
|
self._title_label: QLabel = QLabel(title, self)
|
||||||
self._title_label.setObjectName("Title")
|
self._title_label.setOpenExternalLinks(True)
|
||||||
|
self._title_label.setObjectName("NotificationTitle")
|
||||||
self._title_label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred))
|
self._title_label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred))
|
||||||
self._title_label.setWordWrap(True)
|
self._title_label.setWordWrap(True)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
"""
|
||||||
|
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||||
|
its licensors.
|
||||||
|
|
||||||
|
For complete copyright and license terms please see the LICENSE at the root of this
|
||||||
|
distribution (the "License"). All use of this software is governed by the License,
|
||||||
|
or, if provided, by the license below or the license accompanying this file. Do not
|
||||||
|
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PySide2.QtGui import QPixmap
|
||||||
|
from PySide2.QtWidgets import (QHBoxLayout, QLayout, QPushButton, QSizePolicy, QSpacerItem, QVBoxLayout, QWidget)
|
||||||
|
|
||||||
|
from model import (error_messages, notification_label_text, view_size_constants)
|
||||||
|
from view.common_view_components import NotificationFrame
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorPage(QWidget):
|
||||||
|
"""
|
||||||
|
Error Page
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(0, 0,
|
||||||
|
view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||||
|
view_size_constants.ERROR_PAGE_MAIN_WINDOW_HEIGHT)
|
||||||
|
|
||||||
|
page_vertical_layout: QVBoxLayout = QVBoxLayout(self)
|
||||||
|
page_vertical_layout.setSizeConstraint(QLayout.SetMinimumSize)
|
||||||
|
page_vertical_layout.setMargin(0)
|
||||||
|
|
||||||
|
self._setup_notification_area()
|
||||||
|
page_vertical_layout.addWidget(self._notification_area)
|
||||||
|
|
||||||
|
self._setup_footer_area()
|
||||||
|
page_vertical_layout.addWidget(self._footer_area)
|
||||||
|
|
||||||
|
def _setup_notification_area(self) -> None:
|
||||||
|
self._notification_area: QWidget = QWidget(self)
|
||||||
|
self._notification_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
|
self._notification_area.setMinimumSize(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||||
|
view_size_constants.ERROR_PAGE_NOTIFICATION_AREA_HEIGHT)
|
||||||
|
|
||||||
|
notification_area_layout: QVBoxLayout = QVBoxLayout(self._notification_area)
|
||||||
|
notification_area_layout.setSizeConstraint(QLayout.SetMinimumSize)
|
||||||
|
notification_area_layout.setContentsMargins(
|
||||||
|
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT,
|
||||||
|
view_size_constants.MAIN_PAGE_LAYOUT_MARGIN_TOPBOTTOM,
|
||||||
|
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT, 0)
|
||||||
|
|
||||||
|
notification_frame: NotificationFrame = \
|
||||||
|
NotificationFrame(self, QPixmap(":/error_report_warning.svg"),
|
||||||
|
error_messages.ERROR_PAGE_TOOL_SETUP_ERROR_MESSAGE, False)
|
||||||
|
notification_frame.setObjectName("ErrorPage")
|
||||||
|
notification_frame.setMinimumSize(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||||
|
view_size_constants.ERROR_PAGE_NOTIFICATION_AREA_HEIGHT)
|
||||||
|
notification_frame.setVisible(True)
|
||||||
|
notification_area_layout.addWidget(notification_frame)
|
||||||
|
|
||||||
|
def _setup_footer_area(self) -> None:
|
||||||
|
self._footer_area: QWidget = QWidget(self)
|
||||||
|
self._footer_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
|
self._footer_area.setMaximumSize(view_size_constants.TOOL_APPLICATION_MAIN_WINDOW_WIDTH,
|
||||||
|
view_size_constants.ERROR_PAGE_FOOTER_AREA_HEIGHT)
|
||||||
|
|
||||||
|
footer_area_layout: QHBoxLayout = QHBoxLayout(self._footer_area)
|
||||||
|
footer_area_layout.setSizeConstraint(QLayout.SetMinimumSize)
|
||||||
|
footer_area_layout.setContentsMargins(
|
||||||
|
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT,
|
||||||
|
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM,
|
||||||
|
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT,
|
||||||
|
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM)
|
||||||
|
|
||||||
|
footer_area_spacer: QSpacerItem = QSpacerItem(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||||
|
view_size_constants.INTERACTION_COMPONENT_HEIGHT,
|
||||||
|
QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
|
||||||
|
footer_area_layout.addItem(footer_area_spacer)
|
||||||
|
|
||||||
|
self._ok_button: QPushButton = QPushButton(self._footer_area)
|
||||||
|
self._ok_button.setObjectName("Secondary")
|
||||||
|
self._ok_button.setText(notification_label_text.ERROR_PAGE_OK_TEXT)
|
||||||
|
self._ok_button.setMinimumSize(view_size_constants.OK_BUTTON_WIDTH,
|
||||||
|
view_size_constants.INTERACTION_COMPONENT_HEIGHT)
|
||||||
|
footer_area_layout.addWidget(self._ok_button)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ok_button(self) -> QPushButton:
|
||||||
|
return self._ok_button
|
||||||
Reference in New Issue
Block a user