|
@@ -4674,6 +4674,80 @@ TEST_F(AssetProcessorManagerTest, JobDependencyOrderOnce_MultipleJobs_EmitOK)
|
|
|
EXPECT_STREQ(jobDetails[1].m_jobDependencyList[0].m_jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str(), secondSourceFile.toUtf8().constData()); // there should only be one job dependency
|
|
|
}
|
|
|
|
|
|
+TEST_F(AssetProcessorManagerTest, JobDependency_WrongPlatformEmitted_FailsJob)
|
|
|
+{
|
|
|
+ using namespace AssetProcessor;
|
|
|
+ using namespace AssetBuilderSDK;
|
|
|
+
|
|
|
+ QString watchFolderPath = m_assetRootDir.absoluteFilePath("subfolder1");
|
|
|
+ const ScanFolderInfo* scanFolder = m_config->GetScanFolderByPath(watchFolderPath);
|
|
|
+ ASSERT_NE(scanFolder, nullptr);
|
|
|
+ const char relSourceFileName[] = "a.dummy";
|
|
|
+ const char secondRelSourceFile[] = "b.dummy";
|
|
|
+ QString sourceFileName = m_assetRootDir.absoluteFilePath("subfolder1/a.dummy");
|
|
|
+ QString secondSourceFile = m_assetRootDir.absoluteFilePath("subfolder1/b.dummy");
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(sourceFileName, QString("tempdata\n")));
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(secondSourceFile, QString("tempdata\n")));
|
|
|
+
|
|
|
+ AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
|
|
|
+ builderDescriptor.m_name = "Test Dummy Builder";
|
|
|
+ builderDescriptor.m_patterns.push_back(
|
|
|
+ AssetBuilderSDK::AssetBuilderPattern("*.dummy", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
|
|
+ builderDescriptor.m_busId = AZ::Uuid::CreateRandom();
|
|
|
+ builderDescriptor.m_createJobFunction =
|
|
|
+ [&](const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
|
|
|
+ {
|
|
|
+ AssetBuilderSDK::JobDescriptor jobDescriptor;
|
|
|
+ jobDescriptor.m_jobKey = builderDescriptor.m_name;
|
|
|
+
|
|
|
+ // create a job for PC
|
|
|
+ jobDescriptor.SetPlatformIdentifier("pc");
|
|
|
+ if (AzFramework::StringFunc::EndsWith(request.m_sourceFile.c_str(), relSourceFileName))
|
|
|
+ {
|
|
|
+ AssetBuilderSDK::SourceFileDependency dep = { secondRelSourceFile, AZ::Uuid::CreateNull() };
|
|
|
+
|
|
|
+ // - SEE BELOW this is the crucial part of the test
|
|
|
+ AssetBuilderSDK::JobDependency jobDep(builderDescriptor.m_name, "ios", AssetBuilderSDK::JobDependencyType::Order, dep);
|
|
|
+ jobDescriptor.m_jobDependencyList.emplace_back(jobDep);
|
|
|
+ }
|
|
|
+ response.m_createJobOutputs.emplace_back(jobDescriptor);
|
|
|
+ response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
|
|
+ };
|
|
|
+ builderDescriptor.m_processJobFunction =
|
|
|
+ [](const AssetBuilderSDK::ProcessJobRequest& /*request*/, AssetBuilderSDK::ProcessJobResponse& response)
|
|
|
+ {
|
|
|
+ response.m_resultCode = AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success;
|
|
|
+ };
|
|
|
+
|
|
|
+ MockApplicationManager::BuilderFilePatternMatcherAndBuilderDesc builderFilePatternMatcher;
|
|
|
+ builderFilePatternMatcher.m_builderDesc = builderDescriptor;
|
|
|
+ builderFilePatternMatcher.m_internalBuilderName = builderDescriptor.m_name;
|
|
|
+ builderFilePatternMatcher.m_internalUuid = builderDescriptor.m_busId;
|
|
|
+ builderFilePatternMatcher.m_matcherBuilderPattern =
|
|
|
+ AssetUtilities::BuilderFilePatternMatcher(builderDescriptor.m_patterns.back(), builderDescriptor.m_busId);
|
|
|
+ m_mockApplicationManager->m_matcherBuilderPatterns.emplace_back(builderFilePatternMatcher);
|
|
|
+
|
|
|
+ // Capture the job details as the APM inspects the file.
|
|
|
+ AZStd::vector<JobDetails> jobDetails;
|
|
|
+ auto connection = QObject::connect(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ &AssetProcessorManager::AssetToProcess,
|
|
|
+ [&jobDetails](JobDetails job)
|
|
|
+ {
|
|
|
+ jobDetails.emplace_back(job);
|
|
|
+ });
|
|
|
+
|
|
|
+ // Tell the APM about the file:
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileName));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, secondSourceFile));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ // the job should auto fail.
|
|
|
+ EXPECT_EQ(jobDetails.size(), 2);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), sourceFileName);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_autoFail, true); // the job should be auto-failed because the dependency is for a different platform
|
|
|
+}
|
|
|
|
|
|
TEST_F(AssetProcessorManagerTest, JobDependencyOrderOnly_MultipleJobs_EmitOK)
|
|
|
{
|
|
@@ -4814,6 +4888,338 @@ TEST_F(AssetProcessorManagerTest, JobDependencyOrderOnly_MultipleJobs_EmitOK)
|
|
|
EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), secondSourceFile);
|
|
|
}
|
|
|
|
|
|
+TEST_F(AssetProcessorManagerTest, JobDependencyOrdered_CausesReprocessingIfDependencyChanges)
|
|
|
+{
|
|
|
+ using namespace AssetProcessor;
|
|
|
+ using namespace AssetBuilderSDK;
|
|
|
+
|
|
|
+ QString watchFolderPath = m_assetRootDir.absoluteFilePath("subfolder1");
|
|
|
+ const ScanFolderInfo* scanFolder = m_config->GetScanFolderByPath(watchFolderPath);
|
|
|
+ ASSERT_NE(scanFolder, nullptr);
|
|
|
+
|
|
|
+ // A.dummy depends on B.dummy, as a JOB dep ordered
|
|
|
+ const char relSourceFileName[] = "a.dummy";
|
|
|
+ const char secondRelSourceFile[] = "b.dummy";
|
|
|
+ QString sourceFileName = m_assetRootDir.absoluteFilePath("subfolder1/a.dummy");
|
|
|
+ QString secondSourceFile = m_assetRootDir.absoluteFilePath("subfolder1/b.dummy");
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(sourceFileName, QString("tempdata\n")));
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(secondSourceFile, QString("tempdata\n")));
|
|
|
+
|
|
|
+ AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
|
|
|
+ builderDescriptor.m_name = "Test Dummy Builder";
|
|
|
+ builderDescriptor.m_patterns.push_back(
|
|
|
+ AssetBuilderSDK::AssetBuilderPattern("*.dummy", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
|
|
+ builderDescriptor.m_busId = AZ::Uuid::CreateRandom();
|
|
|
+ builderDescriptor.m_createJobFunction =
|
|
|
+ [&](const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
|
|
|
+ {
|
|
|
+ AssetBuilderSDK::JobDescriptor jobDescriptor;
|
|
|
+ jobDescriptor.m_jobKey = builderDescriptor.m_name;
|
|
|
+ jobDescriptor.SetPlatformIdentifier("pc");
|
|
|
+ if (AzFramework::StringFunc::EndsWith(request.m_sourceFile.c_str(), relSourceFileName))
|
|
|
+ {
|
|
|
+ AssetBuilderSDK::SourceFileDependency dep = { secondRelSourceFile, AZ::Uuid::CreateNull() };
|
|
|
+ AssetBuilderSDK::JobDependency jobDep(builderDescriptor.m_name, "pc", AssetBuilderSDK::JobDependencyType::Order, dep);
|
|
|
+ jobDescriptor.m_jobDependencyList.emplace_back(jobDep);
|
|
|
+ }
|
|
|
+ response.m_createJobOutputs.emplace_back(jobDescriptor);
|
|
|
+ response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
|
|
+ };
|
|
|
+ builderDescriptor.m_processJobFunction =
|
|
|
+ [](const AssetBuilderSDK::ProcessJobRequest& /*request*/, AssetBuilderSDK::ProcessJobResponse& response)
|
|
|
+ {
|
|
|
+ response.m_resultCode = AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success;
|
|
|
+ };
|
|
|
+
|
|
|
+ MockApplicationManager::BuilderFilePatternMatcherAndBuilderDesc builderFilePatternMatcher;
|
|
|
+ builderFilePatternMatcher.m_builderDesc = builderDescriptor;
|
|
|
+ builderFilePatternMatcher.m_internalBuilderName = builderDescriptor.m_name;
|
|
|
+ builderFilePatternMatcher.m_internalUuid = builderDescriptor.m_busId;
|
|
|
+ builderFilePatternMatcher.m_matcherBuilderPattern =
|
|
|
+ AssetUtilities::BuilderFilePatternMatcher(builderDescriptor.m_patterns.back(), builderDescriptor.m_busId);
|
|
|
+ m_mockApplicationManager->m_matcherBuilderPatterns.emplace_back(builderFilePatternMatcher);
|
|
|
+
|
|
|
+ // Capture the job details as the APM inspects the file.
|
|
|
+ AZStd::vector<JobDetails> jobDetails;
|
|
|
+ auto connection = QObject::connect(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ &AssetProcessorManager::AssetToProcess,
|
|
|
+ [&jobDetails](JobDetails job)
|
|
|
+ {
|
|
|
+ jobDetails.emplace_back(job);
|
|
|
+ });
|
|
|
+
|
|
|
+ // Tell the APM about both files.
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileName));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, secondSourceFile));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ // Although we have processed a.dummy first, APM should send us notification of b.dummy job first and than of a.dummy job
|
|
|
+ EXPECT_EQ(jobDetails.size(), 2);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), secondSourceFile);
|
|
|
+ EXPECT_EQ(jobDetails[1].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), sourceFileName);
|
|
|
+ EXPECT_EQ(jobDetails[1].m_jobDependencyList.size(), 1); // there should only be one job dependency
|
|
|
+ EXPECT_EQ(
|
|
|
+ jobDetails[1].m_jobDependencyList[0].m_jobDependency.m_sourceFile.m_sourceFileDependencyPath,
|
|
|
+ secondSourceFile.toUtf8().constData()); // there should only be one job dependency
|
|
|
+
|
|
|
+ // Process jobs in APM
|
|
|
+ auto destination = jobDetails[0].m_cachePath;
|
|
|
+ QString productAFileName = (destination / "aoutput.txt").AsPosix().c_str();
|
|
|
+ QString productBFileName = (destination / "boutput.txt").AsPosix().c_str();
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(productBFileName, QString("tempdata\n")));
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(productAFileName, QString("tempdata\n")));
|
|
|
+
|
|
|
+ AssetBuilderSDK::ProcessJobResponse responseB;
|
|
|
+ responseB.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
|
+ responseB.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("boutput.txt", AZ::Uuid::CreateNull(), 1));
|
|
|
+
|
|
|
+ AssetBuilderSDK::ProcessJobResponse responseA;
|
|
|
+ responseA.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
|
+ responseA.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("aoutput.txt", AZ::Uuid::CreateNull(), 1));
|
|
|
+
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssetProcessed", Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[0].m_jobEntry), Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseB));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssetProcessed", Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[1].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseA));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ jobDetails.clear();
|
|
|
+ m_isIdling = false;
|
|
|
+
|
|
|
+ // Modify source file b.dummy, a.dummy should auto process since a job order dependency exists on it.
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(secondSourceFile, QString("temp\n")));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, secondSourceFile));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+ // both files should have been reprocesed.
|
|
|
+ // Although we have processed a.dummy first, APM should send us notification of b.dummy job first and than of a.dummy job
|
|
|
+ ASSERT_EQ(jobDetails.size(), 2);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), secondSourceFile);
|
|
|
+ EXPECT_EQ(jobDetails[1].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), sourceFileName);
|
|
|
+ ASSERT_EQ(jobDetails[1].m_jobDependencyList.size(), 1); // there should only be one job dependency
|
|
|
+ EXPECT_EQ(jobDetails[1].m_jobDependencyList[0].m_jobDependency.m_sourceFile.m_sourceFileDependencyPath,
|
|
|
+ secondSourceFile.toUtf8().constData()); // there should only be one job dependency
|
|
|
+
|
|
|
+ // Ack both files as having processed.
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[0].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseB));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[1].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseA));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ jobDetails.clear();
|
|
|
+
|
|
|
+ // Modify source file a.dummy, we should only see one job with source file a.dummy getting processed in this case.
|
|
|
+ // Becuase b.dummy does not depend on it, the dependency goes the other way.
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(sourceFileName, QString("temp\n")));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileName));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+ EXPECT_EQ(jobDetails.size(), 1);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), sourceFileName);
|
|
|
+ EXPECT_EQ(
|
|
|
+ jobDetails[0].m_jobDependencyList.size(),
|
|
|
+ 1); // there should be one job dependency since APM has already processed b.dummy before but a.dummy has OrderOnly dependency on it.
|
|
|
+
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[0].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseA));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ jobDetails.clear();
|
|
|
+ m_isIdling = false;
|
|
|
+}
|
|
|
+
|
|
|
+// this test has
|
|
|
+// a.dummy
|
|
|
+// depends on b.dummy as a job dependency on b.dummy subid 0
|
|
|
+// b.dummy outputs subid 1
|
|
|
+// a should not reprocess
|
|
|
+// b.dummy outputs subid 0
|
|
|
+// a should reprocess.
|
|
|
+
|
|
|
+TEST_F(AssetProcessorManagerTest, JobDependencyOrdered_CausesReprocessingIfDependencyChanges_UsingSubID)
|
|
|
+{
|
|
|
+ using namespace AssetProcessor;
|
|
|
+ using namespace AssetBuilderSDK;
|
|
|
+
|
|
|
+ QString watchFolderPath = m_assetRootDir.absoluteFilePath("subfolder1");
|
|
|
+ const ScanFolderInfo* scanFolder = m_config->GetScanFolderByPath(watchFolderPath);
|
|
|
+ ASSERT_NE(scanFolder, nullptr);
|
|
|
+
|
|
|
+ // A.dummy depends on B.dummy, as a JOB dep ordered
|
|
|
+ const char relSourceFileName[] = "a.dummy";
|
|
|
+ const char secondRelSourceFile[] = "b.dummy";
|
|
|
+ QString sourceFileName = m_assetRootDir.absoluteFilePath("subfolder1/a.dummy");
|
|
|
+ QString secondSourceFile = m_assetRootDir.absoluteFilePath("subfolder1/b.dummy");
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(sourceFileName, QString("tempdata\n")));
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(secondSourceFile, QString("tempdata\n")));
|
|
|
+
|
|
|
+ AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
|
|
|
+ builderDescriptor.m_name = "Test Dummy Builder";
|
|
|
+ builderDescriptor.m_patterns.push_back(
|
|
|
+ AssetBuilderSDK::AssetBuilderPattern("*.dummy", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
|
|
+ builderDescriptor.m_busId = AZ::Uuid::CreateRandom();
|
|
|
+ builderDescriptor.m_createJobFunction =
|
|
|
+ [&](const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
|
|
|
+ {
|
|
|
+ AssetBuilderSDK::JobDescriptor jobDescriptor;
|
|
|
+ jobDescriptor.m_jobKey = builderDescriptor.m_name;
|
|
|
+ jobDescriptor.SetPlatformIdentifier("pc");
|
|
|
+ if (AzFramework::StringFunc::EndsWith(request.m_sourceFile.c_str(), relSourceFileName))
|
|
|
+ {
|
|
|
+ AssetBuilderSDK::SourceFileDependency dep = { secondRelSourceFile, AZ::Uuid::CreateNull() };
|
|
|
+ AssetBuilderSDK::JobDependency jobDep(builderDescriptor.m_name, "pc", AssetBuilderSDK::JobDependencyType::Order, dep);
|
|
|
+
|
|
|
+ // specify that we only depend on subid 0 of b.dummy, not the entire job so only reprocess if subid 0 changes
|
|
|
+ jobDep.m_productSubIds.push_back(0); // <------------------------------------------------- KEY LINE OF TEST DIFFERING FROM PRIOR TEST
|
|
|
+ jobDescriptor.m_jobDependencyList.emplace_back(jobDep);
|
|
|
+ }
|
|
|
+ response.m_createJobOutputs.emplace_back(jobDescriptor);
|
|
|
+ response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
|
|
+ };
|
|
|
+ builderDescriptor.m_processJobFunction =
|
|
|
+ [](const AssetBuilderSDK::ProcessJobRequest& /*request*/, AssetBuilderSDK::ProcessJobResponse& response)
|
|
|
+ {
|
|
|
+ response.m_resultCode = AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success;
|
|
|
+ };
|
|
|
+
|
|
|
+ MockApplicationManager::BuilderFilePatternMatcherAndBuilderDesc builderFilePatternMatcher;
|
|
|
+ builderFilePatternMatcher.m_builderDesc = builderDescriptor;
|
|
|
+ builderFilePatternMatcher.m_internalBuilderName = builderDescriptor.m_name;
|
|
|
+ builderFilePatternMatcher.m_internalUuid = builderDescriptor.m_busId;
|
|
|
+ builderFilePatternMatcher.m_matcherBuilderPattern =
|
|
|
+ AssetUtilities::BuilderFilePatternMatcher(builderDescriptor.m_patterns.back(), builderDescriptor.m_busId);
|
|
|
+ m_mockApplicationManager->m_matcherBuilderPatterns.emplace_back(builderFilePatternMatcher);
|
|
|
+
|
|
|
+ // Capture the job details as the APM inspects the file.
|
|
|
+ AZStd::vector<JobDetails> jobDetails;
|
|
|
+ auto connection = QObject::connect(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ &AssetProcessorManager::AssetToProcess,
|
|
|
+ [&jobDetails](JobDetails job)
|
|
|
+ {
|
|
|
+ jobDetails.emplace_back(job);
|
|
|
+ });
|
|
|
+
|
|
|
+ // Tell the APM about both files.
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileName));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, secondSourceFile));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ // Although we have processed a.dummy first, APM should send us notification of b.dummy job first and than of a.dummy job
|
|
|
+ EXPECT_EQ(jobDetails.size(), 2);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), secondSourceFile);
|
|
|
+ EXPECT_EQ(jobDetails[1].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), sourceFileName);
|
|
|
+ EXPECT_EQ(jobDetails[1].m_jobDependencyList.size(), 1); // there should only be one job dependency
|
|
|
+ EXPECT_EQ(
|
|
|
+ jobDetails[1].m_jobDependencyList[0].m_jobDependency.m_sourceFile.m_sourceFileDependencyPath,
|
|
|
+ secondSourceFile.toUtf8().constData()); // there should only be one job dependency
|
|
|
+
|
|
|
+ // Process jobs in APM
|
|
|
+ auto destination = jobDetails[0].m_cachePath;
|
|
|
+ QString productAFileName = (destination / "aoutput.txt").AsPosix().c_str();
|
|
|
+ QString productBFileName = (destination / "boutput.txt").AsPosix().c_str();
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(productBFileName, QString("tempdata\n")));
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(productAFileName, QString("tempdata\n")));
|
|
|
+
|
|
|
+ AssetBuilderSDK::ProcessJobResponse responseB;
|
|
|
+ responseB.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
|
+ responseB.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("boutput.txt", AZ::Uuid::CreateNull(), 1)); // <-- note we are updating subid 1 only
|
|
|
+
|
|
|
+ AssetBuilderSDK::ProcessJobResponse responseA;
|
|
|
+ responseA.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
|
+ responseA.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("aoutput.txt", AZ::Uuid::CreateNull(), 1)); // <-- note we are updating subid 1 only
|
|
|
+
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[0].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseB));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[1].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseA));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ jobDetails.clear();
|
|
|
+ m_isIdling = false;
|
|
|
+ // Modify source file b.dummy, a.dummy should not process unless b.dummy outputs a file of subid 0.
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(secondSourceFile, QString("temp\n")));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, secondSourceFile));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+ ASSERT_EQ(jobDetails.size(), 1);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), secondSourceFile);
|
|
|
+
|
|
|
+ // Ack processing to return to idle state.
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[0].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseB)); // <-- note we are updating subid 1 only This should not result in reprocessing anything
|
|
|
+ jobDetails.clear();
|
|
|
+ m_isIdling = false;
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+ ASSERT_EQ(jobDetails.size(), 0); // no jobs should have been emitted even though b.dummy finished, as it only updated subid 1 and it depends on subid 0
|
|
|
+ jobDetails.clear();
|
|
|
+ m_isIdling = false;
|
|
|
+
|
|
|
+ // KEY PART OF TEST
|
|
|
+ // modify source file b but this time, then output subid 0, which is the one the other job depends on.
|
|
|
+ ASSERT_TRUE(UnitTestUtils::CreateDummyFile(secondSourceFile, QString("temp2\n")));
|
|
|
+ QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, secondSourceFile));
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+
|
|
|
+ // We should only see one job so far, to process the file that has just changed. Notifications of aditional files wait until the job finishes.
|
|
|
+ ASSERT_EQ(jobDetails.size(), 1);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), secondSourceFile);
|
|
|
+
|
|
|
+ // Ack processing to return to idle state. This should also trigger processing of the original file with the dep.
|
|
|
+ responseB.m_outputProducts[0].m_productSubID = 0;
|
|
|
+ m_isIdling = false;
|
|
|
+ QMetaObject::invokeMethod(
|
|
|
+ m_assetProcessorManager.get(),
|
|
|
+ "AssetProcessed",
|
|
|
+ Qt::QueuedConnection,
|
|
|
+ Q_ARG(JobEntry, jobDetails[0].m_jobEntry),
|
|
|
+ Q_ARG(AssetBuilderSDK::ProcessJobResponse, responseB));
|
|
|
+ jobDetails.clear();
|
|
|
+ ASSERT_TRUE(BlockUntilIdle(5000));
|
|
|
+ ASSERT_EQ(jobDetails.size(), 1);
|
|
|
+ EXPECT_EQ(jobDetails[0].m_jobEntry.m_sourceAssetReference.AbsolutePath().c_str(), sourceFileName);
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
TEST_F(AssetProcessorManagerTest, SourceFile_With_NonASCII_Characters_Job_OK)
|
|
|
{
|