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.
358 lines
14 KiB
C++
358 lines
14 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AzTest/AzTest.h>
|
|
#include <AzCore/std/parallel/atomic.h>
|
|
#include <qcoreapplication.h>
|
|
#include "native/tests/AssetProcessorTest.h"
|
|
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
|
#include "native/assetprocessor.h"
|
|
#include "native/unittests/UnitTestRunner.h"
|
|
#include "native/AssetManager/assetProcessorManager.h"
|
|
#include "native/utilities/PlatformConfiguration.h"
|
|
#include "native/unittests/MockApplicationManager.h"
|
|
#include <AssetManager/FileStateCache.h>
|
|
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
|
|
|
#include <QTemporaryDir>
|
|
#include <QMetaObject>
|
|
#include <AzCore/Jobs/JobContext.h>
|
|
#include <AzCore/Jobs/JobManager.h>
|
|
#include <AzCore/UnitTest/TestTypes.h>
|
|
#include <AzToolsFramework/API/AssetDatabaseBus.h>
|
|
#include "resourcecompiler/rccontroller.h"
|
|
|
|
class AssetProcessorManager_Test;
|
|
|
|
class MockDatabaseLocationListener : public AzToolsFramework::AssetDatabase::AssetDatabaseRequests::Bus::Handler
|
|
{
|
|
public:
|
|
MOCK_METHOD1(GetAssetDatabaseLocation, bool(AZStd::string&));
|
|
};
|
|
|
|
class AssetProcessorManager_Test : public AssetProcessor::AssetProcessorManager
|
|
{
|
|
public:
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AssetProcessorManagerTest, AssetProcessedImpl_DifferentProductDependenciesPerProduct_SavesCorrectlyToDatabase);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies);
|
|
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_DeferredResolution);
|
|
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, SameFilenameForAllPlatforms);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, DeleteFolder_SignalsDeleteOfContainedFiles);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_BasicTest);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_WithDifferentTypes_BasicTest);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_Reverse_BasicTest);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_MissingFiles_ReturnsNoPathWithPlaceholders);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_BeforeComputingDirtiness_AllDirty);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_EmptyDatabase_AllDirty);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_SameAsLastTime_NoneDirty);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_MoreThanLastTime_NewOneIsDirty);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_FewerThanLastTime_Dirty);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_ChangedPattern_CountsAsNew);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_ChangedPatternType_CountsAsNew);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_NewPattern_CountsAsNewBuilder);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_NewVersionNumber_IsNotANewBuilder);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_NewAnalysisFingerprint_IsNotANewBuilder);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_BasicTest);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_UpdateTest);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_MissingFiles_ByUuid);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_MissingFiles_ByName);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_MissingFiles_ByUuid_UpdatesWhenTheyAppear);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_MissingFiles_ByName_UpdatesWhenTheyAppear);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_WildcardMissingFiles_ByName_UpdatesWhenTheyAppear);
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, JobDependencyOrderOnce_MultipleJobs_EmitOK);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, SourceFileProcessFailure_ClearsFingerprint);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AbsolutePathProductDependencyTest, UnresolvedProductPathDependency_AssetProcessedTwice_DoesNotDuplicateDependency);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AbsolutePathProductDependencyTest, AbsolutePathProductDependency_RetryDeferredDependenciesWithMatchingSource_DependencyResolves);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AbsolutePathProductDependencyTest, UnresolvedProductPathDependency_AssetProcessedTwice_ValidatePathDependenciesMap);
|
|
friend class GTEST_TEST_CLASS_NAME_(
|
|
AbsolutePathProductDependencyTest,
|
|
UnresolvedSourceFileTypeProductPathDependency_DependencyHasNoProductOutput_ValidatePathDependenciesMap);
|
|
|
|
friend class GTEST_TEST_CLASS_NAME_(DeleteTest, DeleteFolderSharedAcrossTwoScanFolders_CorrectFileAndFolderAreDeletedFromCache);
|
|
friend class GTEST_TEST_CLASS_NAME_(MetadataFileTest, MetadataFile_SourceFileExtensionDifferentCase);
|
|
|
|
friend class AssetProcessorManagerTest;
|
|
friend struct JobDependencyTest;
|
|
friend struct ChainJobDependencyTest;
|
|
friend struct DeleteTest;
|
|
friend struct PathDependencyTest;
|
|
friend struct DuplicateProductsTest;
|
|
friend struct DuplicateProcessTest;
|
|
friend struct AbsolutePathProductDependencyTest;
|
|
friend struct WildcardSourceDependencyTest;
|
|
|
|
explicit AssetProcessorManager_Test(AssetProcessor::PlatformConfiguration* config, QObject* parent = nullptr);
|
|
~AssetProcessorManager_Test() override;
|
|
|
|
bool CheckJobKeyToJobRunKeyMap(AZStd::string jobKey);
|
|
|
|
int CountDirtyBuilders() const
|
|
{
|
|
int numDirty = 0;
|
|
for (const auto& element : m_builderDataCache)
|
|
{
|
|
if (element.second.m_isDirty)
|
|
{
|
|
++numDirty;
|
|
}
|
|
}
|
|
return numDirty;
|
|
}
|
|
|
|
bool IsBuilderDirty(const AZ::Uuid& builderBusId) const
|
|
{
|
|
auto finder = m_builderDataCache.find(builderBusId);
|
|
if (finder == m_builderDataCache.end())
|
|
{
|
|
return true;
|
|
}
|
|
return finder->second.m_isDirty;
|
|
}
|
|
|
|
void RecomputeDirtyBuilders()
|
|
{
|
|
// Run this twice so the test builder doesn't get counted as a "new" builder and bypass the modtime skipping
|
|
ComputeBuilderDirty();
|
|
ComputeBuilderDirty();
|
|
}
|
|
|
|
using AssetProcessorManager::m_stateData;
|
|
using AssetProcessorManager::ComputeBuilderDirty;
|
|
};
|
|
|
|
|
|
class AssetProcessorManagerTest
|
|
: public AssetProcessor::AssetProcessorTest
|
|
{
|
|
public:
|
|
|
|
|
|
AssetProcessorManagerTest();
|
|
virtual ~AssetProcessorManagerTest()
|
|
{
|
|
}
|
|
|
|
// utility function. Blocks and runs the QT event pump for up to millisecondsMax and will break out as soon as the APM is idle.
|
|
bool BlockUntilIdle(int millisecondsMax);
|
|
|
|
protected:
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
QTemporaryDir m_tempDir;
|
|
|
|
AZStd::unique_ptr<AssetProcessorManager_Test> m_assetProcessorManager;
|
|
AZStd::unique_ptr<AssetProcessor::MockApplicationManager> m_mockApplicationManager;
|
|
AZStd::unique_ptr<AssetProcessor::PlatformConfiguration> m_config;
|
|
QString m_gameName;
|
|
QDir m_normalizedCacheRootDir;
|
|
AZStd::atomic_bool m_isIdling;
|
|
QMetaObject::Connection m_idleConnection;
|
|
|
|
struct StaticData
|
|
{
|
|
AZStd::string m_databaseLocation;
|
|
::testing::NiceMock<MockDatabaseLocationListener> m_databaseLocationListener;
|
|
AZ::Entity* m_jobManagerEntity{};
|
|
AZ::ComponentDescriptor* m_descriptor{};
|
|
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
|
};
|
|
|
|
AZStd::unique_ptr<StaticData> m_data;
|
|
|
|
private:
|
|
int m_argc;
|
|
char** m_argv;
|
|
AZStd::unique_ptr<UnitTestUtils::ScopedDir> m_scopeDir;
|
|
|
|
AZStd::unique_ptr<QCoreApplication> m_qApp;
|
|
};
|
|
|
|
struct AbsolutePathProductDependencyTest
|
|
: public AssetProcessorManagerTest
|
|
{
|
|
void SetUp() override;
|
|
|
|
AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry SetAndReadAbsolutePathProductDependencyFromRelativePath(
|
|
const AZStd::string& relativePath);
|
|
|
|
AZStd::string BuildScanFolderRelativePath(const AZStd::string& relativePath) const;
|
|
|
|
AzToolsFramework::AssetDatabase::ProductDatabaseEntry m_productToHaveDependency;
|
|
const AssetProcessor::ScanFolderInfo* m_scanFolderInfo = nullptr;
|
|
AZStd::string m_testPlatform = "SomePlatform";
|
|
};
|
|
|
|
struct PathDependencyTest
|
|
: public AssetProcessorManagerTest
|
|
{
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
using OutputAssetSet = AZStd::vector<AZStd::vector<const char*>>;
|
|
|
|
struct TestAsset
|
|
{
|
|
TestAsset() = default;
|
|
TestAsset(const char* name) : m_name(name) {}
|
|
|
|
AZStd::string m_name;
|
|
AZStd::vector<AZ::Data::AssetId> m_products;
|
|
};
|
|
|
|
void CaptureJobs(AZStd::vector<AssetProcessor::JobDetails>& jobDetails, const char* sourceFilePath);
|
|
bool ProcessAsset(TestAsset& asset, const OutputAssetSet& outputAssets, const AssetBuilderSDK::ProductPathDependencySet& dependencies = {}, const AZStd::string& folderPath = "subfolder1/", const AZStd::string& extension = ".txt");
|
|
|
|
void RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst);
|
|
AssetProcessor::AssetDatabaseConnection* m_sharedConnection{};
|
|
};
|
|
|
|
struct DuplicateProcessTest
|
|
: public PathDependencyTest
|
|
{
|
|
void SetUp() override;
|
|
};
|
|
|
|
struct MultiplatformPathDependencyTest
|
|
: public PathDependencyTest
|
|
{
|
|
void SetUp() override;
|
|
};
|
|
|
|
struct WildcardSourceDependencyTest
|
|
: AssetProcessorManagerTest
|
|
{
|
|
bool Test(const AZStd::string& dependencyPath, AZStd::vector<AZStd::string>& resolvedPaths);
|
|
AZStd::vector<AZStd::string> FileAddedTest(const QString& path);
|
|
|
|
void SetUp() override;
|
|
};
|
|
|
|
struct MockBuilderInfoHandler
|
|
: public AssetProcessor::AssetBuilderInfoBus::Handler
|
|
{
|
|
~MockBuilderInfoHandler();
|
|
|
|
//! AssetProcessor::AssetBuilderInfoBus Interface
|
|
void GetMatchingBuildersInfo(const AZStd::string& assetPath, AssetProcessor::BuilderInfoList& builderInfoList) override;
|
|
void GetAllBuildersInfo(AssetProcessor::BuilderInfoList& builderInfoList) override;
|
|
|
|
void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response);
|
|
void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response);
|
|
|
|
AssetBuilderSDK::AssetBuilderDesc CreateBuilderDesc(const QString& builderName, const QString& builderId, const AZStd::vector<AssetBuilderSDK::AssetBuilderPattern>& builderPatterns);
|
|
|
|
AssetBuilderSDK::AssetBuilderDesc m_builderDesc;
|
|
QString m_jobFingerprint;
|
|
QString m_dependencyFilePath;
|
|
QString m_jobDependencyFilePath;
|
|
int m_createJobsCount = 0;
|
|
};
|
|
|
|
|
|
struct MetadataFileTest
|
|
: public AssetProcessorManagerTest
|
|
{
|
|
void SetUp() override;
|
|
};
|
|
|
|
struct FingerprintTest
|
|
: public AssetProcessorManagerTest
|
|
{
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
void RunFingerprintTest(QString builderFingerprint, QString jobFingerprint, bool expectedResult);
|
|
|
|
QString m_absolutePath;
|
|
MockBuilderInfoHandler m_mockBuilderInfoHandler;
|
|
AZStd::vector<AssetProcessor::JobDetails> m_jobResults;
|
|
};
|
|
|
|
struct JobDependencyTest
|
|
: public PathDependencyTest
|
|
{
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
struct StaticData
|
|
{
|
|
MockBuilderInfoHandler m_mockBuilderInfoHandler;
|
|
AZ::Uuid m_builderUuid;
|
|
};
|
|
|
|
AZStd::unique_ptr<StaticData> m_data;
|
|
};
|
|
|
|
struct MockMultiBuilderInfoHandler
|
|
: public AssetProcessor::AssetBuilderInfoBus::Handler
|
|
{
|
|
~MockMultiBuilderInfoHandler();
|
|
|
|
struct AssetBuilderExtraInfo
|
|
{
|
|
QString m_jobDependencyFilePath;
|
|
};
|
|
|
|
//! AssetProcessor::AssetBuilderInfoBus Interface
|
|
void GetMatchingBuildersInfo(const AZStd::string& assetPath, AssetProcessor::BuilderInfoList& builderInfoList) override;
|
|
void GetAllBuildersInfo(AssetProcessor::BuilderInfoList& builderInfoList) override;
|
|
|
|
void CreateJobs(AssetBuilderExtraInfo extraInfo, const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response);
|
|
void ProcessJob(AssetBuilderExtraInfo extraInfo, const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response);
|
|
|
|
void CreateBuilderDesc(const QString& builderName, const QString& builderId, const AZStd::vector<AssetBuilderSDK::AssetBuilderPattern>& builderPatterns, AssetBuilderExtraInfo extraInfo);
|
|
|
|
AZStd::vector<AssetBuilderSDK::AssetBuilderDesc> m_builderDesc;
|
|
AZStd::vector<AssetUtilities::BuilderFilePatternMatcher> m_matcherBuilderPatterns;
|
|
AZStd::unordered_map<AZ::Uuid, AssetBuilderSDK::AssetBuilderDesc> m_builderDescMap;
|
|
|
|
int m_createJobsCount = 0;
|
|
};
|
|
|
|
struct ChainJobDependencyTest
|
|
: public PathDependencyTest
|
|
{
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
struct StaticData
|
|
{
|
|
MockMultiBuilderInfoHandler m_mockBuilderInfoHandler;
|
|
AZStd::unique_ptr<AssetProcessor::RCController> m_rcController;
|
|
};
|
|
|
|
static constexpr int ChainLength = 10;
|
|
AZStd::unique_ptr<StaticData> m_data;
|
|
};
|
|
|
|
struct DuplicateProductsTest
|
|
: public AssetProcessorManagerTest
|
|
{
|
|
void SetupDuplicateProductsTest(QString& sourceFile, QDir& tempPath, QString& productFile, AZStd::vector<AssetProcessor::JobDetails>& jobDetails, AssetBuilderSDK::ProcessJobResponse& response, bool multipleOutputs, QString extension);
|
|
};
|