Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,888 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "RCBuilderTest.h"
TEST_F(RCBuilderTest, CreateBuilderDesc_CreateBuilder_Valid)
{
AssetBuilderSDK::AssetBuilderPattern pattern;
pattern.m_pattern = "*.foo";
AZStd::vector<AssetBuilderSDK::AssetBuilderPattern> builderPatterns;
builderPatterns.push_back(pattern);
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
AssetBuilderSDK::AssetBuilderDesc result = test.CreateBuilderDesc(this->GetBuilderID(), builderPatterns);
ASSERT_EQ(this->GetBuilderName(), result.m_name);
ASSERT_EQ(this->GetBuilderUUID(), result.m_busId);
ASSERT_EQ(false, result.IsExternalBuilder());
ASSERT_TRUE(result.m_patterns.size() == 1);
ASSERT_EQ(result.m_patterns[0].m_pattern, pattern.m_pattern);
}
TEST_F(RCBuilderTest, Shutdown_NormalShutdown_Requested)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
test.ShutDown();
ASSERT_EQ(mockRC->m_request_quit, 1);
}
TEST_F(RCBuilderTest, Initialize_StandardInitialization_Fail)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
mockRC->SetResultInitialize(false);
bool initialization_result = test.Initialize(configuration);
ASSERT_FALSE(initialization_result);
}
TEST_F(RCBuilderTest, Initialize_StandardInitializationWithDuplicateAndInvalidRecognizers_Valid)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// 3 Asset recognizers, 1 duplicate & 1 without platform should result in only 1 InternalAssetRecognizer
// Good spec
AssetRecognizer good;
good.m_name = "Good";
good.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_spec;
good_spec.m_extraRCParams = "/i";
good.m_platformSpecs["pc"] = good_spec;
// No Platform spec
AssetRecognizer no_platform;
no_platform.m_name = "No Platform";
no_platform.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.ccc", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
// Duplicate
AssetRecognizer duplicate(good.m_name, good.m_testLockSource, good.m_priority, good.m_isCritical, good.m_supportsCreateJobs, good.m_patternMatcher, good.m_version, good.m_productAssetType, good.m_outputProductDependencies);
duplicate.m_platformSpecs["pc"] = good_spec;
configuration.m_recognizerContainer["good"] = good;
configuration.m_recognizerContainer["no_platform"] = no_platform;
configuration.m_recognizerContainer["duplicate"] = duplicate;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
ASSERT_EQ(mockRC->m_initialize, 1);
AZStd::vector<AssetBuilderSDK::PlatformInfo> platformInfos;
AZStd::unordered_set<AZStd::string> tags;
tags.insert("tools");
tags.insert("desktop");
platformInfos.emplace_back(AssetBuilderSDK::PlatformInfo("pc", tags));
InternalRecognizerPointerContainer good_recognizers;
bool good_recognizers_found = test.GetMatchingRecognizers(platformInfos, "test.foo", good_recognizers);
ASSERT_TRUE(good_recognizers_found); // Should find at least 1
ASSERT_EQ(good_recognizers.size(), 1); // 1, not 2 since the duplicates should be removed
ASSERT_EQ(good_recognizers.at(0)->m_name, good.m_name); // Match the same recognizer
InternalRecognizerPointerContainer bad_recognizers;
bool no_recognizers_found = !test.GetMatchingRecognizers(platformInfos, "test.ccc", good_recognizers);
ASSERT_TRUE(no_recognizers_found);
ASSERT_EQ(bad_recognizers.size(), 0); // 1, not 2 since the duplicates should be removed
ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 1); // this should be the "duplicate builder" warning.
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
TEST_F(RCBuilderTest, CreateJobs_CreateSingleJobStandard_Valid)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetRecognizer good;
good.m_name = "Good";
good.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_spec;
good_spec.m_extraRCParams = "/i";
good.m_platformSpecs["pc"] = good_spec;
configuration.m_recognizerContainer["good"] = good;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
AssetBuilderSDK::CreateJobsRequest request;
AssetBuilderSDK::CreateJobsResponse response;
request.m_watchFolder = "c:\temp";
request.m_sourceFile = "test.foo";
request.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc", { "desktop", "renderer" }) };
AssetProcessor::BUILDER_ID_RC.GetUuid(request.m_builderid);
test.CreateJobs(request, response);
ASSERT_EQ(response.m_result, AssetBuilderSDK::CreateJobsResultCode::Success);
ASSERT_EQ(response.m_createJobOutputs.size(), 1);
AssetBuilderSDK::JobDescriptor descriptor = response.m_createJobOutputs.at(0);
ASSERT_EQ(descriptor.GetPlatformIdentifier(), "pc");
ASSERT_FALSE(descriptor.m_critical);
}
TEST_F(RCBuilderTest, CreateJobs_CreateMultiplesJobStandard_Valid)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetRecognizer standard_AR_RC;
const AZStd::string job_key_rc = "RCjob";
{
standard_AR_RC.m_name = "RCjob";
standard_AR_RC.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_rc_spec;
good_rc_spec.m_extraRCParams = "/i";
standard_AR_RC.m_platformSpecs["pc"] = good_rc_spec;
}
configuration.m_recognizerContainer["rc_foo"] = standard_AR_RC;
AssetRecognizer standard_AR_Copy;
const AZStd::string job_key_copy = "Copyjob";
{
standard_AR_Copy.m_name = QString(job_key_copy.c_str());
standard_AR_Copy.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_copy_spec;
good_copy_spec.m_extraRCParams = "copy";
standard_AR_Copy.m_platformSpecs["pc"] = good_copy_spec;
}
configuration.m_recognizerContainer["copy_foo"] = standard_AR_Copy;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
// Request is for the copy builder
{
AssetBuilderSDK::CreateJobsRequest request_copy;
AssetBuilderSDK::CreateJobsResponse response_copy;
request_copy.m_watchFolder = "c:\temp";
request_copy.m_sourceFile = "test.foo";
request_copy.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
AssetProcessor::BUILDER_ID_COPY.GetUuid(request_copy.m_builderid);
test.CreateJobs(request_copy, response_copy);
ASSERT_EQ(response_copy.m_result, AssetBuilderSDK::CreateJobsResultCode::Success);
ASSERT_EQ(response_copy.m_createJobOutputs.size(), 1);
AssetBuilderSDK::JobDescriptor descriptor = response_copy.m_createJobOutputs.at(0);
ASSERT_EQ(descriptor.GetPlatformIdentifier(), "pc");
ASSERT_EQ(descriptor.m_jobKey.compare(job_key_copy), 0);
ASSERT_TRUE(descriptor.m_critical);
}
// Request is for the rc builder
{
AssetBuilderSDK::CreateJobsRequest request_rc;
AssetBuilderSDK::CreateJobsResponse response_rc;
request_rc.m_watchFolder = "c:\temp";
request_rc.m_sourceFile = "test.foo";
request_rc.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
AssetProcessor::BUILDER_ID_RC.GetUuid(request_rc.m_builderid);
test.CreateJobs(request_rc, response_rc);
ASSERT_EQ(response_rc.m_result, AssetBuilderSDK::CreateJobsResultCode::Success);
ASSERT_EQ(response_rc.m_createJobOutputs.size(), 1);
AssetBuilderSDK::JobDescriptor descriptor = response_rc.m_createJobOutputs.at(0);
ASSERT_EQ(descriptor.GetPlatformIdentifier(), "pc");
ASSERT_EQ(descriptor.m_jobKey.compare(job_key_rc), 0);
ASSERT_FALSE(descriptor.m_critical);
}
}
TEST_F(RCBuilderTest, CreateJobs_CreateSingleJobCopy_Valid)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetRecognizer copy;
copy.m_name = "Copy";
copy.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.copy", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec copy_spec;
copy_spec.m_extraRCParams = "copy";
copy.m_platformSpecs["pc"] = copy_spec;
configuration.m_recognizerContainer["copy"] = copy;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
AssetBuilderSDK::CreateJobsRequest request;
AssetBuilderSDK::CreateJobsResponse response;
request.m_watchFolder = "c:\temp";
request.m_sourceFile = "test.copy";
request.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
AssetProcessor::BUILDER_ID_COPY.GetUuid(request.m_builderid);
test.CreateJobs(request, response);
ASSERT_EQ(response.m_result, AssetBuilderSDK::CreateJobsResultCode::Success);
ASSERT_EQ(response.m_createJobOutputs.size(), 1);
AssetBuilderSDK::JobDescriptor descriptor = response.m_createJobOutputs.at(0);
ASSERT_EQ(descriptor.GetPlatformIdentifier(), "pc");
ASSERT_TRUE(descriptor.m_critical);
}
TEST_F(RCBuilderTest, CreateJobs_CreateSingleJobStandardSkip_Valid)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
{
AssetRecognizer skip;
skip.m_name = "Skip";
skip.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.skip", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec skip_spec;
skip_spec.m_extraRCParams = "skip";
skip.m_platformSpecs["pc"] = skip_spec;
configuration.m_recognizerContainer["skip"] = skip;
}
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
AssetBuilderSDK::CreateJobsRequest request;
AssetBuilderSDK::CreateJobsResponse response;
request.m_watchFolder = "c:\temp";
request.m_sourceFile = "test.skip";
request.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
request.m_builderid = this->GetBuilderUUID();
test.CreateJobs(request, response);
ASSERT_EQ(response.m_result, AssetBuilderSDK::CreateJobsResultCode::Success);
ASSERT_EQ(response.m_createJobOutputs.size(), 0);
}
TEST_F(RCBuilderTest, CreateJobs_CreateSingleJobStandard_Failed)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetRecognizer good;
good.m_name = "Good";
good.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_spec;
good_spec.m_extraRCParams = "/i";
good.m_platformSpecs["pc"] = good_spec;
configuration.m_recognizerContainer["good"] = good;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
AssetBuilderSDK::CreateJobsRequest request;
AssetBuilderSDK::CreateJobsResponse response;
request.m_watchFolder = "c:\temp";
request.m_sourceFile = "test.ccc";
request.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
request.m_builderid = this->GetBuilderUUID();
test.CreateJobs(request, response);
ASSERT_EQ(response.m_result, AssetBuilderSDK::CreateJobsResultCode::Failed);
ASSERT_EQ(response.m_createJobOutputs.size(), 0);
}
TEST_F(RCBuilderTest, CreateJobs_CreateSingleJobStandard_ShuttingDown)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetRecognizer good;
good.m_name = "Good";
good.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_spec;
good_spec.m_extraRCParams = "/i";
good.m_platformSpecs["pc"] = good_spec;
configuration.m_recognizerContainer["good"] = good;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
test.ShutDown();
AssetBuilderSDK::CreateJobsRequest request;
AssetBuilderSDK::CreateJobsResponse response;
request.m_watchFolder = "c:\temp";
request.m_sourceFile = "test.ccc";
request.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
request.m_builderid = this->GetBuilderUUID();
test.CreateJobs(request, response);
ASSERT_EQ(response.m_result, AssetBuilderSDK::CreateJobsResultCode::ShuttingDown);
ASSERT_EQ(response.m_createJobOutputs.size(), 0);
}
TEST_F(RCBuilderTest, CreateJobs_CreateSingleJobBadJobRequest1_Failed)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetRecognizer good;
good.m_name = "Good";
good.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
AssetPlatformSpec good_spec;
good_spec.m_extraRCParams = "/i";
good.m_platformSpecs["pc"] = good_spec;
configuration.m_recognizerContainer["good"] = good;
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
AssetBuilderSDK::CreateJobsRequest request;
AssetBuilderSDK::CreateJobsResponse response;
request.m_sourceFile = "test.ccc";
request.m_enabledPlatforms = { AssetBuilderSDK::PlatformInfo("pc",{ "desktop", "renderer" }) };
request.m_builderid = this->GetBuilderUUID();
test.CreateJobs(request, response);
ASSERT_EQ(response.m_result, AssetBuilderSDK::CreateJobsResultCode::Failed);
ASSERT_EQ(response.m_createJobOutputs.size(), 0);
}
TEST_F(RCBuilderTest, ProcessLegacyRCJob_ProcessStandardSingleJob_Failed)
{
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("file.c", false, "pc", 1);
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
// Case 1: execution failed
mockRC->SetResultResultExecute(NativeLegacyRCCompiler::Result(1, true, ""));
mockRC->SetResultExecute(false);
AssetBuilderSDK::ProcessJobResponse responseCrashed;
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
test.TestProcessLegacyRCJob(request, "/i", assetTypeUUid, jobCancelListener, responseCrashed);
ASSERT_EQ(responseCrashed.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Crashed);
// case 2: result code from execution non-zero
mockRC->SetResultExecute(true);
mockRC->SetResultResultExecute(NativeLegacyRCCompiler::Result(1, false, ""));
AssetBuilderSDK::ProcessJobResponse responseFailed;
test.TestProcessLegacyRCJob(request, "/i", assetTypeUUid, jobCancelListener, responseFailed);
ASSERT_EQ(responseFailed.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, ProcessLegacyRCJob_ProcessStandardSingleJob_Valid)
{
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("file.c", false, "pc");
test.AddTestFileInfo("c:\\temp\\file.a").AddTestFileInfo("c:\\temp\\file.b");
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
mockRC->SetResultResultExecute(NativeLegacyRCCompiler::Result(0, false, "c:\\temp"));
mockRC->SetResultExecute(true);
AssetBuilderSDK::ProcessJobResponse response;
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
test.TestProcessLegacyRCJob(request, "/i", assetTypeUUid, jobCancelListener, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success);
ASSERT_EQ(response.m_outputProducts.size(), 2); // file.c->(file.a, file.b)
}
TEST_F(RCBuilderTest, ProcessLegacyRCJob_ProcessCopySingleJob_Valid)
{
AZStd::string name = "test";
AZ::Uuid builderUuid = AZ::Uuid::CreateRandom();
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("file.c", false, "pc");
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
mockRC->SetResultResultExecute(NativeLegacyRCCompiler::Result(0, false, "c:\\temp"));
mockRC->SetResultExecute(true);
AssetBuilderSDK::ProcessJobResponse response;
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
test.TestProcessCopyJob(request, assetTypeUUid, jobCancelListener, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success);
ASSERT_EQ(response.m_outputProducts.size(), 1); // file.c->(file.a, file.b)
AssetBuilderSDK::JobProduct resultJobProd = response.m_outputProducts.at(0);
ASSERT_EQ(resultJobProd.m_productAssetType, assetTypeUUid);
ASSERT_EQ(resultJobProd.m_productFileName, request.m_fullPath);
}
TEST_F(RCBuilderTest, MatchTempFileToSkip_SkipRCFiles_true)
{
const char* rc_skip_fileNames[] = {
"rc_createdfiles.txt",
"rc_log.log",
"rc_log_warnings.log",
"rc_log_errors.log"
};
for (const char* filename : rc_skip_fileNames)
{
ASSERT_TRUE(AssetProcessor::InternalRecognizerBasedBuilder::MatchTempFileToSkip(filename));
}
}
TEST_F(RCBuilderTest, MatchTempFileToSkip_SkipRCFiles_false)
{
const char* rc_not_skip_fileNames[] = {
"foo.log",
"bar.txt"
};
for (const char* filename : rc_not_skip_fileNames)
{
ASSERT_FALSE(AssetProcessor::InternalRecognizerBasedBuilder::MatchTempFileToSkip(filename));
}
}
TEST_F(RCBuilderTest, ProcessJob_ProcessStandardRCSingleJob_Valid)
{
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create a dummy test recognizer
AZ::u32 recID = test.AddTestRecognizer(this->GetBuilderID(),QString("/i"), "pc");
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("test.tif", false, "pc");
request.m_jobDescription.m_jobParameters[recID] = "/i";
test.AddTestFileInfo("c:\\temp\\file.a").AddTestFileInfo("c:\\temp\\file.b");
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
mockRC->SetResultResultExecute(NativeLegacyRCCompiler::Result(0, false, "c:\\temp"));
mockRC->SetResultExecute(true);
AssetBuilderSDK::ProcessJobResponse response;
test.TestProcessJob(request, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success);
ASSERT_EQ(response.m_outputProducts.size(), 2); // file.c->(file.a, file.b)
}
TEST_F(RCBuilderTest, ProcessJob_ProcessStandardRCSingleJob_Failed)
{
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create a dummy test recognizer
AZ::u32 recID = test.AddTestRecognizer(this->GetBuilderID(), QString("/i"), "pc");
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("test.tif", false, "pc");
request.m_jobDescription.m_jobParameters[recID] = "/i";
test.AddTestFileInfo("c:\\temp\\file.a").AddTestFileInfo("c:\\temp\\file.b");
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
mockRC->SetResultResultExecute(NativeLegacyRCCompiler::Result(1, false, "c:\\temp"));
mockRC->SetResultExecute(true);
AssetBuilderSDK::ProcessJobResponse response;
test.TestProcessJob(request, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, ProcessJob_ProcessStandardCopySingleJob_Valid)
{
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create a dummy test recognizer
AZ::u32 recID = test.AddTestRecognizer(this->GetBuilderID(), QString("copy"), "pc");
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("test.tif", true, "pc");
request.m_jobDescription.m_jobParameters[recID] = "copy";
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
mockRC->SetResultExecute(true);
AssetBuilderSDK::ProcessJobResponse response;
test.TestProcessJob(request, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success);
ASSERT_EQ(response.m_outputProducts.size(), 1); // test.
ASSERT_TRUE(response.m_outputProducts[0].m_productFileName.find("test.tif") != AZStd::string::npos);
}
TEST_F(RCBuilderTest, ProcessJob_ProcessStandardSkippedSingleJob_Invalid)
{
AZ::Uuid assetTypeUUid = AZ::Uuid::CreateRandom();
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
// Create a dummy test recognizer
AZ::u32 recID = test.AddTestRecognizer(this->GetBuilderID(), QString("skip"), "pc");
// Create the test job
AssetBuilderSDK::ProcessJobRequest request = CreateTestJobRequest("test.tif", true, "pc");
request.m_jobDescription.m_jobParameters[recID] = "copy";
bool initialization_result = test.Initialize(configuration);
ASSERT_TRUE(initialization_result);
mockRC->SetResultExecute(true);
AssetBuilderSDK::ProcessJobResponse response;
test.TestProcessJob(request, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_LegacySystem)
{
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
test.AddTestFileInfo("file.dds")
.AddTestFileInfo("file.caf")
.AddTestFileInfo("file.png")
.AddTestFileInfo("rc_createdfiles.txt")
.AddTestFileInfo("rc_log.log")
.AddTestFileInfo("rc_log_warnings.log")
.AddTestFileInfo("rc_log_errors.log")
.AddTestFileInfo("ProcessJobRequest.xml")
.AddTestFileInfo("ProcessJobResponse.xml");
AZ::Uuid productGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
AssetBuilderSDK::ProcessJobResponse response;
test.TestProcessRCResultFolder("c:\\temp", productGUID, false, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success);
// we expect it to have ignored most of the file cruft.
ASSERT_EQ(response.m_outputProducts.size(), 3);
AZStd::string fileJoined;
AzFramework::StringFunc::Path::Join("c:\\temp", "file.dds", fileJoined);
ASSERT_EQ(response.m_outputProducts[0].m_productFileName, fileJoined);
ASSERT_EQ(response.m_outputProducts[0].m_productAssetType, productGUID);
ASSERT_EQ(response.m_outputProducts[0].m_productSubID, 0x00000000);
ASSERT_EQ(response.m_outputProducts[0].m_legacySubIDs.size(), 0);
AzFramework::StringFunc::Path::Join("c:\\temp", "file.caf", fileJoined);
ASSERT_EQ(response.m_outputProducts[1].m_productFileName, fileJoined);
ASSERT_EQ(response.m_outputProducts[1].m_productAssetType, productGUID);
ASSERT_EQ(response.m_outputProducts[1].m_productSubID, (AZ_CRC("file.caf", 0x91277b80) & 0x0000FFFF)); // legacy subids are just the lower 16 bits of the crc of filename.
ASSERT_EQ(response.m_outputProducts[1].m_legacySubIDs.size(), 0);
AzFramework::StringFunc::Path::Join("c:\\temp", "file.png", fileJoined);
ASSERT_EQ(response.m_outputProducts[2].m_productFileName, fileJoined);
ASSERT_EQ(response.m_outputProducts[2].m_productAssetType, productGUID);
ASSERT_EQ(response.m_outputProducts[2].m_productSubID, (AZ_CRC("file.png", 0x7fd84af0) & 0x0000FFFF));
ASSERT_EQ(response.m_outputProducts[2].m_legacySubIDs.size(), 0);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_Fail_Fail)
{
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
AssetBuilderSDK::ProcessJobResponse response;
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
AZ::Uuid productGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
test.TestProcessRCResultFolder("c:\\temp", productGUID, true, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_Succeed_NothingBuilt)
{
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
AssetBuilderSDK::ProcessJobResponse response;
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
AZ::Uuid productGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
test.TestProcessRCResultFolder("c:\\temp", productGUID, true, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResult_Success);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_Fail_BadName)
{
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
AssetBuilderSDK::ProcessJobResponse response;
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
AZ::Uuid productGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
// note: empty name on next line
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("", productGUID, 1234));
test.TestProcessRCResultFolder("c:\\temp", productGUID, true, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_Fail_DuplicateFile)
{
m_errorAbsorber->m_debugMessages = true;
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
AssetBuilderSDK::ProcessJobResponse response;
test.AddTestFileInfo("file.dds");
AZ::Uuid productGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("file.dds", productGUID, 1234));
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("file.dds", productGUID, 5679));
test.TestProcessRCResultFolder("c:\\temp", productGUID, true, response);
m_errorAbsorber->AssertErrors(1);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_Fail_DuplicateSubID)
{
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
AssetBuilderSDK::ProcessJobResponse response;
test.AddTestFileInfo("file.dds")
.AddTestFileInfo("file.caf");
AZ::Uuid productGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("file.dds", productGUID, 1234));
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("file.caf", productGUID, 1234));
test.TestProcessRCResultFolder("c:\\temp", productGUID, true, response);
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 1);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResult_Failed);
}
TEST_F(RCBuilderTest, TestProcessRCResultFolder_WithResponseFromRC)
{
TestInternalRecognizerBasedBuilder test(new MockRCCompiler());
test.AddTestFileInfo("file.dds")
.AddTestFileInfo("file.caf")
.AddTestFileInfo("file.png")
.AddTestFileInfo("rc_createdfiles.txt")
.AddTestFileInfo("rc_log.log")
.AddTestFileInfo("rc_log_warnings.log")
.AddTestFileInfo("rc_log_errors.log")
.AddTestFileInfo("ProcessJobRequest.xml")
.AddTestFileInfo("ProcessJobResponse.xml");
AZ::Uuid productGUID = AZ::Uuid::CreateNull(); // this is to make sure that it doesn't matter what we pass in
AZ::Uuid actualGUID = AZ::Uuid("{60554E3C-D8D5-4429-AC77-740F0ED46193}");
AssetBuilderSDK::ProcessJobResponse response;
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("file.dds", actualGUID, 1234));
response.m_outputProducts.back().m_legacySubIDs.push_back(3333);
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct("file.caf", actualGUID, 3456));
response.m_outputProducts.back().m_legacySubIDs.push_back(2222);
response.m_outputProducts.back().m_legacySubIDs.push_back((AZ_CRC("file.caf", 0x91277b80) & 0x0000FFFF)); // push back the existing one to make sure no dupes.
response.m_resultCode = AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success;
// in this test we pretend the response was actually populated by the builder and make sure it populates the legacy IDs correctly
// 1. there should actually BE legacy IDs
// 2. there should be no duplicate IDs (legacy IDs should not duplicate ACTUAL ids)
// 3. there should be no duplicate Legacy IDs (legacy IDs should not duplicate each other)
// 4. if we provide legacy Ids, they should be used in addition to the automatic ones.
test.TestProcessRCResultFolder("c:\\temp", productGUID, true, response);
ASSERT_EQ(response.m_resultCode, AssetBuilderSDK::ProcessJobResultCode::ProcessJobResult_Success);
// we expect it to only have accepted the products we specified.
ASSERT_EQ(response.m_outputProducts.size(), 2);
AZStd::string fileJoined;
AzFramework::StringFunc::Path::Join("c:\\temp", "file.dds", fileJoined);
ASSERT_EQ(response.m_outputProducts[0].m_productFileName, fileJoined);
ASSERT_EQ(response.m_outputProducts[0].m_productAssetType, actualGUID);
ASSERT_EQ(response.m_outputProducts[0].m_productSubID, 1234);
ASSERT_EQ(response.m_outputProducts[0].m_legacySubIDs.size(), 2); // it must include our new one AND the zero that it would have generated before.
ASSERT_EQ(response.m_outputProducts[0].m_legacySubIDs[0], 3333);
ASSERT_EQ(response.m_outputProducts[0].m_legacySubIDs[1], 0);
AzFramework::StringFunc::Path::Join("c:\\temp", "file.caf", fileJoined);
ASSERT_EQ(response.m_outputProducts[1].m_productFileName, fileJoined);
ASSERT_EQ(response.m_outputProducts[1].m_productAssetType, actualGUID);
ASSERT_EQ(response.m_outputProducts[1].m_productSubID, 3456); // legacy subids are just the lower 16 bits of the crc of filename.
ASSERT_EQ(response.m_outputProducts[1].m_legacySubIDs.size(), 2); // we only expect the one legacy, no dupes!
ASSERT_EQ(response.m_outputProducts[1].m_legacySubIDs[0], 2222);
ASSERT_EQ(response.m_outputProducts[1].m_legacySubIDs[1], (AZ_CRC("file.caf", 0x91277b80) & 0x0000FFFF));
}
class MockBuilderListener : public AssetBuilderSDK::AssetBuilderBus::Handler
{
public:
void RegisterBuilderInformation(const AssetBuilderSDK::AssetBuilderDesc& builderDesc) override
{
m_wasCalled = true;
m_result = builderDesc;
}
bool m_wasCalled = false;
AssetBuilderSDK::AssetBuilderDesc m_result;
};
class RCBuilderFingerprintTest
: public RCBuilderTest
{
public:
// A utility function which feeds in the version and asset type to the builder, fingerprints it, and returns the fingerprint
AZStd::string BuildFingerprint(int versionNumber, AZ::Uuid builderProductType)
{
MockRCCompiler* mockRC = new MockRCCompiler();
TestInternalRecognizerBasedBuilder test(mockRC);
MockRecognizerConfiguration configuration;
AssetPlatformSpec good_spec;
good_spec.m_extraRCParams = "/i";
AssetRecognizer good;
good.m_name = "Good";
good.m_version = versionNumber;
good.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.foo", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
good.m_platformSpecs["pc"] = good_spec;
good.m_productAssetType = builderProductType;
configuration.m_recognizerContainer["good"] = good;
MockBuilderListener listener;
listener.BusConnect();
bool initialization_result = test.Initialize(configuration);
listener.BusDisconnect();
EXPECT_TRUE(listener.m_wasCalled);
EXPECT_TRUE(initialization_result);
EXPECT_STRNE(listener.m_result.m_analysisFingerprint.c_str(), "");
return listener.m_result.m_analysisFingerprint;
}
};
TEST_F(RCBuilderFingerprintTest, DifferentVersion_Has_DifferentAnalysisFingerprint)
{
AZ::Uuid uuid1 = AZ::Uuid::CreateRandom();
AZStd::string analysisFingerprint1 = BuildFingerprint(1, uuid1);
AZStd::string analysisFingerprint2 = BuildFingerprint(2, uuid1);
EXPECT_STRNE(analysisFingerprint1.c_str(), analysisFingerprint2.c_str());
}
TEST_F(RCBuilderFingerprintTest, DifferentAssetType_Has_DifferentAnalysisFingerprint)
{
AZ::Uuid uuid1 = AZ::Uuid::CreateRandom();
AZ::Uuid uuid2 = AZ::Uuid::CreateRandom();
AZStd::string analysisFingerprint1 = BuildFingerprint(1, uuid1);
AZStd::string analysisFingerprint2 = BuildFingerprint(1, uuid2);
EXPECT_STRNE(analysisFingerprint1.c_str(), analysisFingerprint2.c_str());
}
TEST_F(RCBuilderFingerprintTest, DifferentAssetTypeAndVersion_Has_DifferentAnalysisFingerprint)
{
AZ::Uuid uuid1 = AZ::Uuid::CreateRandom();
AZ::Uuid uuid2 = AZ::Uuid::CreateRandom();
AZStd::string analysisFingerprint1 = BuildFingerprint(1, uuid1);
AZStd::string analysisFingerprint2 = BuildFingerprint(2, uuid2);
EXPECT_STRNE(analysisFingerprint1.c_str(), analysisFingerprint2.c_str());
}
TEST_F(RCBuilderFingerprintTest, SameVersionAndSameType_Has_SameAnalysisFingerprint)
{
AZ::Uuid uuid1 = AZ::Uuid::CreateRandom();
AZStd::string analysisFingerprint1 = BuildFingerprint(1, uuid1);
AZStd::string analysisFingerprint2 = BuildFingerprint(1, uuid1);
EXPECT_STREQ(analysisFingerprint1.c_str(), analysisFingerprint2.c_str());
}
@@ -0,0 +1,250 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzTest/AzTest.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <qcoreapplication.h>
#include "../../utilities/assetUtils.h"
#include "../../resourcecompiler/RCBuilder.h"
#include "native/tests/AssetProcessorTest.h"
using namespace AssetProcessor;
extern const BuilderIdAndName BUILDER_ID_COPY;
extern const BuilderIdAndName BUILDER_ID_RC;
extern const BuilderIdAndName BUILDER_ID_SKIP;
class MockRCCompiler
: public AssetProcessor::RCCompiler
{
public:
MockRCCompiler()
: m_executeResultResult(0, false, "c:\temp")
{
}
bool Initialize([[maybe_unused]] const QString& systemRoot, [[maybe_unused]] const QString& rcExecutableFullPath) override
{
m_initialize++;
return m_initializeResult;
}
bool Execute([[maybe_unused]] const QString& inputFile, [[maybe_unused]] const QString& watchFolder, [[maybe_unused]] const QString& platformIdentifier, [[maybe_unused]] const QString& params, [[maybe_unused]] const QString& dest,
[[maybe_unused]] const AssetBuilderSDK::JobCancelListener* jobCancelListener, Result& result) const override
{
m_execute++;
result = m_executeResultResult;
return m_executeResult;
}
void RequestQuit() override
{
m_request_quit++;
}
void ResetCounters()
{
this->m_initialize = 0;
this->m_execute = 0;
this->m_request_quit = 0;
}
void SetResultInitialize(bool result)
{
m_initializeResult = result;
}
void SetResultExecute(bool result)
{
m_executeResult = result;
}
void SetResultResultExecute(Result result)
{
m_executeResultResult = result;
}
bool m_initializeResult = true;
bool m_executeResult = true;
Result m_executeResultResult;
mutable int m_initialize = 0;
mutable int m_execute = 0;
mutable int m_request_quit = 0;
};
struct MockRecognizerConfiguration
: public RecognizerConfiguration
{
const RecognizerContainer& GetAssetRecognizerContainer() const override
{
return m_recognizerContainer;
}
const ExcludeRecognizerContainer& GetExcludeAssetRecognizerContainer() const override
{
return m_excludeContainer;
}
RecognizerContainer m_recognizerContainer;
ExcludeRecognizerContainer m_excludeContainer;
};
struct TestInternalRecognizerBasedBuilder
: public InternalRecognizerBasedBuilder
{
TestInternalRecognizerBasedBuilder(RCCompiler* rcCompiler = nullptr)
: InternalRecognizerBasedBuilder()
{
if (rcCompiler != nullptr)
{
m_rcCompiler.reset(rcCompiler);
}
}
bool FindRC([[maybe_unused]] QString& rcPathOut) override
{
return true;
}
QFileInfoList GetFilesInDirectory([[maybe_unused]] const QString& directoryPath) override
{
QFileInfoList mockFileInfoList;
mockFileInfoList.append(m_testFileInfo);
return mockFileInfoList;
}
bool SaveProcessJobRequestFile(const char* /*requestFileDir*/, const char* /*requestFileName*/, const AssetBuilderSDK::ProcessJobRequest& /*request*/) override
{
m_savedProcessJob = true;
return true;
}
// returns false only if there is a critical failure.
bool LoadProcessJobResponseFile(const char* /*responseFileDir*/, const char* /*responseFileName*/, AssetBuilderSDK::ProcessJobResponse& /*response*/, bool& /*responseLoaded*/) override
{
m_loadedProcessJob = true;
return true;
}
void TestProcessJob(const AssetBuilderSDK::ProcessJobRequest& request,
AssetBuilderSDK::ProcessJobResponse& response)
{
InternalRecognizerBasedBuilder::ProcessJob(request, response);
}
void TestProcessLegacyRCJob(const AssetBuilderSDK::ProcessJobRequest& request,
QString rcParam,
AZ::Uuid productAssetType,
const AssetBuilderSDK::JobCancelListener& jobCancelListener,
AssetBuilderSDK::ProcessJobResponse& response)
{
InternalRecognizerBasedBuilder::ProcessLegacyRCJob(request, rcParam, productAssetType, jobCancelListener, response);
}
void TestProcessCopyJob(const AssetBuilderSDK::ProcessJobRequest& request,
AZ::Uuid productAssetType,
const AssetBuilderSDK::JobCancelListener& jobCancelListener,
AssetBuilderSDK::ProcessJobResponse& response)
{
const bool outputProductDependency = false;
InternalRecognizerBasedBuilder::ProcessCopyJob(request, productAssetType, outputProductDependency, jobCancelListener, response);
}
TestInternalRecognizerBasedBuilder& AddTestFileInfo(const QString& testFileFullPath)
{
QFileInfo testFileInfo(testFileFullPath);
m_testFileInfo.push_back(testFileInfo);
return *this;
}
AZ::u32 AddTestRecognizer(QString builderID, QString extraRCParam, QString platformString)
{
// Create a dummy test recognizer
AssetBuilderSDK::FilePatternMatcher patternMatcher;
QString versionZero("0");
AZ::Data::AssetType productAssetType = AZ::Uuid::CreateRandom();
AssetRecognizer baseAssetRecognizer(QString("test-").append(extraRCParam), false, 1, false, false, patternMatcher, versionZero, productAssetType, false);
QHash<QString, AssetPlatformSpec> assetPlatformSpecByPlatform;
AssetPlatformSpec assetSpec;
assetSpec.m_extraRCParams = extraRCParam;
assetPlatformSpecByPlatform[platformString] = assetSpec;
InternalAssetRecognizer* pTestInternalRecognizer = new InternalAssetRecognizer(baseAssetRecognizer, builderID, assetPlatformSpecByPlatform);
this->m_assetRecognizerDictionary[pTestInternalRecognizer->m_paramID] = pTestInternalRecognizer;
return pTestInternalRecognizer->m_paramID;
}
void TestProcessRCResultFolder(const QString &dest, const AZ::Uuid& productAssetType, bool responseFromRCCompiler, AssetBuilderSDK::ProcessJobResponse &response)
{
ProcessRCResultFolder(dest, productAssetType, responseFromRCCompiler, response);
}
QList<QFileInfo> m_testFileInfo;
bool m_savedProcessJob = false;
bool m_loadedProcessJob = false;
};
class RCBuilderTest
: public AssetProcessor::AssetProcessorTest
{
int m_argc;
char** m_argv;
QCoreApplication* m_qApp = nullptr;
public:
RCBuilderTest()
: m_argc(0)
, m_argv(0)
{
m_qApp = new QCoreApplication(m_argc, m_argv);
}
virtual ~RCBuilderTest()
{
delete m_qApp;
}
AZ::Uuid GetBuilderUUID() const
{
AZ::Uuid rcUuid;
AssetProcessor::BUILDER_ID_RC.GetUuid(rcUuid);
return rcUuid;
}
AZStd::string GetBuilderName() const
{
return AZStd::string(AssetProcessor::BUILDER_ID_RC.GetName().toUtf8().data());
}
QString GetBuilderID() const
{
return AssetProcessor::BUILDER_ID_RC.GetId();
}
AssetBuilderSDK::ProcessJobRequest CreateTestJobRequest(const AZStd::string& testFileName, bool critical, QString platform, AZ::s64 jobId = 0)
{
AssetBuilderSDK::ProcessJobRequest request;
request.m_builderGuid = this->GetBuilderUUID();
request.m_sourceFile = testFileName;
request.m_fullPath = AZStd::string("c:\\temp\\") + testFileName;
request.m_tempDirPath = "c:\\temp";
request.m_jobDescription.m_critical = critical;
request.m_jobDescription.SetPlatformIdentifier(platform.toUtf8().constData());
request.m_jobId = jobId;
return request;
}
};
@@ -0,0 +1,300 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "RCControllerTest.h"
#include "native/resourcecompiler/rccontroller.h"
#include "AzCore/std/parallel/binary_semaphore.h"
TEST_F(RCcontrollerTest, CompileGroupCreatedWithUnknownStatusForFailedJobs)
{
//Strategy Add a failed job to the job queue list and than ask the rc controller to request compile, it should emit unknown status
using namespace AssetProcessor;
// we have to initialize this to something other than Assetstatus_Unknown here because later on we will be testing the value of assetstatus
AzFramework::AssetSystem::AssetStatus assetStatus = AzFramework::AssetSystem::AssetStatus_Failed;
RCController rcController;
QObject::connect(&rcController, &RCController::CompileGroupCreated,
[&assetStatus]([[maybe_unused]] AssetProcessor::NetworkRequestID groupID, AzFramework::AssetSystem::AssetStatus status)
{
assetStatus = status;
}
);
RCJobListModel* rcJobListModel = rcController.GetQueueModel();
RCJob* job = new RCJob(rcJobListModel);
AssetProcessor::JobDetails jobDetails;
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = jobDetails.m_jobEntry.m_databaseSourceName = "somepath/failed.dds";
jobDetails.m_jobEntry.m_platformInfo = { "pc", {"desktop", "renderer"} };
jobDetails.m_jobEntry.m_jobKey = "Compile Stuff";
job->SetState(RCJob::failed);
job->Init(jobDetails);
rcJobListModel->addNewJob(job);
// Exact Match
NetworkRequestID requestID(1, 1234);
rcController.OnRequestCompileGroup(requestID, "pc", "somepath/failed.dds", AZ::Data::AssetId());
ASSERT_TRUE(assetStatus == AzFramework::AssetSystem::AssetStatus_Unknown);
assetStatus = AzFramework::AssetSystem::AssetStatus_Failed;
// Broader Match
rcController.OnRequestCompileGroup(requestID, "pc", "somepath", AZ::Data::AssetId() );
ASSERT_TRUE(assetStatus == AzFramework::AssetSystem::AssetStatus_Unknown);
}
class RCcontrollerTest_Cancellation
: public RCcontrollerTest
{
public:
RCcontrollerTest_Cancellation()
{
}
virtual ~RCcontrollerTest_Cancellation()
{
}
void SetUp() override
{
RCcontrollerTest::SetUp();
using namespace AssetProcessor;
m_rcController.reset(new RCController());
m_rcController->SetDispatchPaused(true);
m_rcJobListModel = m_rcController->GetQueueModel();
{
RCJob* job = new RCJob(m_rcJobListModel);
AssetProcessor::JobDetails jobDetails;
jobDetails.m_jobEntry.m_computedFingerprint = 1;
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = jobDetails.m_jobEntry.m_databaseSourceName = "somepath/failed.dds";
jobDetails.m_jobEntry.m_platformInfo = { "ios",{ "mobile", "renderer" } };
jobDetails.m_jobEntry.m_jobRunKey = 1;
jobDetails.m_jobEntry.m_jobKey = "tiff";
job->SetState(RCJob::JobState::pending);
job->Init(jobDetails);
m_rcJobListModel->addNewJob(job);
}
{
RCJob* job = new RCJob(m_rcJobListModel);
// note that Init() is a move operation. we cannot reuse jobDetails.
AssetProcessor::JobDetails jobDetails;
jobDetails.m_jobEntry.m_computedFingerprint = 1;
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = jobDetails.m_jobEntry.m_databaseSourceName = "somepath/failed.dds";
jobDetails.m_jobEntry.m_platformInfo = { "pc",{ "desktop", "renderer" } };
jobDetails.m_jobEntry.m_jobRunKey = 2;
jobDetails.m_jobEntry.m_jobKey = "tiff";
job->SetState(RCJob::JobState::pending);
job->Init(jobDetails);
m_rcJobListModel->addNewJob(job);
m_rcJobListModel->markAsStarted(job);
m_rcJobListModel->markAsProcessing(job); // job is now "in flight"
}
}
void TearDown() override
{
m_rcJobListModel = nullptr;
m_rcController.reset();
RCcontrollerTest::TearDown();
}
AZStd::unique_ptr<AssetProcessor::RCController> m_rcController;
AssetProcessor::RCJobListModel* m_rcJobListModel = nullptr; // convenience pointer into m_rcController->GetQueueModel()
};
TEST_F(RCcontrollerTest_Cancellation, JobSubmitted_SameFingerprint_DoesNotCancelTheJob)
{
// submit a new job for the same details as the already running one.
{
AssetProcessor::JobDetails jobDetails;
jobDetails.m_jobEntry.m_computedFingerprint = 1; // same as above in SetUp
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = jobDetails.m_jobEntry.m_databaseSourceName = "somepath/failed.dds";
jobDetails.m_jobEntry.m_platformInfo = { "pc",{ "desktop", "renderer" } };
jobDetails.m_jobEntry.m_jobKey = "tiff";
jobDetails.m_jobEntry.m_jobRunKey = 3;
m_rcController->JobSubmitted(jobDetails);
}
for (int idx = 0; idx < m_rcJobListModel->itemCount(); idx++)
{
// neither job should be cancelled.
AssetProcessor::RCJob* rcJob = m_rcJobListModel->getItem(idx);
ASSERT_TRUE(rcJob->GetState() != AssetProcessor::RCJob::JobState::cancelled);
}
}
TEST_F(RCcontrollerTest_Cancellation, JobSubmitted_DifferentFingerprint_CancelsTheJob_OnlyIfInProgress)
{
// submit a new job for the same details as the already running one.
{
AssetProcessor::JobDetails jobDetails;
jobDetails.m_jobEntry.m_computedFingerprint = 2; // different from setup.
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = jobDetails.m_jobEntry.m_databaseSourceName = "somepath/failed.dds";
jobDetails.m_jobEntry.m_platformInfo = { "pc",{ "desktop", "renderer" } };
jobDetails.m_jobEntry.m_jobKey = "tiff";
jobDetails.m_jobEntry.m_jobRunKey = 3;
m_rcController->JobSubmitted(jobDetails);
}
for (int idx = 0; idx < m_rcJobListModel->itemCount(); idx++)
{
// neither job should be cancelled.
AssetProcessor::RCJob* rcJob = m_rcJobListModel->getItem(idx);
if (rcJob->GetJobEntry().m_jobRunKey == 2)
{
// the one with run key 2 should have been cancelled and replaced with run key 3
ASSERT_TRUE(rcJob->GetState() == AssetProcessor::RCJob::JobState::cancelled);
}
else
{
// the other one should have been left alone since it had not yet begun.
ASSERT_TRUE(rcJob->GetState() != AssetProcessor::RCJob::JobState::cancelled);
}
}
}
class RCcontrollerTest_Simple
: public RCcontrollerTest
{
public:
void SetUp() override
{
RCcontrollerTest::SetUp();
using namespace AssetProcessor;
m_rcController.reset(new RCController(/*minJobs*/1, /*maxJobs*/1));
m_rcController->SetDispatchPaused(false);
m_rcJobListModel = m_rcController->GetQueueModel();
qRegisterMetaType<AssetBuilderSDK::ProcessJobResponse>("ProcessJobResponse");
QObject::connect(m_rcController.get(), &RCController::BecameIdle, [this]()
{
m_wait.release();
});
}
void TearDown() override
{
m_rcJobListModel = nullptr;
m_rcController.reset();
RCcontrollerTest::TearDown();
}
void SubmitJob();
AZStd::binary_semaphore m_wait;
AZStd::unique_ptr<AssetProcessor::RCController> m_rcController;
AssetProcessor::RCJobListModel* m_rcJobListModel = nullptr; // convenience pointer into m_rcController->GetQueueModel()
};
void RCcontrollerTest_Simple::SubmitJob()
{
using namespace AssetBuilderSDK;
{
AssetProcessor::JobDetails jobDetails;
jobDetails.m_jobEntry.m_computedFingerprint = 123;
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = jobDetails.m_jobEntry.m_databaseSourceName = "somepath/a.dds";
jobDetails.m_jobEntry.m_platformInfo = { "pc",{ "desktop", "renderer" } };
jobDetails.m_jobEntry.m_jobKey = "tiff";
jobDetails.m_jobEntry.m_jobRunKey = 3;
jobDetails.m_assetBuilderDesc.m_processJobFunction = []([[maybe_unused]] const ProcessJobRequest& request, ProcessJobResponse& response)
{
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
};
m_rcController->JobSubmitted(jobDetails);
}
// Numbers are a bit arbitrary but this should result in a max wait time of 5s
int retryCount = 100;
do
{
QCoreApplication::processEvents(QEventLoop::AllEvents, 10);
} while (m_wait.try_acquire_for(AZStd::chrono::milliseconds(5)) == false && --retryCount > 0);
ASSERT_GT(retryCount, 0);
}
// This is a regresssion test to ensure the rccontroller can handle multiple jobs for the same file being completed before
// the APM has a chance to send OnFinishedProcesssingJob events
TEST_F(RCcontrollerTest_Simple, SameJobIsCompletedMultipleTimes_CompletesWithoutError)
{
using namespace AssetProcessor;
AZStd::vector<JobEntry> jobEntries;
QObject::connect(m_rcController.get(), &RCController::FileCompiled, [&jobEntries](JobEntry entry, AssetBuilderSDK::ProcessJobResponse response)
{
jobEntries.push_back(entry);
});
SubmitJob();
SubmitJob();
ASSERT_EQ(jobEntries.size(), 2);
for (const JobEntry& entry : jobEntries)
{
m_rcController->OnAddedToCatalog(entry);
}
ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 4); // Expected that there are 4 errors related to the files not existing on disk. Error message: GenerateFingerprint was called but no input files were requested for fingerprinting.
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
}
// makes sure to expose parts of RCJob to the unit test
class TestRCJob : public AssetProcessor::RCJob
{
friend class GTEST_TEST_CLASS_NAME_(RCcontrollerTest, BuilderSDK_API_ProcessJob_HasValidParameters_WithOutputFolder);
public:
explicit TestRCJob(QObject* parent = 0) : AssetProcessor::RCJob(parent) {};
};
TEST_F(RCcontrollerTest, BuilderSDK_API_ProcessJob_HasValidParameters_WithOutputFolder)
{
// this test makes sure that the BuilderSDK API is not exposed to any database internals.
AZ::Uuid sourceUUID = AZ::Uuid::CreateRandom();
AZ::Uuid builderGuid = AZ::Uuid::CreateRandom();
AssetBuilderSDK::ProcessJobRequest req;
{
// note that this scope is intentional. job.Init(jobDetails) below is actually a by-ref operation that destroys JobDetails in the process.
AssetProcessor::JobDetails jobDetails;
// the crux of this test: the database source name differs from the relative path to watch folder:
jobDetails.m_jobEntry.m_pathRelativeToWatchFolder = "SomeThing.tif"; // case sensitive
// Note that while this is an OS-SPECIFIC path, this unit test does not actually invoke the file system at all
// and only operates on in-memory structures, so it should work on every platform.
jobDetails.m_jobEntry.m_watchFolderPath = "c:/test/a/B/c"; // just to make sure case is preserved
jobDetails.m_jobEntry.m_databaseSourceName = "somepath/SomeThing.tif"; // case sensitive but outputprefixes are generally lowcase
jobDetails.m_jobEntry.m_sourceFileUUID = sourceUUID;
jobDetails.m_jobEntry.m_platformInfo = { "ios",{ "mobile", "renderer" } };
jobDetails.m_jobEntry.m_jobRunKey = 1;
jobDetails.m_jobEntry.m_jobKey = "tiff";
jobDetails.m_jobEntry.m_builderGuid = builderGuid;
TestRCJob job;
job.Init(jobDetails);
job.PopulateProcessJobRequest(req);
}
EXPECT_STREQ(req.m_sourceFile.c_str(), "SomeThing.tif");
EXPECT_STREQ(req.m_watchFolder.c_str(), "c:/test/a/B/c");
// the crux of the test, tested: make sure that it does not contain 'somepath' in there just becuase its part of the Database Source Name.
EXPECT_STREQ(req.m_fullPath.c_str(), "c:/test/a/B/c/SomeThing.tif");
EXPECT_EQ(req.m_builderGuid, builderGuid);
EXPECT_TRUE(req.m_platformInfo.HasTag("renderer"));
EXPECT_TRUE(req.m_platformInfo.HasTag("mobile"));
EXPECT_STREQ(req.m_platformInfo.m_identifier.c_str(), "ios");
EXPECT_EQ(req.m_sourceFileUUID, sourceUUID);
}
@@ -0,0 +1,42 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "native/tests/AssetProcessorTest.h"
#include <QCoreApplication>
#include "native/assetprocessor.h"
#include <AzFramework/Asset/AssetSystemTypes.h>
class RCcontrollerTest
: public AssetProcessor::AssetProcessorTest
{
public:
RCcontrollerTest()
: m_argc(0)
, m_argv(0)
{
m_qApp = new QCoreApplication(m_argc, m_argv);
qRegisterMetaType<AzFramework::AssetSystem::AssetStatus>("AzFramework::AssetSystem::AssetStatus");
qRegisterMetaType<AssetProcessor::NetworkRequestID>("NetworkRequestID");
}
virtual ~RCcontrollerTest()
{
delete m_qApp;
}
private:
int m_argc;
char** m_argv;
QCoreApplication* m_qApp;
};
@@ -0,0 +1,290 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "RCJobTest.h"
#include <native/tests/AssetProcessorTest.h>
#include <native/resourcecompiler/rcjob.h>
namespace UnitTests
{
using namespace testing;
using ::testing::NiceMock;
using namespace AssetProcessor;
using namespace AssetBuilderSDK;
class MockDiskSpaceResponder : public DiskSpaceInfoBus::Handler
{
public:
MOCK_METHOD3(CheckSufficientDiskSpace, bool(const QString&, qint64, bool));
};
class IgnoreNotifyTracker : public ProcessingJobInfoBus::Handler
{
public:
// Will notify other systems which old product is just about to get removed from the cache
// before we copy the new product instead along.
void BeginCacheFileUpdate(const char* productPath) override
{
m_capturedStartPaths.push_back(productPath);
}
// Will notify other systems which product we are trying to copy in the cache
// along with status of whether that copy succeeded or failed.
void EndCacheFileUpdate(const char* productPath, bool /*queueAgainForProcessing*/) override
{
m_capturedStopPaths.push_back(productPath);
}
AZStd::vector<AZStd::string> m_capturedStartPaths;
AZStd::vector<AZStd::string> m_capturedStopPaths;
};
class RCJobTest : public AssetProcessorTest
{
public:
void SetUp() override
{
AssetProcessorTest::SetUp();
m_data.reset(new StaticData());
m_data->tempDirPath = QDir(m_data->m_tempDir.path());
m_data->m_absolutePathToTempInputFolder = m_data->tempDirPath.absoluteFilePath("InputFolder").toUtf8().constData();
// note that the case of OutputFolder is intentionally upper/lower case becuase
// while files inside the output folder should be lowercased, the path to there should not be lowercased by RCJob.
m_data->m_absolutePathToTempOutputFolder = m_data->tempDirPath.absoluteFilePath("OutputFolder").toUtf8().constData();
m_data->tempDirPath.mkpath(QString::fromUtf8(m_data->m_absolutePathToTempInputFolder.c_str()));
m_data->m_diskSpaceResponder.BusConnect();
m_data->m_notifyTracker.BusConnect();
// this can be overridden in each test but if you don't override it, then this fixture will do it.
ON_CALL(m_data->m_diskSpaceResponder, CheckSufficientDiskSpace(_, _, _))
.WillByDefault(Return(true));
}
void TearDown() override
{
m_data->m_diskSpaceResponder.BusDisconnect();
m_data->m_notifyTracker.BusDisconnect();
m_data.reset();
AssetProcessorTest::TearDown();
}
protected:
struct StaticData
{
QTemporaryDir m_tempDir;
QDir tempDirPath;
AZStd::string m_absolutePathToTempInputFolder;
AZStd::string m_absolutePathToTempOutputFolder;
NiceMock<MockDiskSpaceResponder> m_diskSpaceResponder;
IgnoreNotifyTracker m_notifyTracker;
};
AZStd::unique_ptr<StaticData> m_data;
};
TEST_F(RCJobTest, CopyCompiledAssets_NoWorkToDo_Succeeds)
{
BuilderParams builderParams;
ProcessJobResponse response;
EXPECT_TRUE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
}
TEST_F(RCJobTest, CopyCompiledAssets_InvalidOutputPath_FailsAndAsserts)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
response.m_outputProducts.push_back({ "file1.txt" }); // make sure that there is at least one product so that it doesn't early out.
// set only the input path, not the output path:
builderParams.m_processJobRequest.m_tempDirPath = m_data->m_absolutePathToTempInputFolder.c_str(); // input working scratch space folder
EXPECT_FALSE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 1);
}
TEST_F(RCJobTest, CopyCompiledAssets_InvalidInputPath_FailsAndAsserts)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
response.m_outputProducts.push_back({ "file1.txt" }); // make sure that there is at least one product so that it doesn't early out.
// set the input dir to be a broken invalid dir:
builderParams.m_processJobRequest.m_tempDirPath = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
builderParams.m_finalOutputDir = QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str()); // output folder in the 'cache'
EXPECT_FALSE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 1);
}
TEST_F(RCJobTest, CopyCompiledAssets_TooLongPath_FailsButDoesNotAssert)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
// set only the output path, but not the input path:
builderParams.m_processJobRequest.m_tempDirPath = m_data->m_absolutePathToTempInputFolder.c_str(); // input working scratch space folder
builderParams.m_finalOutputDir = QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str()); // output folder in the 'cache'
// give it an overly long file name:
AZStd::string reallyLongFileName;
reallyLongFileName.resize(4096, 'x');
response.m_outputProducts.push_back({ reallyLongFileName.c_str() });
EXPECT_FALSE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 1);
}
TEST_F(RCJobTest, CopyCompiledAssets_OutOfDiskSpace_FailsButDoesNotAssert)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
// set only the output path, but not the input path:
builderParams.m_processJobRequest.m_tempDirPath = m_data->m_absolutePathToTempInputFolder.c_str(); // input working scratch space folder
builderParams.m_finalOutputDir = QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str()); // output folder in the 'cache'
response.m_resultCode = ProcessJobResult_Success;
response.m_outputProducts.push_back({ "file1.txt" }); // make sure that there is at least one product so that it doesn't early out.
UnitTestUtils::CreateDummyFile(QDir(m_data->m_absolutePathToTempInputFolder.c_str()).absoluteFilePath("file1.txt"), "output of file 1");
response.m_outputProducts.push_back({ "file2.txt" }); // make sure that there is at least one product so that it doesn't early out.
UnitTestUtils::CreateDummyFile(QDir(m_data->m_absolutePathToTempInputFolder.c_str()).absoluteFilePath("file2.txt"), "output of file 2");
// we exepct exactly one call to check for disk space, (not once for each file), and in this case, we'll return false.
EXPECT_CALL(m_data->m_diskSpaceResponder, CheckSufficientDiskSpace(_,_,_))
.Times(1)
.WillRepeatedly(Return(false));
EXPECT_FALSE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 1);
// no notifies should be hit since the operation should not have been attempted at all (disk space should be checked up front)
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStartPaths.size(), 0);
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStopPaths.size(), 0);
// no cached files should have been copied at all.
QString expectedFinalOutputPath = QDir(QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str())).absoluteFilePath("file1.txt");
EXPECT_FALSE(QFile::exists(expectedFinalOutputPath));
expectedFinalOutputPath = QDir(QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str())).absoluteFilePath("file2.txt");
EXPECT_FALSE(QFile::exists(expectedFinalOutputPath));
}
// The RC Copy Compiled Assets routine is supposed to check up front for problem situations such as out of disk space
// or missing source files, before it tries to perform any operation. This test gives it one file which does work
// but one missing file also, and expects it to fail (without asserting) but without even trying to copy the files at all.
TEST_F(RCJobTest, CopyCompiledAssets_MissingInputFile_Fails_DoesNotAssert_DoesNotAlterCache)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
// set only the output path, but not the input path:
builderParams.m_processJobRequest.m_tempDirPath = m_data->m_absolutePathToTempInputFolder.c_str(); // input working scratch space folder
builderParams.m_finalOutputDir = QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str()); // output folder in the 'cache'
response.m_resultCode = ProcessJobResult_Success;
response.m_outputProducts.push_back({ "FiLe1.TxT" }); // make sure that there is at least one product so that it doesn't early out.
UnitTestUtils::CreateDummyFile(QDir(m_data->m_absolutePathToTempInputFolder.c_str()).absoluteFilePath("FiLe1.TxT"), "output of file 1");
response.m_outputProducts.push_back({ "FiLe2.txt" });
// note well that we create the first file but we don't acutally create the second one, so it is missing.
EXPECT_FALSE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 1);
// no notifies should be hit since the operation should not have been attempted at all.
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStartPaths.size(), 0);
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStopPaths.size(), 0);
QString expectedFinalOutputPath = QDir(QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str())).absoluteFilePath("file1.txt");
EXPECT_FALSE(QFile::exists(expectedFinalOutputPath));
}
TEST_F(RCJobTest, CopyCompiledAssets_AbsolutePath_SucceedsAndNotifiesAboutCacheDelete)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
// set only the output path, but not the input path:
builderParams.m_processJobRequest.m_tempDirPath = m_data->m_absolutePathToTempInputFolder.c_str(); // input working scratch space folder
builderParams.m_finalOutputDir = QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str()); // output folder in the 'cache'
response.m_resultCode = ProcessJobResult_Success;
// make up a completely different random path to put an absolute file in:
QTemporaryDir extraDir;
QDir randomDir(extraDir.path());
randomDir.mkpath(extraDir.path());
QString absolutePathToCreate = randomDir.absoluteFilePath("someabsolutefile.txt");
UnitTestUtils::CreateDummyFile(absolutePathToCreate, "output of the file");
response.m_outputProducts.push_back({ absolutePathToCreate.toUtf8().constData() }); // absolute path to file not actually in the product scratch space folder.
// this should copy that file into the target path.
EXPECT_TRUE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStartPaths.size(), 1);
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStopPaths.size(), 1);
// note that output files are automatically lowercased within the cache but the path to the cache folder itself is not lowered, just the output file.
// this is to make sure that game code never has to worry about the casing of output file paths, CRYPAK can just always lower the relpath and always know
// that even on case-sensitive platforms it won't cause trouble or a difference of behavior from non-case-sensitive ones.
QString expectedFinalOutputPath = QDir(QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str())).absoluteFilePath("someabsolutefile.txt");
ASSERT_STREQ(m_data->m_notifyTracker.m_capturedStartPaths[0].c_str(), m_data->m_notifyTracker.m_capturedStopPaths[0].c_str());
ASSERT_STREQ(m_data->m_notifyTracker.m_capturedStartPaths[0].c_str(), expectedFinalOutputPath.toUtf8().constData());
EXPECT_TRUE(QFile::exists(expectedFinalOutputPath));
}
TEST_F(RCJobTest, CopyCompiledAssets_RelativePath_SucceedsAndNotifiesAboutCacheDelete)
{
BuilderParams builderParams;
ProcessJobResponse response;
response.m_resultCode = ProcessJobResult_Success;
// set only the output path, but not the input path:
builderParams.m_processJobRequest.m_tempDirPath = m_data->m_absolutePathToTempInputFolder.c_str(); // input working scratch space folder
builderParams.m_finalOutputDir = QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str()); // output folder in the 'cache'
response.m_resultCode = ProcessJobResult_Success;
response.m_outputProducts.push_back({ "FiLe1.TxT" }); // make sure that there is at least one product so that it doesn't early out.
UnitTestUtils::CreateDummyFile(QDir(m_data->m_absolutePathToTempInputFolder.c_str()).absoluteFilePath("FiLe1.TxT"), "output of file 1");
EXPECT_TRUE(RCJob::CopyCompiledAssets(builderParams, response));
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
EXPECT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStartPaths.size(), 1);
ASSERT_EQ(m_data->m_notifyTracker.m_capturedStopPaths.size(), 1);
// note that output files are automatically lowercased within the cache but the path to the cache folder itself is not lowered, just the output file.
// this is to make sure that game code never has to worry about the casing of output file paths, CRYPAK can just always lower the relpath and always know
// that even on case-sensitive platforms it won't cause trouble or a difference of behavior from non-case-sensitive ones.
QString expectedFinalOutputPath = QDir(QString::fromUtf8(m_data->m_absolutePathToTempOutputFolder.c_str())).absoluteFilePath("file1.txt");
ASSERT_STREQ(m_data->m_notifyTracker.m_capturedStartPaths[0].c_str(), m_data->m_notifyTracker.m_capturedStopPaths[0].c_str());
ASSERT_STREQ(m_data->m_notifyTracker.m_capturedStartPaths[0].c_str(), expectedFinalOutputPath.toUtf8().constData());
EXPECT_TRUE(QFile::exists(expectedFinalOutputPath));
// Start and end paths should, however, be normalized even if the input is not.
QString normalizedStartPath = QString::fromUtf8(m_data->m_notifyTracker.m_capturedStartPaths[0].c_str());
normalizedStartPath = AssetUtilities::NormalizeFilePath(normalizedStartPath);
EXPECT_STREQ(normalizedStartPath.toUtf8().constData(), m_data->m_notifyTracker.m_capturedStartPaths[0].c_str());
QString normalizedStopPath = QString::fromUtf8(m_data->m_notifyTracker.m_capturedStopPaths[0].c_str());
normalizedStopPath = AssetUtilities::NormalizeFilePath(normalizedStopPath);
EXPECT_STREQ(normalizedStopPath.toUtf8().constData(), m_data->m_notifyTracker.m_capturedStopPaths[0].c_str());
}
} // end namespace UnitTests
@@ -0,0 +1,17 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzTest/AzTest.h>