SimulationIterfaceAppTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 "TestFixture.h"
  9. #include <SimulationInterfaces/SimulationEntityManagerRequestBus.h>
  10. #include <ROS2/Frame/ROS2FrameComponentBus.h>
  11. namespace UnitTest
  12. {
  13. class SimulationInterfaceTestEnvironmentWithAssets : public SimulationInterfaceTestEnvironment
  14. {
  15. protected:
  16. void PostSystemEntityActivate();
  17. };
  18. void SimulationInterfaceTestEnvironmentWithAssets::PostSystemEntityActivate()
  19. {
  20. // Prepare the asset catalog and ensure that our test asset (testsimulationentity.spawnable) is loaded and
  21. // ready to be used in test scenarios.
  22. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  23. AZ::ComponentApplication* app = nullptr;
  24. AZ::ComponentApplicationBus::BroadcastResult(app, &AZ::ComponentApplicationBus::Events::GetApplication);
  25. AZ_Assert(app, "Failed to get application");
  26. auto products = AZ::Utils::GetProjectProductPathForPlatform().c_str();
  27. AZ::IO::Path assetCatalogPath = AZ::IO::Path(products) / "assetcatalog.xml";
  28. bool catalogExists = AZ::IO::FileIOBase::GetInstance()->Exists(assetCatalogPath.c_str());
  29. AZ_Assert(catalogExists, "Asset Catalog in %s does not exist", assetCatalogPath.c_str());
  30. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, assetCatalogPath.c_str());
  31. const AZ::IO::Path TestSpawnable = "sampleasset/testsimulationentity.spawnable";
  32. const AZ::IO::Path TestSpawnableGlobalPath = AZ::IO::Path(products) / TestSpawnable;
  33. bool spawnableExists = AZ::IO::FileIOBase::GetInstance()->Exists(assetCatalogPath.c_str());
  34. AZ_Assert(spawnableExists, "%s does not exist", TestSpawnableGlobalPath.c_str());
  35. AZ::Data::AssetId assetId;
  36. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  37. assetId,
  38. &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  39. TestSpawnable.c_str(),
  40. AZ::Data::s_invalidAssetType,
  41. false);
  42. AZ_Assert(assetId.IsValid(), "Failed to get asset id for %s", TestSpawnable.c_str());
  43. }
  44. int getNumberOfEntities()
  45. {
  46. using namespace SimulationInterfaces;
  47. AZ::Outcome<EntityNameList, FailedResult> enitities;
  48. SimulationEntityManagerRequestBus::BroadcastResult(
  49. enitities, &SimulationEntityManagerRequestBus::Events::GetEntities, EntityFilters());
  50. AZ_Assert(enitities.IsSuccess(), "Failed to get entities");
  51. return enitities.GetValue().size();
  52. }
  53. TEST_F(SimulationInterfaceTestFixture, SpawnAppTest)
  54. {
  55. // This is an integration test that runs the test application with the SimulationInterfaces gem enabled.
  56. // It has prepared asset catalog, and we are able to spawn entities with the test asset.
  57. using namespace SimulationInterfaces;
  58. constexpr AZStd::string_view entityName = "MySuperDuperEntity";
  59. const AZ::Transform initialPose = AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, 0.0f, 0.0f));
  60. constexpr AZStd::string_view uri = "product_asset:///sampleasset/testsimulationentity.spawnable";
  61. constexpr AZStd::string_view entityNamespace = "FooNamespace";
  62. AZStd::atomic_bool completed = false;
  63. SpawnCompletedCb completedCb = [&](const AZ::Outcome<AZStd::string, FailedResult>& result)
  64. {
  65. EXPECT_TRUE(result.IsSuccess());
  66. completed = true;
  67. };
  68. PreInsertionCb preinsertionCB = [](const AZ::Outcome<AzFramework::SpawnableEntityContainerView, FailedResult>& outcome)
  69. {
  70. };
  71. constexpr bool allowRename = false;
  72. SimulationEntityManagerRequestBus::Broadcast(
  73. &SimulationEntityManagerRequestBus::Events::SpawnEntity,
  74. entityName,
  75. uri,
  76. entityNamespace,
  77. initialPose,
  78. allowRename,
  79. preinsertionCB,
  80. completedCb);
  81. // entities are spawned asynchronously, so we need to tick the app to let the entity be spawned
  82. TickApp(100);
  83. EXPECT_TRUE(completed);
  84. // try to spawn entity with the same name, expect failure
  85. AZStd::atomic_bool completed2 = false;
  86. SpawnCompletedCb failedSpawnCompletedCb = [&](const AZ::Outcome<AZStd::string, FailedResult>& result)
  87. {
  88. EXPECT_FALSE(result.IsSuccess());
  89. completed2 = true;
  90. };
  91. SimulationEntityManagerRequestBus::Broadcast(
  92. &SimulationEntityManagerRequestBus::Events::SpawnEntity,
  93. entityName,
  94. uri,
  95. entityNamespace,
  96. initialPose,
  97. allowRename,
  98. preinsertionCB,
  99. failedSpawnCompletedCb);
  100. EXPECT_TRUE(completed2);
  101. // list simulation entities
  102. AZ::Outcome<EntityNameList, FailedResult> entitiesResult;
  103. SimulationEntityManagerRequestBus::BroadcastResult(
  104. entitiesResult, &SimulationEntityManagerRequestBus::Events::GetEntities, EntityFilters());
  105. ASSERT_TRUE(entitiesResult.IsSuccess());
  106. const auto& entities = entitiesResult.GetValue();
  107. EXPECT_EQ(entities.size(), 1);
  108. ASSERT_FALSE(entities.empty()) << "Simulated Entities Empty";
  109. const AZStd::string spawnedEntityName = entities.front();
  110. printf("Spawned entity name %s\n", spawnedEntityName.c_str());
  111. // get entity id by name
  112. AZ::Outcome<AZ::EntityId, FailedResult> entityIdResult;
  113. SimulationEntityManagerRequestBus::BroadcastResult(
  114. entityIdResult, &SimulationEntityManagerRequestBus::Events::GetEntityId, spawnedEntityName);
  115. ASSERT_TRUE(entityIdResult.IsSuccess()) << "Failed to get entity id";
  116. const AZ::EntityId entityId = entityIdResult.GetValue();
  117. // check namespace
  118. AZStd::string entityNamespaceOut;
  119. ROS2::ROS2FrameComponentBus::EventResult(entityNamespaceOut, entityId, &ROS2::ROS2FrameComponentBus::Events::GetNamespace);
  120. EXPECT_EQ(entityNamespaceOut, entityNamespace);
  121. // run physics simulation
  122. StepPhysics(100);
  123. // Get entity state,
  124. AZ::Outcome<MultipleEntitiesStates, FailedResult> entityStatesResult;
  125. SimulationEntityManagerRequestBus::BroadcastResult(
  126. entityStatesResult, &SimulationEntityManagerRequestBus::Events::GetEntitiesStates, EntityFilters());
  127. ASSERT_TRUE(entityStatesResult.IsSuccess());
  128. const auto& entityStates = entityStatesResult.GetValue();
  129. auto entityState = entityStates.find(spawnedEntityName);
  130. ASSERT_NE(entityState, entityStates.end());
  131. EXPECT_EQ(entityState->first, spawnedEntityName);
  132. // check if the entity moved
  133. EXPECT_GE(entityState->second.m_pose.GetTranslation().GetDistance(initialPose.GetTranslation()), 1.0f);
  134. // set new entity state - move the entity to X=1000 meters
  135. const AZ::Vector3 newPosition = AZ::Vector3(1000.0f, 0.0f, 0.0f);
  136. const EntityState newState = { AZ::Transform::CreateTranslation(newPosition),
  137. AZ::Vector3::CreateZero(),
  138. AZ::Vector3::CreateZero() };
  139. SimulationEntityManagerRequestBus::Broadcast(
  140. &SimulationEntityManagerRequestBus::Events::SetEntityState, spawnedEntityName, newState);
  141. StepPhysics();
  142. // Check if entity was teleported by setting the new state, we use a filter to check if the entity is at the new position
  143. EntityFilters filter;
  144. filter.m_boundsShape = AZStd::make_shared<Physics::SphereShapeConfiguration>(2.0f);
  145. filter.m_boundsPose = AZ::Transform::CreateTranslation(AZ::Vector3(1000.0f, 0.0f, 0.0f));
  146. AZ::Outcome<EntityNameList, FailedResult> entitiesFiltered;
  147. SimulationEntityManagerRequestBus::BroadcastResult(
  148. entitiesFiltered, &SimulationEntityManagerRequestBus::Events::GetEntities, filter);
  149. ASSERT_TRUE(entitiesFiltered.IsSuccess());
  150. EXPECT_EQ(entitiesFiltered.GetValue().size(), 1);
  151. // delete entity using its name
  152. DeletionCompletedCb deletionCompletedCb = [](const AZ::Outcome<void, FailedResult>& result)
  153. {
  154. EXPECT_TRUE(result.IsSuccess());
  155. };
  156. SimulationEntityManagerRequestBus::Broadcast(
  157. &SimulationEntityManagerRequestBus::Events::DeleteEntity, entityName, deletionCompletedCb);
  158. TickApp(100);
  159. // check if the entity was deleted
  160. EXPECT_EQ(getNumberOfEntities(), 0);
  161. // spawn 3 entities of entities and despawn all of them
  162. SpawnCompletedCb cb = [&](const AZ::Outcome<AZStd::string, FailedResult>& result)
  163. {
  164. };
  165. SimulationEntityManagerRequestBus::Broadcast(
  166. &SimulationEntityManagerRequestBus::Events::SpawnEntity,
  167. "entity1",
  168. uri,
  169. entityNamespace,
  170. initialPose,
  171. false,
  172. preinsertionCB,
  173. cb);
  174. SimulationEntityManagerRequestBus::Broadcast(
  175. &SimulationEntityManagerRequestBus::Events::SpawnEntity,
  176. "entity2",
  177. uri,
  178. entityNamespace,
  179. initialPose,
  180. false,
  181. preinsertionCB,
  182. cb);
  183. SimulationEntityManagerRequestBus::Broadcast(
  184. &SimulationEntityManagerRequestBus::Events::SpawnEntity,
  185. "entity3",
  186. uri,
  187. entityNamespace,
  188. initialPose,
  189. false,
  190. preinsertionCB,
  191. cb);
  192. TickApp(100);
  193. EXPECT_EQ(getNumberOfEntities(), 3);
  194. // delete all entities
  195. bool deletionWasCompleted = false;
  196. DeletionCompletedCb deleteAllCompletion = [&deletionWasCompleted](const AZ::Outcome<void, FailedResult>& result)
  197. {
  198. deletionWasCompleted = true;
  199. EXPECT_TRUE(result.IsSuccess());
  200. };
  201. SimulationEntityManagerRequestBus::Broadcast(&SimulationEntityManagerRequestBus::Events::DeleteAllEntities, deleteAllCompletion);
  202. TickApp(100);
  203. EXPECT_TRUE(deletionWasCompleted);
  204. EXPECT_EQ(getNumberOfEntities(), 0);
  205. }
  206. } // namespace UnitTest
  207. // required to support running integration tests with Qt and PhysX
  208. AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv)
  209. {
  210. ::testing::InitGoogleMock(&argc, argv);
  211. AzQtComponents::PrepareQtPaths();
  212. QApplication app(argc, argv);
  213. AZ::Test::printUnusedParametersWarning(argc, argv);
  214. AZ::Test::addTestEnvironments({ new UnitTest::SimulationInterfaceTestEnvironmentWithAssets() });
  215. int result = RUN_ALL_TESTS();
  216. return result;
  217. }
  218. IMPLEMENT_TEST_EXECUTABLE_MAIN();