AssetCatalog.cpp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  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 <FileIOBaseTestTypes.h>
  9. #include <AzCore/Asset/AssetManagerBus.h>
  10. #include <AzCore/Asset/AssetTypeInfoBus.h>
  11. #include <AzCore/Component/TickBus.h>
  12. #include <AzCore/Interface/Interface.h>
  13. #include <AzCore/IO/Streamer/Streamer.h>
  14. #include <AzCore/IO/Streamer/StreamerComponent.h>
  15. #include <AzCore/Jobs/JobFunction.h>
  16. #include <AzCore/Jobs/JobManager.h>
  17. #include <AzCore/Jobs/JobContext.h>
  18. #include <AzCore/Math/Uuid.h>
  19. #include <AzCore/Memory/Memory.h>
  20. #include <AzCore/Memory/PoolAllocator.h>
  21. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  22. #include <AzCore/std/containers/vector.h>
  23. #include <AzCore/std/parallel/binary_semaphore.h>
  24. #include <AzCore/Task/TaskExecutor.h>
  25. #include <AzCore/UnitTest/TestTypes.h>
  26. #include <AzCore/UserSettings/UserSettingsComponent.h>
  27. #include <AzFramework/Asset/AssetCatalog.h>
  28. #include <AzFramework/Asset/AssetProcessorMessages.h>
  29. #include <AzFramework/Asset/GenericAssetHandler.h>
  30. #include <AzFramework/Asset/NetworkAssetNotification_private.h>
  31. #include <AzFramework/Application/Application.h>
  32. namespace UnitTest
  33. {
  34. namespace
  35. {
  36. AZ::Data::AssetId asset1;
  37. AZ::Data::AssetId asset2;
  38. AZ::Data::AssetId asset3;
  39. AZ::Data::AssetId asset4;
  40. AZ::Data::AssetId asset5;
  41. bool Search(const AZStd::vector<AZ::Data::ProductDependency>& dependencies, const AZ::Data::AssetId& assetId)
  42. {
  43. for (const auto& dependency : dependencies)
  44. {
  45. if (dependency.m_assetId == assetId)
  46. {
  47. return true;
  48. }
  49. }
  50. return false;
  51. }
  52. }
  53. class AssetCatalogDependencyTest
  54. : public LeakDetectionFixture
  55. {
  56. AzFramework::AssetCatalog* m_assetCatalog;
  57. public:
  58. const char* path1 = "SomeFolder/Asset1Path";
  59. const char* path2 = "SomeFolder/Asset2Path";
  60. const char* path3 = "OtherFolder/Asset3Path";
  61. const char* path4 = "OtherFolder/Asset4Path";
  62. const char* path5 = "OtherFolder/Asset5Path";
  63. void SetUp() override
  64. {
  65. AZ::Data::AssetManager::Descriptor desc;
  66. AZ::Data::AssetManager::Create(desc);
  67. m_assetCatalog = aznew AzFramework::AssetCatalog();
  68. m_assetCatalog->StartMonitoringAssets();
  69. AzFramework::AssetSystem::NetworkAssetUpdateInterface* notificationInterface = AZ::Interface<AzFramework::AssetSystem::NetworkAssetUpdateInterface>::Get();
  70. ASSERT_NE(notificationInterface, nullptr);
  71. asset1 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  72. asset2 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  73. asset3 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  74. asset4 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  75. asset5 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  76. AZ::Data::AssetInfo info1, info2, info3, info4, info5;
  77. info1.m_relativePath = path1;
  78. info1.m_sizeBytes = 1; // Need to initialize m_sizeBytes to non-zero number to avoid a FileIO call
  79. info2.m_relativePath = path2;
  80. info2.m_sizeBytes = 1;
  81. info3.m_relativePath = path3;
  82. info3.m_sizeBytes = 1;
  83. info4.m_relativePath = path4;
  84. info4.m_sizeBytes = 1;
  85. info5.m_relativePath = path5;
  86. info5.m_sizeBytes = 1;
  87. // asset1 -> asset2 -> asset3 -> asset5
  88. // --> asset4
  89. {
  90. m_assetCatalog->RegisterAsset(asset1, info1);
  91. AzFramework::AssetSystem::AssetNotificationMessage message("test", AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  92. message.m_assetId = asset1;
  93. message.m_dependencies.emplace_back(asset2, 0);
  94. notificationInterface->AssetChanged({ message });
  95. }
  96. {
  97. m_assetCatalog->RegisterAsset(asset2, info2);
  98. AzFramework::AssetSystem::AssetNotificationMessage message("test", AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  99. message.m_assetId = asset2;
  100. message.m_dependencies.emplace_back(asset3, 0);
  101. message.m_dependencies.emplace_back(asset4, 0);
  102. notificationInterface->AssetChanged({ message });
  103. }
  104. {
  105. m_assetCatalog->RegisterAsset(asset3, info3);
  106. AzFramework::AssetSystem::AssetNotificationMessage message("test", AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  107. message.m_assetId = asset3;
  108. message.m_dependencies.emplace_back(asset5, 0);
  109. notificationInterface->AssetChanged({ message });
  110. }
  111. {
  112. m_assetCatalog->RegisterAsset(asset4, info4);
  113. AzFramework::AssetSystem::AssetNotificationMessage message("test", AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  114. message.m_assetId = asset4;
  115. notificationInterface->AssetChanged({ message });
  116. }
  117. {
  118. m_assetCatalog->RegisterAsset(asset5, info5);
  119. AzFramework::AssetSystem::AssetNotificationMessage message("test", AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  120. message.m_assetId = asset5;
  121. notificationInterface->AssetChanged({ message });
  122. }
  123. }
  124. void TearDown() override
  125. {
  126. delete m_assetCatalog;
  127. AzFramework::LegacyAssetEventBus::ClearQueuedEvents();
  128. AZ::TickBus::ClearQueuedEvents();
  129. AZ::Data::AssetManager::Destroy();
  130. }
  131. void CheckDirectDependencies(AZ::Data::AssetId assetId, AZStd::initializer_list<AZ::Data::AssetId> expectedDependencies)
  132. {
  133. AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result = AZ::Failure<AZStd::string>("No response");
  134. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, assetId);
  135. EXPECT_TRUE(result.IsSuccess());
  136. auto& actualDependencies = result.GetValue();
  137. EXPECT_TRUE(actualDependencies.size() == actualDependencies.size());
  138. for (const auto& dependency : expectedDependencies)
  139. {
  140. EXPECT_TRUE(Search(actualDependencies, dependency));
  141. }
  142. }
  143. void CheckAllDependencies(AZ::Data::AssetId assetId, AZStd::initializer_list<AZ::Data::AssetId> expectedDependencies)
  144. {
  145. AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result = AZ::Failure<AZStd::string>("No response");
  146. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::GetAllProductDependencies, assetId);
  147. EXPECT_TRUE(result.IsSuccess());
  148. auto& actualDependencies = result.GetValue();
  149. EXPECT_TRUE(actualDependencies.size() == actualDependencies.size());
  150. for (const auto& dependency : expectedDependencies)
  151. {
  152. EXPECT_TRUE(Search(actualDependencies, dependency));
  153. }
  154. }
  155. void CheckAllDependenciesFilter(AZ::Data::AssetId assetId, const AZStd::unordered_set<AZ::Data::AssetId>& filterSet, const AZStd::vector<AZStd::string>& wildcardList, AZStd::initializer_list<AZ::Data::AssetId> expectedDependencies)
  156. {
  157. AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result = AZ::Failure<AZStd::string>("No response");
  158. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::GetAllProductDependenciesFilter, assetId, filterSet, wildcardList);
  159. EXPECT_TRUE(result.IsSuccess());
  160. auto& actualDependencies = result.GetValue();
  161. EXPECT_TRUE(actualDependencies.size() == actualDependencies.size());
  162. for (const auto& dependency : expectedDependencies)
  163. {
  164. EXPECT_TRUE(Search(actualDependencies, dependency));
  165. }
  166. }
  167. };
  168. TEST_F(AssetCatalogDependencyTest, directDependencies)
  169. {
  170. CheckDirectDependencies(asset1, { asset2 });
  171. CheckDirectDependencies(asset2, { asset3, asset4 });
  172. CheckDirectDependencies(asset3, { asset5 });
  173. CheckDirectDependencies(asset4, { });
  174. CheckDirectDependencies(asset5, { });
  175. }
  176. TEST_F(AssetCatalogDependencyTest, allDependencies)
  177. {
  178. CheckAllDependencies(asset1, { asset2, asset3, asset4, asset5 });
  179. CheckAllDependencies(asset2, { asset3, asset4, asset5 });
  180. CheckAllDependencies(asset3, { asset5 });
  181. CheckAllDependencies(asset4, {});
  182. CheckAllDependencies(asset5, {});
  183. }
  184. TEST_F(AssetCatalogDependencyTest, allDependenciesFilter_AssetIdFilter)
  185. {
  186. CheckAllDependenciesFilter(asset1, { asset2 }, { }, { });
  187. CheckAllDependenciesFilter(asset1, { asset3 }, { }, { asset2 });
  188. CheckAllDependenciesFilter(asset1, { asset5 }, { }, { asset2, asset3, asset4 });
  189. CheckAllDependenciesFilter(asset1, { asset4, asset5 }, { }, { asset2, asset3 });
  190. }
  191. TEST_F(AssetCatalogDependencyTest, allDependenciesFilter_WildcardFilter)
  192. {
  193. CheckAllDependenciesFilter(asset1, { }, { "*/*" }, { });
  194. CheckAllDependenciesFilter(asset1, { }, { "*/Asset?Path" }, {});
  195. CheckAllDependenciesFilter(asset1, { }, { "other*" }, { asset2 });
  196. CheckAllDependenciesFilter(asset1, { }, { "*4*" }, { asset2, asset3, asset5 });
  197. CheckAllDependenciesFilter(asset1, { }, { "*4*", "*5*" }, { asset2, asset3 });
  198. }
  199. TEST_F(AssetCatalogDependencyTest, allDependenciesFilter_AssetIdAndWildcardFilter)
  200. {
  201. CheckAllDependenciesFilter(asset1, { asset5 }, { "*4*" }, { asset2, asset3 });
  202. }
  203. TEST_F(AssetCatalogDependencyTest, unregisterTest)
  204. {
  205. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset4);
  206. CheckDirectDependencies(asset2, { asset3 });
  207. CheckAllDependencies(asset1, { asset2, asset3, asset5 });
  208. }
  209. class AssetCatalogDeltaTest :
  210. public LeakDetectionFixture
  211. {
  212. public:
  213. const char* path1 = "Asset1Path";
  214. const char* path2 = "Asset2Path";
  215. const char* path3 = "Asset3Path";
  216. const char* path4 = "Asset4Path";
  217. const char* path5 = "Asset5Path";
  218. const char* path6 = "Asset6Path";
  219. AZ::IO::FixedMaxPath sourceCatalogPath1;
  220. AZ::IO::FixedMaxPath sourceCatalogPath2;
  221. AZ::IO::FixedMaxPath sourceCatalogPath3;
  222. AZ::IO::FixedMaxPath baseCatalogPath;
  223. AZ::IO::FixedMaxPath deltaCatalogPath;
  224. AZ::IO::FixedMaxPath deltaCatalogPath2;
  225. AZ::IO::FixedMaxPath deltaCatalogPath3;
  226. AZStd::vector<AZStd::string> deltaCatalogFiles;
  227. AZStd::vector<AZStd::string> deltaCatalogFiles2;
  228. AZStd::vector<AZStd::string> deltaCatalogFiles3;
  229. AZStd::shared_ptr<AzFramework::AssetRegistry> baseCatalog;
  230. AZStd::shared_ptr<AzFramework::AssetRegistry> deltaCatalog;
  231. AZStd::shared_ptr<AzFramework::AssetRegistry> deltaCatalog2;
  232. AZStd::shared_ptr<AzFramework::AssetRegistry> deltaCatalog3;
  233. AZStd::unique_ptr<AzFramework::Application> m_app;
  234. AZ::Test::ScopedAutoTempDirectory m_tempDirectory;
  235. void SetUp() override
  236. {
  237. m_app.reset(aznew AzFramework::Application());
  238. AZ::ComponentApplication::Descriptor desc;
  239. desc.m_useExistingAllocator = true;
  240. AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
  241. auto projectPathKey =
  242. AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
  243. AZ::IO::FixedMaxPath enginePath;
  244. registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
  245. registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
  246. AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
  247. AZ::ComponentApplication::StartupParameters startupParameters;
  248. startupParameters.m_loadAssetCatalog = false;
  249. startupParameters.m_loadSettingsRegistry = false;
  250. m_app->Start(desc, startupParameters);
  251. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  252. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  253. // in the unit tests.
  254. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  255. asset1 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  256. asset2 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  257. asset3 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  258. asset4 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  259. asset5 = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  260. sourceCatalogPath1 = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogSource1.xml";
  261. sourceCatalogPath2 = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogSource2.xml";
  262. sourceCatalogPath3 = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogSource3.xml";
  263. baseCatalogPath = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogBase.xml";
  264. deltaCatalogPath = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogDelta.xml";
  265. deltaCatalogPath2 = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogDelta2.xml";
  266. deltaCatalogPath3 = m_tempDirectory.GetDirectoryAsPath() / "AssetCatalogDelta3.xml";
  267. AZ::Data::AssetInfo info1, info2, info3, info4, info5, info6;
  268. info1.m_relativePath = path1;
  269. info2.m_relativePath = path2;
  270. info3.m_relativePath = path3;
  271. info4.m_relativePath = path4;
  272. info5.m_relativePath = path5;
  273. info6.m_relativePath = path6;
  274. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset1, info1);
  275. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset2, info2);
  276. // baseCatalog - asset1 path1, asset2 path2
  277. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, baseCatalogPath.c_str());
  278. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset1, info3);
  279. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset4, info4);
  280. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StartMonitoringAssets);
  281. AzFramework::AssetSystem::NetworkAssetUpdateInterface* notificationInterface = AZ::Interface<AzFramework::AssetSystem::NetworkAssetUpdateInterface>::Get();
  282. ASSERT_NE(notificationInterface, nullptr);
  283. {
  284. AzFramework::AssetSystem::AssetNotificationMessage message(path3, AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  285. message.m_assetId = asset1;
  286. message.m_dependencies.push_back(AZ::Data::ProductDependency(asset2, 0));
  287. notificationInterface->AssetChanged({ message });
  288. }
  289. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StopMonitoringAssets);
  290. // sourcecatalog1 - asset1 path3 (depends on asset 2), asset2 path2, asset4 path4
  291. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, sourceCatalogPath1.c_str());
  292. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset2);
  293. // deltacatalog - asset1 path3 (depends on asset 2), asset4 path4
  294. deltaCatalogFiles.push_back(path3);
  295. deltaCatalogFiles.push_back(path4);
  296. // deltacatalog - asset1 path3, asset4 path4
  297. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, deltaCatalogPath.c_str());
  298. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset2, info2);
  299. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset5, info5);
  300. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StartMonitoringAssets);
  301. {
  302. AzFramework::AssetSystem::AssetNotificationMessage message(path5, AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  303. message.m_assetId = asset5;
  304. message.m_dependencies.push_back(AZ::Data::ProductDependency(asset2, 0));
  305. notificationInterface->AssetChanged({ message });
  306. }
  307. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StopMonitoringAssets);
  308. // sourcecatalog2 - asset1 path3 (depends on asset 2), asset2 path2, asset4 path4, asset5 path5 (depends on asset 2)
  309. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, sourceCatalogPath2.c_str());
  310. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset1);
  311. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset2);
  312. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset4);
  313. // deltacatalog2 - asset5 path5 (depends on asset 2)
  314. deltaCatalogFiles2.push_back(path5);
  315. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, deltaCatalogPath2.c_str());
  316. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset1, info6);
  317. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset2, info2);
  318. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, asset5, info4);
  319. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StartMonitoringAssets);
  320. {
  321. AzFramework::AssetSystem::AssetNotificationMessage message(path4, AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  322. message.m_assetId = asset5;
  323. message.m_dependencies.push_back(AZ::Data::ProductDependency(asset2, 0));
  324. notificationInterface->AssetChanged({ message });
  325. }
  326. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StopMonitoringAssets);
  327. //sourcecatalog3 - asset1 path6, asset2 path2, asset5 path4 (depends on asset 2)
  328. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, sourceCatalogPath3.c_str());
  329. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset2);
  330. // deltacatalog3 - asset1 path6 asset5 path4 (depends on asset 2)
  331. deltaCatalogFiles3.push_back(path6);
  332. deltaCatalogFiles3.push_back(path4);
  333. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::SaveCatalog, deltaCatalogPath3.c_str());
  334. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset1);
  335. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset5);
  336. baseCatalog = AzFramework::AssetCatalog::LoadCatalogFromFile(baseCatalogPath.c_str());
  337. deltaCatalog = AzFramework::AssetCatalog::LoadCatalogFromFile(deltaCatalogPath.c_str());
  338. deltaCatalog2 = AzFramework::AssetCatalog::LoadCatalogFromFile(deltaCatalogPath2.c_str());
  339. deltaCatalog3 = AzFramework::AssetCatalog::LoadCatalogFromFile(deltaCatalogPath3.c_str());
  340. }
  341. void TearDown() override
  342. {
  343. deltaCatalogFiles.set_capacity(0);
  344. deltaCatalogFiles2.set_capacity(0);
  345. deltaCatalogFiles3.set_capacity(0);
  346. baseCatalog.reset();
  347. deltaCatalog.reset();
  348. deltaCatalog2.reset();
  349. deltaCatalog3.reset();
  350. m_app->Stop();
  351. m_app.reset();
  352. AZ::AllocatorInstance<AZ::SystemAllocator>::Get().GarbageCollect();
  353. }
  354. void CheckDirectDependencies(AZ::Data::AssetId assetId, AZStd::initializer_list<AZ::Data::AssetId> expectedDependencies)
  355. {
  356. AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result = AZ::Failure<AZStd::string>("No response");
  357. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, assetId);
  358. EXPECT_TRUE(result.IsSuccess());
  359. auto& actualDependencies = result.GetValue();
  360. EXPECT_TRUE(actualDependencies.size() == actualDependencies.size());
  361. for (const auto& dependency : expectedDependencies)
  362. {
  363. EXPECT_TRUE(Search(actualDependencies, dependency));
  364. }
  365. }
  366. void CheckNoDependencies(AZ::Data::AssetId assetId)
  367. {
  368. AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result = AZ::Failure<AZStd::string>("No response");
  369. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, assetId);
  370. EXPECT_FALSE(result.IsSuccess());
  371. }
  372. };
  373. TEST_F(AssetCatalogDeltaTest, LoadCatalog_AssetChangedCatalogLoaded_AssetStillKnown)
  374. {
  375. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::StartMonitoringAssets);
  376. auto updatedAsset = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0);
  377. AzFramework::AssetSystem::NetworkAssetUpdateInterface* notificationInterface = AZ::Interface<AzFramework::AssetSystem::NetworkAssetUpdateInterface>::Get();
  378. ASSERT_NE(notificationInterface, nullptr);
  379. {
  380. AzFramework::AssetSystem::AssetNotificationMessage message("test", AzFramework::AssetSystem::AssetNotificationMessage::AssetChanged, AZ::Uuid::CreateRandom(), "");
  381. message.m_assetId = updatedAsset;
  382. message.m_dependencies.emplace_back(asset2, 0);
  383. notificationInterface->AssetChanged({ message });
  384. }
  385. AZ::Data::AssetInfo assetInfo;
  386. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, updatedAsset);
  387. EXPECT_TRUE(assetInfo.m_assetId.IsValid());
  388. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, baseCatalogPath.c_str());
  389. //Asset should still be known - the catalog should swap in the new catalog from disk
  390. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, updatedAsset);
  391. EXPECT_TRUE(assetInfo.m_assetId.IsValid());
  392. }
  393. TEST_F(AssetCatalogDeltaTest, DeltaCatalogTest)
  394. {
  395. AZStd::string assetPath;
  396. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  397. EXPECT_EQ(assetPath, "");
  398. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  399. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, baseCatalogPath.c_str());
  400. // Topmost should have precedence
  401. // baseCatalog path1 path2
  402. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  403. EXPECT_EQ(assetPath, path1);
  404. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  405. EXPECT_EQ(assetPath, path2);
  406. CheckNoDependencies(asset1);
  407. CheckNoDependencies(asset2);
  408. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, deltaCatalog);
  409. // deltacatalog path3 path4
  410. /// baseCatalog path1 path2
  411. /// asset1 asset2 asset3 asset4 asset5
  412. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  413. EXPECT_EQ(assetPath, path3);
  414. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  415. EXPECT_EQ(assetPath, path2);
  416. CheckDirectDependencies(asset1, { asset2 });
  417. CheckNoDependencies(asset2);
  418. CheckNoDependencies(asset4);
  419. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, deltaCatalog2);
  420. // deltacatalog2 path5
  421. // deltacatalog path3 path4
  422. /// baseCatalog path1 path2
  423. /// asset1 asset2 asset3 asset4 asset5
  424. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  425. EXPECT_EQ(assetPath, path3);
  426. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  427. EXPECT_EQ(assetPath, path2);
  428. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  429. EXPECT_EQ(assetPath, path5);
  430. CheckDirectDependencies(asset1, { asset2 });
  431. CheckNoDependencies(asset2);
  432. CheckNoDependencies(asset4);
  433. CheckDirectDependencies(asset5, { asset2 });
  434. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RemoveDeltaCatalog, deltaCatalog);
  435. // deltacatalog2 path5
  436. /// baseCatalog path1 path2
  437. /// asset1 asset2 asset3 asset4 asset5
  438. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  439. EXPECT_EQ(assetPath, path1);
  440. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset3);
  441. EXPECT_EQ(assetPath, "");
  442. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  443. EXPECT_EQ(assetPath, path2);
  444. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  445. EXPECT_EQ(assetPath, path5);
  446. CheckNoDependencies(asset1);
  447. CheckNoDependencies(asset2);
  448. CheckDirectDependencies(asset5, { asset2 });
  449. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, deltaCatalog);
  450. // deltacatalog path3 path4
  451. // deltacatalog2 path5
  452. /// baseCatalog path1 path2
  453. /// asset1 asset2 asset3 asset4 asset5
  454. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  455. EXPECT_EQ(assetPath, path3);
  456. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  457. EXPECT_EQ(assetPath, path2);
  458. CheckDirectDependencies(asset1, { asset2 });
  459. CheckNoDependencies(asset2);
  460. CheckNoDependencies(asset4);
  461. CheckDirectDependencies(asset5, { asset2 });
  462. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::InsertDeltaCatalog, deltaCatalog3, 0);
  463. // deltacatalog path3 path4
  464. // deltacatalog2 path5
  465. // deltacatalog3 path6 path4
  466. /// baseCatalog path1 path2
  467. /// asset1 asset2 asset3 asset4 asset5
  468. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  469. EXPECT_EQ(assetPath, path3);
  470. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  471. EXPECT_EQ(assetPath, path5);
  472. CheckDirectDependencies(asset1, { asset2 });
  473. CheckNoDependencies(asset2);
  474. CheckNoDependencies(asset4);
  475. CheckDirectDependencies(asset5, { asset2 });
  476. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RemoveDeltaCatalog, deltaCatalog3);
  477. // deltacatalog path3 path4
  478. // deltacatalog2 path5
  479. /// baseCatalog path1 path2
  480. /// asset1 asset2 asset3 asset4 asset5
  481. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  482. EXPECT_EQ(assetPath, path3);
  483. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  484. EXPECT_EQ(assetPath, path5);
  485. CheckDirectDependencies(asset1, { asset2 });
  486. CheckNoDependencies(asset2);
  487. CheckNoDependencies(asset4);
  488. CheckDirectDependencies(asset5, { asset2 });
  489. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::InsertDeltaCatalog, deltaCatalog3, 1);
  490. // deltacatalog path3 path4
  491. // deltacatalog3 path6 path4
  492. // deltacatalog2 path5
  493. /// baseCatalog path1 path2
  494. /// asset1 asset2 asset3 asset4 asset5
  495. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  496. EXPECT_EQ(assetPath, path3);
  497. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  498. EXPECT_EQ(assetPath, path4);
  499. CheckDirectDependencies(asset1, { asset2 });
  500. CheckNoDependencies(asset2);
  501. CheckNoDependencies(asset4);
  502. CheckDirectDependencies(asset5, { asset2 });
  503. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RemoveDeltaCatalog, baseCatalog);
  504. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::InsertDeltaCatalog, baseCatalog, 3);
  505. /// baseCatalog path1 path2
  506. // deltacatalog path3 path4
  507. // deltacatalog3 path6 path4
  508. // deltacatalog2 path5
  509. /// asset1 asset2 asset3 asset4 asset5
  510. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  511. EXPECT_EQ(assetPath, path1);
  512. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  513. EXPECT_EQ(assetPath, path2);
  514. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset3);
  515. EXPECT_EQ(assetPath, "");
  516. CheckNoDependencies(asset1);
  517. CheckNoDependencies(asset2);
  518. CheckNoDependencies(asset4);
  519. CheckDirectDependencies(asset5, { asset2 });
  520. }
  521. TEST_F(AssetCatalogDeltaTest, DeltaCatalogTest_AddDeltaCatalogNext_Success)
  522. {
  523. AZStd::string assetPath;
  524. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  525. EXPECT_EQ(assetPath, "");
  526. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  527. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, baseCatalogPath.c_str());
  528. // Topmost should have precedence
  529. // baseCatalog path1 path2
  530. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  531. EXPECT_EQ(assetPath, path1);
  532. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  533. EXPECT_EQ(assetPath, path2);
  534. CheckNoDependencies(asset1);
  535. CheckNoDependencies(asset2);
  536. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, deltaCatalog);
  537. // deltacatalog path3 path4
  538. /// baseCatalog path1 path2
  539. /// asset1 asset2 asset3 asset4 asset5
  540. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  541. EXPECT_EQ(assetPath, path3);
  542. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  543. EXPECT_EQ(assetPath, path2);
  544. CheckDirectDependencies(asset1, { asset2 });
  545. CheckNoDependencies(asset2);
  546. CheckNoDependencies(asset4);
  547. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, deltaCatalog2);
  548. // deltacatalog2 path5
  549. // deltacatalog path3 path4
  550. /// baseCatalog path1 path2
  551. /// asset1 asset2 asset3 asset4 asset5
  552. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  553. EXPECT_EQ(assetPath, path3);
  554. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  555. EXPECT_EQ(assetPath, path2);
  556. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  557. EXPECT_EQ(assetPath, path5);
  558. CheckDirectDependencies(asset1, { asset2 });
  559. CheckNoDependencies(asset2);
  560. CheckNoDependencies(asset4);
  561. CheckDirectDependencies(asset5, { asset2 });
  562. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RemoveDeltaCatalog, deltaCatalog);
  563. // deltacatalog2 path5
  564. /// baseCatalog path1 path2
  565. /// asset1 asset2 asset3 asset4 asset5
  566. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  567. EXPECT_EQ(assetPath, path1);
  568. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset3);
  569. EXPECT_EQ(assetPath, "");
  570. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  571. EXPECT_EQ(assetPath, path2);
  572. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  573. EXPECT_EQ(assetPath, path5);
  574. CheckNoDependencies(asset1);
  575. CheckNoDependencies(asset2);
  576. CheckDirectDependencies(asset5, { asset2 });
  577. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, deltaCatalog);
  578. // deltacatalog path3 path4
  579. // deltacatalog2 path5
  580. /// baseCatalog path1 path2
  581. /// asset1 asset2 asset3 asset4 asset5
  582. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  583. EXPECT_EQ(assetPath, path3);
  584. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  585. EXPECT_EQ(assetPath, path2);
  586. CheckDirectDependencies(asset1, { asset2 });
  587. CheckNoDependencies(asset2);
  588. CheckNoDependencies(asset4);
  589. CheckDirectDependencies(asset5, { asset2 });
  590. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::InsertDeltaCatalogBefore, deltaCatalog3, deltaCatalog2);
  591. // deltacatalog path3 path4
  592. // deltacatalog2 path5
  593. // deltacatalog3 path6 path4
  594. /// baseCatalog path1 path2
  595. /// asset1 asset2 asset3 asset4 asset5
  596. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  597. EXPECT_EQ(assetPath, path3);
  598. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  599. EXPECT_EQ(assetPath, path5);
  600. CheckDirectDependencies(asset1, { asset2 });
  601. CheckNoDependencies(asset2);
  602. CheckNoDependencies(asset4);
  603. CheckDirectDependencies(asset5, { asset2 });
  604. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RemoveDeltaCatalog, deltaCatalog3);
  605. // deltacatalog path3 path4
  606. // deltacatalog2 path5
  607. /// baseCatalog path1 path2
  608. /// asset1 asset2 asset3 asset4 asset5
  609. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  610. EXPECT_EQ(assetPath, path3);
  611. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  612. EXPECT_EQ(assetPath, path5);
  613. CheckDirectDependencies(asset1, { asset2 });
  614. CheckNoDependencies(asset2);
  615. CheckNoDependencies(asset4);
  616. CheckDirectDependencies(asset5, { asset2 });
  617. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::InsertDeltaCatalogBefore, deltaCatalog3, deltaCatalog);
  618. // deltacatalog path3 path4
  619. // deltacatalog3 path6 path4
  620. // deltacatalog2 path5
  621. /// baseCatalog path1 path2
  622. /// asset1 asset2 asset3 asset4 asset5
  623. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  624. EXPECT_EQ(assetPath, path3);
  625. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  626. EXPECT_EQ(assetPath, path4);
  627. CheckDirectDependencies(asset1, { asset2 });
  628. CheckNoDependencies(asset2);
  629. CheckNoDependencies(asset4);
  630. CheckDirectDependencies(asset5, { asset2 });
  631. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::RemoveDeltaCatalog, baseCatalog);
  632. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::AddDeltaCatalog, baseCatalog);
  633. /// baseCatalog path1 path2
  634. // deltacatalog path3 path4
  635. // deltacatalog3 path6 path4
  636. // deltacatalog2 path5
  637. /// asset1 asset2 asset3 asset4 asset5
  638. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  639. EXPECT_EQ(assetPath, path1);
  640. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  641. EXPECT_EQ(assetPath, path2);
  642. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset3);
  643. EXPECT_EQ(assetPath, "");
  644. CheckNoDependencies(asset1);
  645. CheckNoDependencies(asset2);
  646. CheckNoDependencies(asset4);
  647. CheckDirectDependencies(asset5, { asset2 });
  648. }
  649. TEST_F(AssetCatalogDeltaTest, DeltaCatalogCreationTest)
  650. {
  651. bool result = false;
  652. AZStd::string assetPath;
  653. // load source catalog 1
  654. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  655. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, sourceCatalogPath1.c_str());
  656. // generate delta catalog 1
  657. AZ::IO::Path testDeltaCatalogPath1 = m_tempDirectory.GetDirectoryAsPath() / "TestAssetCatalogDelta.xml";
  658. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::CreateDeltaCatalog, deltaCatalogFiles, testDeltaCatalogPath1.Native());
  659. EXPECT_TRUE(result);
  660. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  661. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, testDeltaCatalogPath1.c_str());
  662. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  663. EXPECT_EQ(assetPath, path3);
  664. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset4);
  665. EXPECT_EQ(assetPath, path4);
  666. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  667. EXPECT_EQ(assetPath, "");
  668. // check against depenency info
  669. CheckDirectDependencies(asset1, { asset2 });
  670. // load source catalog 2
  671. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  672. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, sourceCatalogPath2.c_str());
  673. // generate delta catalog 3
  674. AZ::IO::Path testDeltaCatalogPath2 = m_tempDirectory.GetDirectoryAsPath() / "TestAssetCatalogDelta2.xml";
  675. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::CreateDeltaCatalog, deltaCatalogFiles2, testDeltaCatalogPath2.Native());
  676. EXPECT_TRUE(result);
  677. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  678. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, testDeltaCatalogPath2.c_str());
  679. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  680. EXPECT_EQ(assetPath, path5);
  681. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  682. EXPECT_EQ(assetPath, "");
  683. // check against dependency info
  684. CheckDirectDependencies(asset5, { asset2 });
  685. // load source catalog 3
  686. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  687. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, sourceCatalogPath3.c_str());
  688. // generate delta catalog 3
  689. AZ::IO::Path testDeltaCatalogPath3 = m_tempDirectory.GetDirectoryAsPath() / "TestAssetCatalogDelta3.xml";
  690. AZ::Data::AssetCatalogRequestBus::BroadcastResult(result, &AZ::Data::AssetCatalogRequestBus::Events::CreateDeltaCatalog, deltaCatalogFiles3, testDeltaCatalogPath3.Native());
  691. EXPECT_TRUE(result);
  692. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::ClearCatalog);
  693. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, testDeltaCatalogPath3.c_str());
  694. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset1);
  695. EXPECT_EQ(assetPath, path6);
  696. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset5);
  697. EXPECT_EQ(assetPath, path4);
  698. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset2);
  699. EXPECT_EQ(assetPath, "");
  700. // check against dependency info
  701. CheckDirectDependencies(asset5, { asset2 });
  702. CheckNoDependencies(asset1);
  703. }
  704. class AssetCatalogAPITest
  705. : public LeakDetectionFixture
  706. {
  707. public:
  708. void SetUp() override
  709. {
  710. using namespace AZ::Data;
  711. m_application = new AzFramework::Application();
  712. auto settingsRegistry = AZ::SettingsRegistry::Get();
  713. ASSERT_NE(nullptr, settingsRegistry);
  714. EXPECT_TRUE(settingsRegistry->Get(m_assetRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder));
  715. m_assetCatalog = aznew AzFramework::AssetCatalog();
  716. m_firstAssetId = AssetId(AZ::Uuid::CreateRandom(), 0);
  717. AssetInfo assetInfo;
  718. assetInfo.m_assetId = m_firstAssetId;
  719. assetInfo.m_relativePath = "AssetA.txt";
  720. assetInfo.m_sizeBytes = 1; //any non zero value
  721. m_assetCatalog->RegisterAsset(m_firstAssetId, assetInfo);
  722. m_secondAssetId = AssetId(AZ::Uuid::CreateRandom(), 0);
  723. assetInfo.m_assetId = m_secondAssetId;
  724. assetInfo.m_relativePath = "Foo/AssetA.txt";
  725. assetInfo.m_sizeBytes = 1; //any non zero value
  726. m_assetCatalog->RegisterAsset(m_secondAssetId, assetInfo);
  727. }
  728. void TearDown() override
  729. {
  730. delete m_assetCatalog;
  731. delete m_application;
  732. }
  733. AzFramework::Application* m_application;
  734. AzFramework::AssetCatalog* m_assetCatalog;
  735. AZ::Data::AssetId m_firstAssetId;
  736. AZ::Data::AssetId m_secondAssetId;
  737. AZ::IO::Path m_assetRoot;
  738. };
  739. TEST_F(AssetCatalogAPITest, GetAssetPathById_AbsolutePath_Valid)
  740. {
  741. AZ::IO::Path absPath = m_assetRoot / "AssetA.txt";
  742. EXPECT_EQ(m_firstAssetId, m_assetCatalog->GetAssetIdByPath(absPath.c_str(), AZ::Data::s_invalidAssetType, false));
  743. }
  744. TEST_F(AssetCatalogAPITest, GetAssetPathById_AbsolutePathWithSubFolder_Valid)
  745. {
  746. AZ::IO::Path absPath = (m_assetRoot / "Foo/AssetA.txt").LexicallyNormal();
  747. EXPECT_EQ(m_secondAssetId, m_assetCatalog->GetAssetIdByPath(absPath.c_str(), AZ::Data::s_invalidAssetType, false));
  748. }
  749. TEST_F(AssetCatalogAPITest, GetAssetPathById_RelPath_Valid)
  750. {
  751. EXPECT_EQ(m_firstAssetId, m_assetCatalog->GetAssetIdByPath("AssetA.txt", AZ::Data::s_invalidAssetType, false));
  752. }
  753. TEST_F(AssetCatalogAPITest, GetAssetPathById_RelPathWithSubFolders_Valid)
  754. {
  755. EXPECT_EQ(m_secondAssetId, m_assetCatalog->GetAssetIdByPath("Foo/AssetA.txt", AZ::Data::s_invalidAssetType, false));
  756. }
  757. TEST_F(AssetCatalogAPITest, GetAssetPathById_AbsPath_Invalid)
  758. {
  759. // A path that begins with a Posix path separator '/' is absolute not a relative path
  760. EXPECT_NE(m_firstAssetId, m_assetCatalog->GetAssetIdByPath("//AssetA.txt", AZ::Data::s_invalidAssetType, false));
  761. }
  762. TEST_F(AssetCatalogAPITest, GetRegisteredAssetPaths_TwoAssetsRegistered_RetrieveAssetPaths)
  763. {
  764. AZStd::vector<AZStd::string> assetPaths = m_assetCatalog->GetRegisteredAssetPaths();
  765. EXPECT_EQ(assetPaths.size(), 2);
  766. ASSERT_THAT(assetPaths, testing::ElementsAre(
  767. "AssetA.txt",
  768. "Foo/AssetA.txt"));
  769. }
  770. TEST_F(AssetCatalogAPITest, DoesAssetIdMatchWildcardPattern_Matches)
  771. {
  772. EXPECT_TRUE(m_assetCatalog->DoesAssetIdMatchWildcardPattern(m_firstAssetId, "*.txt"));
  773. EXPECT_TRUE(m_assetCatalog->DoesAssetIdMatchWildcardPattern(m_firstAssetId, "asset?.txt"));
  774. }
  775. TEST_F(AssetCatalogAPITest, DoesAssetIdMatchWildcardPattern_DoesNotMatch)
  776. {
  777. EXPECT_FALSE(m_assetCatalog->DoesAssetIdMatchWildcardPattern(AZ::Data::AssetId(), "*.txt"));
  778. EXPECT_FALSE(m_assetCatalog->DoesAssetIdMatchWildcardPattern(m_firstAssetId, "*.xml"));
  779. EXPECT_FALSE(m_assetCatalog->DoesAssetIdMatchWildcardPattern(m_firstAssetId, ""));
  780. }
  781. TEST_F(AssetCatalogAPITest, EnumerateAssetsListsCorrectAssets)
  782. {
  783. AZStd::vector<AZ::Data::AssetId> foundAssets;
  784. AZ::Data::AssetCatalogRequestBus::Broadcast(
  785. &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr,
  786. [&foundAssets](const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo)
  787. {
  788. foundAssets.emplace_back(assetId);
  789. },
  790. nullptr);
  791. ASSERT_EQ(foundAssets.size(), 2);
  792. EXPECT_EQ(foundAssets[0], m_firstAssetId);
  793. EXPECT_EQ(foundAssets[1], m_secondAssetId);
  794. }
  795. TEST_F(AssetCatalogAPITest, EnumerateAssetsDoesNotBlockMutex)
  796. {
  797. // This test simulates a previously-occurring deadlock bug caused by having the main thread call AssetCatalog::EnumerateAssets
  798. // with a callback that calls the AssetManager, and a loading thread running underneath the AssetManager that calls the
  799. // AssetCatalog.
  800. // To reproduce this state, we will do the following:
  801. // Main Thread Job Thread
  802. // wait on mainToJobSync
  803. // call EnumerateAssets
  804. // unblock mainToJobSync
  805. // wait on jobToMainSync call AssetCatalog::X
  806. // unblock jobToMainSync
  807. //
  808. // These steps should ensure that we create a theoretical "lock inversion", if EnumerateAssets locked an AssetCatalog mutex.
  809. // Even though we're using binary semaphores instead of mutexes, we're creating the same blocking situation.
  810. // EnumerateAssets itself should no longer lock the AssetCatalog mutex, so this test should succeed since there won't be any
  811. // actual lock inversion.
  812. // Set up job manager with one thread that we can use to set up the concurrent mutex access.
  813. AZ::JobManagerDesc desc;
  814. AZ::JobManagerThreadDesc threadDesc;
  815. desc.m_workerThreads.push_back(threadDesc);
  816. auto jobManager = aznew AZ::JobManager(desc);
  817. auto jobContext = aznew AZ::JobContext(*jobManager);
  818. AZ::JobContext::SetGlobalContext(jobContext);
  819. AZStd::binary_semaphore mainToJobSync;
  820. AZStd::binary_semaphore jobToMainSync;
  821. // Create a job whose sole purpose is to wait for EnumerateAssets to get called, call AssetCatalog, then tell EnumerateAssets
  822. // to finish. If EnumerateAssets has a mutex held, this will deadlock.
  823. auto job = AZ::CreateJobFunction(
  824. [&mainToJobSync, &jobToMainSync]() mutable
  825. {
  826. // wait for the main thread to be inside the EnumerateAssets callback.
  827. mainToJobSync.acquire();
  828. // call AssetCatalog::X. This will deadlock if EnumerateAssets is holding an AssetCatalog mutex.
  829. [[maybe_unused]] AZStd::string assetPath;
  830. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  831. assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, AZ::Data::AssetId());
  832. // signal the main thread to continue
  833. jobToMainSync.release();
  834. },
  835. true);
  836. job->Start();
  837. bool testCompletedSuccessfully = false;
  838. // Call EnumerateAssets with a callback that also tries to lock the mutex.
  839. AZ::Data::AssetCatalogRequestBus::Broadcast(
  840. &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr,
  841. [this, &mainToJobSync, &jobToMainSync, &testCompletedSuccessfully]
  842. (const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo)
  843. {
  844. // Only run this logic on the first assetId.
  845. if (assetId == m_firstAssetId)
  846. {
  847. // Tell the job it can continue
  848. mainToJobSync.release();
  849. // Wait for the job to finish calling AssetCatalog::X. This will deadlock if EnumerateAssets is holding an
  850. // AssetCatalog mutex.
  851. if (jobToMainSync.try_acquire_for(AZStd::chrono::seconds(5)))
  852. {
  853. // Only mark the test as completed successfully if we ran this logic and didn't deadlock.
  854. testCompletedSuccessfully = true;
  855. }
  856. }
  857. },
  858. nullptr);
  859. EXPECT_TRUE(testCompletedSuccessfully);
  860. // Clean up the job manager
  861. AZ::JobContext::SetGlobalContext(nullptr);
  862. delete jobContext;
  863. delete jobManager;
  864. }
  865. class AssetType1
  866. : public AZ::Data::AssetData
  867. {
  868. public:
  869. AZ_CLASS_ALLOCATOR(AssetType1, AZ::SystemAllocator);
  870. AZ_RTTI(AssetType1, "{64ECE3AE-2BEB-4502-9243-D17425249E08}", AZ::Data::AssetData);
  871. AssetType1()
  872. : m_data(nullptr)
  873. {
  874. }
  875. explicit AssetType1(const AZ::Data::AssetId& assetId, const AZ::Data::AssetData::AssetStatus assetStatus = AZ::Data::AssetData::AssetStatus::NotLoaded)
  876. : AZ::Data::AssetData(assetId, assetStatus)
  877. , m_data(nullptr)
  878. {
  879. }
  880. ~AssetType1() override
  881. {
  882. if (m_data)
  883. {
  884. azfree(m_data);
  885. }
  886. }
  887. char* m_data;
  888. };
  889. class AssetType2
  890. : public AZ::Data::AssetData
  891. {
  892. public:
  893. AZ_CLASS_ALLOCATOR(AssetType2, AZ::SystemAllocator);
  894. AZ_RTTI(AssetType2, "{F5EDAAAB-2398-4967-A2C7-6B7C9421C1CE}", AZ::Data::AssetData);
  895. AssetType2()
  896. : m_data(nullptr)
  897. {
  898. }
  899. explicit AssetType2(const AZ::Data::AssetId& assetId, const AZ::Data::AssetData::AssetStatus assetStatus = AZ::Data::AssetData::AssetStatus::NotLoaded)
  900. : AZ::Data::AssetData(assetId, assetStatus)
  901. , m_data(nullptr)
  902. {
  903. }
  904. ~AssetType2() override
  905. {
  906. if (m_data)
  907. {
  908. azfree(m_data);
  909. }
  910. }
  911. char* m_data;
  912. };
  913. class AssetCatalogDisplayNameTest
  914. : public LeakDetectionFixture
  915. {
  916. virtual AZ::IO::IStreamer* CreateStreamer() { return aznew AZ::IO::Streamer(AZStd::thread_desc{}, AZ::StreamerComponent::CreateStreamerStack()); }
  917. virtual void DestroyStreamer(AZ::IO::IStreamer* streamer) { delete streamer; }
  918. AZ::IO::FileIOBase* m_prevFileIO{ nullptr };
  919. TestFileIOBase m_fileIO;
  920. AZ::TaskExecutor* m_taskExecutor{ nullptr };
  921. AZ::IO::IStreamer* m_streamer{ nullptr };
  922. AzFramework::AssetCatalog* m_assetCatalog;
  923. public:
  924. void SetUp() override
  925. {
  926. m_prevFileIO = AZ::IO::FileIOBase::GetInstance();
  927. AZ::IO::FileIOBase::SetInstance(&m_fileIO);
  928. m_taskExecutor = aznew AZ::TaskExecutor();
  929. AZ::TaskExecutor::SetInstance(m_taskExecutor);
  930. m_streamer = CreateStreamer();
  931. if (m_streamer)
  932. {
  933. AZ::Interface<AZ::IO::IStreamer>::Register(m_streamer);
  934. }
  935. // create the database
  936. AZ::Data::AssetManager::Descriptor desc;
  937. AZ::Data::AssetManager::Create(desc);
  938. m_assetCatalog = aznew AzFramework::AssetCatalog();
  939. }
  940. void TearDown() override
  941. {
  942. delete m_assetCatalog;
  943. // destroy the database
  944. AZ::Data::AssetManager::Destroy();
  945. if (m_streamer)
  946. {
  947. AZ::Interface<AZ::IO::IStreamer>::Unregister(m_streamer);
  948. }
  949. DestroyStreamer(m_streamer);
  950. AZ::TaskExecutor::SetInstance(m_taskExecutor);
  951. delete m_taskExecutor;
  952. AZ::IO::FileIOBase::SetInstance(m_prevFileIO);
  953. }
  954. };
  955. TEST_F(AssetCatalogDisplayNameTest, GetAssetTypeByDisplayName_GetRegistered)
  956. {
  957. // Register an asset type
  958. AZ::TypeId assetTypeId = AZ::AzTypeInfo<AssetType1>::Uuid();
  959. AZStd::string assetTypeName = "Test Asset Type";
  960. auto handler = aznew AzFramework::GenericAssetHandler<AssetType1>(assetTypeName.data(), "SomeGroup", "someextension", assetTypeId);
  961. handler->Register();
  962. {
  963. // Get the Asset Type from the Display Name
  964. AZ::Data::AssetType id;
  965. AZ::Data::AssetCatalogRequestBus::BroadcastResult(id, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetTypeByDisplayName, assetTypeName);
  966. EXPECT_EQ(id, assetTypeId);
  967. }
  968. // Delete the handler
  969. handler->Unregister();
  970. delete handler;
  971. }
  972. TEST_F(AssetCatalogDisplayNameTest, GetAssetTypeByDisplayName_GetNotRegistered)
  973. {
  974. // Register an asset type
  975. AZ::TypeId assetTypeId = AZ::AzTypeInfo<AssetType1>::Uuid();
  976. AZStd::string assetTypeName = "Test Asset Type";
  977. auto handler = aznew AzFramework::GenericAssetHandler<AssetType1>(assetTypeName.data(), "SomeGroup", "someextension", assetTypeId);
  978. handler->Register();
  979. {
  980. // Try to get an Asset Type with a Display Name that was never registered
  981. AZ::Data::AssetType id;
  982. AZ::Data::AssetCatalogRequestBus::BroadcastResult(id, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetTypeByDisplayName, "Some Asset Type We Did Not Register");
  983. EXPECT_TRUE(id.IsNull());
  984. }
  985. // Delete the handler
  986. handler->Unregister();
  987. delete handler;
  988. }
  989. TEST_F(AssetCatalogDisplayNameTest, GetAssetTypeByDisplayName_GetWrongCasing)
  990. {
  991. // Register an asset type
  992. AZ::TypeId assetTypeId = AZ::AzTypeInfo<AssetType1>::Uuid();
  993. AZStd::string assetTypeName = "Test Asset Type";
  994. auto handler = aznew AzFramework::GenericAssetHandler<AssetType1>(assetTypeName.data(), "SomeGroup", "someextension", assetTypeId);
  995. handler->Register();
  996. {
  997. // Try to get the Asset Type we registered, but with a lowercase Display Name
  998. AZ::Data::AssetType id;
  999. AZ::Data::AssetCatalogRequestBus::BroadcastResult(id, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetTypeByDisplayName, "test asset type");
  1000. EXPECT_TRUE(id.IsNull());
  1001. }
  1002. // Delete the handler
  1003. handler->Unregister();
  1004. delete handler;
  1005. }
  1006. TEST_F(AssetCatalogDisplayNameTest, GetAssetTypeByDisplayName_NoRegisteredType)
  1007. {
  1008. // Get the Asset Type from a Display Name we did not register
  1009. AZ::Data::AssetType id;
  1010. AZ::Data::AssetCatalogRequestBus::BroadcastResult(id, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetTypeByDisplayName, "Some Asset Type We Did Not Register");
  1011. EXPECT_TRUE(id.IsNull());
  1012. }
  1013. TEST_F(AssetCatalogDisplayNameTest, GetAssetTypeByDisplayName_MultiRegisteredType_SameDisplayName)
  1014. {
  1015. AZStd::string assetTypeName = "Test Asset Type";
  1016. // Register an asset type
  1017. AZ::TypeId asset1TypeId = AZ::AzTypeInfo<AssetType1>::Uuid();
  1018. auto handler1 = aznew AzFramework::GenericAssetHandler<AssetType1>(assetTypeName.data(), "SomeGroup", "someextension", asset1TypeId);
  1019. handler1->Register();
  1020. // Register a different type handler with the same Display Name
  1021. AZ::TypeId asset2TypeId = AZ::AzTypeInfo<AssetType2>::Uuid();
  1022. auto handler2 = aznew AzFramework::GenericAssetHandler<AssetType2>(assetTypeName.data(), "SomeGroup", "someextension", asset2TypeId);
  1023. handler2->Register();
  1024. // Verify one of the types is returned.
  1025. // Note that we have no control over which one is returned as it's an implementation detail of the AssetCatalog
  1026. {
  1027. AZ::Data::AssetType id;
  1028. AZ::Data::AssetCatalogRequestBus::BroadcastResult(id, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetTypeByDisplayName, assetTypeName);
  1029. EXPECT_TRUE((id == asset1TypeId) || (id == asset2TypeId));
  1030. }
  1031. // Delete both handlers
  1032. handler1->Unregister();
  1033. handler2->Unregister();
  1034. delete handler1;
  1035. delete handler2;
  1036. }
  1037. }