Merge branch 'development' into Atom/jromnoa/fix-asset-path-calls-to-use-new-asset-test-class

This commit is contained in:
jromnoa
2021-11-05 14:11:59 -07:00
26 changed files with 842 additions and 704 deletions
@@ -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.
"""
@@ -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)
@@ -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)
+9 -7
View File
@@ -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"
}
}
}
+4 -1
View File
@@ -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"
}
}
}
+4 -1
View File
@@ -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
+5
View File
@@ -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
+100 -40
View File
@@ -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"
]
}