fix merge conflict

Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com>
This commit is contained in:
sphrose
2021-12-06 16:43:08 +00:00
2432 changed files with 44421 additions and 33300 deletions
+5 -5
View File
@@ -15,9 +15,9 @@ ly_add_target(
awsclientauth_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
Include/Public
Include
PRIVATE
Include/Private
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
@@ -35,7 +35,7 @@ ly_add_target(
awsclientauth_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
@@ -97,8 +97,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
awsclientauth_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
"Include/Private"
"Include/Public"
Source
Include
Tests
BUILD_DEPENDENCIES
PRIVATE
@@ -7,46 +7,43 @@
#
set(FILES
Include/Public/Authentication/AuthenticationProviderBus.h
Include/Public/Authentication/AuthenticationTokens.h
Include/Public/Authorization/AWSCognitoAuthorizationBus.h
Include/Public/Authorization/ClientAuthAWSCredentials.h
Include/Public/UserManagement/AWSCognitoUserManagementBus.h
Include/Authentication/AuthenticationProviderBus.h
Include/Authentication/AuthenticationTokens.h
Include/Authorization/AWSCognitoAuthorizationBus.h
Include/Authorization/ClientAuthAWSCredentials.h
Include/UserManagement/AWSCognitoUserManagementBus.h
Include/Private/AWSClientAuthSystemComponent.h
Include/Private/AWSClientAuthBus.h
Include/Private/AWSClientAuthResourceMappingConstants.h
Include/Private/Authentication/AuthenticationProviderTypes.h
Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h
Include/Private/Authentication/AuthenticationProviderManager.h
Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h
Include/Private/Authorization/AWSCognitoAuthorizationController.h
Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h
Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h
Include/Private/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h
Include/Private/UserManagement/AWSCognitoUserManagementController.h
Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h
Include/Private/Authentication/AuthenticationProviderInterface.h
Include/Private/Authentication/OAuthConstants.h
Include/Private/Authentication/AWSCognitoAuthenticationProvider.h
Include/Private/Authentication/LWAAuthenticationProvider.h
Include/Private/Authentication/GoogleAuthenticationProvider.h
Source/AWSClientAuthSystemComponent.cpp
Source/Authentication/AuthenticationTokens.cpp
Source/Authentication/AuthenticationProviderInterface.cpp
Source/Authentication/AuthenticationProviderManager.cpp
Source/Authentication/AWSCognitoAuthenticationProvider.cpp
Source/Authentication/LWAAuthenticationProvider.cpp
Source/Authentication/GoogleAuthenticationProvider.cpp
Source/AWSClientAuthSystemComponent.h
Source/AWSClientAuthBus.h
Source/AWSClientAuthResourceMappingConstants.h
Source/Authentication/AuthenticationNotificationBusBehaviorHandler.h
Source/Authentication/AuthenticationProviderInterface.cpp
Source/Authentication/AuthenticationProviderInterface.h
Source/Authentication/AuthenticationProviderManager.cpp
Source/Authentication/AuthenticationProviderManager.h
Source/Authentication/AuthenticationProviderScriptCanvasBus.h
Source/Authentication/AuthenticationProviderTypes.h
Source/Authentication/AuthenticationTokens.cpp
Source/Authentication/AWSCognitoAuthenticationProvider.cpp
Source/Authentication/AWSCognitoAuthenticationProvider.h
Source/Authentication/LWAAuthenticationProvider.cpp
Source/Authentication/LWAAuthenticationProvider.h
Source/Authentication/GoogleAuthenticationProvider.cpp
Source/Authentication/GoogleAuthenticationProvider.h
Source/Authentication/OAuthConstants.h
Source/Authorization/ClientAuthAWSCredentials.cpp
Source/Authorization/AWSCognitoAuthorizationController.cpp
Source/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.cpp
Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.cpp
Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h
Source/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.cpp
Source/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h
Source/Authorization/AWSCognitoAuthorizationController.cpp
Source/Authorization/AWSCognitoAuthorizationController.h
Source/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h
Source/Authorization/ClientAuthAWSCredentials.cpp
Source/UserManagement/AWSCognitoUserManagementController.cpp
Source/UserManagement/AWSCognitoUserManagementController.h
Source/UserManagement/UserManagementNotificationBusBehaviorHandler.h
)
@@ -7,6 +7,6 @@
#
set(FILES
Include/Private/AWSClientAuthModule.h
Source/AWSClientAuthModule.cpp
Source/AWSClientAuthModule.h
)
+57 -26
View File
@@ -16,10 +16,10 @@ ly_add_target(
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
Include/Public
Include
${pal_dir}
PRIVATE
Include/Private
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
@@ -36,7 +36,7 @@ ly_add_target(
awscore_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
@@ -60,6 +60,9 @@ ly_create_alias(
)
if (PAL_TRAIT_BUILD_HOST_TOOLS)
include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_traits_editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
ly_add_target(
NAME AWSCore.Editor.Static STATIC
NAMESPACE Gem
@@ -68,10 +71,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_editor_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
Source
${pal_dir}
PUBLIC
Include/Public
Include
BUILD_DEPENDENCIES
PRIVATE
AZ::AzQtComponents
@@ -90,29 +93,38 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
awscore_editor_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
Gem::AWSCore.Editor.Static
)
# This target is not a real gem module
# It is not meant to be loaded by the ModuleManager in C++
ly_add_target(
NAME AWSCore.ResourceMappingTool MODULE
NAMESPACE Gem
OUTPUT_SUBDIRECTORY AWSCoreEditorQtBin
FILES_CMAKE
awscore_resourcemappingtool_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
BUILD_DEPENDENCIES
PRIVATE
Gem::AWSCore.Editor.Static
)
ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool)
if (PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL)
# This target is not a real gem module
# It is not meant to be loaded by the ModuleManager in C++
ly_add_target(
NAME AWSCore.ResourceMappingTool MODULE
NAMESPACE Gem
OUTPUT_SUBDIRECTORY AWSCoreEditorQtBin
FILES_CMAKE
awscore_resourcemappingtool_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
BUILD_DEPENDENCIES
PRIVATE
Gem::AWSCore.Editor.Static
RUNTIME_DEPENDENCIES
3rdParty::pyside2
)
ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool)
ly_install_directory(DIRECTORIES Tools/ResourceMappingTool)
endif()
# Builders and Tools (such as the Editor use AWSCore.Editor) use the .Editor module above.
ly_create_alias(
@@ -144,8 +156,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
awscore_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
Include/Public
Source
Include
Tests
BUILD_DEPENDENCIES
PRIVATE
@@ -154,10 +166,20 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
AZ::AWSNativeSDKInit
Gem::AWSCore.Static
)
ly_add_googletest(
NAME Gem::AWSCore.Tests
)
ly_add_target_files(
TARGETS
AWSCore.Tests
FILES
${CMAKE_CURRENT_SOURCE_DIR}/Tools/ResourceMappingTool/resource_mapping_schema.json
OUTPUT_SUBDIRECTORY
Gems/AWSCore
)
if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME AWSCore.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
@@ -168,9 +190,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_editor_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include/Private
Source
${pal_dir}
Include/Public
Include
Tests
COMPILE_DEFINITIONS
PRIVATE
@@ -189,4 +211,13 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
endif()
endif()
ly_add_target_files(
TARGETS
AWSCore
FILES
${CMAKE_CURRENT_SOURCE_DIR}/Tools/ResourceMappingTool/resource_mapping_schema.json
OUTPUT_SUBDIRECTORY
Gems/AWSCore
)
ly_install_directory(DIRECTORIES Tools/ResourceMappingTool)
@@ -7,4 +7,6 @@
*/
#pragma once
#define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 0
#define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 1
#define AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT ""
#define AWSCORE_EDITOR_PYTHON_COMMAND "python/python.sh"
@@ -0,0 +1,9 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL TRUE)
@@ -8,3 +8,5 @@
#pragma once
#define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 0
#define AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT ""
#define AWSCORE_EDITOR_PYTHON_COMMAND "python/python.sh"
@@ -0,0 +1,9 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL FALSE)
@@ -8,3 +8,5 @@
#pragma once
#define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 1
#define AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT "debug "
#define AWSCORE_EDITOR_PYTHON_COMMAND "python/python.cmd"
@@ -0,0 +1,9 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL TRUE)
@@ -58,7 +58,7 @@ namespace AWSCore
if (m_isDebug)
{
return AZStd::string::format(
"\"%s\" debug -B \"%s\" --binaries-path \"%s\" --debug --profile \"%s\" --config-path \"%s\" --log-path \"%s\"",
"\"%s\" " AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT "-B \"%s\" --binaries-path \"%s\" --debug --profile \"%s\" --config-path \"%s\" --log-path \"%s\"",
m_enginePythonEntryPath.c_str(), m_toolScriptPath.c_str(), m_toolQtBinDirectoryPath.c_str(),
profileName.c_str(), m_toolConfigDirectoryPath.c_str(), m_toolLogDirectoryPath.c_str());
}
@@ -13,6 +13,8 @@
#include <QAction>
#include <QObject>
#include "AWSCoreEditor_Traits_Platform.h"
namespace AWSCore
{
class AWSCoreResourceMappingToolAction
@@ -22,7 +24,7 @@ namespace AWSCore
static constexpr const char AWSCoreResourceMappingToolActionName[] = "AWSCoreResourceMappingToolAction";
static constexpr const char ResourceMappingToolDirectoryPath[] = "Gems/AWSCore/Code/Tools/ResourceMappingTool";
static constexpr const char ResourceMappingToolLogDirectoryPath[] = "user/log/";
static constexpr const char EngineWindowsPythonEntryScriptPath[] = "python/python.cmd";
static constexpr const char EngineWindowsPythonEntryScriptPath[] = AWSCORE_EDITOR_PYTHON_COMMAND;
AWSCoreResourceMappingToolAction(const QString& text, QObject* parent = nullptr);
@@ -0,0 +1,27 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AWSCore
{
static constexpr const char AWSChinaRegionPrefix[] = "cn-";
static constexpr const char AWSFeatureGemRESTApiIdKeyNameSuffix[] = ".RESTApiId";
static constexpr const char AWSFeatureGemRESTApiStageKeyNameSuffix[] = ".RESTApiStage";
static constexpr const char ResourceMappingAccountIdKeyName[] = "AccountId";
static constexpr const char ResourceMappingResourcesKeyName[] = "AWSResourceMappings";
static constexpr const char ResourceMappingNameIdKeyName[] = "Name/ID";
static constexpr const char ResourceMappingRegionKeyName[] = "Region";
static constexpr const char ResourceMappingTypeKeyName[] = "Type";
static constexpr const char ResourceMappingVersionKeyName[] = "Version";
static constexpr const char ResourceMapppingJsonSchemaFilePath[] =
"Gems/AWSCore/resource_mapping_schema.json";
} // namespace AWSCore
@@ -12,6 +12,7 @@
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AWSCoreInternalBus.h>
@@ -244,14 +245,16 @@ namespace AWSCore
bool AWSResourceMappingManager::ValidateJsonDocumentAgainstSchema(const rapidjson::Document& jsonDocument)
{
rapidjson::Document jsonSchemaDocument;
if (jsonSchemaDocument.Parse(ResourceMappingJsonSchema).HasParseError())
AZ::IO::Path executablePath = AZ::IO::PathView(AZ::Utils::GetExecutableDirectory());
AZ::IO::Path jsonSchemaPath = (executablePath / ResourceMapppingJsonSchemaFilePath).LexicallyNormal();
AZ::Outcome<rapidjson::Document, AZStd::string> readJsonOutcome = AZ::JsonSerializationUtils::ReadJsonFile(jsonSchemaPath.c_str());
if (!readJsonOutcome.IsSuccess() || readJsonOutcome.TakeValue().ObjectEmpty())
{
AZ_Error(AWSResourceMappingManagerName, false, ResourceMappingFileInvalidSchemaErrorMessage);
return false;
}
auto jsonSchema = rapidjson::SchemaDocument(jsonSchemaDocument);
auto jsonSchema = rapidjson::SchemaDocument(readJsonOutcome.TakeValue());
rapidjson::SchemaValidator validator(jsonSchema);
if (!jsonDocument.Accept(validator))
@@ -121,7 +121,7 @@ public:
void SetUp() override
{
AWSCoreFixture::SetUp();
AWSCoreFixture::SetUpFixture(false);
m_normalizedSourceProjectFolder = AZStd::string::format("%s/%s%s/", AZ::Test::GetCurrentExecutablePath().c_str(),
"AWSResourceMappingManager", AZ::Uuid::CreateRandom().ToString<AZStd::string>(false, false).c_str());
@@ -142,7 +142,7 @@ public:
m_resourceMappingManager->DeactivateManager();
m_resourceMappingManager.reset();
AWSCoreFixture::TearDown();
AWSCoreFixture::TearDownFixture(false);
}
// AWSCoreInternalRequestBus interface implementation
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
@@ -111,6 +112,11 @@ public:
~AWSCoreFixture() override = default;
void SetUp() override
{
SetUpFixture();
}
void SetUpFixture(bool mockSettingsRegistry = true)
{
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
@@ -120,14 +126,33 @@ public:
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_localFileIO);
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
AZ::SettingsRegistry::Register(m_settingsRegistry.get());
if (mockSettingsRegistry)
{
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
AZ::SettingsRegistry::Register(m_settingsRegistry.get());
}
else
{
m_app = AZStd::make_unique<AZ::ComponentApplication>();
}
}
void TearDown() override
{
AZ::SettingsRegistry::Unregister(m_settingsRegistry.get());
m_settingsRegistry.reset();
TearDownFixture();
}
void TearDownFixture(bool mockSettingsRegistry = true)
{
if (mockSettingsRegistry)
{
AZ::SettingsRegistry::Unregister(m_settingsRegistry.get());
m_settingsRegistry.reset();
}
else
{
m_app.reset();
}
AZ::IO::FileIOBase::SetInstance(nullptr);
@@ -173,4 +198,5 @@ private:
protected:
AZStd::unique_ptr<AZ::SettingsRegistryImpl> m_settingsRegistry;
AZStd::unique_ptr<AZ::ComponentApplication> m_app;
};
@@ -39,6 +39,16 @@ Follow cmake instructions to configure your project, for example:
```
$ python\python.cmd debug Gems\AWSCore\Code\Tools\ResourceMappingTool\resource_mapping_tool.py --binaries_path <PATH_TO_BUILD_FOLDER>\bin\debug\AWSCoreEditorQtBin
```
* Linux
* release mode
```
$ python/python.sh Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py --binaries_path <PATH_TO_BUILD_FOLDER>/bin/profile/AWSCoreEditorQtBin
```
* debug mode
```
$ python/python.sh Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py --binaries_path <PATH_TO_BUILD_FOLDER>/bin/debug/AWSCoreEditorQtBin
```
* Note - Editor is integrated with the same engine python environment to launch Resource Mapping Tool. If it is failed to launch the tool
in Editor, please follow above steps to make sure expected scripts/binaries are present.
@@ -1,42 +1,16 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AWSCore
{
static constexpr const char AWSChinaRegionPrefix[] = "cn-";
static constexpr const char AWSFeatureGemRESTApiIdKeyNameSuffix[] = ".RESTApiId";
static constexpr const char AWSFeatureGemRESTApiStageKeyNameSuffix[] = ".RESTApiStage";
static constexpr const char ResourceMappingAccountIdKeyName[] = "AccountId";
static constexpr const char ResourceMappingResourcesKeyName[] = "AWSResourceMappings";
static constexpr const char ResourceMappingNameIdKeyName[] = "Name/ID";
static constexpr const char ResourceMappingRegionKeyName[] = "Region";
static constexpr const char ResourceMappingTypeKeyName[] = "Type";
static constexpr const char ResourceMappingVersionKeyName[] = "Version";
// TODO: move this into an independent file under AWSCore gem, if resource mapping tool can reuse it
static constexpr const char ResourceMappingJsonSchema[] =
R"({
"$schema": "http://json-schema.org/draft-04/schema",
"type": "object",
"title": "The AWS Resource Mapping Root schema",
"title": "O3DE AWS Resource mapping file schema",
"required": ["AWSResourceMappings", "AccountId", "Region", "Version"],
"properties": {
"AWSResourceMappings": {
"type": "object",
"title": "The AWSResourceMappings schema",
"title": "AWS resource mappings schema",
"patternProperties": {
"^.+$": {
"type": "object",
"title": "The AWS Resource Entry schema",
"title": "AWS resource entry schema",
"required": ["Type", "Name/ID"],
"properties": {
"Type": {
@@ -79,6 +53,4 @@ namespace AWSCore
"pattern": "^[a-z]{2}-[a-z]{4,9}-[0-9]{1}$"
},
"additionalProperties": false
})";
} // namespace AWSCore
}
@@ -10,6 +10,7 @@ import logging
import sys
from utils import environment_utils
from utils import json_utils
from utils import file_utils
# arguments setup
@@ -20,6 +21,7 @@ argument_parser.add_argument('--debug', action='store_true', help='Execute on de
argument_parser.add_argument('--log-path', help='Path to resource mapping tool logging directory '
'(if not provided, logging file will be located at tool directory)')
argument_parser.add_argument('--profile', default='default', help='Named AWS profile to use for querying AWS resources')
arguments: Namespace = argument_parser.parse_args()
# logging setup
@@ -74,6 +76,15 @@ if __name__ == "__main__":
except FileNotFoundError:
logger.warning("Failed to load style sheet for resource mapping tool")
try:
schema_path: str = file_utils.join_path(file_utils.get_parent_directory_path(__file__),
'resource_mapping_schema.json')
json_utils.load_resource_mapping_json_schema(schema_path)
except (FileNotFoundError, ValueError, KeyError) as e:
logger.error(f"Failed to load schema file {e}")
environment_utils.cleanup_qt_environment()
exit(-1)
logger.info("Initializing configuration manager ...")
configuration_manager: ConfigurationManager = ConfigurationManager()
configuration_error: bool = not configuration_manager.setup(arguments.profile, arguments.config_path)
@@ -5,6 +5,7 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import platform
from typing import List
from unittest import TestCase
from unittest.mock import (ANY, call, MagicMock, patch)
@@ -27,14 +28,24 @@ class TestEnvironmentUtils(TestCase):
self.addCleanup(os_pathsep_patcher.stop)
self._mock_os_pathsep: MagicMock = os_pathsep_patcher.start()
def test_setup_qt_environment_global_flag_is_set(self) -> None:
@patch('os.path.exists')
@patch('ctypes.CDLL')
def test_setup_qt_environment_global_flag_is_set(self, mock_os_path_exists, mock_ctype_cdll) -> None:
mock_os_path_exists.return_value = True
environment_utils.setup_qt_environment("dummy")
self._mock_os_environ.copy.assert_called_once()
self._mock_os_pathsep.join.assert_called_once()
assert environment_utils.is_qt_linked() is True
if platform.system() == 'Linux':
mock_os_path_exists.assert_called()
def test_cleanup_qt_environment_global_flag_is_set(self) -> None:
@patch('os.path.exists')
@patch('ctypes.CDLL')
def test_cleanup_qt_environment_global_flag_is_set(self, mock_os_path_exists, mock_ctype_cdll) -> None:
mock_os_path_exists.return_value = True
environment_utils.setup_qt_environment("dummy")
assert environment_utils.is_qt_linked() is True
environment_utils.cleanup_qt_environment()
assert environment_utils.is_qt_linked() is False
if platform.system() == 'Linux':
mock_os_path_exists.assert_called()
@@ -68,12 +68,65 @@ class TestFileUtils(TestCase):
self._mock_path.cwd.assert_called_once()
assert actual_path_name == TestFileUtils._expected_path_name
def test_get_parent_directory_path_return_expected_path_name(self) -> None:
self._mock_path.return_value.parent = TestFileUtils._expected_path_name
def test_get_parent_directory_path_return_empty_when_invalid_input(self) -> None:
mocked_path: MagicMock = self._mock_path.return_value
mocked_path.exists.return_value = False
actual_path_name: str = file_utils.get_parent_directory_path("dummy")
self._mock_path.assert_called_once()
assert actual_path_name == TestFileUtils._expected_path_name
assert actual_path_name == ""
def test_get_parent_directory_path_return_empty_when_parent_invalid(self) -> None:
mocked_path: MagicMock = self._mock_path.return_value
mocked_path.exists.return_value = True
mocked_parent_path: MagicMock = MagicMock()
mocked_path.parent = mocked_parent_path
mocked_parent_path.exists.return_value = False
actual_path_name: str = file_utils.get_parent_directory_path("dummy")
self._mock_path.assert_called()
assert actual_path_name == ""
def test_get_parent_directory_path_return_expected_path_when_parent_valid(self) -> None:
mocked_path: MagicMock = self._mock_path.return_value
mocked_path.exists.return_value = True
mocked_parent_path: MagicMock = MagicMock()
mocked_path.parent = mocked_parent_path
mocked_parent_path.exists.return_value = True
mocked_parent_path.resolve.return_value = TestFileUtils._expected_file_name
actual_path_name: str = file_utils.get_parent_directory_path("dummy")
self._mock_path.assert_called()
assert actual_path_name == TestFileUtils._expected_file_name
def test_get_parent_directory_path_return_empty_when_level_two_parent_invalid(self) -> None:
mocked_path: MagicMock = self._mock_path.return_value
mocked_path.exists.return_value = True
mocked_parent_path1: MagicMock = MagicMock()
mocked_path.parent = mocked_parent_path1
mocked_parent_path1.exists.return_value = True
mocked_parent_path2: MagicMock = MagicMock()
mocked_parent_path1.parent = mocked_parent_path2
mocked_parent_path2.exists.return_value = False
actual_path_name: str = file_utils.get_parent_directory_path("dummy", 2)
self._mock_path.assert_called()
assert actual_path_name == ""
def test_get_parent_directory_path_return_expected_path_when_level_two_parent_valid(self) -> None:
mocked_path: MagicMock = self._mock_path.return_value
mocked_path.exists.return_value = True
mocked_parent_path1: MagicMock = MagicMock()
mocked_path.parent = mocked_parent_path1
mocked_parent_path1.exists.return_value = True
mocked_parent_path2: MagicMock = MagicMock()
mocked_parent_path1.parent = mocked_parent_path2
mocked_parent_path2.exists.return_value = True
mocked_parent_path2.resolve.return_value = TestFileUtils._expected_file_name
actual_path_name: str = file_utils.get_parent_directory_path("dummy", 2)
self._mock_path.assert_called()
assert actual_path_name == TestFileUtils._expected_file_name
def test_find_files_with_suffix_under_directory_return_expected_file_name(self) -> None:
mocked_path: MagicMock = self._mock_path.return_value
@@ -10,6 +10,7 @@ from typing import (Dict, List)
from unittest import TestCase
from unittest.mock import (MagicMock, mock_open, patch)
from utils import file_utils
from utils import json_utils
from model import constants
from model.resource_mapping_attributes import (ResourceMappingAttributes, ResourceMappingAttributesBuilder,
@@ -49,6 +50,10 @@ class TestJsonUtils(TestCase):
}
def setUp(self) -> None:
schema_path: str = file_utils.join_path(file_utils.get_parent_directory_path(__file__, 4),
'resource_mapping_schema.json')
json_utils.load_resource_mapping_json_schema(schema_path)
self._mock_open = mock_open()
open_patcher: patch = patch("utils.json_utils.open", self._mock_open)
self.addCleanup(open_patcher.stop)
@@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
import logging
import os
import platform
from typing import Dict
from utils import file_utils
@@ -38,6 +39,20 @@ def setup_qt_environment(bin_path: str) -> None:
new_path = os.pathsep.join([binaries_path, path])
os.environ['PATH'] = new_path
# On Linux, we need to load pyside2 and related modules as well
if platform.system() == 'Linux':
import ctypes
preload_shared_libs = [f'{bin_path}/libpyside2.abi3.so.5.14',
f'{bin_path}/libQt5Widgets.so.5']
for preload_shared_lib in preload_shared_libs:
if not os.path.exists(preload_shared_lib):
logger.error(f"Cannot find required shared library at {preload_shared_lib}")
return
else:
ctypes.CDLL(preload_shared_lib)
global qt_binaries_linked
qt_binaries_linked = True
@@ -33,8 +33,29 @@ def get_current_directory_path() -> str:
return str(pathlib.Path.cwd())
def get_parent_directory_path(file_path: str) -> str:
return pathlib.Path(file_path).parent
def get_parent_directory_path(file_path: str, level: int = 1) -> str:
"""
Get parent directory path based on requested file path
:param file_path: The requested file path
:param level: The level of parent directory, default value is 1
:return The string value of parent directory path if exist; otherwise empty string
"""
if not pathlib.Path(file_path).exists():
return ""
result: pathlib.Path = pathlib.Path(file_path).parent
current_level: int = 1
while current_level < level:
current_level += 1
if result.exists():
result = result.parent
else:
return ""
if not result.exists():
return ""
else:
return result.resolve()
def find_files_with_suffix_under_directory(dir_path: str, suffix: str) -> List[str]:
@@ -19,18 +19,29 @@ Json Utils provide related functions to read/write/serialize/deserialize json fo
"""
logger = logging.getLogger(__name__)
# resource mapping json content constants
_RESOURCE_MAPPING_JSON_KEY_NAME: str = "AWSResourceMappings"
_RESOURCE_MAPPING_TYPE_JSON_KEY_NAME: str = "Type"
_RESOURCE_MAPPING_NAMEID_JSON_KEY_NAME: str = "Name/ID"
_RESOURCE_MAPPING_REGION_JSON_KEY_NAME: str = "Region"
_RESOURCE_MAPPING_VERSION_JSON_KEY_NAME: str = "Version"
_RESOURCE_MAPPING_JSON_FORMAT_VERSION: str = "1.1.0"
RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME: str = "AccountId"
RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE: str = "EMPTY"
_RESOURCE_MAPPING_ACCOUNTID_PATTERN: str = f"^[0-9]{{12}}$|{RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE}|^$"
_RESOURCE_MAPPING_REGION_PATTERN: str = "^[a-z]{2}-[a-z]{4,9}-[0-9]{1}$"
_RESOURCE_MAPPING_VERSION_PATTERN: str = "^[0-9]{1}.[0-9]{1}.[0-9]{1}$"
# resource mapping json schema constants
_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_KEY_NAME: str = "AccountIdString"
_RESOURCE_MAPPING_SCHEMA_REGION_KEY_NAME: str = "RegionString"
_RESOURCE_MAPPING_SCHEMA_REQUIRED_PROPERTIES_KEY_NAME: str = "required"
_RESOURCE_MAPPING_SCHEMA_PROPERTIES_KEY_NAME: str = "properties"
_RESOURCE_MAPPING_SCHEMA_PATTERN_PROPERTIES_KEY_NAME: str = "patternProperties"
_RESOURCE_MAPPING_SCHEMA_PROPERTY_PATTERN_KEY_NAME: str = "pattern"
_RESOURCE_MAPPING_SCHEMA: Dict[str, any] = {}
_RESOURCE_MAPPING_SCHEMA_REQUIRED_ROOT_PROPERTIES: List[str] = []
_RESOURCE_MAPPING_SCHEMA_REQUIRED_RESOURCE_PROPERTIES: List[str] = []
_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN: str = ""
_RESOURCE_MAPPING_SCHEMA_REGION_PATTERN: str = ""
_RESOURCE_MAPPING_SCHEMA_VERSION_PATTERN: str = ""
def _add_validation_error_message(errors: Dict[int, List[str]], row: int, error_message: str) -> None:
if row in errors.keys():
@@ -119,6 +130,26 @@ def convert_json_dict_to_resources(json_dict: Dict[str, any]) -> List[ResourceMa
return resources
def load_resource_mapping_json_schema(schema_path: str) -> None:
global _RESOURCE_MAPPING_SCHEMA, _RESOURCE_MAPPING_SCHEMA_REQUIRED_ROOT_PROPERTIES, _RESOURCE_MAPPING_SCHEMA_REQUIRED_RESOURCE_PROPERTIES,\
_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN, _RESOURCE_MAPPING_SCHEMA_REGION_PATTERN, _RESOURCE_MAPPING_SCHEMA_VERSION_PATTERN
if not _RESOURCE_MAPPING_SCHEMA:
# assume schema should be in correct format, and manually load expected pattern; tool will log error if schema is invalid
_RESOURCE_MAPPING_SCHEMA = read_from_json_file(schema_path)
_RESOURCE_MAPPING_SCHEMA_REQUIRED_ROOT_PROPERTIES = _RESOURCE_MAPPING_SCHEMA[_RESOURCE_MAPPING_SCHEMA_REQUIRED_PROPERTIES_KEY_NAME]
schema_properties: Dict[str, any] = _RESOURCE_MAPPING_SCHEMA[_RESOURCE_MAPPING_SCHEMA_PROPERTIES_KEY_NAME]
schema_pattern_properties: Dict[str, any] = \
schema_properties[_RESOURCE_MAPPING_JSON_KEY_NAME][_RESOURCE_MAPPING_SCHEMA_PATTERN_PROPERTIES_KEY_NAME]
_RESOURCE_MAPPING_SCHEMA_REQUIRED_RESOURCE_PROPERTIES = list(schema_pattern_properties.values())[0][_RESOURCE_MAPPING_SCHEMA_REQUIRED_PROPERTIES_KEY_NAME]
_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN = \
_RESOURCE_MAPPING_SCHEMA[_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_KEY_NAME][_RESOURCE_MAPPING_SCHEMA_PROPERTY_PATTERN_KEY_NAME]
_RESOURCE_MAPPING_SCHEMA_REGION_PATTERN = \
_RESOURCE_MAPPING_SCHEMA[_RESOURCE_MAPPING_SCHEMA_REGION_KEY_NAME][_RESOURCE_MAPPING_SCHEMA_PROPERTY_PATTERN_KEY_NAME]
_RESOURCE_MAPPING_SCHEMA_VERSION_PATTERN = \
schema_properties[_RESOURCE_MAPPING_VERSION_JSON_KEY_NAME][_RESOURCE_MAPPING_SCHEMA_PROPERTY_PATTERN_KEY_NAME]
def read_from_json_file(file_name: str) -> Dict[str, any]:
try:
json_dict: Dict[str, any] = {}
@@ -166,20 +197,20 @@ def validate_resources_according_to_json_schema(resources: List[ResourceMappingA
invalid_resources, row_count,
error_messages.INVALID_FORMAT_DUPLICATED_KEY_ERROR_MESSAGE.format(resource.key_name))
if not re.match(_RESOURCE_MAPPING_ACCOUNTID_PATTERN, resource.account_id):
if not re.match(_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN, resource.account_id):
_add_validation_error_message(
invalid_resources, row_count,
error_messages.INVALID_FORMAT_UNEXPECTED_VALUE_IN_TABLE_ERROR_MESSAGE.format(
resource.account_id,
RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME,
_RESOURCE_MAPPING_ACCOUNTID_PATTERN))
_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN))
if not re.match(_RESOURCE_MAPPING_REGION_PATTERN, resource.region):
if not re.match(_RESOURCE_MAPPING_SCHEMA_REGION_PATTERN, resource.region):
_add_validation_error_message(
invalid_resources, row_count,
error_messages.INVALID_FORMAT_UNEXPECTED_VALUE_IN_TABLE_ERROR_MESSAGE.format(
resource.region, _RESOURCE_MAPPING_REGION_JSON_KEY_NAME,
_RESOURCE_MAPPING_REGION_PATTERN))
_RESOURCE_MAPPING_SCHEMA_REGION_PATTERN))
row_count += 1
@@ -187,30 +218,32 @@ def validate_resources_according_to_json_schema(resources: List[ResourceMappingA
def validate_json_dict_according_to_json_schema(json_dict: Dict[str, any]) -> None:
_validate_required_key_in_json_dict(json_dict, "root", _RESOURCE_MAPPING_VERSION_JSON_KEY_NAME)
_validate_required_key_in_json_dict(json_dict, "root", _RESOURCE_MAPPING_JSON_KEY_NAME)
# The reason we keep this manual json schema validation is python missing supportive feature in default libs
# When it is ready, we should be able to replace this with straightforward lib function call
root_property: str
for root_property in _RESOURCE_MAPPING_SCHEMA_REQUIRED_ROOT_PROPERTIES:
_validate_required_key_in_json_dict(json_dict, "root", root_property)
_validate_required_key_in_json_dict(json_dict, "root", RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME)
if not re.match(_RESOURCE_MAPPING_ACCOUNTID_PATTERN, json_dict[RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME]):
if not re.match(_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN, json_dict[RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME]):
raise ValueError(error_messages.INVALID_FORMAT_UNEXPECTED_VALUE_IN_FILE_ERROR_MESSAGE.format(
json_dict[RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME],
f"root/{RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME}",
_RESOURCE_MAPPING_ACCOUNTID_PATTERN))
_RESOURCE_MAPPING_SCHEMA_ACCOUNTID_PATTERN))
_validate_required_key_in_json_dict(json_dict, "root", _RESOURCE_MAPPING_REGION_JSON_KEY_NAME)
if not re.match(_RESOURCE_MAPPING_REGION_PATTERN, json_dict[_RESOURCE_MAPPING_REGION_JSON_KEY_NAME]):
if not re.match(_RESOURCE_MAPPING_SCHEMA_REGION_PATTERN, json_dict[_RESOURCE_MAPPING_REGION_JSON_KEY_NAME]):
raise ValueError(error_messages.INVALID_FORMAT_UNEXPECTED_VALUE_IN_FILE_ERROR_MESSAGE.format(
json_dict[_RESOURCE_MAPPING_REGION_JSON_KEY_NAME],
f"root/{_RESOURCE_MAPPING_REGION_JSON_KEY_NAME}",
_RESOURCE_MAPPING_REGION_PATTERN))
_RESOURCE_MAPPING_SCHEMA_REGION_PATTERN))
json_resources: Dict[str, any] = json_dict[_RESOURCE_MAPPING_JSON_KEY_NAME]
if json_resources:
resource_key: str
resource_value: Dict[str, str]
for resource_key, resource_value in json_resources.items():
_validate_required_key_in_json_dict(resource_value, resource_key, _RESOURCE_MAPPING_TYPE_JSON_KEY_NAME)
_validate_required_key_in_json_dict(resource_value, resource_key, _RESOURCE_MAPPING_NAMEID_JSON_KEY_NAME)
resource_property: str
for resource_property in _RESOURCE_MAPPING_SCHEMA_REQUIRED_RESOURCE_PROPERTIES:
_validate_required_key_in_json_dict(resource_value, resource_key, resource_property)
def write_into_json_file(file_name: str, json_dict: Dict[str, any]) -> None:

Some files were not shown because too many files have changed in this diff Show More