2
0

SimulationIterfaceAppTest.cpp 9.5 KB

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