You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp

630 lines
28 KiB
C++

/*
* 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 <QHash>
#include "native/tests/AssetProcessorTest.h"
#include <native/utilities/PlatformConfiguration.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/std/parallel/thread.h>
#include <AzTest/AzTest.h>
using namespace AssetUtilities;
class AssetUtilitiesTest
: public AssetProcessor::AssetProcessorTest
{
void SetUp() override
{
AssetProcessorTest::SetUp();
if (AZ::IO::FileIOBase::GetInstance() == nullptr)
{
m_localFileIo = aznew AZ::IO::LocalFileIO();
AZ::IO::FileIOBase::SetInstance(m_localFileIo);
}
}
void TearDown() override
{
if (m_localFileIo)
{
delete m_localFileIo;
m_localFileIo = nullptr;
AZ::IO::FileIOBase::SetInstance(nullptr);
}
AssetProcessorTest::TearDown();
}
AZ::IO::FileIOBase* m_localFileIo{};
};
TEST_F(AssetUtilitiesTest, NormlizeFilePath_NormalizedValidPathRelPath_Valid)
{
QString result = NormalizeFilePath("a/b\\c\\d/E.txt");
EXPECT_STREQ(result.toUtf8().constData(), "a/b/c/d/E.txt");
}
TEST_F(AssetUtilitiesTest, NormlizeFilePath_NormalizedValidPathFullPath_Valid)
{
QString result = NormalizeFilePath("c:\\a/b\\c\\d/E.txt");
// on windows, drive letters are normalized to full
#if defined(AZ_PLATFORM_WINDOWS)
ASSERT_TRUE(result.compare("C:/a/b/c/d/E.txt", Qt::CaseSensitive) == 0);
#else
// on other platforms, C: is a relative path to a file called 'c:')
EXPECT_STREQ(result.toUtf8().constData(), "c:/a/b/c/d/E.txt");
#endif
}
TEST_F(AssetUtilitiesTest, NormlizeFilePath_NormalizedValidDirRelPath_Valid)
{
QString result = NormalizeDirectoryPath("a/b\\c\\D");
EXPECT_STREQ(result.toUtf8().constData(), "a/b/c/D");
}
TEST_F(AssetUtilitiesTest, NormlizeFilePath_NormalizedValidDirFullPath_Valid)
{
QString result = NormalizeDirectoryPath("c:\\a/b\\C\\d\\");
// on windows, drive letters are normalized to full
#if defined(AZ_PLATFORM_WINDOWS)
EXPECT_STREQ(result.toUtf8().constData(), "C:/a/b/C/d");
#else
EXPECT_STREQ(result.toUtf8().constData(), "c:/a/b/C/d");
#endif
}
TEST_F(AssetUtilitiesTest, ComputeCRC32Lowercase_IsCaseInsensitive)
{
const char* upperCaseString = "HELLOworld";
const char* lowerCaseString = "helloworld";
EXPECT_EQ(AssetUtilities::ComputeCRC32Lowercase(lowerCaseString), AssetUtilities::ComputeCRC32Lowercase(upperCaseString));
// also try the length-based one.
EXPECT_EQ(AssetUtilities::ComputeCRC32Lowercase(lowerCaseString, size_t(5)), AssetUtilities::ComputeCRC32Lowercase(upperCaseString, size_t(5)));
}
TEST_F(AssetUtilitiesTest, ComputeCRC32_IsCaseSensitive)
{
const char* upperCaseString = "HELLOworld";
const char* lowerCaseString = "helloworld";
EXPECT_NE(AssetUtilities::ComputeCRC32(lowerCaseString), AssetUtilities::ComputeCRC32(upperCaseString));
// also try the length-based one.
EXPECT_NE(AssetUtilities::ComputeCRC32(lowerCaseString, size_t(5)), AssetUtilities::ComputeCRC32(upperCaseString, size_t(5)));
}
TEST_F(AssetUtilitiesTest, UpdateToCorrectCase_MissingFile_ReturnsFalse)
{
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString fileName = "someFile.txt";
EXPECT_FALSE(AssetUtilities::UpdateToCorrectCase(canonicalTempDirPath, fileName));
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(AssetUtilitiesTest, DISABLED_UpdateToCorrectCase_ExistingFile_ReturnsTrue_CorrectsCase)
#else
TEST_F(AssetUtilitiesTest, UpdateToCorrectCase_ExistingFile_ReturnsTrue_CorrectsCase)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QStringList thingsToTry;
thingsToTry << "SomeFile.TxT";
thingsToTry << "otherfile.txt";
thingsToTry << "subfolder1/otherfile.txt";
#if defined(AZ_PLATFORM_WINDOWS)
thingsToTry << "subfolder2\\otherfile.txt";
thingsToTry << "subFolder3\\somefile.txt";
thingsToTry << "subFolder4\\subfolder6\\somefile.txt";
thingsToTry << "subFolder5\\subfolder7/someFile.txt";
#endif // AZ_PLATFORM_WINDOWS
thingsToTry << "specialFileName[.txt";
thingsToTry << "specialFileName].txt";
thingsToTry << "specialFileName!.txt";
thingsToTry << "specialFileName#.txt";
thingsToTry << "specialFileName$.txt";
thingsToTry << "specialFile%Name%.txt";
thingsToTry << "specialFileName&.txt";
thingsToTry << "specialFileName(.txt";
thingsToTry << "specialFileName+.txt";
thingsToTry << "specialFileName[9].txt";
thingsToTry << "specialFileName[A-Za-z].txt"; // these should all be treated as literally the name of the file, not a regex!
for (QString triedThing : thingsToTry)
{
triedThing = NormalizeFilePath(triedThing);
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath(triedThing)));
QString lowercaseVersion = triedThing.toLower();
// each one should be found. If it fails, we'll pipe out the name of the file it fails on for extra context.
EXPECT_TRUE(AssetUtilities::UpdateToCorrectCase(canonicalTempDirPath, lowercaseVersion)) << "File being Examined: " << lowercaseVersion.toUtf8().constData();
// each one should correct, and return a normalized path.
EXPECT_STREQ(AssetUtilities::NormalizeFilePath(lowercaseVersion).toUtf8().constData(), AssetUtilities::NormalizeFilePath(triedThing).toUtf8().constData());
}
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_BasicTest)
{
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
QString absoluteTestFilePath2 = tempPath.absoluteFilePath("basicfile2.txt");
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "contents"));
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath2, "contents"));
AZStd::string fileEncoded1 = absoluteTestFilePath1.toUtf8().constData();
AZStd::string fileEncoded2 = absoluteTestFilePath2.toUtf8().constData();
AssetProcessor::JobDetails jobDetail;
// it is expected that the only parts of jobDetails that matter are:
// jobDetail.m_extraInformationForFingerprinting
// jobDetail.m_fingerprintFiles
// jobDetail.m_jobDependencyList
jobDetail.m_extraInformationForFingerprinting = "extra info1";
// the fingerprint should always be stable over repeated runs, even with minimal info:
unsigned int result1 = AssetUtilities::GenerateFingerprint(jobDetail);
unsigned int result2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_EQ(result1, result2);
// the fingerprint should always be different when anything changes:
jobDetail.m_extraInformationForFingerprinting = "extra info1";
result1 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_extraInformationForFingerprinting = "extra info2";
result2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(result1, result2);
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(absoluteTestFilePath1.toUtf8().constData(), "basicfile.txt"));
result1 = AssetUtilities::GenerateFingerprint(jobDetail);
result2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_EQ(result1, result2);
// mutating the dependency list should mutate the fingerprint, even if the extra info doesn't change.
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(absoluteTestFilePath2.toUtf8().constData(), "basicfile2.txt"));
result2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(result1, result2);
UnitTestUtils::SleepForMinimumFileSystemTime();
// mutating the actual files should mutate the fingerprint, even if the file list doesn't change.
// note that both files are in the file list, so changing just the one should result in a change in hash:
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "contents new"));
result1 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(result1, result2);
// changing the other should also change the hash:
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath2, "contents new2"));
result2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(result1, result2);
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_Empty_Asserts)
{
AssetProcessor::JobDetails jobDetail;
AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 1);
m_errorAbsorber->Clear();
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_MissingFile_NotSameAsZeroByteFile)
{
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
QString absoluteTestFilePath2 = tempPath.absoluteFilePath("basicfile2.txt");
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "")); // empty file
// note: basicfile1 exists but is empty, whereas basicfile2, 3 are missing entirely.
AssetProcessor::JobDetails jobDetail;
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
AZ::u32 fingerprint1 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
AZ::u32 fingerprint2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(fingerprint1, fingerprint2);
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_MissingFile_NotSameAsOtherMissingFile)
{
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
QString absoluteTestFilePath2 = tempPath.absoluteFilePath("basicfile2.txt");
// we create no files on disk.
AssetProcessor::JobDetails jobDetail;
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
AZ::u32 fingerprint1 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
AZ::u32 fingerprint2 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(fingerprint1, fingerprint2);
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_OneFile_Differs)
{
// this test makes sure that changing each part of jobDetail relevant to fingerprints causes the resulting fingerprint to change.
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
QString absoluteTestFilePath2 = tempPath.absoluteFilePath("basicfile2.txt");
QString absoluteTestFilePath3 = tempPath.absoluteFilePath("basicfile3.txt");
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "contents"));
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath2, "contents")); // same contents
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath3, "contents2")); // different contents
AssetProcessor::JobDetails jobDetail;
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
AZ::u32 fingerprint1 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
AZ::u32 fingerprint2 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile3.txt").toUtf8().constData(), "basicfile3.txt"));
AZ::u32 fingerprint3 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
EXPECT_EQ(AssetUtilities::GenerateFingerprint(jobDetail), fingerprint1);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
EXPECT_EQ(AssetUtilities::GenerateFingerprint(jobDetail), fingerprint2);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile3.txt").toUtf8().constData(), "basicfile3.txt"));
EXPECT_EQ(AssetUtilities::GenerateFingerprint(jobDetail), fingerprint3);
EXPECT_NE(fingerprint1, fingerprint2);
EXPECT_NE(fingerprint2, fingerprint3);
EXPECT_NE(fingerprint3, fingerprint1);
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_MultipleFile_Differs)
{
// given multiple files, make sure that the fingerprint for multiple files differs from the one file (that each file is taken into account)
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
QString absoluteTestFilePath2 = tempPath.absoluteFilePath("basicfile2.txt");
QString absoluteTestFilePath3 = tempPath.absoluteFilePath("basicfile3.txt");
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "contents"));
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath2, "contents")); // same contents
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath3, "contents2")); // different contents
AssetProcessor::JobDetails jobDetail;
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
AZ::u32 fingerprint1 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
AZ::u32 fingerprint2 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile3.txt").toUtf8().constData(), "basicfile3.txt"));
AZ::u32 fingerprint3 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(fingerprint1, fingerprint2);
EXPECT_NE(fingerprint2, fingerprint3);
EXPECT_NE(fingerprint3, fingerprint1);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
fingerprint1 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile2.txt").toUtf8().constData(), "basicfile2.txt"));
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile3.txt").toUtf8().constData(), "basicfile3.txt"));
fingerprint2 = AssetUtilities::GenerateFingerprint(jobDetail);
jobDetail.m_fingerprintFiles.clear();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile1.txt").toUtf8().constData(), "basicfile1.txt"));
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile3.txt").toUtf8().constData(), "basicfile3.txt"));
fingerprint3 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(fingerprint1, fingerprint2);
EXPECT_NE(fingerprint2, fingerprint3);
EXPECT_NE(fingerprint3, fingerprint1);
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_OrderOnceJobDependency_NoChange)
{
// OrderOnce Job dependency should not alter the fingerprint of the job
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
const char relFile1Path[] = "file.txt";
const char relFile2Path[] = "secondFile.txt";
QString absoluteTestFile1Path = tempPath.absoluteFilePath(relFile1Path);
QString absoluteTestFile2Path = tempPath.absoluteFilePath(relFile2Path);
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFile1Path, "contents"));
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFile2Path, "contents"));
AssetProcessor::JobDetails jobDetail;
jobDetail.m_jobEntry.m_databaseSourceName = relFile1Path;
jobDetail.m_jobEntry.m_watchFolderPath = tempPath.absolutePath();
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(absoluteTestFile1Path.toUtf8().constData(), relFile1Path));
AZ::u32 fingerprintWithoutOrderOnceJobDependency = AssetUtilities::GenerateFingerprint(jobDetail);
AssetBuilderSDK::SourceFileDependency dep = { relFile2Path, AZ::Uuid::CreateNull() };
AssetBuilderSDK::JobDependency jobDep("key", "pc", AssetBuilderSDK::JobDependencyType::OrderOnce, dep);
jobDetail.m_jobDependencyList.push_back(AssetProcessor::JobDependencyInternal(jobDep));
AZ::u32 fingerprintWithOrderOnceJobDependency = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_EQ(fingerprintWithoutOrderOnceJobDependency, fingerprintWithOrderOnceJobDependency);
}
namespace AssetUtilsTest
{
class MockJobDependencyResponder : public AssetProcessor::ProcessingJobInfoBus::Handler
{
public:
MOCK_METHOD1(GetJobFingerprint, AZ::u32(const AssetProcessor::JobIndentifier&));
};
}
TEST_F(AssetUtilitiesTest, GenerateFingerprint_GivenJobDependencies_AffectsOutcome)
{
using namespace testing;
using ::testing::NiceMock;
NiceMock<AssetUtilsTest::MockJobDependencyResponder> responder;
responder.BusConnect();
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
AssetProcessor::JobDetails jobDetail;
jobDetail.m_fingerprintFiles.insert(AZStd::make_pair(tempPath.absoluteFilePath("basicfile.txt").toUtf8().constData(), "basicfile.txt"));
AZ::u32 fingerprint1 = AssetUtilities::GenerateFingerprint(jobDetail);
// add a job dependency - it should alter the fingerprint, even if the file does not exist.
AssetBuilderSDK::JobDependency jobDep("thing", "pc", AssetBuilderSDK::JobDependencyType::Order, AssetBuilderSDK::SourceFileDependency("basicfile2.txt", AZ::Uuid::CreateNull()));
AssetProcessor::JobDependencyInternal internalJobDep(jobDep);
internalJobDep.m_builderUuidList.insert(AZ::Uuid::CreateRandom());
jobDetail.m_jobDependencyList.push_back(internalJobDep);
EXPECT_CALL(responder, GetJobFingerprint(_))
.WillOnce(
Return(0x12341234));
AZ::u32 fingerprint2 = AssetUtilities::GenerateFingerprint(jobDetail);
// different job fingerprint -> different result
EXPECT_CALL(responder, GetJobFingerprint(_))
.WillOnce(
Return(0x11111111));
AZ::u32 fingerprint3 = AssetUtilities::GenerateFingerprint(jobDetail);
EXPECT_NE(fingerprint1, fingerprint2);
EXPECT_NE(fingerprint2, fingerprint3);
EXPECT_NE(fingerprint3, fingerprint1);
}
TEST_F(AssetUtilitiesTest, GetFileFingerprint_BasicTest)
{
QTemporaryDir dir;
QDir tempPath(dir.path());
QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath());
UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath);
tempPath = QDir(canonicalTempDirPath);
QString absoluteTestFilePath1 = tempPath.absoluteFilePath("basicfile.txt");
QString absoluteTestFilePath2 = tempPath.absoluteFilePath("basicfile2.txt");
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "contents"));
UnitTestUtils::SleepForMinimumFileSystemTime();
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath2, "contents2"));
AZStd::string fileEncoded1 = absoluteTestFilePath1.toUtf8().constData();
AZStd::string fileEncoded2 = absoluteTestFilePath2.toUtf8().constData();
// repeatedly hashing the same file should result in the same hash:
EXPECT_STREQ(AssetUtilities::GetFileFingerprint(fileEncoded1, "").c_str(), AssetUtilities::GetFileFingerprint(fileEncoded1, "").c_str());
EXPECT_STREQ(AssetUtilities::GetFileFingerprint(fileEncoded1, "Name").c_str(), AssetUtilities::GetFileFingerprint(fileEncoded1, "Name").c_str());
EXPECT_STREQ(AssetUtilities::GetFileFingerprint(fileEncoded2, "").c_str(), AssetUtilities::GetFileFingerprint(fileEncoded2, "").c_str());
EXPECT_STREQ(AssetUtilities::GetFileFingerprint(fileEncoded2, "Name").c_str(), AssetUtilities::GetFileFingerprint(fileEncoded2, "Name").c_str());
// mutating the 'name' should mutate the fingerprint:
EXPECT_STRNE(AssetUtilities::GetFileFingerprint(fileEncoded1, "").c_str(), AssetUtilities::GetFileFingerprint(fileEncoded1, "Name").c_str());
// two different files should not hash to the same fingerprint:
EXPECT_STRNE(AssetUtilities::GetFileFingerprint(fileEncoded1, "").c_str(), AssetUtilities::GetFileFingerprint(fileEncoded2, "").c_str());
UnitTestUtils::SleepForMinimumFileSystemTime();
AZStd::string oldFingerprint1 = AssetUtilities::GetFileFingerprint(fileEncoded1, "");
AZStd::string oldFingerprint2 = AssetUtilities::GetFileFingerprint(fileEncoded2, "");
AZStd::string oldFingerprint1a = AssetUtilities::GetFileFingerprint(fileEncoded1, "Name1");
AZStd::string oldFingerprint2a = AssetUtilities::GetFileFingerprint(fileEncoded2, "Name2");
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath1, "contents1a"));
EXPECT_TRUE(UnitTestUtils::CreateDummyFile(absoluteTestFilePath2, "contents2a"));
EXPECT_STRNE(oldFingerprint1.c_str(), AssetUtilities::GetFileFingerprint(fileEncoded1, "").c_str());
EXPECT_STRNE(oldFingerprint2.c_str(), AssetUtilities::GetFileFingerprint(fileEncoded2, "").c_str());
EXPECT_STRNE(oldFingerprint1a.c_str(), AssetUtilities::GetFileFingerprint(fileEncoded1, "Name1").c_str());
EXPECT_STRNE(oldFingerprint2a.c_str(), AssetUtilities::GetFileFingerprint(fileEncoded2, "Name2").c_str());
}
TEST_F(AssetUtilitiesTest, GetFileFingerprint_NonExistentFiles)
{
AZStd::string nonExistentFile1 = AZ::Uuid::CreateRandom().ToString<AZStd::string>() + ".txt";
ASSERT_FALSE(QFileInfo::exists(nonExistentFile1.c_str()));
EXPECT_STRNE(AssetUtilities::GetFileFingerprint(nonExistentFile1, "").c_str(), AssetUtilities::GetFileFingerprint(nonExistentFile1, "Name").c_str());
EXPECT_STREQ(AssetUtilities::GetFileFingerprint(nonExistentFile1, "Name").c_str(), AssetUtilities::GetFileFingerprint(nonExistentFile1, "Name").c_str());
}
TEST_F(AssetUtilitiesTest, GetServerAddress_ReadFromConfig_Valid)
{
QTemporaryDir tempDir;
QDir tempPath(tempDir.path());
QString assetServerAddress("T:/AssetServerCacheDummyFolder");
QString assetProcesorPlatformConfigPath = tempPath.absoluteFilePath("AssetProcessorPlatformConfig.ini");
UnitTestUtils::CreateDummyFile(assetProcesorPlatformConfigPath, QString("[Server]\ncacheServerAddress=%1\n").arg(assetServerAddress));
AssetUtilities::ResetAssetRoot();
QDir newRoot;
AssetUtilities::ComputeEngineRoot(newRoot, &tempPath);
auto settingsRegistry = AZ::SettingsRegistry::Get();
AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings;
configParserSettings.m_registryRootPointerPath = AssetProcessor::AssetProcessorSettingsKey;
AssetProcessor::PlatformConfiguration::MergeConfigFileToSettingsRegistry(*settingsRegistry,
assetProcesorPlatformConfigPath.toUtf8().data());
QString assetServerAddressReturned = AssetUtilities::ServerAddress();
EXPECT_STREQ(assetServerAddressReturned.toUtf8().data(), assetServerAddress.toUtf8().data());
}
TEST_F(AssetUtilitiesTest, CreateDirWithTimeout_Valid)
{
QTemporaryDir tempDir;
QDir tempPath(tempDir.path());
QDir dir(tempPath.filePath("folder"));
unsigned int timeToWaitInSecs = 3;
AZStd::vector<AZStd::thread*> threadList;
AZStd::vector<bool> resultList;
AZStd::mutex resultMutex;
auto runFunc = [&]()
{
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(100));// sleeping to sync all the threads
bool result = AssetUtilities::CreateDirectoryWithTimeout(dir, timeToWaitInSecs);
AZStd::lock_guard<AZStd::mutex> locker(resultMutex);
resultList.push_back(result);
};
int numberOfThreads = 5;
ASSERT_FALSE(dir.exists());
for (int idx = 0; idx < numberOfThreads; idx++)
{
AZStd::thread* workerThread = new AZStd::thread(runFunc);
threadList.emplace_back(workerThread);
}
for (auto thread : threadList)
{
if (thread->joinable())
{
thread->join();
}
delete thread;
}
for (int idx = 0; idx < numberOfThreads; idx++)
{
ASSERT_TRUE(resultList[idx]);
}
ASSERT_TRUE(dir.exists());
}
TEST_F(AssetUtilitiesTest, CreateDir_InvalidDir_Timeout_Valid)
{
QDir dir(":\folder");
unsigned int timeToWaitInSecs = 1;
AZStd::vector<AZStd::thread*> threadList;
AZStd::vector<bool> resultList;
AZStd::mutex resultMutex;
auto runFunc = [&]()
{
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(100));// sleeping to sync all the threads
bool result = AssetUtilities::CreateDirectoryWithTimeout(dir, timeToWaitInSecs);
AZStd::lock_guard<AZStd::mutex> locker(resultMutex);
resultList.push_back(result);
};
int numberOfThreads = 5;
ASSERT_FALSE(dir.exists());
for (int idx = 0; idx < numberOfThreads; idx++)
{
AZStd::thread* workerThread = new AZStd::thread(runFunc);
threadList.emplace_back(workerThread);
}
for (auto thread : threadList)
{
if (thread->joinable())
{
thread->join();
}
delete thread;
}
for (int idx = 0; idx < numberOfThreads; idx++)
{
ASSERT_FALSE(resultList[idx]);
}
ASSERT_FALSE(dir.exists());
}