Merge branch 'development' into Atom/jromnoa/fix-asset-path-calls-to-use-new-asset-test-class
This commit is contained in:
@@ -20,19 +20,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main_Optimized
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 600
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Sandbox
|
||||
TEST_SUITE sandbox
|
||||
|
||||
@@ -4,252 +4,95 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
from Atom.atom_utils.atom_constants import LIGHT_TYPES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
"""Holds tests for Atom components."""
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
@pytest.mark.test_case_id("C32078118") # Decal
|
||||
@pytest.mark.test_case_id("C32078119") # DepthOfField
|
||||
@pytest.mark.test_case_id("C32078120") # Directional Light
|
||||
@pytest.mark.test_case_id("C32078121") # Exposure Control
|
||||
@pytest.mark.test_case_id("C32078115") # Global Skylight (IBL)
|
||||
@pytest.mark.test_case_id("C32078125") # Physical Sky
|
||||
@pytest.mark.test_case_id("C32078127") # PostFX Layer
|
||||
@pytest.mark.test_case_id("C32078131") # PostFX Radius Weight Modifier
|
||||
@pytest.mark.test_case_id("C32078117") # Light
|
||||
@pytest.mark.test_case_id("C36525660") # Display Mapper
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the Atom components & verifies all "expected_lines" appear in Editor.log
|
||||
"""
|
||||
cfg_args = [level]
|
||||
@pytest.mark.test_case_id("C36525657")
|
||||
class AtomEditorComponents_BloomAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_BloomAdded as test_module
|
||||
|
||||
expected_lines = [
|
||||
# Decal Component
|
||||
"Decal Entity successfully created",
|
||||
"Decal_test: Component added to the entity: True",
|
||||
"Decal_test: Component removed after UNDO: True",
|
||||
"Decal_test: Component added after REDO: True",
|
||||
"Decal_test: Entered game mode: True",
|
||||
"Decal_test: Exit game mode: True",
|
||||
"Decal Controller|Configuration|Material: SUCCESS",
|
||||
"Decal_test: Entity is hidden: True",
|
||||
"Decal_test: Entity is shown: True",
|
||||
"Decal_test: Entity deleted: True",
|
||||
"Decal_test: UNDO entity deletion works: True",
|
||||
"Decal_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
"DepthOfField_test: Component removed after UNDO: True",
|
||||
"DepthOfField_test: Component added after REDO: True",
|
||||
"DepthOfField_test: Entered game mode: True",
|
||||
"DepthOfField_test: Exit game mode: True",
|
||||
"DepthOfField_test: Entity disabled initially: True",
|
||||
"DepthOfField_test: Entity enabled after adding required components: True",
|
||||
"DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
|
||||
"DepthOfField_test: Entity is hidden: True",
|
||||
"DepthOfField_test: Entity is shown: True",
|
||||
"DepthOfField_test: Entity deleted: True",
|
||||
"DepthOfField_test: UNDO entity deletion works: True",
|
||||
"DepthOfField_test: REDO entity deletion works: True",
|
||||
# Directional Light Component
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light_test: Component added to the entity: True",
|
||||
"Directional Light_test: Component removed after UNDO: True",
|
||||
"Directional Light_test: Component added after REDO: True",
|
||||
"Directional Light_test: Entered game mode: True",
|
||||
"Directional Light_test: Exit game mode: True",
|
||||
"Directional Light_test: Entity is hidden: True",
|
||||
"Directional Light_test: Entity is shown: True",
|
||||
"Directional Light_test: Entity deleted: True",
|
||||
"Directional Light_test: UNDO entity deletion works: True",
|
||||
"Directional Light_test: REDO entity deletion works: True",
|
||||
# Exposure Control Component
|
||||
"Exposure Control Entity successfully created",
|
||||
"Exposure Control_test: Component added to the entity: True",
|
||||
"Exposure Control_test: Component removed after UNDO: True",
|
||||
"Exposure Control_test: Component added after REDO: True",
|
||||
"Exposure Control_test: Entered game mode: True",
|
||||
"Exposure Control_test: Exit game mode: True",
|
||||
"Exposure Control_test: Entity disabled initially: True",
|
||||
"Exposure Control_test: Entity enabled after adding required components: True",
|
||||
"Exposure Control_test: Entity is hidden: True",
|
||||
"Exposure Control_test: Entity is shown: True",
|
||||
"Exposure Control_test: Entity deleted: True",
|
||||
"Exposure Control_test: UNDO entity deletion works: True",
|
||||
"Exposure Control_test: REDO entity deletion works: True",
|
||||
# Global Skylight (IBL) Component
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL)_test: Component added to the entity: True",
|
||||
"Global Skylight (IBL)_test: Component removed after UNDO: True",
|
||||
"Global Skylight (IBL)_test: Component added after REDO: True",
|
||||
"Global Skylight (IBL)_test: Entered game mode: True",
|
||||
"Global Skylight (IBL)_test: Exit game mode: True",
|
||||
"Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
|
||||
"Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
|
||||
"Global Skylight (IBL)_test: Entity is hidden: True",
|
||||
"Global Skylight (IBL)_test: Entity is shown: True",
|
||||
"Global Skylight (IBL)_test: Entity deleted: True",
|
||||
"Global Skylight (IBL)_test: UNDO entity deletion works: True",
|
||||
"Global Skylight (IBL)_test: REDO entity deletion works: True",
|
||||
# Physical Sky Component
|
||||
"Physical Sky Entity successfully created",
|
||||
"Physical Sky component was added to entity",
|
||||
"Entity has a Physical Sky component",
|
||||
"Physical Sky_test: Component added to the entity: True",
|
||||
"Physical Sky_test: Component removed after UNDO: True",
|
||||
"Physical Sky_test: Component added after REDO: True",
|
||||
"Physical Sky_test: Entered game mode: True",
|
||||
"Physical Sky_test: Exit game mode: True",
|
||||
"Physical Sky_test: Entity is hidden: True",
|
||||
"Physical Sky_test: Entity is shown: True",
|
||||
"Physical Sky_test: Entity deleted: True",
|
||||
"Physical Sky_test: UNDO entity deletion works: True",
|
||||
"Physical Sky_test: REDO entity deletion works: True",
|
||||
# PostFX Layer Component
|
||||
"PostFX Layer Entity successfully created",
|
||||
"PostFX Layer_test: Component added to the entity: True",
|
||||
"PostFX Layer_test: Component removed after UNDO: True",
|
||||
"PostFX Layer_test: Component added after REDO: True",
|
||||
"PostFX Layer_test: Entered game mode: True",
|
||||
"PostFX Layer_test: Exit game mode: True",
|
||||
"PostFX Layer_test: Entity is hidden: True",
|
||||
"PostFX Layer_test: Entity is shown: True",
|
||||
"PostFX Layer_test: Entity deleted: True",
|
||||
"PostFX Layer_test: UNDO entity deletion works: True",
|
||||
"PostFX Layer_test: REDO entity deletion works: True",
|
||||
# PostFX Radius Weight Modifier Component
|
||||
"PostFX Radius Weight Modifier Entity successfully created",
|
||||
"PostFX Radius Weight Modifier_test: Component added to the entity: True",
|
||||
"PostFX Radius Weight Modifier_test: Component removed after UNDO: True",
|
||||
"PostFX Radius Weight Modifier_test: Component added after REDO: True",
|
||||
"PostFX Radius Weight Modifier_test: Entered game mode: True",
|
||||
"PostFX Radius Weight Modifier_test: Exit game mode: True",
|
||||
"PostFX Radius Weight Modifier_test: Entity is hidden: True",
|
||||
"PostFX Radius Weight Modifier_test: Entity is shown: True",
|
||||
"PostFX Radius Weight Modifier_test: Entity deleted: True",
|
||||
"PostFX Radius Weight Modifier_test: UNDO entity deletion works: True",
|
||||
"PostFX Radius Weight Modifier_test: REDO entity deletion works: True",
|
||||
# Light Component
|
||||
"Light Entity successfully created",
|
||||
"Light_test: Component added to the entity: True",
|
||||
"Light_test: Component removed after UNDO: True",
|
||||
"Light_test: Component added after REDO: True",
|
||||
"Light_test: Entered game mode: True",
|
||||
"Light_test: Exit game mode: True",
|
||||
"Light_test: Entity is hidden: True",
|
||||
"Light_test: Entity is shown: True",
|
||||
"Light_test: Entity deleted: True",
|
||||
"Light_test: UNDO entity deletion works: True",
|
||||
"Light_test: REDO entity deletion works: True",
|
||||
# Display Mapper Component
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper_test: Component added to the entity: True",
|
||||
"Display Mapper_test: Component removed after UNDO: True",
|
||||
"Display Mapper_test: Component added after REDO: True",
|
||||
"Display Mapper_test: Entered game mode: True",
|
||||
"Display Mapper_test: Exit game mode: True",
|
||||
"Display Mapper_test: Entity is hidden: True",
|
||||
"Display Mapper_test: Entity is shown: True",
|
||||
"Display Mapper_test: Entity deleted: True",
|
||||
"Display Mapper_test: UNDO entity deletion works: True",
|
||||
"Display Mapper_test: REDO entity deletion works: True",
|
||||
]
|
||||
@pytest.mark.test_case_id("C32078118")
|
||||
class AtomEditorComponents_DecalAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
|
||||
|
||||
unexpected_lines = [
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
@pytest.mark.test_case_id("C36525658")
|
||||
class AtomEditorComponents_DeferredFogAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DeferredFogAdded as test_module
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
@pytest.mark.test_case_id("C32078119")
|
||||
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
def test_AtomEditorComponents_LightComponent(
|
||||
self, request, editor, workspace, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests that the Light component has the expected property options available to it.
|
||||
"""
|
||||
cfg_args = [level]
|
||||
@pytest.mark.test_case_id("C32078120")
|
||||
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
|
||||
|
||||
expected_lines = [
|
||||
"light_entity Entity successfully created",
|
||||
"Entity has a Light component",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
|
||||
"Controller|Configuration|Shadows|Enable shadow set to True",
|
||||
"light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 4",
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 64",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 50.0",
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 5000.0",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
|
||||
"light_entity Controller|Configuration|Fast approximation: SUCCESS",
|
||||
"light_entity Controller|Configuration|Both directions: SUCCESS",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
|
||||
f"which matches {LIGHT_TYPES['simple_point']}",
|
||||
"Controller|Configuration|Attenuation radius|Mode set to 0",
|
||||
"Controller|Configuration|Attenuation radius|Radius set to 100.0",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
|
||||
f"which matches {LIGHT_TYPES['simple_spot']}",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 45.0",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 90.0",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
"Light component test (non-GPU) completed.",
|
||||
]
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
|
||||
|
||||
unexpected_lines = [
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
@pytest.mark.test_case_id("C32078121")
|
||||
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_LightComponent.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
@pytest.mark.test_case_id("C32078115")
|
||||
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078122")
|
||||
class AtomEditorComponents_GridAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525671")
|
||||
class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078117")
|
||||
class AtomEditorComponents_LightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078123")
|
||||
class AtomEditorComponents_MaterialAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078124")
|
||||
class AtomEditorComponents_MeshAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525663")
|
||||
class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078125")
|
||||
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525664")
|
||||
class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078127")
|
||||
class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078131")
|
||||
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import (
|
||||
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
|
||||
|
||||
@pytest.mark.test_case_id("C36525665")
|
||||
class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078128")
|
||||
class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
|
||||
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
@pytest.mark.test_case_id("C32078118")
|
||||
class AtomEditorComponents_DecalAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078119")
|
||||
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078120")
|
||||
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078121")
|
||||
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078115")
|
||||
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078122")
|
||||
class AtomEditorComponents_GridAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525671")
|
||||
class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078117")
|
||||
class AtomEditorComponents_LightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078123")
|
||||
class AtomEditorComponents_MaterialAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078124")
|
||||
class AtomEditorComponents_MeshAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525663")
|
||||
class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078125")
|
||||
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525664")
|
||||
class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078127")
|
||||
class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078131")
|
||||
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import (
|
||||
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
|
||||
|
||||
@pytest.mark.test_case_id("C36525665")
|
||||
class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078128")
|
||||
class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
|
||||
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
@@ -9,63 +9,84 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
|
||||
from Atom.atom_utils.atom_constants import LIGHT_TYPES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
|
||||
|
||||
class TestAtomEditorComponentsSandbox(object):
|
||||
|
||||
# It requires at least one test
|
||||
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
"""Holds tests for Atom components."""
|
||||
|
||||
@pytest.mark.test_case_id("C32078128")
|
||||
def test_AtomEditorComponents_ReflectionProbeAddedToEntity(
|
||||
self, request, editor, level, workspace, project, launcher_platform):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the following Atom components and verifies all "expected_lines" appear in Editor.log:
|
||||
1. Reflection Probe
|
||||
"""
|
||||
cfg_args = [level]
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
"""Holds tests for Atom components."""
|
||||
|
||||
expected_lines = [
|
||||
# Reflection Probe Component
|
||||
"Reflection Probe Entity successfully created",
|
||||
"Reflection Probe_test: Component added to the entity: True",
|
||||
"Reflection Probe_test: Component removed after UNDO: True",
|
||||
"Reflection Probe_test: Component added after REDO: True",
|
||||
"Reflection Probe_test: Entered game mode: True",
|
||||
"Reflection Probe_test: Exit game mode: True",
|
||||
"Reflection Probe_test: Entity disabled initially: True",
|
||||
"Reflection Probe_test: Entity enabled after adding required components: True",
|
||||
"Reflection Probe_test: Cubemap is generated: True",
|
||||
"Reflection Probe_test: Entity is hidden: True",
|
||||
"Reflection Probe_test: Entity is shown: True",
|
||||
"Reflection Probe_test: Entity deleted: True",
|
||||
"Reflection Probe_test: UNDO entity deletion works: True",
|
||||
"Reflection Probe_test: REDO entity deletion works: True",
|
||||
]
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
def test_AtomEditorComponents_LightComponent(
|
||||
self, request, editor, workspace, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests that the Light component has the expected property options available to it.
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
"light_entity Entity successfully created",
|
||||
"Entity has a Light component",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
|
||||
"Controller|Configuration|Shadows|Enable shadow set to True",
|
||||
"light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 4",
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 64",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 50.0",
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 5000.0",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
|
||||
"light_entity Controller|Configuration|Fast approximation: SUCCESS",
|
||||
"light_entity Controller|Configuration|Both directions: SUCCESS",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
|
||||
f"which matches {LIGHT_TYPES['simple_point']}",
|
||||
"Controller|Configuration|Attenuation radius|Mode set to 0",
|
||||
"Controller|Configuration|Attenuation radius|Radius set to 100.0",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
|
||||
f"which matches {LIGHT_TYPES['simple_spot']}",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 45.0",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 90.0",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
"Light component test (non-GPU) completed.",
|
||||
]
|
||||
|
||||
unexpected_lines = ["Traceback (most recent call last):"]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_LightComponent.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=[],
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
|
||||
@@ -119,8 +140,6 @@ class TestMaterialEditorBasicTests(object):
|
||||
"Save All worked as expected: True",
|
||||
]
|
||||
unexpected_lines = [
|
||||
# "Trace::Assert",
|
||||
# "Trace::Error",
|
||||
"Traceback (most recent call last):"
|
||||
]
|
||||
|
||||
|
||||
@@ -42,12 +42,14 @@ class AtomComponentProperties:
|
||||
Bloom component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable Bloom' Toggle active state of the component True/False
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Bloom',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'Enable Bloom': 'Controller|Configuration|Enable Bloom',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -83,12 +85,14 @@ class AtomComponentProperties:
|
||||
Deferred Fog component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable Deferred Fog' Toggle active state of the component True/False
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Deferred Fog',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'Enable Deferred Fog': 'Controller|Configuration|Enable Deferred Fog',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -212,6 +216,7 @@ class AtomComponentProperties:
|
||||
HDR Color Grading component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable HDR color grading' Toggle active state of the component True/False
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
|
||||
-238
@@ -1,238 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.paths
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.render as render
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.utils import TestHelper
|
||||
|
||||
|
||||
def run():
|
||||
"""
|
||||
Summary:
|
||||
The below common tests are done for each of the components.
|
||||
1) Addition of component to the entity
|
||||
2) UNDO/REDO of addition of component
|
||||
3) Enter/Exit game mode
|
||||
4) Hide/Show entity containing component
|
||||
5) Deletion of component
|
||||
6) UNDO/REDO of deletion of component
|
||||
Some additional tests for specific components include
|
||||
1) Assigning value to some properties of each component
|
||||
2) Verifying if the component is activated only when the required components are added
|
||||
|
||||
Expected Result:
|
||||
1) Component can be added to an entity.
|
||||
2) The addition of component can be undone and redone.
|
||||
3) Game mode can be entered/exited without issue.
|
||||
4) Entity with component can be hidden/shown.
|
||||
5) Component can be deleted.
|
||||
6) The deletion of component can be undone and redone.
|
||||
7) Component is activated only when the required components are added
|
||||
8) Values can be assigned to the properties of the component
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def create_entity_undo_redo_component_addition(component_name):
|
||||
new_entity = hydra.Entity(f"{component_name}")
|
||||
new_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), [component_name])
|
||||
general.log(f"{component_name}_test: Component added to the entity: "
|
||||
f"{hydra.has_components(new_entity.id, [component_name])}")
|
||||
|
||||
# undo component addition
|
||||
general.undo()
|
||||
TestHelper.wait_for_condition(lambda: not hydra.has_components(new_entity.id, [component_name]), 2.0)
|
||||
general.log(f"{component_name}_test: Component removed after UNDO: "
|
||||
f"{not hydra.has_components(new_entity.id, [component_name])}")
|
||||
|
||||
# redo component addition
|
||||
general.redo()
|
||||
TestHelper.wait_for_condition(lambda: hydra.has_components(new_entity.id, [component_name]), 2.0)
|
||||
general.log(f"{component_name}_test: Component added after REDO: "
|
||||
f"{hydra.has_components(new_entity.id, [component_name])}")
|
||||
|
||||
return new_entity
|
||||
|
||||
def verify_enter_exit_game_mode(component_name):
|
||||
general.enter_game_mode()
|
||||
TestHelper.wait_for_condition(lambda: general.is_in_game_mode(), 2.0)
|
||||
general.log(f"{component_name}_test: Entered game mode: {general.is_in_game_mode()}")
|
||||
general.exit_game_mode()
|
||||
TestHelper.wait_for_condition(lambda: not general.is_in_game_mode(), 2.0)
|
||||
general.log(f"{component_name}_test: Exit game mode: {not general.is_in_game_mode()}")
|
||||
|
||||
def verify_hide_unhide_entity(component_name, entity_obj):
|
||||
|
||||
def is_entity_hidden(entity_id):
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", entity_id)
|
||||
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, False)
|
||||
general.idle_wait_frames(1)
|
||||
general.log(f"{component_name}_test: Entity is hidden: {is_entity_hidden(entity_obj.id)}")
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, True)
|
||||
general.idle_wait_frames(1)
|
||||
general.log(f"{component_name}_test: Entity is shown: {not is_entity_hidden(entity_obj.id)}")
|
||||
|
||||
def verify_deletion_undo_redo(component_name, entity_obj):
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", entity_obj.id)
|
||||
TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0)
|
||||
general.log(f"{component_name}_test: Entity deleted: {not hydra.find_entity_by_name(entity_obj.name)}")
|
||||
|
||||
general.undo()
|
||||
TestHelper.wait_for_condition(lambda: hydra.find_entity_by_name(entity_obj.name) is not None, 2.0)
|
||||
general.log(f"{component_name}_test: UNDO entity deletion works: "
|
||||
f"{hydra.find_entity_by_name(entity_obj.name) is not None}")
|
||||
|
||||
general.redo()
|
||||
TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0)
|
||||
general.log(f"{component_name}_test: REDO entity deletion works: "
|
||||
f"{not hydra.find_entity_by_name(entity_obj.name)}")
|
||||
|
||||
def verify_required_component_addition(entity_obj, components_to_add, component_name):
|
||||
|
||||
def is_component_enabled(entity_componentid_pair):
|
||||
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", entity_componentid_pair)
|
||||
|
||||
general.log(
|
||||
f"{component_name}_test: Entity disabled initially: "
|
||||
f"{not is_component_enabled(entity_obj.components[0])}")
|
||||
for component in components_to_add:
|
||||
entity_obj.add_component(component)
|
||||
TestHelper.wait_for_condition(lambda: is_component_enabled(entity_obj.components[0]), 2.0)
|
||||
general.log(
|
||||
f"{component_name}_test: Entity enabled after adding "
|
||||
f"required components: {is_component_enabled(entity_obj.components[0])}"
|
||||
)
|
||||
|
||||
def verify_set_property(entity_obj, path, value):
|
||||
entity_obj.get_set_test(0, path, value)
|
||||
|
||||
# Verify cubemap generation
|
||||
def verify_cubemap_generation(component_name, entity_obj):
|
||||
# Initially Check if the component has Reflection Probe component
|
||||
if not hydra.has_components(entity_obj.id, ["Reflection Probe"]):
|
||||
raise ValueError(f"Given entity {entity_obj.name} has no Reflection Probe component")
|
||||
render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", entity_obj.id)
|
||||
|
||||
def get_value():
|
||||
hydra.get_component_property_value(entity_obj.components[0], "Cubemap|Baked Cubemap Path")
|
||||
|
||||
TestHelper.wait_for_condition(lambda: get_value() != "", 20.0)
|
||||
general.log(f"{component_name}_test: Cubemap is generated: {get_value() != ''}")
|
||||
|
||||
# Wait for Editor idle loop before executing Python hydra scripts.
|
||||
TestHelper.init_idle()
|
||||
|
||||
# Delete all existing entities initially
|
||||
search_filter = azlmbr.entity.SearchFilter()
|
||||
all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities)
|
||||
|
||||
class ComponentTests:
|
||||
"""Test launcher for each component."""
|
||||
def __init__(self, component_name, *additional_tests):
|
||||
self.component_name = component_name
|
||||
self.additional_tests = additional_tests
|
||||
self.run_component_tests()
|
||||
|
||||
def run_component_tests(self):
|
||||
# Run common and additional tests
|
||||
entity_obj = create_entity_undo_redo_component_addition(self.component_name)
|
||||
|
||||
# Enter/Exit game mode test
|
||||
verify_enter_exit_game_mode(self.component_name)
|
||||
|
||||
# Any additional tests are executed here
|
||||
for test in self.additional_tests:
|
||||
test(entity_obj)
|
||||
|
||||
# Hide/Unhide entity test
|
||||
verify_hide_unhide_entity(self.component_name, entity_obj)
|
||||
|
||||
# Deletion/Undo/Redo test
|
||||
verify_deletion_undo_redo(self.component_name, entity_obj)
|
||||
|
||||
# DepthOfField Component
|
||||
camera_entity = hydra.Entity("camera_entity")
|
||||
camera_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), ["Camera"])
|
||||
depth_of_field = "DepthOfField"
|
||||
ComponentTests(
|
||||
depth_of_field,
|
||||
lambda entity_obj: verify_required_component_addition(entity_obj, ["PostFX Layer"], depth_of_field),
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Camera Entity", camera_entity.id))
|
||||
|
||||
# Decal Component
|
||||
material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# Directional Light Component
|
||||
ComponentTests(
|
||||
"Directional Light",
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Shadow|Camera", camera_entity.id))
|
||||
|
||||
# Exposure Control Component
|
||||
ComponentTests(
|
||||
"Exposure Control", lambda entity_obj: verify_required_component_addition(
|
||||
entity_obj, ["PostFX Layer"], "Exposure Control"))
|
||||
|
||||
# Global Skylight (IBL) Component
|
||||
diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
|
||||
diffuse_image_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", diffuse_image_path, math.Uuid(), False)
|
||||
specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
|
||||
specular_image_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", specular_image_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Global Skylight (IBL)",
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Diffuse Image", diffuse_image_asset),
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Specular Image", specular_image_asset))
|
||||
|
||||
# Physical Sky Component
|
||||
ComponentTests("Physical Sky")
|
||||
|
||||
# PostFX Layer Component
|
||||
ComponentTests("PostFX Layer")
|
||||
|
||||
# PostFX Radius Weight Modifier Component
|
||||
ComponentTests("PostFX Radius Weight Modifier")
|
||||
|
||||
# Light Component
|
||||
ComponentTests("Light")
|
||||
|
||||
# Display Mapper Component
|
||||
ComponentTests("Display Mapper")
|
||||
|
||||
# Reflection Probe Component
|
||||
reflection_probe = "Reflection Probe"
|
||||
ComponentTests(
|
||||
reflection_probe,
|
||||
lambda entity_obj: verify_required_component_addition(entity_obj, ["Box Shape"], reflection_probe),
|
||||
lambda entity_obj: verify_cubemap_generation(reflection_probe, entity_obj),)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
@@ -0,0 +1,189 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
bloom_creation = (
|
||||
"Bloom Entity successfully created",
|
||||
"Bloom Entity failed to be created")
|
||||
bloom_component = (
|
||||
"Entity has a Bloom component",
|
||||
"Entity failed to find Bloom component")
|
||||
bloom_disabled = (
|
||||
"Bloom component disabled",
|
||||
"Bloom component was not disabled")
|
||||
postfx_layer_component = (
|
||||
"Entity has a PostFX Layer component",
|
||||
"Entity did not have an PostFX Layer component")
|
||||
bloom_enabled = (
|
||||
"Bloom component enabled",
|
||||
"Bloom component was not enabled")
|
||||
enable_bloom_parameter_enabled = (
|
||||
"Enable Bloom parameter enabled",
|
||||
"Enable Bloom parameter was not enabled")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_Bloom_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Bloom component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an Bloom entity with no components.
|
||||
2) Add Bloom component to Bloom entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify Bloom component not enabled.
|
||||
6) Add PostFX Layer component since it is required by the Bloom component.
|
||||
7) Verify Bloom component is enabled.
|
||||
8) Enable the "Enable Bloom" parameter.
|
||||
9) Enter/Exit game mode.
|
||||
10) Test IsHidden.
|
||||
11) Test IsVisible.
|
||||
12) Delete Bloom entity.
|
||||
13) UNDO deletion.
|
||||
14) REDO deletion.
|
||||
15) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Bloom entity with no components.
|
||||
bloom_entity = EditorEntity.create_editor_entity(AtomComponentProperties.bloom())
|
||||
Report.critical_result(Tests.bloom_creation, bloom_entity.exists())
|
||||
|
||||
# 2. Add Bloom component to Bloom entity.
|
||||
bloom_component = bloom_entity.add_component(AtomComponentProperties.bloom())
|
||||
Report.critical_result(Tests.bloom_component, bloom_entity.has_component(AtomComponentProperties.bloom()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not bloom_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, bloom_entity.exists())
|
||||
|
||||
# 5. Verify Bloom component not enabled.
|
||||
Report.result(Tests.bloom_disabled, not bloom_component.is_enabled())
|
||||
|
||||
# 6. Add PostFX Layer component since it is required by the Bloom component.
|
||||
bloom_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(
|
||||
Tests.postfx_layer_component,
|
||||
bloom_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
|
||||
# 7. Verify Bloom component is enabled.
|
||||
Report.result(Tests.bloom_enabled, bloom_component.is_enabled())
|
||||
|
||||
# 8. Enable the "Enable Bloom" parameter.
|
||||
bloom_component.set_component_property_value(AtomComponentProperties.bloom('Enable Bloom'), True)
|
||||
Report.result(
|
||||
Tests.enable_bloom_parameter_enabled,
|
||||
bloom_component.get_component_property_value(AtomComponentProperties.bloom('Enable Bloom')) is True)
|
||||
|
||||
# 9. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 10. Test IsHidden.
|
||||
bloom_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, bloom_entity.is_hidden() is True)
|
||||
|
||||
# 11. Test IsVisible.
|
||||
bloom_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, bloom_entity.is_visible() is True)
|
||||
|
||||
# 12. Delete Bloom entity.
|
||||
bloom_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not bloom_entity.exists())
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, bloom_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not bloom_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_Bloom_AddedToEntity)
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
deferred_fog_creation = (
|
||||
"Deferred Fog Entity successfully created",
|
||||
"Deferred Fog Entity failed to be created")
|
||||
deferred_fog_component = (
|
||||
"Entity has a Deferred Fog component",
|
||||
"Entity failed to find Deferred Fog component")
|
||||
deferred_fog_disabled = (
|
||||
"Deferred Fog component disabled",
|
||||
"Deferred Fog component was not disabled")
|
||||
postfx_layer_component = (
|
||||
"Entity has a PostFX Layer component",
|
||||
"Entity did not have an PostFX Layer component")
|
||||
deferred_fog_enabled = (
|
||||
"Deferred Fog component enabled",
|
||||
"Deferred Fog component was not enabled")
|
||||
enable_deferred_fog_parameter_enabled = (
|
||||
"Enable Deferred Fog parameter enabled",
|
||||
"Enable Deferred Fog parameter was not enabled")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_DeferredFog_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Deferred Fog component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an Deferred Fog entity with no components.
|
||||
2) Add Deferred Fog component to Deferred Fog entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify Deferred Fog component not enabled.
|
||||
6) Add PostFX Layer component since it is required by the Deferred Fog component.
|
||||
7) Verify Deferred Fog component is enabled.
|
||||
8) Enable the "Enable Deferred Fog" parameter.
|
||||
9) Enter/Exit game mode.
|
||||
10) Test IsHidden.
|
||||
11) Test IsVisible.
|
||||
12) Delete Deferred Fog entity.
|
||||
13) UNDO deletion.
|
||||
14) REDO deletion.
|
||||
15) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Deferred Fog entity with no components.
|
||||
deferred_fog_entity = EditorEntity.create_editor_entity(AtomComponentProperties.deferred_fog())
|
||||
Report.critical_result(Tests.deferred_fog_creation, deferred_fog_entity.exists())
|
||||
|
||||
# 2. Add Deferred Fog component to Deferred Fog entity.
|
||||
deferred_fog_component = deferred_fog_entity.add_component(
|
||||
AtomComponentProperties.deferred_fog())
|
||||
Report.critical_result(
|
||||
Tests.deferred_fog_component,
|
||||
deferred_fog_entity.has_component(AtomComponentProperties.deferred_fog()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not deferred_fog_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, deferred_fog_entity.exists())
|
||||
|
||||
# 5. Verify Deferred Fog component not enabled.
|
||||
Report.result(Tests.deferred_fog_disabled, not deferred_fog_component.is_enabled())
|
||||
|
||||
# 6. Add PostFX Layer component since it is required by the Deferred Fog component.
|
||||
deferred_fog_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(
|
||||
Tests.postfx_layer_component,
|
||||
deferred_fog_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
|
||||
# 7. Verify Deferred Fog component is enabled.
|
||||
Report.result(Tests.deferred_fog_enabled, deferred_fog_component.is_enabled())
|
||||
|
||||
# 8. Enable the "Enable Deferred Fog" parameter.
|
||||
deferred_fog_component.set_component_property_value(
|
||||
AtomComponentProperties.deferred_fog('Enable Deferred Fog'), True)
|
||||
Report.result(Tests.enable_deferred_fog_parameter_enabled,
|
||||
deferred_fog_component.get_component_property_value(
|
||||
AtomComponentProperties.deferred_fog('Enable Deferred Fog')) is True)
|
||||
|
||||
# 9. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 10. Test IsHidden.
|
||||
deferred_fog_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, deferred_fog_entity.is_hidden() is True)
|
||||
|
||||
# 11. Test IsVisible.
|
||||
deferred_fog_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, deferred_fog_entity.is_visible() is True)
|
||||
|
||||
# 12. Delete Deferred Fog entity.
|
||||
deferred_fog_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not deferred_fog_entity.exists())
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
Report.result(Tests.deletion_undo, deferred_fog_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
Report.result(Tests.deletion_redo, not deferred_fog_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_DeferredFog_AddedToEntity)
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::MultiplayerTests_Main
|
||||
TEST_SUITE main
|
||||
NAME AutomatedTesting::MultiplayerTests_Sandbox
|
||||
TEST_SUITE sandbox
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
AZ::AssetProcessor
|
||||
|
||||
@@ -27,7 +27,3 @@ class TestAutomation(TestAutomationBase):
|
||||
batch_mode=batch_mode,
|
||||
autotest_mode=autotest_mode)
|
||||
|
||||
def test_Multiplayer_AutoComponent_NetworkInput(self, request, workspace, editor, launcher_platform):
|
||||
from .tests import Multiplayer_AutoComponent_NetworkInput as test_module
|
||||
self._run_prefab_test(request, workspace, editor, test_module)
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
# This suite consists of all test cases that are under development and have not been verified yet.
|
||||
# Once they are verified, please move them to TestSuite_Active.py
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
|
||||
|
||||
from base import TestAutomationBase
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(TestAutomationBase):
|
||||
def _run_prefab_test(self, request, workspace, editor, test_module, batch_mode=True, autotest_mode=True):
|
||||
self._run_test(request, workspace, editor, test_module,
|
||||
extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"],
|
||||
batch_mode=batch_mode,
|
||||
autotest_mode=autotest_mode)
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_Multiplayer_AutoComponent_NetworkInput(self, request, workspace, editor, launcher_platform):
|
||||
from .tests import Multiplayer_AutoComponent_NetworkInput as test_module
|
||||
self._run_prefab_test(request, workspace, editor, test_module)
|
||||
|
||||
@@ -11,7 +11,6 @@ OutlinerWidget #m_display_options
|
||||
{
|
||||
qproperty-icon: url(:/Menu/menu.svg);
|
||||
qproperty-iconSize: 16px 16px;
|
||||
qproperty-flat: true;
|
||||
}
|
||||
|
||||
OutlinerWidget QWidget[PulseHighlight="true"]
|
||||
|
||||
@@ -10,7 +10,6 @@ AzToolsFramework--EntityOutlinerWidget #m_display_options
|
||||
{
|
||||
qproperty-icon: url(:/stylesheet/img/UI20/menu-centered.svg);
|
||||
qproperty-iconSize: 16px 16px;
|
||||
qproperty-flat: true;
|
||||
}
|
||||
|
||||
AzToolsFramework--EntityOutlinerWidget QTreeView
|
||||
|
||||
@@ -139,11 +139,20 @@ endif()
|
||||
|
||||
# Configure system includes
|
||||
ly_set(LY_CXX_SYSTEM_INCLUDE_CONFIGURATION_FLAG
|
||||
/experimental:external # Turns on "external" headers feature for MSVC compilers
|
||||
/experimental:external # Turns on "external" headers feature for MSVC compilers, required for MSVC < 16.10
|
||||
/external:W0 # Set warning level in external headers to 0. This is used to suppress warnings 3rdParty libraries which uses the "system_includes" option in their json configuration
|
||||
)
|
||||
|
||||
# CMake 3.22rc added a definition for CMAKE_INCLUDE_SYSTEM_FLAG_CXX. However, its defined as "-external:I ", that space causes
|
||||
# issues when trying to use in TargetIncludeSystemDirectories_unsupported.cmake.
|
||||
# CMake 3.22rc has also not added support for external directories in MSVC through target_include_directories(... SYSTEM
|
||||
# So we will just fix the flag that was added by 3.22rc so it works with our TargetIncludeSystemDirectories_unsupported.cmake
|
||||
# Once target_include_directories(... SYSTEM is supported, we can branch and use TargetIncludeSystemDirectories_supported.cmake
|
||||
# Reported this here: https://gitlab.kitware.com/cmake/cmake/-/issues/17904#note_1078281
|
||||
if(NOT CMAKE_INCLUDE_SYSTEM_FLAG_CXX)
|
||||
ly_set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX /external:I)
|
||||
ly_set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "/external:I")
|
||||
else()
|
||||
string(STRIP ${CMAKE_INCLUDE_SYSTEM_FLAG_CXX} CMAKE_INCLUDE_SYSTEM_FLAG_CXX)
|
||||
endif()
|
||||
|
||||
include(cmake/Platform/Common/TargetIncludeSystemDirectories_unsupported.cmake)
|
||||
|
||||
Vendored
+9
-7
@@ -271,7 +271,7 @@ def CheckoutRepo(boolean disableSubmodules = false) {
|
||||
palRm('commitdate')
|
||||
}
|
||||
|
||||
def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) {
|
||||
def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) {
|
||||
unstash name: 'incremental_build_script'
|
||||
|
||||
def pythonCmd = ''
|
||||
@@ -435,7 +435,7 @@ def ExportTestScreenshots(Map options, String branchName, String platformName, S
|
||||
}
|
||||
}
|
||||
|
||||
def UploadAPLogs(Map options, String branchName, String jobName, String workspace, Map params) {
|
||||
def UploadAPLogs(Map options, String branchName, String platformName, String jobName, String workspace, Map params) {
|
||||
dir("${workspace}/${ENGINE_REPOSITORY_NAME}") {
|
||||
projects = params.CMAKE_LY_PROJECTS.split(",")
|
||||
projects.each{ project ->
|
||||
@@ -449,7 +449,7 @@ def UploadAPLogs(Map options, String branchName, String jobName, String workspac
|
||||
}
|
||||
def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " +
|
||||
"--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " +
|
||||
"--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName} " +
|
||||
"--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${platformName}/${jobName} " +
|
||||
'--extra_args {\\"ACL\\":\\"bucket-owner-full-control\\"}'
|
||||
palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false)
|
||||
}
|
||||
@@ -519,10 +519,10 @@ def CreateExportTestScreenshotsStage(Map pipelineConfig, String branchName, Stri
|
||||
}
|
||||
}
|
||||
|
||||
def CreateUploadAPLogsStage(Map pipelineConfig, String branchName, String jobName, String workspace, Map params) {
|
||||
def CreateUploadAPLogsStage(Map pipelineConfig, String branchName, String platformName, String jobName, String workspace, Map params) {
|
||||
return {
|
||||
stage("${jobName}_upload_ap_logs") {
|
||||
UploadAPLogs(pipelineConfig, branchName, jobName, workspace, params)
|
||||
UploadAPLogs(pipelineConfig, branchName, platformName, jobName, workspace, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -551,9 +551,11 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar
|
||||
CreateSetupStage(pipelineConfig, snapshot, repositoryName, projectName, pipelineName, branchName, platform.key, build_job.key, envVars, onlyMountEBSVolume).call()
|
||||
|
||||
if(build_job.value.steps) { //this is a pipe with many steps so create all the build stages
|
||||
pipelineEnvVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
build_job.value.steps.each { build_step ->
|
||||
build_job_name = build_step
|
||||
envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
// This addition of maps makes it that the right operand will override entries if they overlap with the left operand
|
||||
envVars = pipelineEnvVars + GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
try {
|
||||
CreateBuildStage(pipelineConfig, platform.key, build_step, envVars).call()
|
||||
}
|
||||
@@ -577,7 +579,7 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar
|
||||
}
|
||||
}
|
||||
if (IsAPLogUpload(branchName, build_job_name)) {
|
||||
CreateUploadAPLogsStage(pipelineConfig, branchName, build_job_name, envVars['WORKSPACE'], platform.value.build_types[build_job_name].PARAMETERS).call()
|
||||
CreateUploadAPLogsStage(pipelineConfig, branchName, platform.key, build_job_name, envVars['WORKSPACE'], platform.value.build_types[build_job_name].PARAMETERS).call()
|
||||
}
|
||||
// All other errors will be raised outside the retry block
|
||||
currentResult = envVars['ON_FAILURE_MARK'] ?: 'FAILURE'
|
||||
|
||||
@@ -214,5 +214,48 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "all"
|
||||
}
|
||||
},
|
||||
"install_profile": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "build_linux.sh",
|
||||
"PARAMETERS": {
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build/linux",
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4 -DLY_DISABLE_TEST_MODULES=TRUE",
|
||||
"CMAKE_TARGET": "install"
|
||||
}
|
||||
},
|
||||
"install_profile_pipe": {
|
||||
"TAGS": [
|
||||
"nightly-incremental",
|
||||
"nightly-clean"
|
||||
],
|
||||
"PIPELINE_ENV": {
|
||||
"PROJECT_REPOSITORY_NAME": "TestProject"
|
||||
},
|
||||
"steps": [
|
||||
"install_profile",
|
||||
"project_generate",
|
||||
"project_engineinstall_profile"
|
||||
]
|
||||
},
|
||||
"project_generate": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "python_linux.sh",
|
||||
"PARAMETERS": {
|
||||
"SCRIPT_PATH": "install/scripts/o3de.py",
|
||||
"SCRIPT_PARAMETERS": "create-project -pp ${WORKSPACE}/${PROJECT_REPOSITORY_NAME} --force"
|
||||
}
|
||||
},
|
||||
"project_engineinstall_profile": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "build_linux.sh",
|
||||
"PARAMETERS": {
|
||||
"COMMAND_CWD": "${WORKSPACE}/${PROJECT_REPOSITORY_NAME}",
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build/linux",
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_PARALLEL_LINK_JOBS=4 -DCMAKE_MODULE_PATH=${WORKSPACE}/o3de/install/cmake",
|
||||
"CMAKE_TARGET": "all"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ SOURCE_DIRECTORY=${PWD}
|
||||
pushd $OUTPUT_DIRECTORY
|
||||
|
||||
LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt
|
||||
CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'"
|
||||
CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH}"
|
||||
if [[ -n "$CMAKE_LY_PROJECTS" ]]; then
|
||||
CONFIGURE_CMD="${CONFIGURE_CMD} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'"
|
||||
fi
|
||||
if [[ ! -e "CMakeCache.txt" ]]; then
|
||||
echo [ci_build] First run, generating
|
||||
RUN_CONFIGURE=1
|
||||
|
||||
@@ -18,3 +18,8 @@ if ! command -v ninja &> /dev/null; then
|
||||
echo "[ci_build] Ninja not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${COMMAND_CWD}" ]]; then
|
||||
echo $(eval echo [ci_build] Changing CWD to $COMMAND_CWD)
|
||||
cd $(eval echo ${COMMAND_CWD})
|
||||
fi
|
||||
|
||||
@@ -162,5 +162,50 @@
|
||||
"SCRIPT_PATH": "scripts/build/package/package.py",
|
||||
"SCRIPT_PARAMETERS": "--platform Mac --type all"
|
||||
}
|
||||
},
|
||||
"install_profile": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "build_mac.sh",
|
||||
"PARAMETERS": {
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build/mac",
|
||||
"CMAKE_OPTIONS": "-G Xcode -DLY_DISABLE_TEST_MODULES=TRUE",
|
||||
"CMAKE_LY_PROJECTS": "",
|
||||
"CMAKE_TARGET": "install"
|
||||
}
|
||||
},
|
||||
"install_profile_pipe": {
|
||||
"TAGS": [
|
||||
"nightly-incremental",
|
||||
"nightly-clean"
|
||||
],
|
||||
"PIPELINE_ENV": {
|
||||
"PROJECT_REPOSITORY_NAME": "TestProject"
|
||||
},
|
||||
"steps": [
|
||||
"install_profile",
|
||||
"project_generate",
|
||||
"project_engineinstall_profile"
|
||||
]
|
||||
},
|
||||
"project_generate": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "python_mac.sh",
|
||||
"PARAMETERS": {
|
||||
"SCRIPT_PATH": "install/O3DE_SDK.app/Contents/Engine/scripts/o3de.py",
|
||||
"SCRIPT_PARAMETERS": "create-project -pp ${WORKSPACE}/${PROJECT_REPOSITORY_NAME} --force"
|
||||
}
|
||||
},
|
||||
"project_engineinstall_profile": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "build_mac.sh",
|
||||
"PARAMETERS": {
|
||||
"COMMAND_CWD": "${WORKSPACE}/${PROJECT_REPOSITORY_NAME}",
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build/mac",
|
||||
"CMAKE_OPTIONS": "-G Xcode -DCMAKE_MODULE_PATH=${WORKSPACE}/o3de/install/O3DE_SDK.app/Contents/Engine/cmake",
|
||||
"CMAKE_LY_PROJECTS": "",
|
||||
"CMAKE_TARGET": "ALL_BUILD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ SOURCE_DIRECTORY=${PWD}
|
||||
pushd $OUTPUT_DIRECTORY
|
||||
|
||||
LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt
|
||||
CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'"
|
||||
CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH}"
|
||||
if [[ -n "$CMAKE_LY_PROJECTS" ]]; then
|
||||
CONFIGURE_CMD="${CONFIGURE_CMD} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'"
|
||||
fi
|
||||
if [[ ! -e "CMakeCache.txt" ]]; then
|
||||
echo [ci_build] First run, generating
|
||||
RUN_CONFIGURE=1
|
||||
|
||||
@@ -13,3 +13,8 @@ if ! command -v cmake &> /dev/null; then
|
||||
echo "[ci_build] CMake not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${COMMAND_CWD}" ]]; then
|
||||
echo $(eval echo [ci_build] Changing CWD to $COMMAND_CWD)
|
||||
cd $(eval echo ${COMMAND_CWD})
|
||||
fi
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"COMMAND": "python_windows.cmd",
|
||||
"PARAMETERS": {
|
||||
"SCRIPT_PATH": "scripts/build/ci_build_metrics.py",
|
||||
"SCRIPT_PARAMETERS": "--platform=Windows --repository=!REPOSITORY_NAME! --jobname=!JOB_NAME! --jobnumber=!BUILD_NUMBER! --jobnode=!NODE_LABEL! --changelist=!CHANGE_ID!"
|
||||
"SCRIPT_PARAMETERS": "--platform=Windows --repository=%REPOSITORY_NAME% --jobname=%JOB_NAME% --jobnumber=%BUILD_NUMBER% --jobnode=%NODE_LABEL% --changelist=%CHANGE_ID%"
|
||||
}
|
||||
},
|
||||
"windows_packaging_all": {
|
||||
@@ -88,7 +88,7 @@
|
||||
"CONFIGURATION": "profile",
|
||||
"SCRIPT_PATH": "scripts/build/TestImpactAnalysis/tiaf_driver.py",
|
||||
"SCRIPT_PARAMETERS":
|
||||
"--config=\"!OUTPUT_DIRECTORY!/bin/TestImpactFramework/profile/Persistent/tiaf.json\" --src-branch=!BRANCH_NAME! --dst-branch=!CHANGE_TARGET! --commit=!CHANGE_ID! --s3-bucket=!TEST_IMPACT_S3_BUCKET! --mars-index-prefix=jonawals --s3-top-level-dir=!REPOSITORY_NAME! --build-number=!BUILD_NUMBER! --suite=main --test-failure-policy=continue"
|
||||
"--config=\"%OUTPUT_DIRECTORY%/bin/TestImpactFramework/profile/Persistent/tiaf.json\" --src-branch=%BRANCH_NAME% --dst-branch=%CHANGE_TARGET% --commit=%CHANGE_ID% --s3-bucket=%TEST_IMPACT_S3_BUCKET% --mars-index-prefix=jonawals --s3-top-level-dir=%REPOSITORY_NAME% --build-number=%BUILD_NUMBER% --suite=main --test-failure-policy=continue"
|
||||
}
|
||||
},
|
||||
"debug_vs2019": {
|
||||
@@ -131,7 +131,7 @@
|
||||
"PARAMETERS": {
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build\\windows_vs2019",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_TEST_IMPACT_INSTRUMENTATION_BIN=!TEST_IMPACT_WIN_BINARY!",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_TEST_IMPACT_INSTRUMENTATION_BIN=%TEST_IMPACT_WIN_BINARY%",
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "ALL_BUILD",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo"
|
||||
@@ -337,16 +337,12 @@
|
||||
}
|
||||
},
|
||||
"install_profile_vs2019": {
|
||||
"TAGS": [
|
||||
"nightly-incremental",
|
||||
"nightly-clean"
|
||||
],
|
||||
"TAGS": [],
|
||||
"COMMAND": "build_windows.cmd",
|
||||
"PARAMETERS": {
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build\\windows_vs2019",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE",
|
||||
"CMAKE_LY_PROJECTS": "",
|
||||
"CMAKE_TARGET": "INSTALL",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo"
|
||||
}
|
||||
@@ -363,14 +359,35 @@
|
||||
"PARAMETERS": {
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build\\windows_vs2019",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"",
|
||||
"EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license",
|
||||
"CPACK_BUCKET": "!INSTALLER_BUCKET!",
|
||||
"CMAKE_LY_PROJECTS": "",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"%WIX% \"",
|
||||
"EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=%INSTALLER_DOWNLOAD_URL% -DLY_INSTALLER_LICENSE_URL=%INSTALLER_DOWNLOAD_URL%/license",
|
||||
"CPACK_BUCKET": "%INSTALLER_BUCKET%",
|
||||
"CMAKE_TARGET": "ALL_BUILD",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo"
|
||||
}
|
||||
},
|
||||
"install_profile_vs2019_pipe": {
|
||||
"TAGS": [
|
||||
"nightly-incremental",
|
||||
"nightly-clean"
|
||||
],
|
||||
"PIPELINE_ENV": {
|
||||
"PROJECT_REPOSITORY_NAME": "TestProject"
|
||||
},
|
||||
"steps": [
|
||||
"install_profile_vs2019",
|
||||
"project_generate",
|
||||
"project_engineinstall_profile_vs2019"
|
||||
]
|
||||
},
|
||||
"project_generate": {
|
||||
"TAGS": [],
|
||||
"COMMAND": "python_windows.cmd",
|
||||
"PARAMETERS": {
|
||||
"SCRIPT_PATH": "install\\scripts\\o3de.py",
|
||||
"SCRIPT_PARAMETERS": "create-project -pp %WORKSPACE%\\%PROJECT_REPOSITORY_NAME% --force"
|
||||
}
|
||||
},
|
||||
"project_enginesource_profile_vs2019": {
|
||||
"TAGS": [
|
||||
"project"
|
||||
@@ -382,8 +399,7 @@
|
||||
"PARAMETERS": {
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build\\windows_vs2019",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/cmake",
|
||||
"CMAKE_LY_PROJECTS": "",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=%WORKSPACE%/o3de/cmake",
|
||||
"CMAKE_TARGET": "ALL_BUILD",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo"
|
||||
}
|
||||
@@ -395,10 +411,10 @@
|
||||
},
|
||||
"COMMAND": "build_windows.cmd",
|
||||
"PARAMETERS": {
|
||||
"COMMAND_CWD": "%WORKSPACE%\\%PROJECT_REPOSITORY_NAME%",
|
||||
"CONFIGURATION": "profile",
|
||||
"OUTPUT_DIRECTORY": "build\\windows_vs2019",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/install/cmake",
|
||||
"CMAKE_LY_PROJECTS": "",
|
||||
"CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=%WORKSPACE%/o3de/install/cmake",
|
||||
"CMAKE_TARGET": "ALL_BUILD",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,13 @@ REM
|
||||
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
REM Jenkins reports MSB8029 when TMP/TEMP is not defined, define a dummy folder
|
||||
SET TMP=%cd%/temp
|
||||
SET TEMP=%cd%/temp
|
||||
IF NOT EXIST %TMP% (
|
||||
MKDIR temp
|
||||
)
|
||||
|
||||
CALL %~dp0env_windows.cmd
|
||||
|
||||
IF NOT EXIST "%OUTPUT_DIRECTORY%" (
|
||||
@@ -25,18 +32,14 @@ IF ERRORLEVEL 1 (
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Jenkins reports MSB8029 when TMP/TEMP is not defined, define a dummy folder
|
||||
SET TMP=%cd%/temp
|
||||
SET TEMP=%cd%/temp
|
||||
IF NOT EXIST %TMP% (
|
||||
MKDIR temp
|
||||
)
|
||||
|
||||
REM Compute half the amount of processors so some jobs can run
|
||||
SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2
|
||||
|
||||
SET LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt
|
||||
SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" -DLY_PROJECTS=%CMAKE_LY_PROJECTS%
|
||||
SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%"
|
||||
IF NOT "%CMAKE_LY_PROJECTS%"=="" (
|
||||
SET CONFIGURE_CMD=!CONFIGURE_CMD! -DLY_PROJECTS="%CMAKE_LY_PROJECTS%"
|
||||
)
|
||||
IF NOT EXIST CMakeCache.txt (
|
||||
ECHO [ci_build] First run, generating
|
||||
SET RUN_CONFIGURE=1
|
||||
|
||||
@@ -13,6 +13,11 @@ IF NOT %ERRORLEVEL%==0 (
|
||||
GOTO :error
|
||||
)
|
||||
|
||||
IF NOT "%COMMAND_CWD%"=="" (
|
||||
ECHO [ci_build] Changing CWD to %COMMAND_CWD%
|
||||
CD %COMMAND_CWD%
|
||||
)
|
||||
|
||||
EXIT /b 0
|
||||
|
||||
:error
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#
|
||||
|
||||
import argparse
|
||||
from collections import OrderedDict
|
||||
import fnmatch
|
||||
import json
|
||||
import os
|
||||
@@ -24,15 +25,19 @@ class LicenseScanner:
|
||||
"""
|
||||
|
||||
DEFAULT_CONFIG_FILE = 'scanner_config.json'
|
||||
DEFAULT_EXCLUDE_FILE = '.gitignore'
|
||||
DEFAULT_PACKAGE_INFO_FILE = 'PackageInfo.json'
|
||||
|
||||
def __init__(self, config_file=None):
|
||||
self.config_file = config_file
|
||||
self.config_data = self._load_config()
|
||||
self.license_regex = self._load_license_regex()
|
||||
self.file_regex = self._load_file_regex(self.config_data['license_patterns'])
|
||||
self.package_info = self._load_file_regex(self.config_data['package_patterns'])
|
||||
self.excluded_directories = self._load_file_regex(self.config_data['excluded_directories'])
|
||||
|
||||
def _load_config(self):
|
||||
"""Load config from the provided file. Sets default file if one is not provided."""
|
||||
if self.config_file is None:
|
||||
if not self.config_file:
|
||||
script_directory = os.path.dirname(os.path.abspath(__file__)) # Default file expected in same dir as script
|
||||
self.config_file = os.path.join(script_directory, self.DEFAULT_CONFIG_FILE)
|
||||
|
||||
@@ -43,45 +48,68 @@ class LicenseScanner:
|
||||
print('Config file cannot be found')
|
||||
raise
|
||||
|
||||
def _load_license_regex(self):
|
||||
def _load_file_regex(self, patterns):
|
||||
"""Returns regex object with case-insensitive matching from the list of filename patterns."""
|
||||
regex_patterns = []
|
||||
for pattern in self.config_data['license_patterns']:
|
||||
for pattern in patterns:
|
||||
regex_patterns.append(fnmatch.translate(pattern))
|
||||
|
||||
if not regex_patterns:
|
||||
print(f'Warning: No patterns from {patterns} found')
|
||||
return None
|
||||
|
||||
return re.compile('|'.join(regex_patterns), re.IGNORECASE)
|
||||
|
||||
def scan(self, path=os.curdir):
|
||||
"""Scan directory tree for filenames matching license_regex.
|
||||
def scan(self, paths=os.curdir):
|
||||
"""Scan directory tree for filenames matching file_regex, package info, and exclusion files.
|
||||
|
||||
:param path: Path of the directory to run scanner
|
||||
:return: Package paths and their corresponding license file contents
|
||||
:rtype: dict
|
||||
:param paths: Paths of the directory to run scanner
|
||||
:return: Package paths and their corresponding file contents
|
||||
:rtype: Ordered dict
|
||||
"""
|
||||
licenses = 0
|
||||
license_files = {}
|
||||
files = 0
|
||||
matching_files = OrderedDict()
|
||||
excluded_directories = None
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
for file in filenames:
|
||||
if self.license_regex.match(file):
|
||||
license_file_content = self._get_license_file_contents(os.path.join(dirpath, file))
|
||||
rel_dirpath = os.path.relpath(dirpath, path) # Limit path inside scanned directory
|
||||
license_files[rel_dirpath] = license_file_content
|
||||
licenses += 1
|
||||
print(f'License file: {os.path.join(dirpath, file)}')
|
||||
if not self.package_info:
|
||||
self.package_info = self.DEFAULT_PACKAGE_INFO_FILE
|
||||
|
||||
# Remove directories that should not be scanned
|
||||
for dir in self.config_data['excluded_directories']:
|
||||
if dir in dirnames:
|
||||
dirnames.remove(dir)
|
||||
print(f'{licenses} license files found.')
|
||||
return license_files
|
||||
if not self.excluded_directories:
|
||||
print(f'No excluded directory in config, looking for {self.DEFAULT_EXCLUDE_FILE} instead')
|
||||
|
||||
def _get_license_file_contents(self, filepath):
|
||||
for path in paths:
|
||||
for dirpath, dirnames, filenames in os.walk(path, topdown=True):
|
||||
dirnames.sort(key=str.casefold) # Ensure that results are sorted
|
||||
for file in filenames:
|
||||
if self.file_regex.match(file) or self.package_info.match(file):
|
||||
file_path = os.path.join(dirpath, file)
|
||||
matching_file_content = self._get_file_contents(file_path)
|
||||
matching_files[file_path] = matching_file_content
|
||||
files += 1
|
||||
print(f'Matching file: {file_path}')
|
||||
if self.package_info.match(file):
|
||||
dirnames[:] = [] # Stop scanning subdirectories if package info file found
|
||||
if self.DEFAULT_EXCLUDE_FILE in file and not self.excluded_directories:
|
||||
ignore_list = self._get_file_contents(os.path.join(dirpath, file)).splitlines()
|
||||
ignore_list.append('.git') # .gitignore doesn't usually have .git in its exclusions
|
||||
excluded_directories = self._load_file_regex(ignore_list)
|
||||
|
||||
# Remove directories that should not be scanned
|
||||
if self.excluded_directories:
|
||||
excluded_directories = self.excluded_directories
|
||||
for dir in dirnames:
|
||||
if excluded_directories.match(dir):
|
||||
dirnames.remove(dir)
|
||||
|
||||
print(f'{files} files found.')
|
||||
return matching_files
|
||||
|
||||
def _get_file_contents(self, filepath):
|
||||
try:
|
||||
with open(filepath, encoding='utf8') as f:
|
||||
return f.read()
|
||||
except UnicodeDecodeError:
|
||||
print(f'Unable to read license file: {filepath}')
|
||||
print(f'Unable to read file: {filepath}')
|
||||
pass
|
||||
|
||||
def create_license_file(self, licenses, filepath='NOTICES.txt'):
|
||||
@@ -89,18 +117,44 @@ class LicenseScanner:
|
||||
|
||||
:param licenses: Dict with package paths and their corresponding license file contents
|
||||
:param filepath: Path to write the file
|
||||
"""
|
||||
package_separator = '------------------------------------'
|
||||
with open(filepath, 'w', encoding='utf8') as f:
|
||||
"""
|
||||
license_separator = '------------------------------------'
|
||||
with open(filepath, 'w', encoding='utf8') as lf:
|
||||
for directory, license in licenses.items():
|
||||
license_output = '\n\n'.join([
|
||||
f'{package_separator}',
|
||||
f'Package path: {directory}',
|
||||
'License:',
|
||||
f'{license}\n'
|
||||
])
|
||||
f.write(license_output)
|
||||
if not self.package_info.match(os.path.basename(directory)):
|
||||
license_output = '\n\n'.join([
|
||||
f'{license_separator}',
|
||||
f'Package path: {os.path.relpath(directory)}',
|
||||
'License:',
|
||||
f'{license}\n'
|
||||
])
|
||||
lf.write(license_output)
|
||||
return None
|
||||
|
||||
def create_package_file(self, packages, filepath='SPDX-Licenses.json', get_contents=False):
|
||||
"""Creates file with all the provided SPDX package info summaries in json.
|
||||
Optional dirpath parameter will follow the license file path in the package info and return its contents in a dictionary
|
||||
|
||||
:param licenses: Dict with package info paths and their corresponding file contents
|
||||
:param filepath: Path to write the file
|
||||
:param dirpath: Root path for packages
|
||||
:rtype: Ordered dict
|
||||
"""
|
||||
licenses = OrderedDict()
|
||||
package_json = []
|
||||
|
||||
with open(filepath, 'w', encoding='utf8') as pf:
|
||||
for directory, package in packages.items():
|
||||
if self.package_info.match(os.path.basename(directory)):
|
||||
package_obj = json.loads(package)
|
||||
package_json.append(package_obj)
|
||||
if get_contents:
|
||||
license_path = os.path.join(os.path.dirname(directory), pathlib.Path(package_obj['LicenseFile']))
|
||||
licenses[license_path] = self._get_file_contents(license_path)
|
||||
else:
|
||||
licenses[directory] = package
|
||||
pf.write(json.dumps(package_json, indent=4))
|
||||
return licenses
|
||||
|
||||
|
||||
def parse_args():
|
||||
@@ -108,7 +162,8 @@ def parse_args():
|
||||
description='Script to run LicenseScanner and generate license file')
|
||||
parser.add_argument('--config-file', '-c', type=pathlib.Path, help='Config file for LicenseScanner')
|
||||
parser.add_argument('--license-file-path', '-l', type=pathlib.Path, help='Create license file in the provided path')
|
||||
parser.add_argument('--scan-path', '-s', default=os.curdir, type=pathlib.Path, help='Path to scan')
|
||||
parser.add_argument('--package-file-path', '-p', type=pathlib.Path, help='Create package summary file in the provided path')
|
||||
parser.add_argument('--scan-path', '-s', default=os.curdir, type=pathlib.Path, nargs='+', help='Path to scan, multiple space separated paths can be used')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -116,10 +171,15 @@ def main():
|
||||
try:
|
||||
args = parse_args()
|
||||
ls = LicenseScanner(args.config_file)
|
||||
licenses = ls.scan(args.scan_path)
|
||||
scanned_path_data = ls.scan(args.scan_path)
|
||||
|
||||
if args.license_file_path:
|
||||
ls.create_license_file(licenses, args.license_file_path)
|
||||
ls.create_license_file(scanned_path_data, args.license_file_path)
|
||||
if args.package_file_path:
|
||||
ls.create_package_file(scanned_path_data, args.package_file_path)
|
||||
if args.license_file_path and args.package_file_path:
|
||||
license_files = ls.create_package_file(scanned_path_data, args.package_file_path, True)
|
||||
ls.create_license_file(license_files, args.license_file_path)
|
||||
except FileNotFoundError as e:
|
||||
print(f'Type: {type(e).__name__}, Error: {e}')
|
||||
return 1
|
||||
|
||||
@@ -8,5 +8,8 @@
|
||||
"license_patterns": [
|
||||
"LICENSE*",
|
||||
"COPYING*"
|
||||
],
|
||||
"package_patterns": [
|
||||
"PackageInfo.json"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user