PlatformAddressedAssetCatalogTests.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Settings/SettingsRegistryImpl.h>
  9. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  10. #include <AzCore/UnitTest/TestTypes.h>
  11. #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogManager.h>
  12. #include <AzFramework/Asset/AssetRegistry.h>
  13. #include <AzCore/Interface/Interface.h>
  14. #include <AzCore/IO/FileIO.h>
  15. #include <AzFramework/IO/LocalFileIO.h>
  16. #include <AZTestShared/Utils/Utils.h>
  17. #include <AzToolsFramework/UnitTest/ToolsTestApplication.h>
  18. #include <AzFramework/Platform/PlatformDefaults.h>
  19. #include <AzFramework/StringFunc/StringFunc.h>
  20. #include <AzTest/AzTest.h>
  21. #include <AzCore/UserSettings/UserSettingsComponent.h>
  22. namespace
  23. {
  24. static const int s_totalAssets = 12;
  25. }
  26. namespace UnitTest
  27. {
  28. class PlatformAddressedAssetCatalogManagerTest
  29. : public LeakDetectionFixture
  30. {
  31. public:
  32. void SetUp() override
  33. {
  34. using namespace AZ::Data;
  35. constexpr size_t MaxCommandArgsCount = 128;
  36. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  37. using ArgumentContainer = AZStd::fixed_vector<char*, MaxCommandArgsCount>;
  38. // The first command line argument is assumed to be the executable name so add a blank entry for it
  39. ArgumentContainer argContainer{ {} };
  40. // Append Command Line override for the Project Cache Path
  41. auto cacheProjectRootFolder = AZ::IO::Path{ m_tempDir.GetDirectory() } / "Cache";
  42. auto projectPathOverride = FixedValueString::format(R"(--project-path="%s")", m_tempDir.GetDirectory());
  43. argContainer.push_back(projectPathOverride.data());
  44. m_application = new ToolsTestApplication("AddressedAssetCatalogManager", aznumeric_caster(argContainer.size()), argContainer.data());
  45. AZ::ComponentApplication::StartupParameters startupParameters;
  46. startupParameters.m_loadSettingsRegistry = false;
  47. m_application->Start(AzFramework::Application::Descriptor(), startupParameters);
  48. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  49. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  50. // in the unit tests.
  51. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  52. // By default @products@ is setup to include the platform at the end. But this test is going to
  53. // loop over all platforms and it will be included as part of the relative path of the file.
  54. // So the asset folder for these tests have to point to the cache project root folder, which
  55. // doesn't include the platform.
  56. AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", cacheProjectRootFolder.c_str());
  57. for (int platformNum = AzFramework::PlatformId::PC; platformNum < AzFramework::PlatformId::NumPlatformIds; ++platformNum)
  58. {
  59. const AZStd::string platformName{ AzFramework::PlatformHelper::GetPlatformName(static_cast<AzFramework::PlatformId>(platformNum)) };
  60. if (!platformName.length())
  61. {
  62. // Do not test disabled platforms
  63. continue;
  64. }
  65. AZStd::unique_ptr<AzFramework::AssetRegistry> assetRegistry = AZStd::make_unique<AzFramework::AssetRegistry>();
  66. for (int idx = 0; idx < s_totalAssets; idx++)
  67. {
  68. m_assets[platformNum][idx] = AssetId(AZ::Uuid::CreateRandom(), 0);
  69. AZ::Data::AssetInfo info;
  70. info.m_relativePath = AZStd::move((AZ::IO::Path(platformName) / AZStd::string::format("Asset%d.txt", idx)).Native());
  71. info.m_assetId = m_assets[platformNum][idx];
  72. assetRegistry->RegisterAsset(m_assets[platformNum][idx], info);
  73. m_assetsPath[platformNum][idx] = AZStd::move((cacheProjectRootFolder / info.m_relativePath).Native());
  74. AZ_TEST_START_TRACE_SUPPRESSION;
  75. if (m_fileStreams[platformNum][idx].Open(m_assetsPath[platformNum][idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
  76. {
  77. AZ::IO::SizeType bytesWritten = m_fileStreams[platformNum][idx].Write(info.m_relativePath.size(), info.m_relativePath.data());
  78. EXPECT_EQ(bytesWritten, info.m_relativePath.size());
  79. m_fileStreams[platformNum][idx].Close();
  80. AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder
  81. }
  82. else
  83. {
  84. GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to create temporary file ( %s ) in PlatformAddressedAssetCatalogManagerTest unit tests.\n", m_assetsPath[platformNum][idx].c_str()).c_str());
  85. }
  86. }
  87. bool useRequestBus = false;
  88. AzFramework::AssetCatalog assetCatalog(useRequestBus);
  89. AZStd::string catalogPath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(static_cast<AzFramework::PlatformId>(platformNum));
  90. if (!assetCatalog.SaveCatalog(catalogPath.c_str(), assetRegistry.get()))
  91. {
  92. GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to save the asset catalog file.\n").c_str());
  93. }
  94. }
  95. m_PlatformAddressedAssetCatalogManager = new AzToolsFramework::PlatformAddressedAssetCatalogManager();
  96. }
  97. void TearDown() override
  98. {
  99. delete m_PlatformAddressedAssetCatalogManager;
  100. m_application->Stop();
  101. delete m_application;
  102. }
  103. AzToolsFramework::PlatformAddressedAssetCatalogManager* m_PlatformAddressedAssetCatalogManager = nullptr;
  104. ToolsTestApplication* m_application = nullptr;
  105. AZ::Test::ScopedAutoTempDirectory m_tempDir;
  106. AZ::IO::FileIOStream m_fileStreams[AzFramework::PlatformId::NumPlatformIds][s_totalAssets];
  107. AZ::Data::AssetId m_assets[AzFramework::PlatformId::NumPlatformIds][s_totalAssets];
  108. AZStd::string m_assetsPath[AzFramework::PlatformId::NumPlatformIds][s_totalAssets];
  109. };
  110. TEST_F(PlatformAddressedAssetCatalogManagerTest, PlatformAddressedAssetCatalogManager_AllCatalogsLoaded_Success)
  111. {
  112. for (int platformNum = AzFramework::PlatformId::PC; platformNum < AzFramework::PlatformId::NumPlatformIds; ++platformNum)
  113. {
  114. AZStd::string platformName{ AzFramework::PlatformHelper::GetPlatformName(static_cast<AzFramework::PlatformId>(platformNum)) };
  115. if (!platformName.length())
  116. {
  117. // Do not test disabled platforms
  118. continue;
  119. }
  120. for (int assetNum = 0; assetNum < s_totalAssets; ++assetNum)
  121. {
  122. AZ::Data::AssetInfo assetInfo;
  123. AzToolsFramework::AssetCatalog::PlatformAddressedAssetCatalogRequestBus::EventResult(assetInfo, static_cast<AzFramework::PlatformId>(platformNum), &AZ::Data::AssetCatalogRequests::GetAssetInfoById, m_assets[platformNum][assetNum]);
  124. EXPECT_EQ(m_assets[platformNum][assetNum], assetInfo.m_assetId);
  125. }
  126. }
  127. }
  128. TEST_F(PlatformAddressedAssetCatalogManagerTest, PlatformAddressedAssetCatalogManager_CatalogExistsChecks_Success)
  129. {
  130. EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ANDROID_ID), true);
  131. AZStd::string androidCatalogPath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID);
  132. if (AZ::IO::FileIOBase::GetInstance()->Exists(androidCatalogPath.c_str()))
  133. {
  134. AZ_TEST_START_TRACE_SUPPRESSION;
  135. AZ::IO::Result result = AZ::IO::FileIOBase::GetInstance()->Remove(androidCatalogPath.c_str());
  136. EXPECT_EQ(result.GetResultCode(), AZ::IO::ResultCode::Success);
  137. AZ_TEST_STOP_TRACE_SUPPRESSION(1); // removing from asset cache folder
  138. }
  139. EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ANDROID_ID), false);
  140. }
  141. class PlatformAddressedAssetCatalogMessageTest : public AzToolsFramework::PlatformAddressedAssetCatalog
  142. {
  143. public:
  144. AZ_CLASS_ALLOCATOR(PlatformAddressedAssetCatalogMessageTest, AZ::SystemAllocator)
  145. PlatformAddressedAssetCatalogMessageTest(AzFramework::PlatformId platformId) : AzToolsFramework::PlatformAddressedAssetCatalog(platformId)
  146. {
  147. }
  148. MOCK_METHOD2(AssetChanged, void(const AZStd::vector<AzFramework::AssetSystem::AssetNotificationMessage>& message, bool isCatalogInitialize));
  149. MOCK_METHOD1(AssetRemoved, void(const AZStd::vector<AzFramework::AssetSystem::AssetNotificationMessage>& message));
  150. };
  151. class PlatformAddressedAssetCatalogManagerMessageTest : public AzToolsFramework::PlatformAddressedAssetCatalogManager
  152. {
  153. public:
  154. PlatformAddressedAssetCatalogManagerMessageTest(AzFramework::PlatformId platformId) :
  155. AzToolsFramework::PlatformAddressedAssetCatalogManager(AzFramework::PlatformId::Invalid)
  156. {
  157. TakeSingleCatalog(AZStd::make_unique<PlatformAddressedAssetCatalogMessageTest>(platformId));
  158. }
  159. };
  160. class MessageTest
  161. : public LeakDetectionFixture
  162. {
  163. public:
  164. void SetUp() override
  165. {
  166. constexpr size_t MaxCommandArgsCount = 128;
  167. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  168. using ArgumentContainer = AZStd::fixed_vector<char*, MaxCommandArgsCount>;
  169. // The first command line argument is assumed to be the executable name so add a blank entry for it
  170. ArgumentContainer argContainer{ {} };
  171. // Append Command Line override for the Project Cache Path
  172. auto projectPathOverride = FixedValueString::format(R"(--project-path="%s")", m_tempDir.GetDirectory());
  173. argContainer.push_back(projectPathOverride.data());
  174. m_application = new ToolsTestApplication("MessageTest", aznumeric_caster(argContainer.size()), argContainer.data());
  175. m_platformAddressedAssetCatalogManager = AZStd::make_unique<AzToolsFramework::PlatformAddressedAssetCatalogManager>(AzFramework::PlatformId::Invalid);
  176. }
  177. void TearDown() override
  178. {
  179. m_platformAddressedAssetCatalogManager.reset();
  180. delete m_application;
  181. }
  182. ToolsTestApplication* m_application = nullptr;
  183. AZStd::unique_ptr<AzToolsFramework::PlatformAddressedAssetCatalogManager> m_platformAddressedAssetCatalogManager;
  184. AZ::Test::ScopedAutoTempDirectory m_tempDir;
  185. };
  186. TEST_F(MessageTest, PlatformAddressedAssetCatalogManagerMessageTest_MessagesForwarded_CountsMatch)
  187. {
  188. AzFramework::AssetSystem::AssetNotificationMessage testMessage;
  189. AzFramework::AssetSystem::NetworkAssetUpdateInterface* notificationInterface = AZ::Interface<AzFramework::AssetSystem::NetworkAssetUpdateInterface>::Get();
  190. EXPECT_NE(notificationInterface, nullptr);
  191. AZ_TEST_START_TRACE_SUPPRESSION;
  192. auto* mockCatalog = new ::testing::NiceMock<PlatformAddressedAssetCatalogMessageTest>(AzFramework::PlatformId::ANDROID_ID);
  193. AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Expected error not finding catalog
  194. AZStd::unique_ptr< ::testing::NiceMock<PlatformAddressedAssetCatalogMessageTest>> catalogHolder;
  195. catalogHolder.reset(mockCatalog);
  196. m_platformAddressedAssetCatalogManager->TakeSingleCatalog(AZStd::move(catalogHolder));
  197. EXPECT_CALL(*mockCatalog, AssetChanged(testing::_, false)).Times(0);
  198. notificationInterface->AssetChanged({ testMessage });
  199. testMessage.m_platform = "android";
  200. EXPECT_CALL(*mockCatalog, AssetChanged(testing::_, false)).Times(1);
  201. notificationInterface->AssetChanged({ testMessage });
  202. testMessage.m_platform = "pc";
  203. EXPECT_CALL(*mockCatalog, AssetChanged(testing::_, false)).Times(0);
  204. notificationInterface->AssetChanged({ testMessage });
  205. EXPECT_CALL(*mockCatalog, AssetRemoved(testing::_)).Times(0);
  206. notificationInterface->AssetRemoved({ testMessage });
  207. testMessage.m_platform = "android";
  208. EXPECT_CALL(*mockCatalog, AssetRemoved(testing::_)).Times(1);
  209. notificationInterface->AssetRemoved({ testMessage });
  210. }
  211. }