123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- /*
- * 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
- *
- */
- #include <native/tests/assetmanager/IntermediateAssetTests.h>
- #include <QCoreApplication>
- #include <native/unittests/UnitTestUtils.h>
- #include <native/utilities/ProductOutputUtil.h>
- #include <AzFramework/IO/LocalFileIO.h>
- namespace UnitTests
- {
- void IntermediateAssetTests::SetUp()
- {
- AssetManagerTestingBase::SetUp();
- }
- void IntermediateAssetTests::TearDown()
- {
- AssetManagerTestingBase::TearDown();
- }
- void IntermediateAssetTests::IncorrectBuilderConfigurationTest(bool commonPlatform, AssetBuilderSDK::ProductOutputFlags flags)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", commonPlatform, flags);
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, m_testFilePath.c_str()));
- QCoreApplication::processEvents();
- RunFile(1);
- m_errorChecker.Begin();
- ProcessJob(*m_rc, m_jobDetailsList[0]);
- m_errorChecker.End(1);
- ASSERT_TRUE(m_fileFailed);
- }
- TEST_F(IntermediateAssetTests, FileProcessedAsIntermediateIntoProduct_NotEnabledType_PathBasedUUID)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2","stage3", false, ProductOutputFlags::ProductAsset);
- ProcessFileMultiStage(2, true);
- // Verify the UUID is generated based on the Source:Builder:SubId and not some randomly generated one
- AssetProcessor::BuilderInfoList builders;
- AssetProcessor::AssetBuilderInfoBus::Broadcast(
- &AssetProcessor::AssetBuilderInfoBus::Events::GetMatchingBuildersInfo, MakePath("test.stage1", true), builders);
- ASSERT_EQ(builders.size(), 1);
- auto builderUuid = builders[0].m_busId;
- auto sourceUuid = AssetUtilities::GetSourceUuid(AssetProcessor::SourceAssetReference(m_testFilePath.c_str())).GetValueOr(AZ::Uuid());
- auto actualIntermediateUuid = AssetUtilities::GetSourceUuid(AssetProcessor::SourceAssetReference(MakePath("test.stage2", true).c_str())).GetValueOr(AZ::Uuid());
- auto uuidFormat = AZStd::string::format(
- AZ_STRING_FORMAT ":" AZ_STRING_FORMAT ":%d",
- AZ_STRING_ARG(sourceUuid.ToFixedString()),
- AZ_STRING_ARG(builderUuid.ToFixedString()),
- AssetSubId);
- auto expectedIntermediateUuid = AZ::Uuid::CreateName(uuidFormat);
- EXPECT_NE(actualIntermediateUuid, expectedIntermediateUuid);
- }
- TEST_F(IntermediateAssetTests, FileProcessedAsIntermediateIntoProduct_EnabledType_SourceBasedUUID)
- {
- using namespace AssetBuilderSDK;
- auto* uuidInterface = AZ::Interface<AssetProcessor::IUuidRequests>::Get();
- ASSERT_TRUE(uuidInterface);
- uuidInterface->EnableGenerationForTypes({ ".stage1" });
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", false, ProductOutputFlags::ProductAsset);
- ProcessFileMultiStage(2, true);
- // Verify the UUID is generated based on the Source:Builder:SubId and not some randomly generated one
- AssetProcessor::BuilderInfoList builders;
- AssetProcessor::AssetBuilderInfoBus::Broadcast(
- &AssetProcessor::AssetBuilderInfoBus::Events::GetMatchingBuildersInfo, MakePath("test.stage1", true), builders);
- ASSERT_EQ(builders.size(), 1);
- auto builderUuid = builders[0].m_busId;
- auto sourceUuid = AssetUtilities::GetSourceUuid(AssetProcessor::SourceAssetReference(m_testFilePath.c_str()));
- auto actualIntermediateUuid =
- AssetUtilities::GetSourceUuid(AssetProcessor::SourceAssetReference(MakePath("test.stage2", true).c_str()));
- ASSERT_TRUE(sourceUuid);
- ASSERT_TRUE(actualIntermediateUuid);
- auto uuidFormat = AZStd::string::format(
- AZ_STRING_FORMAT ":" AZ_STRING_FORMAT ":%d",
- AZ_STRING_ARG(sourceUuid.GetValue().ToFixedString()),
- AZ_STRING_ARG(builderUuid.ToFixedString()),
- AssetSubId);
- auto expectedIntermediateUuid = AZ::Uuid::CreateName(uuidFormat);
- EXPECT_STREQ(actualIntermediateUuid.GetValue().ToFixedString().c_str(), expectedIntermediateUuid.ToFixedString().c_str());
- }
- TEST_F(IntermediateAssetTests, IntermediateOutputWithWrongPlatform_CausesFailure)
- {
- IncorrectBuilderConfigurationTest(false, AssetBuilderSDK::ProductOutputFlags::IntermediateAsset);
- }
- TEST_F(IntermediateAssetTests, ProductOutputWithWrongPlatform_CausesFailure)
- {
- IncorrectBuilderConfigurationTest(true, AssetBuilderSDK::ProductOutputFlags::ProductAsset);
- }
- TEST_F(IntermediateAssetTests, IntermediateAndProductOutputFlags_NormalPlatform_CausesFailure)
- {
- IncorrectBuilderConfigurationTest(false, AssetBuilderSDK::ProductOutputFlags::IntermediateAsset | AssetBuilderSDK::ProductOutputFlags::ProductAsset);
- }
- TEST_F(IntermediateAssetTests, IntermediateAndProductOutputFlags_CommonPlatform_CausesFailure)
- {
- IncorrectBuilderConfigurationTest(true, AssetBuilderSDK::ProductOutputFlags::IntermediateAsset | AssetBuilderSDK::ProductOutputFlags::ProductAsset);
- }
- TEST_F(IntermediateAssetTests, NoFlags_CausesFailure)
- {
- IncorrectBuilderConfigurationTest(false, (AssetBuilderSDK::ProductOutputFlags)(0));
- }
- TEST_F(IntermediateAssetTests, ABALoop_CausesFailure)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage2", true, ProductOutputFlags::IntermediateAsset); // Loop back to an intermediate
- ProcessFileMultiStage(3, false);
- ASSERT_EQ(m_jobDetailsList.size(), 3);
- EXPECT_TRUE(m_jobDetailsList[1].m_autoFail);
- EXPECT_TRUE(m_jobDetailsList[2].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage3");
- EXPECT_EQ(m_jobDetailsList[2].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- }
- TEST_F(IntermediateAssetTests, AALoop_CausesFailure)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage1", true, ProductOutputFlags::IntermediateAsset); // Loop back to the source
- ProcessFileMultiStage(2, false);
- ASSERT_EQ(m_jobDetailsList.size(), 3);
- EXPECT_TRUE(m_jobDetailsList[1].m_autoFail);
- EXPECT_TRUE(m_jobDetailsList[2].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage2");
- EXPECT_EQ(m_jobDetailsList[2].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- }
- TEST_F(IntermediateAssetTests, SelfLoop_CausesFailure)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage1", true, ProductOutputFlags::IntermediateAsset); // Loop back to the source with a single job
- ProcessFileMultiStage(1, false);
- ASSERT_EQ(m_jobDetailsList.size(), 2);
- EXPECT_TRUE(m_jobDetailsList[1].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- m_assetProcessorManager->AssessDeletedFile(MakePath("test.stage1", true).c_str());
- RunFile(0);
- m_assetProcessorManager->CheckFilesToExamine(0);
- m_assetProcessorManager->CheckActiveFiles(0);
- m_assetProcessorManager->CheckJobEntries(0);
- }
- TEST_F(IntermediateAssetTests, CopyJob_Works)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage1", false, ProductOutputFlags::ProductAsset); // Copy jobs are ok
- ProcessFileMultiStage(1, false);
- auto expectedProduct = AZ::IO::Path(m_databaseLocationListener.GetAssetRootDir()) / "Cache" / "pc" / "test.stage1";
- ASSERT_EQ(m_jobDetailsList.size(), 1);
- EXPECT_TRUE(AZ::IO::SystemFile::Exists(expectedProduct.c_str())) << expectedProduct.c_str();
- }
- TEST_F(IntermediateAssetTests, DeleteSourceIntermediate_DeletesAllProducts)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", false, ProductOutputFlags::ProductAsset);
- ProcessFileMultiStage(3, true);
- AZ::IO::SystemFile::Delete(m_testFilePath.c_str());
- m_assetProcessorManager->AssessDeletedFile(m_testFilePath.c_str());
- RunFile(0);
- CheckIntermediate("test.stage2", false);
- CheckIntermediate("test.stage3", false);
- CheckProduct("test.stage4", false);
- }
- void IntermediateAssetTests::DeleteIntermediateTest(const char* deleteFilePath)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", false, ProductOutputFlags::ProductAsset);
- ProcessFileMultiStage(3, true);
- AZ::IO::SystemFile::Delete(deleteFilePath);
- m_assetProcessorManager->AssessDeletedFile(deleteFilePath);
- RunFile(0); // Process the delete
- // Reprocess the file
- m_jobDetailsList.clear();
- // Unfortunately we need to just process the events a few times without doing any checks here
- // due to the previous step queuing work which is sometimes executed immediately.
- // Without a way to consistently be sure whether the work has been done or not, we need to just run enough until the job is emitted
- QCoreApplication::processEvents();
- QCoreApplication::processEvents();
- QCoreApplication::processEvents();
- ASSERT_EQ(m_jobDetailsList.size(), 1);
- ProcessJob(*m_rc, m_jobDetailsList[0]);
- ASSERT_TRUE(m_fileCompiled);
- m_assetProcessorManager->AssetProcessed(m_processedJobEntry, m_processJobResponse);
- CheckIntermediate("test.stage2");
- CheckIntermediate("test.stage3");
- CheckProduct("test.stage4");
- }
- TEST_F(IntermediateAssetTests, DeleteIntermediateProduct_Reprocesses)
- {
- DeleteIntermediateTest(MakePath("test.stage2", true).c_str());
- }
- TEST_F(IntermediateAssetTests, DeleteFinalProduct_Reprocesses)
- {
- DeleteIntermediateTest(MakePath("test.stage4", false).c_str());
- }
- TEST_F(IntermediateAssetTests, Override_NormalFileProcessedFirst_NormalFileOutputsIntermediate_FirstStageCausesFailure)
- {
- // Test that a file outputting an intermediate that conflicts with an existing source which outputs an intermediate fails
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", false, ProductOutputFlags::ProductAsset);
- constexpr int NumberOfStages = 3;
- // Make and process a source file which matches an intermediate output name we will create later
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "test.stage2";
- AZStd::string testFilePath = (scanFolderDir / testFilename).AsPosix();
- UnitTestUtils::CreateDummyFile(testFilePath.c_str(), "unit test file");
- ProcessFileMultiStage(NumberOfStages, true, AssetProcessor::SourceAssetReference(testFilePath.c_str()), 2);
- // Now process another file which produces intermediates that conflict with the existing source file above
- // Only go to stage 1 since we're expecting a failure at that point
- ProcessFileMultiStage(1, false);
- // Expect 2 jobs for the same file, 1 is the job that processed successfully and detected the problem, the 2nd is an autofail job
- // used to actually mark the file as failed
- ASSERT_EQ(m_jobDetailsList.size(), 2);
- EXPECT_FALSE(m_jobDetailsList[0].m_autoFail);
- EXPECT_TRUE(m_jobDetailsList[1].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[0].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- }
- TEST_F(IntermediateAssetTests, Override_NormalFileProcessedFirst_NormalFileOutputsIntermediate_SecondStageCausesFailure)
- {
- // Test that an intermediate outputting an intermediate that conflicts with an existing source which outputs an intermediate fails
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage4", "*.stage4", "stage5", false, ProductOutputFlags::ProductAsset);
- constexpr int NumberOfStages = 4;
- // Make and process a source file which matches an intermediate output name we will create later
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "test.stage3";
- AZStd::string testFilePath = (scanFolderDir / testFilename).AsPosix();
- UnitTestUtils::CreateDummyFile(testFilePath.c_str(), "unit test file");
- ProcessFileMultiStage(NumberOfStages, true, AssetProcessor::SourceAssetReference(testFilePath.c_str()), 3);
- // Now process another file which produces intermediates that conflict with the existing source file above
- // Only go to stage 2 since we're expecting a failure at that point
- ProcessFileMultiStage(2, false);
- // Expect 3 jobs:
- // 1 is the job for stage2 that was processing and detected the failure
- // 1 is the autofail job that was created to autofail stage2
- // 1 is the autofail job for the top level source (stage1)
- ASSERT_EQ(m_jobDetailsList.size(), 3);
- EXPECT_FALSE(m_jobDetailsList[0].m_autoFail);
- EXPECT_TRUE(m_jobDetailsList[1].m_autoFail);
- EXPECT_TRUE(m_jobDetailsList[2].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[0].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage2");
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage2");
- EXPECT_EQ(m_jobDetailsList[2].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- }
- TEST_F(IntermediateAssetTests, Override_NormalFileProcessedFirst_NormalFileOutputsProduct_CausesFailure)
- {
- // Test that a source outputting an intermediate that conflicts with an existing source which outputs a product fails
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", false, ProductOutputFlags::ProductAsset);
- constexpr int NumberOfStages = 2;
- // Make and process a source file which matches an intermediate output name we will create later
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "test.stage2";
- AZStd::string testFilePath = (scanFolderDir / testFilename).AsPosix();
- UnitTestUtils::CreateDummyFile(testFilePath.c_str(), "unit test file");
- ProcessFileMultiStage(NumberOfStages, true, AssetProcessor::SourceAssetReference(testFilePath.c_str()), 2);
- // Now process another file which produces intermediates that conflict with the existing source file above
- // Only go to stage 1 since we're expecting a failure at that point
- ProcessFileMultiStage(1, false);
- // Expect 2 jobs for the same file, 1 is the job that processed successfully and detected the problem, the 2nd is an autofail job
- // used to actually mark the file as failed
- ASSERT_EQ(m_jobDetailsList.size(), 2);
- EXPECT_FALSE(m_jobDetailsList[0].m_autoFail);
- EXPECT_TRUE(m_jobDetailsList[1].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[0].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- }
- TEST_F(IntermediateAssetTests, DeleteFileInIntermediateFolder_CorrectlyDeletesOneFile)
- {
- using namespace AzToolsFramework::AssetDatabase;
- // Set up the test files and database entries
- SourceDatabaseEntry source1{ m_scanfolder.m_scanFolderID, "folder/parent.txt", AZ::Uuid::CreateRandom(), "fingerprint" };
- SourceDatabaseEntry source2{ m_platformConfig->GetIntermediateAssetsScanFolderId().value(), "folder/child.txt", AZ::Uuid::CreateRandom(), "fingerprint" };
- auto sourceFile = AZ::IO::Path(m_scanfolder.m_scanFolder) / "folder/parent.txt"; // This file should NOT be deleted
- auto intermediateFile = MakePath("folder/child.txt", true); // This file should be deleted
- auto cacheFile = MakePath("folder/product.txt", false); // This file should NOT be deleted
- auto cacheFile2 = MakePath("folder/product777.txt", false); // This file should be deleted
- UnitTestUtils::CreateDummyFile(sourceFile.Native().c_str(), QString("tempdata"));
- UnitTestUtils::CreateDummyFile(intermediateFile.c_str(), QString("tempdata"));
- UnitTestUtils::CreateDummyFile(cacheFile.c_str(), QString("tempdata"));
- UnitTestUtils::CreateDummyFile(cacheFile2.c_str(), QString("tempdata"));
- ASSERT_TRUE(m_stateData->SetSource(source1));
- ASSERT_TRUE(m_stateData->SetSource(source2));
- JobDatabaseEntry job1{ source1.m_sourceID,
- "Mock Job",
- 1234,
- "pc",
- m_builderInfoHandler.m_builderDescMap.begin()->second.m_busId,
- AzToolsFramework::AssetSystem::JobStatus::Completed,
- 999 };
- JobDatabaseEntry job2{ source2.m_sourceID,
- "Mock Job",
- 1234,
- "pc",
- m_builderInfoHandler.m_builderDescMap.begin()->second.m_busId,
- AzToolsFramework::AssetSystem::JobStatus::Completed,
- 888 };
- ASSERT_TRUE(m_stateData->SetJob(job1));
- ASSERT_TRUE(m_stateData->SetJob(job2));
- ProductDatabaseEntry product1{ job1.m_jobID,
- 0,
- "pc/folder/product.txt",
- AZ::Uuid::CreateName("one"),
- AZ::Uuid::CreateName("product.txt"),
- 0,
- static_cast<int>(AssetBuilderSDK::ProductOutputFlags::ProductAsset) };
- ProductDatabaseEntry product2{ job2.m_jobID,
- 777,
- "pc/folder/product777.txt",
- AZ::Uuid::CreateName("two"),
- AZ::Uuid::CreateName("product777.txt"),
- 0,
- static_cast<int>(AssetBuilderSDK::ProductOutputFlags::ProductAsset) };
- ASSERT_TRUE(m_stateData->SetProduct(product1));
- ASSERT_TRUE(m_stateData->SetProduct(product2));
- // Record the folder so its marked as a known folder
- auto folderPath = MakePath("folder", true);
- m_assetProcessorManager->RecordFoldersFromScanner(
- QSet{ AssetProcessor::AssetFileInfo{ folderPath.c_str(), QDateTime::currentDateTime(), 0,
- m_platformConfig->GetScanFolderForFile(folderPath.c_str()), true } });
- // Delete the file and folder in the intermediate folder
- AZ::IO::LocalFileIO::GetInstance()->DestroyPath(folderPath.c_str());
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessDeletedFile", Qt::QueuedConnection,
- Q_ARG(QString, MakePath("folder", true).c_str()));
- QCoreApplication::processEvents();
- RunFile(0);
- QCoreApplication::processEvents(); // execute ProcessFilesToExamineQueue
- m_assetProcessorManager->CheckActiveFiles(0);
- m_assetProcessorManager->CheckFilesToExamine(0);
- m_assetProcessorManager->CheckJobEntries(0);
- ProductDatabaseEntry checkEntry;
- ASSERT_TRUE(m_stateData->GetProductByProductID(product1.m_productID, checkEntry));
- ASSERT_FALSE(m_stateData->GetProductByProductID(product2.m_productID, checkEntry));
- ASSERT_TRUE(AZ::IO::SystemFile::Exists(sourceFile.c_str()));
- ASSERT_FALSE(AZ::IO::SystemFile::Exists(intermediateFile.c_str()));
- }
- TEST_F(IntermediateAssetTests, Override_IntermediateFileProcessedFirst_NormalFileOutputsIntermediate_CausesFailure)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", false, ProductOutputFlags::ProductAsset);
- constexpr int NumberOfStages = 3;
- // Process a file from stage1 -> stage4, this will create several intermediates
- ProcessFileMultiStage(NumberOfStages, true);
- // Now make a source file which is the same name as an existing intermediate and process it
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "test.stage2";
- AZStd::string testFilePath = (scanFolderDir / testFilename).AsPosix();
- UnitTestUtils::CreateDummyFile(testFilePath.c_str(), "unit test file");
- ProcessFileMultiStage(NumberOfStages, true, AssetProcessor::SourceAssetReference(testFilePath.c_str()), 2, true);
- ASSERT_EQ(m_jobDetailsList.size(), 1);
- EXPECT_FALSE(m_jobDetailsList[0].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[0].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage3");
- }
- TEST_F(IntermediateAssetTests, Override_IntermediateFileProcessedFirst_NormalFileOutputsProduct_CausesFailure)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", false, ProductOutputFlags::ProductAsset);
- constexpr int NumberOfStages = 2;
- // Process a file from stage1 -> stage4, this will create several intermediates
- ProcessFileMultiStage(NumberOfStages, true);
- // Now make a source file which is the same name as an existing intermediate and process it
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "test.stage2";
- AZStd::string testFilePath = (scanFolderDir / testFilename).AsPosix();
- UnitTestUtils::CreateDummyFile(testFilePath.c_str(), "unit test file");
- ProcessFileMultiStage(NumberOfStages, true, AssetProcessor::SourceAssetReference(testFilePath.c_str()), 2, true);
- ASSERT_EQ(m_jobDetailsList.size(), 2);
- EXPECT_TRUE(m_jobDetailsList[0].m_autoFail);
- EXPECT_FALSE(m_jobDetailsList[1].m_autoFail);
- EXPECT_EQ(m_jobDetailsList[0].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage1");
- EXPECT_EQ(m_jobDetailsList[1].m_jobEntry.m_sourceAssetReference.RelativePath().Native(), "test.stage2");
- }
- TEST_F(IntermediateAssetTests, DuplicateOutputs_CausesFailure)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset, true);
- CreateBuilder("stage2", "*.stage2", "stage3", false, ProductOutputFlags::ProductAsset);
- ProcessFileMultiStage(2, true, {}, 1, false, true);
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "test2.stage1";
- UnitTestUtils::CreateDummyFile((scanFolderDir / testFilename).c_str(), "unit test file");
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, (scanFolderDir / testFilename).c_str()));
- QCoreApplication::processEvents();
- RunFile(1);
- ProcessJob(*m_rc, m_jobDetailsList[0]);
- ASSERT_TRUE(m_fileCompiled);
- m_jobDetailsList.clear();
- m_assetProcessorManager->AssetProcessed(m_processedJobEntry, m_processJobResponse);
- ASSERT_EQ(m_jobDetailsList.size(), 1);
- EXPECT_TRUE(m_jobDetailsList[0].m_autoFail);
- }
- TEST_F(IntermediateAssetTests, SourceAsset_SourceDependencyOnIntermediate_Reprocesses)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", false, ProductOutputFlags::ProductAsset);
- // Builder for the normal file, with a source dependency on the .stage2 intermediate
- m_builderInfoHandler.CreateBuilderDesc(
- "normal file builder", AZ::Uuid::CreateName("normal file builder").ToFixedString().c_str(),
- { AssetBuilderPattern{ "*.test", AssetBuilderPattern::Wildcard } },
- UnitTests::MockMultiBuilderInfoHandler::AssetBuilderExtraInfo{ "", "test.stage2", "", "", {} });
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "one.test";
- UnitTestUtils::CreateDummyFile((scanFolderDir / testFilename).c_str(), "unit test file");
- // Process the intermediate-style file first
- ProcessFileMultiStage(2, true);
- // Process the regular source second
- ProcessFileMultiStage(1, false, AssetProcessor::SourceAssetReference((scanFolderDir / testFilename).c_str()));
- // Modify the intermediate-style file so it will be processed again
- QFile writer(m_testFilePath.c_str());
- ASSERT_TRUE(writer.open(QFile::WriteOnly));
- {
- QTextStream ts(&writer);
- ts.setCodec("UTF-8");
- ts << "modified test file";
- }
- // Start processing the test.stage1 file again
- QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, m_testFilePath.c_str()));
- QCoreApplication::processEvents();
- // Process test.stage1, which should queue up test.stage2
- ProcessSingleStep();
- // Start processing test.stage2, this should cause one.test to also be placed in the processing queue
- RunFile(1, 1, 1);
- }
- TEST_F(IntermediateAssetTests, IntermediateAsset_SourceDependencyOnSourceAsset_Reprocesses)
- {
- using namespace AssetBuilderSDK;
- using namespace AzToolsFramework::AssetDatabase;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- m_builderInfoHandler.CreateBuilderDesc(
- "stage2", AZ::Uuid::CreateRandom().ToFixedString().c_str(), { AssetBuilderPattern{ "*.stage2", AssetBuilderPattern::Wildcard } },
- CreateJobStage("stage2", false, PathOrUuid("one.test")),
- ProcessJobStage("stage3", ProductOutputFlags::ProductAsset, false), "fingerprint");
- CreateBuilder("normal file builder", "*.test", "test", false, ProductOutputFlags::ProductAsset);
- AZ::IO::Path scanFolderDir(m_scanfolder.m_scanFolder);
- AZStd::string testFilename = "one.test";
- UnitTestUtils::CreateDummyFile((scanFolderDir / testFilename).c_str(), "unit test file");
- // Process the normal source first
- ProcessFileMultiStage(1, false, AssetProcessor::SourceAssetReference((scanFolderDir / testFilename).c_str()));
- // Process the intermediate-style source second
- ProcessFileMultiStage(2, true);
- // Modify the normal source so it will be processed again
- QFile writer((scanFolderDir / testFilename).c_str());
- ASSERT_TRUE(writer.open(QFile::WriteOnly));
- {
- QTextStream ts(&writer);
- ts.setCodec("UTF-8");
- ts << "modified test file";
- }
- // Start processing the one.test file again
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, (scanFolderDir / testFilename).c_str()));
- QCoreApplication::processEvents();
- // Start processing one.test, this should cause test.stage2 to also be placed in the processing queue
- RunFile(1, 1, 1);
- }
- TEST_F(IntermediateAssetTests, RequestReprocess_ReprocessesAllIntermediates)
- {
- using namespace AssetBuilderSDK;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", false, ProductOutputFlags::ProductAsset);
- ProcessFileMultiStage(3, true);
- EXPECT_EQ(m_assetProcessorManager->RequestReprocess(m_testFilePath.c_str()), 3);
- EXPECT_EQ(m_assetProcessorManager->RequestReprocess(MakePath("test.stage2", true).c_str()), 3);
- }
- TEST_F(IntermediateAssetTests, PriorProductsAreCleanedUp)
- {
- using namespace AssetBuilderSDK;
- int counter = 0;
- CreateBuilder("stage1", "*.stage1", "stage2", true, ProductOutputFlags::IntermediateAsset);
- // Custom builder with random output
- m_builderInfoHandler.CreateBuilderDesc(
- "stage2",
- AZ::Uuid::CreateRandom().ToFixedString().c_str(),
- { AssetBuilderPattern{ "*.stage2", AssetBuilderPattern::Wildcard } },
- CreateJobStage("stage2", true),
- [&counter](const ProcessJobRequest& request, ProcessJobResponse& response)
- {
- ++counter;
- AZ::IO::Path outputFile = request.m_sourceFile;
- outputFile.ReplaceExtension(AZStd::string::format("stage3_%d", counter).c_str());
- AZ::IO::LocalFileIO::GetInstance()->Copy(
- request.m_fullPath.c_str(), (AZ::IO::Path(request.m_tempDirPath) / outputFile).c_str());
- auto product = JobProduct{ outputFile.c_str(), AZ::Data::AssetType::CreateName("stage2"), 1 };
- product.m_outputFlags = ProductOutputFlags::IntermediateAsset;
- product.m_dependenciesHandled = true;
- response.m_outputProducts.push_back(product);
- response.m_resultCode = ProcessJobResult_Success;
- },
- "fingerprint");
- CreateBuilder("stage3", "*.stage3_*", "stage4", false, ProductOutputFlags::ProductAsset);
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, m_testFilePath.c_str()));
- QCoreApplication::processEvents();
- // Process test.stage1, which should queue up test.stage2
- // We're going to do this manually instead of using the helper because this test uses a different file naming convention
- ProcessSingleStep();
- CheckIntermediate("test.stage2");
- ProcessSingleStep();
- CheckIntermediate("test.stage3_1");
- ProcessSingleStep();
- CheckProduct("test.stage4");
- // Modify the source file
- UnitTestUtils::CreateDummyFile(m_testFilePath.c_str(), "modified unit test file");
- // Run again, this time expecting the stage3_2 to be output instead of stage3_1
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, m_testFilePath.c_str()));
- QCoreApplication::processEvents();
- ProcessSingleStep();
- CheckIntermediate("test.stage2");
- ProcessSingleStep();
- CheckIntermediate("test.stage3_1", false); // Prior intermediate is deleted
- CheckIntermediate("test.stage3_2", true); // New intermediate created
- ProcessSingleStep();
- CheckProduct("test.stage4"); // Same product result at the end
- }
- TEST_F(IntermediateAssetTests, UpdateSource_OutputDoesntChange_IntermediateDoesNotReprocess)
- {
- using namespace AssetBuilderSDK;
- // Custom builder with fixed product output
- m_builderInfoHandler.CreateBuilderDesc(
- "stage1",
- AZ::Uuid::CreateRandom().ToFixedString().c_str(),
- { AssetBuilderPattern{ "*.stage1", AssetBuilderPattern::Wildcard } },
- CreateJobStage("stage1", true),
- [](const ProcessJobRequest& request, ProcessJobResponse& response)
- {
- AZ::IO::Path outputFile = request.m_sourceFile;
- outputFile.ReplaceExtension("stage2");
- auto* fileIo = AZ::IO::LocalFileIO::GetInstance();
- AZ::IO::HandleType fileHandle;
- AZStd::string data = "hello world"; // We'll output the same product every time no matter what the input source is
- fileIo->Open((AZ::IO::Path(request.m_tempDirPath) / outputFile).c_str(), AZ::IO::OpenMode::ModeWrite, fileHandle);
- fileIo->Write(fileHandle, data.data(), data.size());
- fileIo->Close(fileHandle);
- auto product = JobProduct{ outputFile.c_str(), AZ::Data::AssetType::CreateName("stage2"), 1 };
- product.m_outputFlags = ProductOutputFlags::IntermediateAsset;
- product.m_dependenciesHandled = true;
- response.m_outputProducts.push_back(product);
- response.m_resultCode = ProcessJobResult_Success;
- }, "fingerprint");
- CreateBuilder("stage2", "*.stage2", "stage3", true, ProductOutputFlags::IntermediateAsset);
- CreateBuilder("stage3", "*.stage3", "stage4", false, ProductOutputFlags::ProductAsset);
- // Process once
- ProcessFileMultiStage(3, true);
- // Modify the source file
- UnitTestUtils::CreateDummyFile(m_testFilePath.c_str(), "modified unit test file");
- // Start processing the test.stage1 file again
- QMetaObject::invokeMethod(
- m_assetProcessorManager.get(), "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, m_testFilePath.c_str()));
- QCoreApplication::processEvents();
- // Process test.stage1, which should queue up test.stage2
- ProcessSingleStep();
- // Start processing test.stage2, this shouldn't create a job since the input is the same
- RunFile(0, 1, 0);
- }
- } // namespace UnitTests
|