2
0
Эх сурвалжийг харах

Atom Level component test support in editor_entity_utils.py and tests for level components (#6082)

* Level component helper and test cases for Atom Level components which currently crash

Signed-off-by: Scott Murray <[email protected]>

* moved a close paren to end of previous line to match existing style

Signed-off-by: Scott Murray <[email protected]>

* adding a forgotten import

Signed-off-by: Scott Murray <[email protected]>

* minor refactor and prep for adding back the Display Mapper Game component test

Signed-off-by: Scott Murray <[email protected]>

* putting Game compoenent Display Mapper test back with addition of setting property Enabled to true

Signed-off-by: Scott Murray <[email protected]>

* typo in line fixed Test. bocomes Tests.

Signed-off-by: Scott Murray <[email protected]>
smurly 3 жил өмнө
parent
commit
e3306f948f

+ 15 - 0
AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py

@@ -12,6 +12,7 @@ import pytest
 import ly_test_tools.environment.file_system as file_system
 import ly_test_tools.environment.file_system as file_system
 import editor_python_test_tools.hydra_test_utils as hydra
 import editor_python_test_tools.hydra_test_utils as hydra
 
 
+from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
 from Atom.atom_utils.atom_constants import LIGHT_TYPES
 from Atom.atom_utils.atom_constants import LIGHT_TYPES
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
@@ -159,3 +160,17 @@ class TestMaterialEditorBasicTests(object):
             enable_prefab_system=False,
             enable_prefab_system=False,
         )
         )
 
 
+
[email protected]("project", ["AutomatedTesting"])
[email protected]("launcher_platform", ['windows_editor'])
+class TestAutomation(EditorTestSuite):
+
+    enable_prefab_system = False
+
+    @pytest.mark.test_case_id("C36529666")
+    class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest):
+        from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module
+
+    @pytest.mark.test_case_id("C36525660")
+    class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest):
+        from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module

+ 25 - 1
AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py

@@ -18,6 +18,13 @@ LIGHT_TYPES = {
     'simple_spot': 7,
     'simple_spot': 7,
 }
 }
 
 
+# Qualiity Level settings for Diffuse Global Illumination level component
+GLOBAL_ILLUMINATION_QUALITY = {
+    'Low': 0,
+    'Medium': 1,
+    'High': 2,
+}
+
 
 
 class AtomComponentProperties:
 class AtomComponentProperties:
     """
     """
@@ -116,6 +123,21 @@ class AtomComponentProperties:
         }
         }
         return properties[property]
         return properties[property]
 
 
+    @staticmethod
+    def diffuse_global_illumination(property: str = 'name') -> str:
+        """
+        Diffuse Global Illumination level component properties.
+        Controls global settings for Diffuse Probe Grid components.
+          - 'Quality Level' from atom_constants.py GLOBAL_ILLUMINATION_QUALITY
+        :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': 'Diffuse Global Illumination',
+            'Quality Level': 'Controller|Configuration|Quality Level'
+        }
+        return properties[property]
+
     @staticmethod
     @staticmethod
     def diffuse_probe_grid(property: str = 'name') -> str:
     def diffuse_probe_grid(property: str = 'name') -> str:
         """
         """
@@ -148,7 +170,8 @@ class AtomComponentProperties:
     @staticmethod
     @staticmethod
     def display_mapper(property: str = 'name') -> str:
     def display_mapper(property: str = 'name') -> str:
         """
         """
-        Display Mapper component properties.
+        Display Mapper level component properties.
+          - 'Enable LDR color grading LUT' toggles the use of LDR color grading LUT
           - 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is
           - 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is
             an Asset.id value corresponding to a lighting asset file.
             an Asset.id value corresponding to a lighting asset file.
         :param property: From the last element of the property tree path. Default 'name' for component name string.
         :param property: From the last element of the property tree path. Default 'name' for component name string.
@@ -156,6 +179,7 @@ class AtomComponentProperties:
         """
         """
         properties = {
         properties = {
             'name': 'Display Mapper',
             'name': 'Display Mapper',
+            'Enable LDR color grading LUT': 'Controller|Configuration|Enable LDR color grading LUT',
             'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT',
             'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT',
         }
         }
         return properties[property]
         return properties[property]

+ 109 - 0
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py

@@ -0,0 +1,109 @@
+"""
+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 Level component addition success",
+        "UNDO Level component addition failed")
+    creation_redo = (
+        "REDO Level component addition success",
+        "REDO Level component addition failed")
+    diffuse_global_illumination_component = (
+        "Level has a Diffuse Global Illumination component",
+        "Level failed to find Diffuse Global Illumination component")
+    diffuse_global_illumination_quality = (
+        "Quality Level set",
+        "Quality Level could not be set")
+    enter_game_mode = (
+        "Entered game mode",
+        "Failed to enter game mode")
+    exit_game_mode = (
+        "Exited game mode",
+        "Couldn't exit game mode")
+
+
+def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity():
+    """
+    Summary:
+    Tests the Diffuse Global Illumination level component can be added to the level entity and is stable.
+
+    Test setup:
+    - Wait for Editor idle loop.
+    - Open the "Base" level.
+
+    Expected Behavior:
+    The component can be added, used in game mode, and has accurate required components.
+    Creation and deletion undo/redo should also work.
+
+    Test Steps:
+    1) Add Diffuse Global Illumination level component to the level entity.
+    2) UNDO the level component addition.
+    3) REDO the level component addition.
+    4) Set Quality Level property to Low
+    5) Enter/Exit game mode.
+    6) Look for errors and asserts.
+
+    :return: None
+    """
+
+    import azlmbr.legacy.general as general
+
+    from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
+    from editor_python_test_tools.utils import Report, Tracer, TestHelper
+    from Atom.atom_utils.atom_constants import AtomComponentProperties, GLOBAL_ILLUMINATION_QUALITY
+
+    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. Add Diffuse Global Illumination level component to the level entity.
+        diffuse_global_illumination_component = EditorLevelEntity.add_component(
+            AtomComponentProperties.diffuse_global_illumination())
+        Report.critical_result(
+            Tests.diffuse_global_illumination_component,
+            EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
+
+        # 2. UNDO the level component addition.
+        # -> UNDO component addition.
+        general.undo()
+        general.idle_wait_frames(1)
+        Report.result(Tests.creation_undo,
+                      not EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
+
+        # 3. REDO the level component addition.
+        # -> REDO component addition.
+        general.redo()
+        general.idle_wait_frames(1)
+        Report.result(Tests.creation_redo,
+                      EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
+
+        # 4. Set Quality Level property to Low
+        diffuse_global_illumination_component.set_component_property_value(
+            AtomComponentProperties.diffuse_global_illumination('Quality Level', GLOBAL_ILLUMINATION_QUALITY['Low']))
+        quality = diffuse_global_illumination_component.get_component_property_value(
+            AtomComponentProperties.diffuse_global_illumination('Quality Level'))
+        Report.result(diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low'])
+
+        # 5. 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)
+
+        # 6. 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(AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity)

+ 124 - 0
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py

@@ -0,0 +1,124 @@
+"""
+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 level component addition success",
+        "UNDO level component addition failed")
+    creation_redo = (
+        "REDO Level component addition success",
+        "REDO Level component addition failed")
+    display_mapper_component = (
+        "Level has a Display Mapper component",
+        "Level failed to find Display Mapper component")
+    ldr_color_grading_lut = (
+        "LDR color Grading LUT asset set",
+        "LDR color Grading LUT asset could not be set")
+    enable_ldr_color_grading_lut = (
+        "Enable LDR color grading LUT set",
+        "Enable LDR color grading LUT could not be set")
+    enter_game_mode = (
+        "Entered game mode",
+        "Failed to enter game mode")
+    exit_game_mode = (
+        "Exited game mode",
+        "Couldn't exit game mode")
+
+
+def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
+    """
+    Summary:
+    Tests the Display Mapper level component can be added to the level 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, and has accurate required components.
+    Creation and deletion undo/redo should also work.
+
+    Test Steps:
+    1) Add Display Mapper level component to the level entity.
+    2) UNDO the level component addition.
+    3) REDO the level component addition.
+    4) Set LDR color Grading LUT asset.
+    5) Set Enable LDR color grading LUT property True
+    6) Enter/Exit game mode.
+    7) Look for errors and asserts.
+
+    :return: None
+    """
+    import os
+
+    import azlmbr.legacy.general as general
+
+    from editor_python_test_tools.asset_utils import Asset
+    from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
+    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. Add Display Mapper level component to the level entity.
+        display_mapper_component = EditorLevelEntity.add_component(AtomComponentProperties.display_mapper())
+        Report.critical_result(
+            Tests.display_mapper_component,
+            EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
+
+        # 2. UNDO the level component addition.
+        # -> UNDO component addition.
+        general.undo()
+        general.idle_wait_frames(1)
+        Report.result(Tests.creation_undo, not EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
+
+        # 3. REDO the level component addition.
+        # -> REDO component addition.
+        general.redo()
+        general.idle_wait_frames(1)
+        Report.result(Tests.creation_redo, EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
+
+        # 4. Set LDR color Grading LUT asset.
+        display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
+        display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
+        display_mapper_component.set_component_property_value(
+            AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id)
+        Report.result(
+            Tests.ldr_color_grading_lut,
+            display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id)
+
+        # 5. Set Enable LDR color grading LUT property True
+        display_mapper_component.set_component_property_value(
+            AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
+        Report.result(
+            Test.enable_ldr_color_grading_lut,
+            display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
+
+        # 6. 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)
+
+        # 7. 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(AtomEditorComponentsLevel_DisplayMapper_AddedToEntity)

+ 37 - 34
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py

@@ -7,15 +7,6 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
 
 
 
 
 class Tests:
 class Tests:
-    camera_creation = (
-        "Camera Entity successfully created",
-        "Camera Entity failed to be created")
-    camera_component_added = (
-        "Camera component was added to entity",
-        "Camera component failed to be added to entity")
-    camera_component_check = (
-        "Entity has a Camera component",
-        "Entity failed to find Camera component")
     creation_undo = (
     creation_undo = (
         "UNDO Entity creation success",
         "UNDO Entity creation success",
         "UNDO Entity creation failed")
         "UNDO Entity creation failed")
@@ -43,6 +34,9 @@ class Tests:
     ldr_color_grading_lut = (
     ldr_color_grading_lut = (
         "LDR color Grading LUT asset set",
         "LDR color Grading LUT asset set",
         "LDR color Grading LUT asset could not be set")
         "LDR color Grading LUT asset could not be set")
+    enable_ldr_color_grading_lut = (
+        "Enable LDR color grading LUT set",
+        "Enable LDR color grading LUT could not be set")
     entity_deleted = (
     entity_deleted = (
         "Entity deleted",
         "Entity deleted",
         "Entity was not deleted")
         "Entity was not deleted")
@@ -72,14 +66,15 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
     2) Add Display Mapper component to Display Mapper entity.
     2) Add Display Mapper component to Display Mapper entity.
     3) UNDO the entity creation and component addition.
     3) UNDO the entity creation and component addition.
     4) REDO the entity creation and component addition.
     4) REDO the entity creation and component addition.
-    5) Enter/Exit game mode.
-    6) Test IsHidden.
-    7) Test IsVisible.
-    8) Set LDR color Grading LUT asset.
-    9) Delete Display Mapper entity.
-    10) UNDO deletion.
-    11) REDO deletion.
-    12) Look for errors and asserts.
+    5) Set LDR color Grading LUT asset.
+    6) Set Enable LDR color grading LUT property True
+    7) Enter/Exit game mode.
+    8) Test IsHidden.
+    9) Test IsVisible.
+    10) Delete Display Mapper entity.
+    11) UNDO deletion.
+    12) REDO deletion.
+    13) Look for errors and asserts.
 
 
     :return: None
     :return: None
     """
     """
@@ -133,43 +128,51 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
         general.idle_wait_frames(1)
         general.idle_wait_frames(1)
         Report.result(Tests.creation_redo, display_mapper_entity.exists())
         Report.result(Tests.creation_redo, display_mapper_entity.exists())
 
 
-        # 5. Enter/Exit game mode.
+        # 5. Set LDR color Grading LUT asset.
+        display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
+        display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
+        display_mapper_component.set_component_property_value(
+            AtomComponentProperties.display_mapper("LDR color Grading LUT"), display_mapper_asset.id)
+        Report.result(
+            Tests.ldr_color_grading_lut,
+            display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper("LDR color Grading LUT")) == display_mapper_asset.id)
+
+        # 6. Set Enable LDR color grading LUT property True
+        display_mapper_component.set_component_property_value(
+            AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
+        Report.result(
+            Tests.enable_ldr_color_grading_lut,
+            display_mapper_component.get_component_property_value(
+                AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
+
+        # 7. Enter/Exit game mode.
         TestHelper.enter_game_mode(Tests.enter_game_mode)
         TestHelper.enter_game_mode(Tests.enter_game_mode)
         general.idle_wait_frames(1)
         general.idle_wait_frames(1)
         TestHelper.exit_game_mode(Tests.exit_game_mode)
         TestHelper.exit_game_mode(Tests.exit_game_mode)
 
 
-        # 6. Test IsHidden.
+        # 8. Test IsHidden.
         display_mapper_entity.set_visibility_state(False)
         display_mapper_entity.set_visibility_state(False)
         Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
         Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
 
 
-        # 7. Test IsVisible.
+        # 9. Test IsVisible.
         display_mapper_entity.set_visibility_state(True)
         display_mapper_entity.set_visibility_state(True)
         general.idle_wait_frames(1)
         general.idle_wait_frames(1)
         Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
         Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
 
 
-        # 8. Set LDR color Grading LUT asset.
-        display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
-        display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
-        display_mapper_component.set_component_property_value(
-            AtomComponentProperties.display_mapper("LDR color Grading LUT"), display_mapper_asset.id)
-        Report.result(
-            Tests.ldr_color_grading_lut,
-            display_mapper_component.get_component_property_value(
-                AtomComponentProperties.display_mapper("LDR color Grading LUT")) == display_mapper_asset.id)
-
-        # 9. Delete Display Mapper entity.
+        # 10. Delete Display Mapper entity.
         display_mapper_entity.delete()
         display_mapper_entity.delete()
         Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
         Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
 
 
-        # 10. UNDO deletion.
+        # 11. UNDO deletion.
         general.undo()
         general.undo()
         Report.result(Tests.deletion_undo, display_mapper_entity.exists())
         Report.result(Tests.deletion_undo, display_mapper_entity.exists())
 
 
-        # 11. REDO deletion.
+        # 12. REDO deletion.
         general.redo()
         general.redo()
         Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
         Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
 
 
-        # 12. Look for errors and asserts.
+        # 13. Look for errors and asserts.
         TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
         TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
         for error_info in error_tracer.errors:
         for error_info in error_tracer.errors:
             Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
             Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")

+ 97 - 1
AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py

@@ -107,7 +107,6 @@ class EditorComponent:
         return type_ids
         return type_ids
 
 
 
 
-
 def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
 def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
     """
     """
     Converts a vector3-like element into a azlmbr.math.Vector3
     Converts a vector3-like element into a azlmbr.math.Vector3
@@ -120,6 +119,7 @@ def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
     else:
     else:
         raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
         raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
 
 
+
 class EditorEntity:
 class EditorEntity:
     """
     """
     Entity class is used to create and interact with Editor Entities.
     Entity class is used to create and interact with Editor Entities.
@@ -470,3 +470,99 @@ class EditorEntity:
         assert self.id.isValid(), "A valid entity id is required to focus on its owning prefab."
         assert self.id.isValid(), "A valid entity id is required to focus on its owning prefab."
         focus_prefab_result = azlmbr.prefab.PrefabFocusPublicRequestBus(bus.Broadcast, "FocusOnOwningPrefab", self.id)
         focus_prefab_result = azlmbr.prefab.PrefabFocusPublicRequestBus(bus.Broadcast, "FocusOnOwningPrefab", self.id)
         assert focus_prefab_result.IsSuccess(), f"Prefab operation 'FocusOnOwningPrefab' failed. Error: {focus_prefab_result.GetError()}"
         assert focus_prefab_result.IsSuccess(), f"Prefab operation 'FocusOnOwningPrefab' failed. Error: {focus_prefab_result.GetError()}"
+
+
+class EditorLevelEntity:
+    """
+    EditorLevel class used to add and fetch level components.
+    Level entity is a special entity that you do not create/destroy independently of larger systems of level creation.
+    This collects a number of staticmethods that do not rely on entityId since Level entity is found internally by
+    EditorLevelComponentAPIBus requests.
+    """
+
+    @staticmethod
+    def get_type_ids(component_names: list) -> list:
+        """
+        Used to get type ids of given components list for EntityType Level
+        :param: component_names: List of components to get type ids
+        :return: List of type ids of given components.
+        """
+        type_ids = editor.EditorComponentAPIBus(
+            bus.Broadcast, "FindComponentTypeIdsByEntityType", component_names, azlmbr.entity.EntityType().Level
+        )
+        return type_ids
+
+    @staticmethod
+    def add_component(component_name: str) -> EditorComponent:
+        """
+        Used to add new component to Level.
+        :param component_name: String of component name to add.
+        :return: Component object of newly added component.
+        """
+        component = EditorLevelEntity.add_components([component_name])[0]
+        return component
+
+    @staticmethod
+    def add_components(component_names: list) -> List[EditorComponent]:
+        """
+        Used to add multiple components
+        :param: component_names: List of components to add to level
+        :return: List of newly added components to the level
+        """
+        components = []
+        type_ids = EditorLevelEntity.get_type_ids(component_names)
+        for type_id in type_ids:
+            new_comp = EditorComponent()
+            new_comp.type_id = type_id
+            add_component_outcome = editor.EditorLevelComponentAPIBus(
+                bus.Broadcast, "AddComponentsOfType", [type_id]
+            )
+            assert (
+                add_component_outcome.IsSuccess()
+            ), f"Failure: Could not add component: '{new_comp.get_component_name()}' to level"
+            new_comp.id = add_component_outcome.GetValue()[0]
+            components.append(new_comp)
+        return components
+
+    @staticmethod
+    def get_components_of_type(component_names: list) -> List[EditorComponent]:
+        """
+        Used to get components of type component_name that already exists on the level
+        :param component_names: List of names of components to check
+        :return: List of Level Component objects of given component name
+        """
+        component_list = []
+        type_ids = EditorLevelEntity.get_type_ids(component_names)
+        for type_id in type_ids:
+            component = EditorComponent()
+            component.type_id = type_id
+            get_component_of_type_outcome = editor.EditorLevelComponentAPIBus(
+                bus.Broadcast, "GetComponentOfType", type_id
+            )
+            assert (
+                get_component_of_type_outcome.IsSuccess()
+            ), f"Failure: Level does not have component:'{component.get_component_name()}'"
+            component.id = get_component_of_type_outcome.GetValue()
+            component_list.append(component)
+
+        return component_list
+
+    @staticmethod
+    def has_component(component_name: str) -> bool:
+        """
+        Used to verify if the level has the specified component
+        :param component_name: Name of component to check for
+        :return: True, if level has specified component. Else, False
+        """
+        type_ids = EditorLevelEntity.get_type_ids([component_name])
+        return editor.EditorLevelComponentAPIBus(bus.Broadcast, "HasComponentOfType", type_ids[0])
+
+    @staticmethod
+    def count_components_of_type(component_name: str) -> int:
+        """
+        Used to get a count of the specified level component attached to the level
+        :param component_name: Name of component to check for
+        :return: integer count of occurences of level component attached to level or zero if none are present
+        """
+        type_ids = EditorLevelEntity.get_type_ids([component_name])
+        return editor.EditorLevelComponentAPIBus(bus.Broadcast, "CountComponentsOfType", type_ids[0])