scene_tests.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. """
  2. Copyright (c) Contributors to the Open 3D Engine Project.
  3. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. """
  6. import logging
  7. import os
  8. import re
  9. from pprint import pformat
  10. import pytest
  11. import ly_test_tools.o3de.pipeline_utils as utils
  12. from _pytest.mark import ParameterSet
  13. from ly_test_tools._internal.managers.workspace import AbstractWorkspaceManager
  14. from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
  15. from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor
  16. from assetpipeline.ap_fixtures.ap_setup_fixture import ap_setup_fixture
  17. import assetpipeline.scene_tests_fixtures.scene_test_debug_compare as parse_and_compare
  18. import assetpipeline.scene_tests_fixtures.scene_test_builder as test_builder
  19. from automatedtesting_shared import asset_database_utils as asset_db_utils
  20. logger = logging.getLogger(__name__)
  21. targetProjects = ["AutomatedTesting"]
  22. test_dir_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "tests")
  23. blackbox_scene_tests, blackbox_test_ids = test_builder.parametrize_blackbox_scene_test(test_dir_path)
  24. def get_cache_folder(asset_processor: object) -> str:
  25. """Helper: Gets a case correct version of the cache folder."""
  26. # Leave the "c" in Cache uppercase.
  27. return re.sub("ache[/\\\\](.*)", lambda m: m.group().lower(), asset_processor.project_test_cache_folder())
  28. @pytest.fixture
  29. def local_resources(request: any, workspace: AbstractWorkspaceManager, ap_setup_fixture: dict) -> None:
  30. """Test-level asset folder. Directory contains a subfolder for each test."""
  31. ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__))
  32. @pytest.mark.usefixtures("asset_processor")
  33. @pytest.mark.usefixtures("ap_setup_fixture")
  34. @pytest.mark.usefixtures("local_resources")
  35. @pytest.mark.parametrize("project", targetProjects)
  36. @pytest.mark.assetpipeline
  37. @pytest.mark.SUITE_sandbox
  38. class TestScene_AllPlatforms(object):
  39. @pytest.mark.BAT
  40. @pytest.mark.parametrize("blackbox_param", blackbox_scene_tests, ids=blackbox_test_ids)
  41. def test_SceneBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace: AbstractWorkspaceManager,
  42. ap_setup_fixture: dict,
  43. asset_processor: object, project: any,
  44. blackbox_param: ParameterSet) -> None:
  45. """
  46. Please see run_fbx_test(...) for details
  47. Test Steps:
  48. 1. Determine if blackbox is set to none
  49. 2. Run FBX Test
  50. 3. Determine if override assets is set to none
  51. 4. If not, re-run FBX test and validate the information in override assets
  52. """
  53. self.run_scene_test(workspace, ap_setup_fixture, asset_processor, project, blackbox_param)
  54. if blackbox_param.override_assets is not None:
  55. # Run the test again and validate the information in the override assets
  56. self.run_scene_test(workspace, ap_setup_fixture,
  57. asset_processor, project, blackbox_param, True)
  58. @staticmethod
  59. def run_ap_debug_skip_atom_output(asset_processor: object) -> None:
  60. """Helper: Run Asset Processor with debug output enabled and Atom output disabled."""
  61. result, output = asset_processor.batch_process(capture_output=True, extra_params=["--debugOutput",
  62. "--regset=\"/O3DE/SceneAPI/AssetImporter/SkipAtomOutput=true\""])
  63. # If the test fails, it's helpful to have the output from asset processor in the logs, to track the failure down.
  64. logger.info(f"Asset Processor Output: {pformat(output)}")
  65. assert result, "Asset Processor Failed"
  66. @staticmethod
  67. def check_missing_assets(expected_product_list: list, cache_folder: str) -> None:
  68. """Helper: Compare expected products with products in cache, report on missing products."""
  69. missing_assets, _ = utils.compare_assets_with_cache(expected_product_list,
  70. cache_folder)
  71. # If the test is going to fail, print information to help track down the cause of failure.
  72. if missing_assets:
  73. in_cache = os.listdir(cache_folder)
  74. logger.info(f"The following assets were missing from cache: {pformat(missing_assets)}")
  75. logger.info(f"The cache {cache_folder} contains this content: {pformat(in_cache)}")
  76. assert not missing_assets, \
  77. f'The following assets were expected to be in, but not found in cache: {str(missing_assets)}'
  78. @staticmethod
  79. def populate_asset_info(workspace: AbstractWorkspaceManager, project: any, assets: iter) -> None:
  80. """Helper: Populates the platform info for each given source asset in the expected jobs and products."""
  81. for expected_source in assets:
  82. for expected_job in expected_source.jobs:
  83. expected_job.platform = ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]
  84. for expected_product in expected_job.products:
  85. expected_product.product_name = expected_job.platform + "/" \
  86. + expected_product.product_name
  87. def run_scene_test(self, workspace: AbstractWorkspaceManager, ap_setup_fixture: dict, asset_processor: object,
  88. project: any, blackbox_params: "BlackboxAssetTest", overrideAsset: bool = False) -> None:
  89. """
  90. These tests work by having the test case ingest the test data and determine the run pattern.
  91. Tests will process scene settings files and will additionally do a verification against a provided debug file
  92. Additionally, if an override is passed, the output is checked against the override.
  93. Test Steps:
  94. 1. Create temporary test environment
  95. 2. Process Assets
  96. 3. Determine what assets to validate based upon test data
  97. 4. Validate assets were created in cache
  98. 5. If debug file provided, verify scene files were generated correctly
  99. 6. Verify that each given source asset resulted in the expected jobs and products
  100. """
  101. # Test Setup: Setup variables and test environment based on whether or not the test is using overrides
  102. if not overrideAsset:
  103. assets_to_validate = blackbox_params.assets
  104. test_assets_folder = blackbox_params.asset_folder
  105. expected_scene_debug_file = blackbox_params.scene_debug_file
  106. asset_processor.prepare_test_environment(ap_setup_fixture['tests_dir'], test_assets_folder)
  107. else:
  108. assets_to_validate = blackbox_params.override_assets
  109. test_assets_folder = blackbox_params.override_asset_folder
  110. expected_scene_debug_file = blackbox_params.override_scene_debug_file
  111. asset_processor.prepare_test_environment(ap_setup_fixture['tests_dir'], test_assets_folder,
  112. use_current_root=True, add_scan_folder=False,
  113. existing_function_name=blackbox_params.asset_folder)
  114. logger.info(f"{blackbox_params.test_name}: Processing assets in folder '"
  115. f"{test_assets_folder}' and verifying they match expected output.")
  116. self.run_ap_debug_skip_atom_output(asset_processor)
  117. logger.info(f"Validating assets.")
  118. # Get a list of the expected product assets and compare it with the actual product assets in cache.
  119. expected_product_list = parse_and_compare.populate_expected_product_assets(assets_to_validate)
  120. cache_folder = get_cache_folder(asset_processor)
  121. self.check_missing_assets(expected_product_list, cache_folder)
  122. # Load the asset database and cache root paths.
  123. db_path = os.path.join(asset_processor.temp_asset_root(), "Cache", "assetdb.sqlite")
  124. cache_root = os.path.dirname(os.path.join(asset_processor.temp_asset_root(), "Cache",
  125. ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]))
  126. actual_scene_debug_file = os.path.join(get_cache_folder(asset_processor), blackbox_params.scene_debug_file)
  127. # Compare expected and actual debug output from .dbgsg files
  128. if blackbox_params.scene_debug_file:
  129. expected_hashes_to_skip, actual_hashes_to_skip = parse_and_compare.compare_scene_debug_file(
  130. asset_processor,
  131. expected_scene_debug_file,
  132. actual_scene_debug_file
  133. )
  134. # Run again for the .dbgsg.xml file
  135. parse_and_compare.compare_scene_debug_file(
  136. asset_processor,
  137. expected_scene_debug_file + ".xml",
  138. actual_scene_debug_file + ".xml",
  139. expected_hashes_to_skip=expected_hashes_to_skip,
  140. actual_hashes_to_skip=actual_hashes_to_skip
  141. )
  142. # Check that each given source asset resulted in the expected jobs and products.
  143. self.populate_asset_info(workspace, project, assets_to_validate)
  144. for expected_source in assets_to_validate:
  145. for expected_job in expected_source.jobs:
  146. for expected_product in expected_job.products:
  147. asset_db_utils.compare_expected_asset_to_actual_asset(
  148. db_path,
  149. expected_source,
  150. f"{blackbox_params.asset_folder}/"
  151. f"{expected_source.source_file_name}",
  152. cache_root
  153. )