SliceEntityOwnershipTests.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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 <AzFramework/Entity/SliceEntityOwnershipService.h>
  9. #include "EntityOwnershipServiceTestFixture.h"
  10. #include <AzToolsFramework/Slice/SliceMetadataEntityContextBus.h>
  11. namespace UnitTest
  12. {
  13. class SliceEntityOwnershipTests
  14. : public EntityOwnershipServiceTestFixture
  15. {
  16. public:
  17. void SetUp() override
  18. {
  19. SetUpEntityOwnershipServiceTest();
  20. m_sliceEntityOwnershipService = AZStd::make_unique<AzFramework::SliceEntityOwnershipService>(AZ::Uuid::CreateNull(),
  21. m_app->GetSerializeContext());
  22. m_sliceEntityOwnershipService->Initialize();
  23. m_sliceEntityOwnershipService->SetEntitiesAddedCallback([this](const AzFramework::EntityList& entityList)
  24. {
  25. this->HandleEntitiesAdded(entityList);
  26. });
  27. m_sliceEntityOwnershipService->SetEntitiesRemovedCallback([this](const AzFramework::EntityIdList& entityIds)
  28. {
  29. this->HandleEntitiesRemoved(entityIds);
  30. });
  31. m_sliceEntityOwnershipService->SetValidateEntitiesCallback([this](const AzFramework::EntityList& entityList)
  32. {
  33. return this->ValidateEntities(entityList);
  34. });
  35. }
  36. void TearDown() override
  37. {
  38. m_sliceEntityOwnershipService->SetEntitiesAddedCallback(nullptr);
  39. // In order for the death tests to work, we have to destroy the EOS early. So, don't try to destroy again.
  40. if (m_sliceEntityOwnershipService->IsInitialized())
  41. {
  42. m_sliceEntityOwnershipService->Destroy();
  43. }
  44. m_sliceEntityOwnershipService.reset();
  45. TearDownEntityOwnershipServiceTest();
  46. }
  47. protected:
  48. AZStd::unique_ptr<AzFramework::SliceEntityOwnershipService> m_sliceEntityOwnershipService;
  49. };
  50. TEST_F(SliceEntityOwnershipTests, AddEntity_InitalizedCorrectly_EntityCreated)
  51. {
  52. AZ::Entity* testEntity = aznew AZ::Entity("testEntity");
  53. m_sliceEntityOwnershipService->AddEntity(testEntity);
  54. // Validate that entities-added callback is triggerted.
  55. EXPECT_TRUE(m_entitiesAddedCallbackTriggered);
  56. const AzFramework::EntityList& entitiesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetNewEntities();
  57. // Validate that there is only one entity under root slice.
  58. EXPECT_EQ(entitiesUnderRootSlice.size(), 1);
  59. EXPECT_EQ(entitiesUnderRootSlice.at(0)->GetName(), "testEntity");
  60. }
  61. TEST_F(SliceEntityOwnershipTests, DestroyEntityById_EntityAdded_EntityDestroyed)
  62. {
  63. AZ::Entity* testEntity = aznew AZ::Entity("testEntity");
  64. m_sliceEntityOwnershipService->AddEntity(testEntity);
  65. AzFramework::EntityList entitiesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetNewEntities();
  66. // Verify that entity is added
  67. EXPECT_EQ(entitiesUnderRootSlice.size(), 1);
  68. EXPECT_TRUE(m_sliceEntityOwnershipService->DestroyEntityById(testEntity->GetId()));
  69. entitiesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetNewEntities();
  70. // Verify that entity is destroyed
  71. EXPECT_EQ(entitiesUnderRootSlice.size(), 0);
  72. }
  73. TEST_F(SliceEntityOwnershipTests, GetRootSlice_RootAssetAbsent_ReturnNull)
  74. {
  75. m_sliceEntityOwnershipService->Destroy();
  76. AZ::SliceComponent* rootSlice = nullptr;
  77. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootSlice,
  78. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetRootSlice);
  79. EXPECT_EQ(rootSlice, nullptr);
  80. }
  81. TEST_F(SliceEntityOwnershipTests, GetRootSlice_RootAssetPresent_ReturnRootSlice)
  82. {
  83. AZ::SliceComponent* rootSlice = nullptr;
  84. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootSlice,
  85. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetRootSlice);
  86. EXPECT_NE(rootSlice, nullptr);
  87. }
  88. TEST_F(SliceEntityOwnershipTests, Reset_SliceAdded_DestroySliceEntities)
  89. {
  90. AzFramework::EntityList entitiesToAdd = AzFramework::EntityList{ aznew AZ::Entity() };
  91. AddSlice(entitiesToAdd);
  92. size_t slicesCountBeforeReset = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  93. // Verify that slice exists
  94. EXPECT_EQ(slicesCountBeforeReset, 1);
  95. m_sliceEntityOwnershipService->Reset();
  96. size_t slicesCountAfterReset = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  97. // Verify that slices under rootSlice were removed after reset of EntityOwnershipService.
  98. EXPECT_EQ(slicesCountAfterReset, 0);
  99. // Verify that call to destroy entities in the added slice occured.
  100. EXPECT_TRUE(m_entityRemovedCallbackTriggered);
  101. }
  102. TEST_F(SliceEntityOwnershipTests, Reset_SliceInstantiationStarted_StopSliceInstantiation)
  103. {
  104. AddSlice(AzFramework::EntityList{}, true);
  105. m_sliceEntityOwnershipService->Reset();
  106. AZ::TickBus::ExecuteQueuedEvents();
  107. size_t slicesCountUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  108. EXPECT_EQ(slicesCountUnderRootSlice, 0);
  109. }
  110. TEST_F(SliceEntityOwnershipTests, Reset_EntityAdded_EntityDestroyedAfterReset)
  111. {
  112. AZ::Entity* testEntity = aznew AZ::Entity("testEntity");
  113. m_sliceEntityOwnershipService->AddEntity(testEntity);
  114. m_sliceEntityOwnershipService->Reset();
  115. const AzFramework::EntityList& entitiesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetNewEntities();
  116. EXPECT_EQ(entitiesUnderRootSlice.size(), 0);
  117. EXPECT_TRUE(m_entityRemovedCallbackTriggered);
  118. }
  119. TEST_F(SliceEntityOwnershipTests, HandleRootEntityReloadedFromStream_NoRootEntity_FailToLoadEntity)
  120. {
  121. bool rootEntityLoadSuccessful = false;
  122. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootEntityLoadSuccessful,
  123. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::HandleRootEntityReloadedFromStream, nullptr, false, nullptr);
  124. EXPECT_FALSE(rootEntityLoadSuccessful);
  125. }
  126. TEST_F(SliceEntityOwnershipTests, HandleRootEntityReloadedFromStream_NoSliceComponent_FailToLoadEntity)
  127. {
  128. AZ::Entity* testEntity = aznew AZ::Entity();
  129. // Suppress the AZ_Error thrown for not creating the root slice.
  130. AZ_TEST_START_TRACE_SUPPRESSION;
  131. bool rootEntityLoadSuccessful = false;
  132. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootEntityLoadSuccessful,
  133. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::HandleRootEntityReloadedFromStream, testEntity, false, nullptr);
  134. EXPECT_FALSE(rootEntityLoadSuccessful);
  135. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  136. delete testEntity;
  137. }
  138. TEST_F(SliceEntityOwnershipTests, HandleRootEntityReloadedFromStream_RemapIdsTrue_IdsRemapped)
  139. {
  140. AZ::Entity* rootEntity = aznew AZ::Entity();
  141. AZ::SliceComponent* rootSliceComponent = rootEntity->CreateComponent<AZ::SliceComponent>();
  142. AZ::Entity* testEntity = aznew AZ::Entity();
  143. rootSliceComponent->AddEntity(testEntity);
  144. AZ::SliceComponent::EntityIdToEntityIdMap previousToNewIdMap;
  145. previousToNewIdMap.emplace(testEntity->GetId(), testEntity->GetId());
  146. bool rootEntityLoadSuccessful = false;
  147. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootEntityLoadSuccessful,
  148. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::HandleRootEntityReloadedFromStream,
  149. rootEntity, true, &previousToNewIdMap);
  150. EXPECT_TRUE(rootEntityLoadSuccessful);
  151. // Verify that remapping of entityIds is done by comparing the entityIds in previousToNewIdMap
  152. EXPECT_TRUE(previousToNewIdMap.begin()->first != previousToNewIdMap.begin()->second);
  153. }
  154. TEST_F(SliceEntityOwnershipTests, FindLoadedEntityIdMapping_IdsNotRemapped_EntityIdPresent)
  155. {
  156. AZ::Entity* rootEntity = aznew AZ::Entity();
  157. AZ::SliceComponent* rootSliceComponent = rootEntity->CreateComponent<AZ::SliceComponent>();
  158. AZ::Entity* testEntity = aznew AZ::Entity();
  159. rootSliceComponent->AddEntity(testEntity);
  160. bool rootEntityLoadSuccessful = false;
  161. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootEntityLoadSuccessful,
  162. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::HandleRootEntityReloadedFromStream, rootEntity, false, nullptr);
  163. EXPECT_TRUE(rootEntityLoadSuccessful);
  164. AZ::EntityId loadedEntityId;
  165. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(loadedEntityId,
  166. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::FindLoadedEntityIdMapping, testEntity->GetId());
  167. // Verify that the entityId in the loadedEntityIdMap is same as the provided entityId, which happens when remapping is not done.
  168. EXPECT_TRUE(loadedEntityId == testEntity->GetId());
  169. }
  170. TEST_F(SliceEntityOwnershipTests, FindLoadedEntityIdMapping_IdsRemapped_EntityIdAbsent)
  171. {
  172. AZ::Entity* rootEntity = aznew AZ::Entity();
  173. AZ::SliceComponent* rootSliceComponent = rootEntity->CreateComponent<AZ::SliceComponent>();
  174. AZ::Entity* testEntity = aznew AZ::Entity();
  175. rootSliceComponent->AddEntity(testEntity);
  176. AZ::SliceComponent::EntityIdToEntityIdMap previousToNewIdMap;
  177. previousToNewIdMap.emplace(testEntity->GetId(), testEntity->GetId());
  178. bool rootEntityLoadSuccessful = false;
  179. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootEntityLoadSuccessful,
  180. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::HandleRootEntityReloadedFromStream,
  181. rootEntity, true, &previousToNewIdMap);
  182. EXPECT_TRUE(rootEntityLoadSuccessful);
  183. AZ::EntityId loadedEntityId;
  184. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(loadedEntityId,
  185. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::FindLoadedEntityIdMapping, testEntity->GetId());
  186. // Verify that entityId is not present in the loadedEntityIdMap when remapping is done.
  187. EXPECT_FALSE(loadedEntityId.IsValid());
  188. }
  189. TEST_F(SliceEntityOwnershipTests, OnAssetReady_RootSliceAssetReady_DoNotInstantiate)
  190. {
  191. m_sliceEntityOwnershipService->OnAssetReady(GetRootSliceAsset());
  192. // Verify that validate entities callback is not triggered,
  193. // which will only happen when an attempt to instantiate slice didn't occur.
  194. EXPECT_FALSE(m_validateEntitiesCallbackTriggered);
  195. }
  196. TEST_F(SliceEntityOwnershipTests, OnAssetError_RootSliceAssetError_DoNotClearOtherSliceInstantiations)
  197. {
  198. AddSlice(AzFramework::EntityList{}, true);
  199. m_sliceEntityOwnershipService->OnAssetError(GetRootSliceAsset());
  200. // Try to finish any queued slice instantiations
  201. AZ::TickBus::ExecuteQueuedEvents();
  202. // Verify that slice instantiation was successful.
  203. size_t slicesCountUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  204. EXPECT_EQ(slicesCountUnderRootSlice, 1);
  205. }
  206. TEST_F(SliceEntityOwnershipTests, OnAssetError_InstantiatingAssetError_StopSliceInstantiation)
  207. {
  208. AZ::Data::Asset<AZ::SliceAsset> sliceAsset1;
  209. AZ::Data::AssetId sliceAsset1Id = AZ::Data::AssetId(AZ::Uuid::CreateRandom());
  210. sliceAsset1.Create(sliceAsset1Id, false);
  211. AddSlice(AzFramework::EntityList{}, true, sliceAsset1);
  212. AZ::Data::Asset<AZ::SliceAsset> sliceAsset2;
  213. sliceAsset2.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), false);
  214. AddSlice(AzFramework::EntityList{}, true, sliceAsset2);
  215. m_sliceEntityOwnershipService->OnAssetError(sliceAsset2);
  216. // Try to finish any queued slice instantiations
  217. AZ::TickBus::ExecuteQueuedEvents();
  218. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  219. // Verify that there is only one slice under root slice
  220. EXPECT_EQ(slicesUnderRootSlice.size(), 1);
  221. // Verify that the slice without the asset error was instantiated
  222. EXPECT_EQ(slicesUnderRootSlice.front().GetSliceAsset().GetId(), sliceAsset1Id);
  223. }
  224. TEST_F(SliceEntityOwnershipTests, InstantiateSlice_InvalidAssetId_ReturnBlankInstantiationTicket)
  225. {
  226. // Set the asset id to null to invalidate it.
  227. AZ_TEST_START_TRACE_SUPPRESSION;
  228. AZ::Data::Asset<AZ::SliceAsset> sliceAssetHolder = AZ::Data::AssetManager::Instance().
  229. CreateAsset<AZ::SliceAsset>(AZ::Data::AssetId{});
  230. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  231. EXPECT_EQ(nullptr, sliceAssetHolder.Get());
  232. AzFramework::SliceInstantiationTicket sliceInstantiationTicket;
  233. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(sliceInstantiationTicket,
  234. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::InstantiateSlice, sliceAssetHolder, nullptr, nullptr);
  235. AZ::TickBus::ExecuteQueuedEvents();
  236. // Verify that there is no request id or context id associated with the sliceInstantiationTicket
  237. EXPECT_EQ(sliceInstantiationTicket.GetContextId(), AZ::Uuid::CreateNull());
  238. EXPECT_EQ(sliceInstantiationTicket.GetRequestId(), 0);
  239. }
  240. TEST_F(SliceEntityOwnershipTests, InstantiateSlice_InstantiateTwoSlices_SlicesInstantiated)
  241. {
  242. // Add 2 slices asynchronously
  243. AddSlice(AzFramework::EntityList{}, true);
  244. AddSlice(AzFramework::EntityList{}, true);
  245. AZ::TickBus::ExecuteQueuedEvents();
  246. size_t slicesCountUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  247. EXPECT_EQ(slicesCountUnderRootSlice, 2);
  248. }
  249. TEST_F(SliceEntityOwnershipTests, CloneSliceInstance_InstantiateSlice_SliceCloned)
  250. {
  251. AZ::Entity* testEntity = aznew AZ::Entity("testEntity");
  252. AddSlice(AzFramework::EntityList{ testEntity });
  253. AZ::SliceComponent::EntityIdSet entityIdsInSlice;
  254. GetRootSliceAsset()->GetComponent()->GetEntityIds(entityIdsInSlice);
  255. AZ::SliceComponent* rootSlice = nullptr;
  256. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(rootSlice,
  257. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetRootSlice);
  258. AZ::SliceComponent::SliceInstanceAddress sourceSliceInstanceAddress = rootSlice->FindSlice(*entityIdsInSlice.begin());
  259. AZ::SliceComponent::EntityIdToEntityIdMap entityIdToEntityIdMap;
  260. AZ::SliceComponent::SliceInstanceAddress clonedSliceInstanceAddress;
  261. AzFramework::SliceEntityOwnershipServiceRequestBus::BroadcastResult(clonedSliceInstanceAddress,
  262. &AzFramework::SliceEntityOwnershipServiceRequests::CloneSliceInstance, sourceSliceInstanceAddress, entityIdToEntityIdMap);
  263. // Verify that the entity was cloned successfully with the slice
  264. EXPECT_EQ(clonedSliceInstanceAddress.GetInstance()->GetInstantiated()->m_entities.front()->GetName(), "testEntity");
  265. // Verify that the source slice and the cloned slice have the same reference.
  266. EXPECT_EQ(sourceSliceInstanceAddress.GetReference(), clonedSliceInstanceAddress.GetReference());
  267. }
  268. TEST_F(SliceEntityOwnershipTests, InstantiateSlice_EntitiesInvalid_SliceInstantiationFailed)
  269. {
  270. m_areEntitiesValidForContext = false;
  271. AddSlice(AzFramework::EntityList{});
  272. size_t slicesCountUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  273. // If entities are invalid, then slice instantiation would fail
  274. EXPECT_EQ(slicesCountUnderRootSlice, 0);
  275. }
  276. TEST_F(SliceEntityOwnershipTests, CancelSliceInstantiation_SetupCorrect_SliceInstantiationCanceled)
  277. {
  278. AzFramework::SliceInstantiationTicket sliceInstantiationTicket = AddSlice(AzFramework::EntityList{}, true);
  279. AzFramework::SliceEntityOwnershipServiceRequestBus::Broadcast(
  280. &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::CancelSliceInstantiation, sliceInstantiationTicket);
  281. // This will try to finish any queued slice instantiations.
  282. AZ::TickBus::ExecuteQueuedEvents();
  283. size_t slicesCountUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices().size();
  284. EXPECT_EQ(slicesCountUnderRootSlice, 0);
  285. }
  286. TEST_F(SliceEntityOwnershipTests, GetOwningSlice_SliceAdded_OwningSliceFetchedCorrectly)
  287. {
  288. AZ::SliceComponent::SliceList& slicesUnderRootSlice = GetRootSliceAsset()->GetComponent()->GetSlices();
  289. AddSlice(AzFramework::EntityList{ aznew AZ::Entity() });
  290. ASSERT_EQ(slicesUnderRootSlice.size(), 1);
  291. AZ::SliceComponent::SliceReference& sliceReference = slicesUnderRootSlice.front();
  292. ASSERT_EQ(sliceReference.GetInstances().size(), 1);
  293. AzFramework::EntityList entitiesOfSlice = sliceReference.GetInstances().begin()->GetInstantiated()->m_entities;
  294. ASSERT_EQ(entitiesOfSlice.size(), 1);
  295. AZ::SliceComponent::SliceInstanceAddress sliceInstanceAddress;
  296. AzFramework::SliceEntityRequestBus::EventResult(sliceInstanceAddress, entitiesOfSlice.front()->GetId(),
  297. &AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
  298. // Verify that the source slice and the cloned slice have the same slice asset.
  299. EXPECT_EQ(sliceInstanceAddress.GetReference()->GetSliceAsset(), sliceReference.GetSliceAsset());
  300. }
  301. TEST_F(SliceEntityOwnershipTests, GetOwningSlice_LooseEntityAdded_EntityHasNoOwningSlice)
  302. {
  303. AZ::Entity* testEntity = aznew AZ::Entity();
  304. m_sliceEntityOwnershipService->AddEntity(testEntity);
  305. AZ::SliceComponent::SliceInstanceAddress sliceInstanceAddress;
  306. AzFramework::SliceEntityRequestBus::EventResult(sliceInstanceAddress, testEntity->GetId(),
  307. &AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
  308. // Verify that the loose entity doesn't belong to a slice instance
  309. EXPECT_FALSE(sliceInstanceAddress.IsValid());
  310. }
  311. TEST_F(SliceEntityOwnershipTests, AddEntity_RootSliceAssetAbsent_EntityNotCreated)
  312. {
  313. m_sliceEntityOwnershipService->Destroy();
  314. AZ::Entity testEntity = AZ::Entity("testEntity");
  315. AZ_TEST_START_ASSERTTEST;
  316. m_sliceEntityOwnershipService->AddEntity(&testEntity);
  317. AZ_TEST_STOP_ASSERTTEST(1); // we expect an assert here but we expect NO death or crash, just a clean return.
  318. }
  319. }