diff --git a/Jenkinsfile b/Jenkinsfile index 9375c9739a28bc749750dcc53d329c25301016bc..f47058414ba4cb4ec204fb6f3ee4bb2a427c3690 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -91,29 +91,29 @@ spec: stages { stage('Windows: Prepare openscenario_api dependency') { steps { - bat 'subst E: %WORKSPACE%' - dir('E:/') { + bat 'subst W: %WORKSPACE%' + dir('W:/') { bat 'C:\\msys64\\usr\\bin\\bash -lc repo/utils/ci/scripts/10_prepare_openscenario_api.sh' } } } stage('Windows: Configure build') { steps { - dir('E:/') { + dir('W:/') { bat 'C:\\msys64\\usr\\bin\\bash -lc repo/utils/ci/scripts/20_configure.sh' } } } stage('Windows: Build and install project') { steps { - dir('E:/') { + dir('W:/') { bat 'C:\\msys64\\usr\\bin\\bash -lc repo/utils/ci/scripts/30_build.sh' } } } stage('Windows: Build and run unit tests') { steps { - dir('E:/') { + dir('W:/') { bat 'C:\\msys64\\usr\\bin\\bash -lc repo/utils/ci/scripts/40_unit_tests.sh' } } @@ -121,7 +121,7 @@ spec: } post { always { - bat 'subst E: /d' + bat 'subst W: /d' } } } diff --git a/README.md b/README.md index 551439e12ad6a2ab1a2b0a7a96b6a3ec832907bc..a5d2bcd9f5abd4c68d9b9f8a99b5489edcee6694 100644 --- a/README.md +++ b/README.md @@ -252,11 +252,11 @@ Converts `NET_ASAM_OPENSCENARIO::v1_2::ITransitionDynamics` object type to [mant | Dependency | Commit | Version | License | | ---------- | ------ | ------- | ------- | -| [MantleAPI](https://gitlab.eclipse.org/eclipse/openpass/mantle-api) | cab24eba | | EPL 2.0 | +| [MantleAPI](https://gitlab.eclipse.org/eclipse/openpass/mantle-api) | 9a038989 | | EPL 2.0 | | [OpenSCENARIO API](https://github.com/RA-Consulting-GmbH/openscenario.api.test/) | 65f8dca | 1.3.1 | Apache 2.0 | | [YASE](https://gitlab.eclipse.org/eclipse/openpass/yase) | e687b5c4 | | EPL 2.0 | | [Units](https://github.com/nholthaus/units) | ea6d126 | | MIT License | -| [googletest](https://github.com/google/googletest) | 58d77fa | 1.12.1 | BSD-3-Clause License | +| [googletest](https://github.com/google/googletest) | f8d7d77 | 1.14.0 | BSD-3-Clause License | | [CPM](https://github.com/cpm-cmake/CPM.cmake) | 03705fc | 0.36.0 | MIT License | # Issues diff --git a/engine/deps/scenario_api b/engine/deps/scenario_api index cab24ebad3b6d8d8bb85487d7bc80c91029da566..9a038989604e8da62ecddbe2094b16ce1b778be1 160000 --- a/engine/deps/scenario_api +++ b/engine/deps/scenario_api @@ -1 +1 @@ -Subproject commit cab24ebad3b6d8d8bb85487d7bc80c91029da566 +Subproject commit 9a038989604e8da62ecddbe2094b16ce1b778be1 diff --git a/engine/src/Conversion/OscToMantle/ConvertScenarioTrafficDefinition.cpp b/engine/src/Conversion/OscToMantle/ConvertScenarioTrafficDefinition.cpp index 26b99000b01205938c9a56e5620c8e6e476c9be1..7fc2a53a94c322fe942b739098458664f9ed37cc 100644 --- a/engine/src/Conversion/OscToMantle/ConvertScenarioTrafficDefinition.cpp +++ b/engine/src/Conversion/OscToMantle/ConvertScenarioTrafficDefinition.cpp @@ -102,7 +102,7 @@ TrafficDefinition ConvertScenarioTrafficDefinition(const std::shared_ptr<NET_ASA for(const auto& vehicle_category_distribution_entry : osc_traffic_definition->GetVehicleCategoryDistribution()->GetVehicleCategoryDistributionEntries()) { auto converted{detail::ConvertVehicleCategoryDistributionEntry(vehicle_category_distribution_entry)}; - vehicle_category_distribution_entries.push_back(converted); + vehicle_category_distribution_entries.push_back(std::move(converted)); } std::vector<ControllerDistribution> controller_distribution_entries; @@ -110,7 +110,7 @@ TrafficDefinition ConvertScenarioTrafficDefinition(const std::shared_ptr<NET_ASA for(const auto& controller_distribution_entry : osc_traffic_definition->GetControllerDistribution()->GetControllerDistributionEntries()) { auto converted{detail::ConvertControllerDistributionEntry(controller_distribution_entry)}; - controller_distribution_entries.push_back(converted); + controller_distribution_entries.push_back(std::move(converted)); } return {osc_traffic_definition->GetName(), vehicle_category_distribution_entries, controller_distribution_entries}; diff --git a/engine/src/Utils/ControllerCreator.cpp b/engine/src/Utils/ControllerCreator.cpp index 53988446a9330e4ec720876a9775f9bea1e433ac..0ad917d1ae4b4d3e9cf220ab265d9110475d804a 100644 --- a/engine/src/Utils/ControllerCreator.cpp +++ b/engine/src/Utils/ControllerCreator.cpp @@ -31,18 +31,19 @@ bool IsCatalogReferenceControllableObject( return NET_ASAM_OPENSCENARIO::v1_2::CatalogHelper::IsVehicle(catalog_element) || NET_ASAM_OPENSCENARIO::v1_2::CatalogHelper::IsPedestrian(catalog_element); } - throw std::runtime_error("ControllerCreator: CatalogReference " + catalog_reference->GetEntryName() + + throw std::runtime_error("ControllerCreator: CatalogReference \"" + catalog_reference->GetEntryName() + "\"" + " for entity object cannot be resolved."); } auto CreateExternalControllerConfig( + const std::string& controller_name, const std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IController>& controller) { auto external_config = std::make_unique<mantle_api::ExternalControllerConfig>(); if (controller) { - external_config->name = controller->GetName(); + external_config->name = controller_name; for (const auto& property : controller->GetProperties()->GetProperties()) { external_config->parameters.emplace(property->GetName(), property->GetValue()); @@ -52,12 +53,11 @@ auto CreateExternalControllerConfig( return external_config; } -auto CreateExternalControllerConfig( - const std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IObjectController>& object_controller) +std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IController> Parse(const std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IObjectController>& object_controller) { if (auto controller = object_controller->GetController()) { - return detail::CreateExternalControllerConfig(controller); + return controller; } if (auto catalog_reference = object_controller->GetCatalogReference()) { @@ -65,9 +65,9 @@ auto CreateExternalControllerConfig( NET_ASAM_OPENSCENARIO::v1_2::CatalogHelper::IsController(ref)) { const auto& controller = NET_ASAM_OPENSCENARIO::v1_2::CatalogHelper::AsController(ref); - return detail::CreateExternalControllerConfig(controller); + return controller; } - throw std::runtime_error("ControllerCreator: CatalogReference " + catalog_reference->GetEntryName() + + throw std::runtime_error("ControllerCreator: CatalogReference \"" + catalog_reference->GetEntryName() + "\"" + " for object controller cannot be resolved."); } throw std::runtime_error( @@ -76,13 +76,20 @@ auto CreateExternalControllerConfig( "Please correct the scenario."); } +auto CreateExternalControllerConfig( + const std::string& controller_name, + const std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IObjectController>& object_controller) +{ + return detail::CreateExternalControllerConfig(controller_name, detail::Parse(object_controller)); +} + bool IsNotControllable(const std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IScenarioObject>& scenario_object) { auto entity_object = scenario_object->GetEntityObject(); if (!entity_object) { - throw std::runtime_error("ControllerCreator: EntityObject missing in ScenarioObject " + scenario_object->GetName()); + throw std::runtime_error("ControllerCreator: EntityObject missing in ScenarioObject \"" + scenario_object->GetName() + "\""); } if (entity_object->GetVehicle() || entity_object->GetPedestrian()) @@ -128,14 +135,14 @@ void ControllerCreator::CreateControllers(const std::vector<std::shared_ptr<NET_ const auto entity_name = scenario_object->GetName(); if (detail::IsNotControllable(scenario_object)) { - Logger::Info("ControllerCreator: No controller created for non-vehicle and non-pedestrian type scenario object " + entity_name); + Logger::Info("ControllerCreator: No controller created for non-vehicle and non-pedestrian type scenario object \"" + entity_name + "\""); return; } const auto entity = environment_.GetEntityRepository().Get(entity_name); if (!entity.has_value()) { - throw std::runtime_error("ControllerCreator: Trying to create controller for unavailable entity " + entity_name); + throw std::runtime_error("ControllerCreator: Trying to create controller for unavailable entity \"" + entity_name + "\""); } auto& controller_repository = environment_.GetControllerRepository(); @@ -170,11 +177,12 @@ ControllerRegistrar::ControllerRegistrar( void ControllerRegistrar::CreateDefaultController() { - Logger::Info("ControllerCreator: Setting up internal controller for entity " + entity_name_); + Logger::Info("ControllerCreator: Setting up internal controller for entity \"" + entity_name_ + "\""); auto default_config = std::make_unique<mantle_api::InternalControllerConfig>(); default_config->control_strategies.push_back(std::make_unique<mantle_api::KeepVelocityControlStrategy>()); default_config->control_strategies.push_back(std::make_unique<mantle_api::KeepLaneOffsetControlStrategy>()); + default_config->name = CONTROLLER_NAME_DEFAULT; auto& controller = controller_repository_.Create(std::move(default_config)); RegisterDefaultController(controller); } @@ -185,9 +193,11 @@ void ControllerRegistrar::CreateUserDefinedControllers(bool control_override) { if (control_override && IsDrivingFunctionControlledEntity(entity_name_)) { - // Empty external controller, as control override is active - auto& controller = controller_repository_.Create( - std::make_unique<mantle_api::ExternalControllerConfig>()); + auto external_config = std::make_unique<mantle_api::ExternalControllerConfig>(); + external_config->name = CONTROLLER_NAME_OVERRIDE; + + Logger::Info("ControllerRegistrar: Setting up external controller \"" + external_config->name + "\" for entity \"" + entity_name_ + "\""); + auto& controller = controller_repository_.Create(std::move(external_config)); RegisterUserDefinedController(controller); } } @@ -195,9 +205,10 @@ void ControllerRegistrar::CreateUserDefinedControllers(bool control_override) { for (const auto& object_controller : object_controllers_) { - Logger::Info("ControllerRegistrar: Setting up external controller for entity " + entity_name_); + auto controller_name = detail::Parse(object_controller)->GetName(); + auto external_config = detail::CreateExternalControllerConfig(controller_name, object_controller); - auto external_config = detail::CreateExternalControllerConfig(object_controller); + Logger::Info("ControllerRegistrar: Setting up external controller \"" + external_config->name + "\" for entity \"" + entity_name_ + "\""); auto& controller = controller_repository_.Create(std::move(external_config)); RegisterUserDefinedController(controller); } diff --git a/engine/src/Utils/ControllerCreator.h b/engine/src/Utils/ControllerCreator.h index 2bb5e6cf0250e7d5a431a2df8143c5e568fcddc0..636a140eb101794921b227d6a476272527c52cab 100644 --- a/engine/src/Utils/ControllerCreator.h +++ b/engine/src/Utils/ControllerCreator.h @@ -19,6 +19,10 @@ namespace OpenScenarioEngine::v1_2 { + +static constexpr const char* CONTROLLER_NAME_DEFAULT {"OpenScenarioEngine::v1_2::Default"}; +static constexpr const char* CONTROLLER_NAME_OVERRIDE {"OpenScenarioEngine::v1_2::ExternalOverride"}; + class ControllerService; class ControllerCreator @@ -56,9 +60,9 @@ public: void CreateUserDefinedControllers(bool control_override); private: - void RegisterController(mantle_api::IController& controller, bool is_default); void RegisterDefaultController(mantle_api::IController& controller); void RegisterUserDefinedController(mantle_api::IController& controller); + void RegisterController(mantle_api::IController& controller, bool is_default); const std::vector<std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IObjectController>> object_controllers_; const std::string& entity_name_; diff --git a/engine/tests/OpenScenarioEngineTest.cpp b/engine/tests/OpenScenarioEngineTest.cpp index 15bb0b4ebd3c2516a4e5df676f341f95063dbf21..4634783b9525573b34b98c51d5bc390bd77c5a17 100644 --- a/engine/tests/OpenScenarioEngineTest.cpp +++ b/engine/tests/OpenScenarioEngineTest.cpp @@ -29,6 +29,7 @@ using testing::_; using testing::Return; using testing::ReturnRef; using testing::Pointee; +using testing::SaveArgPointee; using namespace units::literals; using namespace std::string_literals; @@ -36,7 +37,7 @@ using namespace std::string_literals; class OpenScenarioEngineTest : public OpenScenarioEngineTestBase { protected: - void SetUp() override { + void SetUp() override { OpenScenarioEngineTestBase::SetUp(); ON_CALL(controller_, GetName()).WillByDefault(ReturnRef(controller_name)); ON_CALL(controller_, GetUniqueId()).WillByDefault(Return(1234)); @@ -256,26 +257,63 @@ TEST_F(OpenScenarioEngineTest, GivenScenarioWithEntities_WhenInitScenario_ThenCr EXPECT_NO_THROW(engine.Init()); } + + TEST_F(OpenScenarioEngineTest, GivenScenarioWithExternallyControlledEntity_WhenInit_ThenControllerWithExternalConfigIsCreatedAndAssigned) { std::string xosc_file_path{GetScenariosPath(test_info_->file()) + default_xosc_scenario_}; OpenScenarioEngine::v1_2::OpenScenarioEngine engine(xosc_file_path, env_); - mantle_api::InternalControllerConfig internal_controller_config{}; - internal_controller_config.control_strategies = { - std::make_unique<mantle_api::KeepVelocityControlStrategy>(), - std::make_unique<mantle_api::KeepLaneOffsetControlStrategy>()}; + mantle_api::MockController mock_default_controller; + const mantle_api::UniqueId DEFAULT_CONTROLLER_ID {1234}; + const std::string DEFAULT_CONTROLLER_NAME {"TestDefaultController"}; + ON_CALL(mock_default_controller, GetUniqueId()).WillByDefault(Return(DEFAULT_CONTROLLER_ID)); + ON_CALL(mock_default_controller, GetName()).WillByDefault(ReturnRef(DEFAULT_CONTROLLER_NAME)); + + mantle_api::MockController mock_user_defined_controller; + const mantle_api::UniqueId USER_DEFINED_CONTROLLER_ID {5678}; + const std::string USER_DEFINED_CONTROLLER_NAME {"TestUserDefinedController"}; + ON_CALL(mock_user_defined_controller, GetUniqueId()).WillByDefault(Return(USER_DEFINED_CONTROLLER_ID)); + ON_CALL(mock_user_defined_controller, GetName()).WillByDefault(ReturnRef(USER_DEFINED_CONTROLLER_NAME)); + + mantle_api::InternalControllerConfig internal_config_actual; + mantle_api::ExternalControllerConfig external_config_actual; + ON_CALL(env_->GetControllerRepository(), Create(_)) + .WillByDefault(::testing::Invoke([&](std::unique_ptr<mantle_api::IControllerConfig> received_controller) -> mantle_api::IController& + { + if (auto internal = dynamic_cast<mantle_api::InternalControllerConfig*>(received_controller.get())) + { + internal_config_actual = *internal; // copy assignment, as we drop the unique_ptr + return mock_default_controller; + } - mantle_api::ExternalControllerConfig external_controller_config{}; - external_controller_config.name = "ALKSController", - external_controller_config.parameters.emplace("controller_property", "3"); + if (auto external = dynamic_cast<mantle_api::ExternalControllerConfig*>(received_controller.get())) + { + external_config_actual = *external; // copy assignment, as we drop the unique_ptr + return mock_user_defined_controller; + } + + throw std::runtime_error("Untested ControllerConfigType"); + })); - EXPECT_CALL(env_->GetControllerRepository(), Create(Pointee(internal_controller_config))); - EXPECT_CALL(env_->GetControllerRepository(), Create(Pointee(external_controller_config))); - EXPECT_CALL(*env_, AddEntityToController(_, 1234)).Times(2); + EXPECT_CALL(*env_, AddEntityToController(_, DEFAULT_CONTROLLER_ID)); + EXPECT_CALL(*env_, AddEntityToController(_, USER_DEFINED_CONTROLLER_ID)); EXPECT_NO_THROW(engine.Init()); + + mantle_api::InternalControllerConfig internal_config_expected{}; + internal_config_expected.name = OpenScenarioEngine::v1_2::CONTROLLER_NAME_DEFAULT; + internal_config_expected.control_strategies = { + std::make_shared<mantle_api::KeepVelocityControlStrategy>(), + std::make_shared<mantle_api::KeepLaneOffsetControlStrategy>()}; + + mantle_api::ExternalControllerConfig external_config_expected{}; + external_config_expected.name = "ALKSController", + external_config_expected.parameters.emplace("controller_property", "3"); + + EXPECT_EQ(internal_config_expected, internal_config_actual); + EXPECT_EQ(external_config_expected, external_config_actual); } TEST_F(OpenScenarioEngineTest, GivenScenarioWithInitTeleportAction_WhenInitAndStepEngine_ThenSetPositionIsCalled)