diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..1713f9f0 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,37 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Refresh compile_commands.json", + "type": "shell", + "isBackground": true, + "command": "bazel run @hedron_compile_commands//:refresh_all", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": false + }, + "presentation": { + "reveal": "always", + "panel": "shared" + } + }, + { + "label": "Refresh IntelliSense", + "dependsOn": [ + "Refresh compile_commands.json" + ], + "command": "${command:clangd.restart}", + "isBackground": true, + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "silent", + "panel": "shared" + } + } + ] +} diff --git a/README.md b/README.md index f0fbc37f..d8950555 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This section contains information on how to build and use Lifecycle feature. * Build System: Bazel * Operating System: Linux (Ubuntu 22.04+) * Dependencies: S-Core Baselibs, Google Flatbuffers, libacl1-dev -* Dependencies of demo applications: Docker, Python (3.12) +* Dependencies of example applications: Docker, Python (3.12) ## Building the project @@ -122,7 +122,7 @@ TODO: Currently rust binaries are not compiling for QNX. ## Running Lifecycle feature and example applications -The ``demo`` folder contains a demo setup running in a docker container, consisting of a set of example applications and corresponding configuration. As per configuration, Launch Manager will start Health Monitor and a set of configured applications. For more information see [demo/README.md](demo/README.md) file. +The ``examples`` folder contains a demo setup running in a docker container, consisting of a set of example applications and corresponding configuration. As per configuration, Launch Manager will start Health Monitor and a set of configured applications. For more information see [examples/README.md](examples/README.md) file. ## Configuration @@ -444,7 +444,7 @@ Sample configuration of Health Monitor daemon: } ``` -Full configuration for example applications can be found in ``demo/config`` folder. +Full configuration for example applications can be found in ``examples/config`` folder. # Architecture diff --git a/examples/control_application/control_daemon.cpp b/examples/control_application/control_daemon.cpp index 9c8cd91d..5cd0533e 100644 --- a/examples/control_application/control_daemon.cpp +++ b/examples/control_application/control_daemon.cpp @@ -40,7 +40,7 @@ int main(int argc, char** argv) { } score::lcm::ControlClient client([](const score::lcm::ExecutionErrorEvent& event) { - std::cerr << "Undefined state callback invoked for process group id: " << event.processGroup.data() << std::endl; + std::cerr << "Undefined state callback invoked for process group id: " << event.processGroup << std::endl; }); score::safecpp::Scope<> scope{}; diff --git a/src/launch_manager_daemon/BUILD b/src/launch_manager_daemon/BUILD index a18d5545..1822430c 100644 --- a/src/launch_manager_daemon/BUILD +++ b/src/launch_manager_daemon/BUILD @@ -12,6 +12,8 @@ # ******************************************************************************* load("//config:common_cc.bzl", "cc_binary_with_common_opts", "cc_library_with_common_opts") +package(default_visibility = ["//tests:__subpackages__"]) + cc_library( name = "config", hdrs = ["config/lm_flatcfg_generated.h"], diff --git a/src/launch_manager_daemon/common/include/score/lcm/identifier_hash.hpp b/src/launch_manager_daemon/common/include/score/lcm/identifier_hash.hpp index 0160bdfc..8fe24d1f 100644 --- a/src/launch_manager_daemon/common/include/score/lcm/identifier_hash.hpp +++ b/src/launch_manager_daemon/common/include/score/lcm/identifier_hash.hpp @@ -11,18 +11,21 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ - #ifndef IDENTIFIER_HASH_H_ #define IDENTIFIER_HASH_H_ #include - +#include +#include #include #include +#include -namespace score { +namespace score +{ -namespace lcm { +namespace lcm +{ /// @file identifier_hash.hpp /// @brief This file contains the declaration of the IdentifierHash class, @@ -36,8 +39,9 @@ namespace lcm { /// @details The class is designed to be used in contexts where IDs needs to be managed, /// compared, and manipulated. It ensures that IDs are handled efficiently and provides /// necessary operators and functions for common operations. -class IdentifierHash final { - public: +class IdentifierHash final +{ + public: /// @brief Constructs an IdentifierHash object from the given ID. /// @param id A const reference to std::string representing an ID. explicit IdentifierHash(const std::string& id); @@ -85,8 +89,8 @@ class IdentifierHash final { bool operator<(const IdentifierHash& other) const; // Overloaded operator for comparison ///@brief Default constructor for the IdentifierHash class. - ///This constructor initializes the IdentifierHash object with a default ID value. - ///The ID value is calculated by hashing an empty string using std::hash. + /// This constructor initializes the IdentifierHash object with a default ID value. + /// The ID value is calculated by hashing an empty string using std::hash. // this constructor is used in the code that is not part of the POC // not sure if we should have this constructor or not, but there is code like this: @@ -116,11 +120,46 @@ class IdentifierHash final { /// @return A constant reference to the data stored in the IdentifierHash object. std::size_t data() const; - private: + /// @brief Returns the registry mapping hash values to their corresponding string representations. + /// + /// Static registry, which gets initialized per process. + /// + /// @return A reference to the static unordered_map that serves as the registry. + static std::unordered_map& get_registry(); + + private: /// internal representation of the ID, that was passed in constructor std::size_t hash_id_ = 0; }; +/// @brief Overloaded stream insertion operator for IdentifierHash. +/// +/// This operator allows IdentifierHash objects to be output to an ostream. +/// It uses the the static registry to find the string representation of the hash ID. +/// +/// If there is no value stored in the registry for the given hash +/// (i.e. the IdentifierHash is not constructed in this process, +/// instead it has been transferred from another process via e.g. shared memory), +/// it outputs an error message. +/// +/// @param os The output stream. +/// @param id The IdentifierHash object to output. +/// @return A reference to the output stream. +inline std::ostream& operator<<(std::ostream& os, const IdentifierHash& id) +{ + const auto& reg = IdentifierHash::get_registry(); + const auto it = reg.find(id.data()); + if (it != reg.end()) + { + os << it->second; + } + else + { + os << ""; + } + return os; +} + } // namespace lcm } // namespace score diff --git a/src/launch_manager_daemon/common/src/identifier_hash.cpp b/src/launch_manager_daemon/common/src/identifier_hash.cpp index 078203ce..56910a01 100644 --- a/src/launch_manager_daemon/common/src/identifier_hash.cpp +++ b/src/launch_manager_daemon/common/src/identifier_hash.cpp @@ -13,10 +13,13 @@ #include #include +#include -namespace score { +namespace score +{ -namespace lcm { +namespace lcm +{ // Please note that a lot of the following info, would normally belong to identifier_hash.hpp file. // However, decision was made to publish identifier_hash.hpp alongside other headers. @@ -55,47 +58,68 @@ namespace lcm { // One thing to note: hashing function is implementation specific. // So if this should work between different compilers, we may need to go for our own hash function. -IdentifierHash::IdentifierHash(const std::string& id) { +IdentifierHash::IdentifierHash(const std::string& id) +{ hash_id_ = std::hash{}(id); + get_registry()[hash_id_] = id; } -IdentifierHash::IdentifierHash(std::string_view id) { +IdentifierHash::IdentifierHash(std::string_view id) +{ hash_id_ = std::hash{}(id); + get_registry()[hash_id_] = id; } -IdentifierHash::IdentifierHash(const char* id) { - hash_id_ = - std::hash{}(id != nullptr ? std::string_view(id) : std::string_view("")); +IdentifierHash::IdentifierHash(const char* id) +{ + const std::string_view sv = (id != nullptr) ? std::string_view(id) : std::string_view(""); + hash_id_ = std::hash{}(sv); + get_registry()[hash_id_] = sv; } -bool IdentifierHash::operator==(const IdentifierHash& other) const { +bool IdentifierHash::operator==(const IdentifierHash& other) const +{ return hash_id_ == other.hash_id_; } -bool IdentifierHash::operator!=(const IdentifierHash& other) const { +bool IdentifierHash::operator!=(const IdentifierHash& other) const +{ return !operator==(other); } -bool IdentifierHash::operator==(const std::string_view& other) const { +bool IdentifierHash::operator==(const std::string_view& other) const +{ return hash_id_ == (IdentifierHash{other}).hash_id_; } -bool IdentifierHash::operator!=(const std::string_view& other) const { +bool IdentifierHash::operator!=(const std::string_view& other) const +{ return !operator==(IdentifierHash{other}); } -bool IdentifierHash::operator<(const IdentifierHash& other) const { +bool IdentifierHash::operator<(const IdentifierHash& other) const +{ return hash_id_ < other.hash_id_; } -IdentifierHash::IdentifierHash() { +IdentifierHash::IdentifierHash() +{ hash_id_ = std::hash{}(std::string_view("")); + get_registry()[hash_id_] = ""; } -std::size_t IdentifierHash::data() const { +std::size_t IdentifierHash::data() const +{ return hash_id_; } +std::unordered_map& IdentifierHash::get_registry() +{ + /// Static registry, which gets initialized per process. + static std::unordered_map registry; + return registry; +} + } // namespace lcm } // namespace score diff --git a/src/launch_manager_daemon/health_monitor_lib/src/score/lcm/saf/ifexm/ProcessStateReader.cpp b/src/launch_manager_daemon/health_monitor_lib/src/score/lcm/saf/ifexm/ProcessStateReader.cpp index 1b1bf1a9..a7b44e94 100644 --- a/src/launch_manager_daemon/health_monitor_lib/src/score/lcm/saf/ifexm/ProcessStateReader.cpp +++ b/src/launch_manager_daemon/health_monitor_lib/src/score/lcm/saf/ifexm/ProcessStateReader.cpp @@ -79,8 +79,8 @@ bool ProcessStateReader::distributeChanges(const timers::NanoSecondType f_syncTi const auto changedPosixProcess{resultChangedProcess.value()}; if (changedPosixProcess) { - logger_r.LogDebug() << "Process with Id" << changedPosixProcess->id.data() << "changed state PG" - << changedPosixProcess->processGroupStateId.data() << "PS" + logger_r.LogDebug() << "Process with Id" << changedPosixProcess->id << "changed state PG" + << changedPosixProcess->processGroupStateId << "PS" << static_cast(changedPosixProcess->processStateId); isPushPending = pushUpdateTill(*changedPosixProcess, f_syncTimestamp); flagContinue = (!isPushPending); diff --git a/src/launch_manager_daemon/src/configuration_manager/configurationmanager.cpp b/src/launch_manager_daemon/src/configuration_manager/configurationmanager.cpp index a3279e1e..0d79443d 100644 --- a/src/launch_manager_daemon/src/configuration_manager/configurationmanager.cpp +++ b/src/launch_manager_daemon/src/configuration_manager/configurationmanager.cpp @@ -126,10 +126,10 @@ std::optional ConfigurationManager::getMainPGStartup if (pg_state) { result = &main_pg_startup_state_; } else { - LM_LOG_DEBUG() << "Process group state not found:" << main_pg_startup_state_.pg_state_name_.data(); + LM_LOG_DEBUG() << "Process group state not found:" << main_pg_startup_state_.pg_state_name_; } } else { - LM_LOG_DEBUG() << "Process group not found:" << main_pg_startup_state_.pg_name_.data(); + LM_LOG_DEBUG() << "Process group not found:" << main_pg_startup_state_.pg_name_; } return result; @@ -154,8 +154,8 @@ std::optional*> ConfigurationManager::getProcessInde if (state) { result = &state->process_indexes_; } else { - LM_LOG_DEBUG() << "Process group state '" << pg_state_id.pg_state_name_.data() << "' not found in group '" - << pg_state_id.pg_name_.data() << "'."; + LM_LOG_DEBUG() << "Process group state '" << pg_state_id.pg_state_name_ << "' not found in group '" + << pg_state_id.pg_name_ << "'."; } return result; @@ -168,7 +168,7 @@ std::optional ConfigurationManager::getOsProcessConfiguration( if (auto pg = getProcessGroupByNameAndIndex(pg_name, index)) { result = &(*pg)->processes_[index]; } else { - LM_LOG_DEBUG() << "Unable to retrieve process configuration for process group" << pg_name.data() + LM_LOG_DEBUG() << "Unable to retrieve process configuration for process group" << pg_name << "with index" << index; } @@ -182,7 +182,7 @@ std::optional ConfigurationManager::getOsProcessDependenc if (auto pg = getProcessGroupByNameAndIndex(pg_name, index)) { result = &(*pg)->processes_[index].dependencies_; } else { - LM_LOG_DEBUG() << "Unable to retrieve process dependencies for process group" << pg_name.data() << "with index" + LM_LOG_DEBUG() << "Unable to retrieve process dependencies for process group" << pg_name << "with index" << index; } @@ -304,7 +304,7 @@ bool ConfigurationManager::parseMachineConfigurations(const ModeGroup* node, con process_group_data.name_ = getStringViewFromFlatBuffer(node->identifier()); process_group_data.sw_cluster_ = cluster; LM_LOG_DEBUG() << "FlatBufferParser::getModeGroupPgName:" << getStringFromFlatBuffer(node->identifier()) - << "( IdentifierHash:" << process_group_data.name_.data() << ")"; + << "( IdentifierHash:" << process_group_data.name_ << ")"; if (process_group_data.name_ != score::lcm::IdentifierHash(std::string_view(""))) { // Add process group name to the PG name list @@ -339,7 +339,7 @@ bool ConfigurationManager::parseModeGroups(const ModeGroup* node, ProcessGroup& pg_state.name_ = getStringViewFromFlatBuffer(flatbuffer_string); LM_LOG_DEBUG() << "FlatBufferParser::getModeGroupPgStateName:" << mode_declaration_node->identifier()->c_str() - << "( IdentifierHash:" << pg_state.name_.data() << ")"; + << "( IdentifierHash:" << pg_state.name_ << ")"; process_group_data.states_.push_back(pg_state); // Is this the "Off" state, i.e. does it end with "/Off" ? auto str_len = string_name.length(); @@ -593,8 +593,8 @@ void ConfigurationManager::parseProcessGroup( ProcessGroupStateID pg_info; pg_info.pg_name_ = getStringViewFromFlatBuffer(process_pg_node->stateMachine_name()); pg_info.pg_state_name_ = getStringViewFromFlatBuffer(process_pg_node->stateName()); - LM_LOG_DEBUG() << "ParseProcessProcessGroup: id:::pg_name_:" << pg_info.pg_name_.data() - << ", pg_state_name_:" << pg_info.pg_state_name_.data(); + LM_LOG_DEBUG() << "ParseProcessProcessGroup: id:::pg_name_:" << pg_info.pg_name_ + << ", pg_state_name_:" << pg_info.pg_state_name_; // Assign OsProcess instance to the process group AssignOsProcessInstanceToProcessGroup(pg_info, process_instance); @@ -618,7 +618,7 @@ void ConfigurationManager::parseExecutionDependency( dep.target_process_id_ = getStringViewFromFlatBuffer(process_dependency_node->targetProcess_identifier()); LM_LOG_DEBUG() << "ParseProcessExecutionDependency: target process path:" << getStringFromFlatBuffer(process_dependency_node->targetProcess_identifier()) - << "ID:" << dep.target_process_id_.data(); + << "ID:" << dep.target_process_id_; process_instance.dependencies_.push_back(dep); } @@ -715,10 +715,10 @@ void ConfigurationManager::AssignOsProcessInstanceToProcessGroup(const ProcessGr state->process_indexes_.push_back(index_in_pg); } } else { - LM_LOG_WARN() << "Process group state not found:" << process_pg.pg_state_name_.data(); + LM_LOG_WARN() << "Process group state not found:" << process_pg.pg_state_name_; } } else { - LM_LOG_WARN() << "Process group not found:", process_pg.pg_name_.data(); + LM_LOG_WARN() << "Process group not found:" << process_pg.pg_name_; } } @@ -827,10 +827,10 @@ osal::CommsType ConfigurationManager::isReportingProcess(const ExecutionStateRep if (reporting_behaviour == ExecutionStateReportingBehaviorEnum::ExecutionStateReportingBehaviorEnum_ReportsExecutionState) { reporting_status = osal::CommsType::kReporting; - LM_LOG_DEBUG() << "Process" << process_name.data() << "is Reporting execution state"; + LM_LOG_DEBUG() << "Process" << process_name << "is Reporting execution state"; } else { // ExecutionStateReportingBehaviorEnum::DoesNotReportExecutionState - LM_LOG_DEBUG() << "Process" << process_name.data() << "is NOT Reporting execution state"; + LM_LOG_DEBUG() << "Process" << process_name << "is NOT Reporting execution state"; } return reporting_status; @@ -842,10 +842,10 @@ bool ConfigurationManager::isSelfTerminatingProcess(const TerminationBehaviorEnu if (termination_behavior == TerminationBehaviorEnum::TerminationBehaviorEnum_ProcessIsSelfTerminating) { termination_status = true; - LM_LOG_DEBUG() << "Process" << process_name.data() << "is Self terminating"; + LM_LOG_DEBUG() << "Process" << process_name << "is Self terminating"; } else { // TerminationBehaviorEnum::ProcessIsNotSelfTerminating - LM_LOG_DEBUG() << "Process" << process_name.data() << "is NOT Self terminating"; + LM_LOG_DEBUG() << "Process" << process_name << "is NOT Self terminating"; } return termination_status; @@ -861,10 +861,10 @@ std::optional ConfigurationManager::getProcessGroupByNameAn if (index < pg->processes_.size()) { result = pg; } else { - LM_LOG_DEBUG() << "Process index" << index << "is out of bounds in process group" << pg_name.data(); + LM_LOG_DEBUG() << "Process index" << index << "is out of bounds in process group" << pg_name; } } else { - LM_LOG_DEBUG() << "Process group not found:" << pg_name.data(); + LM_LOG_DEBUG() << "Process group not found:" << pg_name; } return result; diff --git a/src/launch_manager_daemon/src/process_group_manager/graph.cpp b/src/launch_manager_daemon/src/process_group_manager/graph.cpp index 4de7baac..5866c0b5 100644 --- a/src/launch_manager_daemon/src/process_group_manager/graph.cpp +++ b/src/launch_manager_daemon/src/process_group_manager/graph.cpp @@ -62,7 +62,7 @@ void Graph::initProcessGroupNodes( IdentifierHash pg_name, uint32_t num_processe requested_state_.pg_state_name_ = off_state_; requested_state_.pg_name_ = pg_name; - LM_LOG_DEBUG() << "Process group index" << index << "(with name" << pg_name.data() << ") has" << num_processes + LM_LOG_DEBUG() << "Process group index" << index << "(with name" << pg_name << ") has" << num_processes << "processes"; createProcessInfoNodes(num_processes); @@ -84,7 +84,7 @@ inline void Graph::createProcessInfoNodes(uint32_t num_processes) { } inline void Graph::createSuccessorLists(IdentifierHash pg_name) { - LM_LOG_DEBUG() << "Creating successor lists for process group" << pg_name.data(); + LM_LOG_DEBUG() << "Creating successor lists for process group" << pg_name; // Now create the successor lists for each process in this process group for (auto& node : nodes_) { @@ -128,7 +128,7 @@ void Graph::setState(GraphState new_state) { if (state_.compare_exchange_strong(old_state, target_state)) { LM_LOG_DEBUG() << "Graph::setState changes from" << toString(old_state) << "to" << toString(target_state) << "for PG" << pg_index_ << "(" - << requested_state_.pg_name_.data() << ")"; + << requested_state_.pg_name_ << ")"; old_state = target_state; if (new_state == GraphState::kSuccess) { @@ -139,8 +139,8 @@ void Graph::setState(GraphState new_state) { auto timeDiff = std::chrono::duration_cast(request_end_time - getRequestStartTime()); - LM_LOG_INFO() << "Completed the request for PG" << getProcessGroupName().data() << "to State" - << getProcessGroupState().data() << "in" << timeDiff.count() << "ms"; + LM_LOG_INFO() << "Completed the request for PG" << getProcessGroupName() << "to State" + << getProcessGroupState() << "in" << timeDiff.count() << "ms"; } } } @@ -440,8 +440,8 @@ IdentifierHash Graph::setPendingState(IdentifierHash new_state) { pending_state_ = new_state; if (new_state != result_state) { - LM_LOG_DEBUG() << "Pending state for process group" << requested_state_.pg_name_.data() << "changed from" - << result_state.data() << "to" << pending_state_.data(); + LM_LOG_DEBUG() << "Pending state for process group" << requested_state_.pg_name_ << "changed from" + << result_state << "to" << pending_state_; } return result_state; diff --git a/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp b/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp index dde42d37..3d8e3d99 100644 --- a/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp +++ b/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp @@ -363,8 +363,8 @@ bool ProcessGroupManager::sendResponse(ControlClientMessage msg) { LM_LOG_DEBUG() << "ProcessGroupManager::ControlClientHandler: Sending" << scc->toString(msg.request_or_response_) << "(" << static_cast(msg.request_or_response_) << ") re state" - << msg.process_group_state_.pg_state_name_.data() << "of PG" - << msg.process_group_state_.pg_name_.data(); + << msg.process_group_state_.pg_state_name_ << "of PG" + << msg.process_group_state_.pg_name_; ret = scc->sendResponse(msg); if (!ret) { ControlClientChannel::nudgeControlClientHandler(); @@ -395,8 +395,8 @@ inline void ProcessGroupManager::controlClientRequests(Graph& pg) { LM_LOG_DEBUG() << "ProcessGroupManager::ControlClientHandler: got request" << scc->toString(scc->request().request_or_response_) << "(" << static_cast(scc->request().request_or_response_) << ") re state" - << scc->request().process_group_state_.pg_state_name_.data() << "of PG" - << scc->request().process_group_state_.pg_name_.data(); + << scc->request().process_group_state_.pg_state_name_ << "of PG" + << scc->request().process_group_state_.pg_name_; // Now process the request switch (scc->request().request_or_response_) { @@ -583,7 +583,7 @@ inline void ProcessGroupManager::processGroupHandler(Graph& pg) { if ((pgs.pg_state_name_ != IdentifierHash("")) && ((pgs.pg_state_name_ != pg.getProcessGroupState()) || (GraphState::kUndefinedState == graph_state))) { pgs.pg_name_ = pg.getProcessGroupName(); - LM_LOG_DEBUG() << "Start transition to" << pgs.pg_state_name_.data() << "for PG" << pgs.pg_name_.data(); + LM_LOG_DEBUG() << "Start transition to" << pgs.pg_state_name_ << "for PG" << pgs.pg_name_; if (!pg.startTransition(pgs)) { pg.setPendingEvent(ControlClientCode::kSetStateInvalidArguments); @@ -607,7 +607,7 @@ inline void ProcessGroupManager::processGroupHandler(Graph& pg) { recovery_state.pg_state_name_ = configuration_manager_.getNameOfRecoveryState(recovery_state.pg_name_); LM_LOG_WARN() << "Problem discovered in PG" - << recovery_state.pg_name_.data() + << recovery_state.pg_name_ << "Activating Recovery state."; // no point checking errors here... diff --git a/src/launch_manager_daemon/src/process_group_manager/processinfonode.cpp b/src/launch_manager_daemon/src/process_group_manager/processinfonode.cpp index 5a180fa5..57f2adb0 100644 --- a/src/launch_manager_daemon/src/process_group_manager/processinfonode.cpp +++ b/src/launch_manager_daemon/src/process_group_manager/processinfonode.cpp @@ -48,7 +48,7 @@ void ProcessInfoNode::initNode(Graph* graph, uint32_t index) { LM_LOG_DEBUG() << "Process" << process_index_ << "has" << start_dependencies_ << "start dependencies"; } } else { - LM_LOG_ERROR() << "No configuration for process" << process_index_ << "of process group" << pg.data(); + LM_LOG_ERROR() << "No configuration for process" << process_index_ << "of process group" << pg; } } } @@ -202,7 +202,7 @@ void ProcessInfoNode::unexpectedTermination() { } void ProcessInfoNode::terminated(int32_t process_status) { - LM_LOG_DEBUG() << "Child process" << process_index_ << "of" << graph_->getProcessGroupName().data() << "pid" + LM_LOG_DEBUG() << "Child process" << process_index_ << "of" << graph_->getProcessGroupName() << "pid" << pid_ << "(" << config_->startup_config_.short_name_ << ") for node" << this << "terminated with status" << process_status; status_ = process_status; @@ -270,7 +270,7 @@ void ProcessInfoNode::startProcess() { } sync_.reset(); } while ((status_ != 0) && (restart_counter_-- != 0U)); - LM_LOG_DEBUG() << "startProcess for" << graph_->getProcessGroupName().data() << "process" << process_index_ << "(" + LM_LOG_DEBUG() << "startProcess for" << graph_->getProcessGroupName() << "process" << process_index_ << "(" << config_->startup_config_.short_name_ << ") done"; } @@ -315,7 +315,7 @@ void ProcessInfoNode::handleProcessAlreadyTerminated(uint32_t execution_error_co // and to have exited with zero status LM_LOG_WARN() << "Got process termination before kRunning for pid" << pid_ << "(" << config_->startup_config_.short_name_ << ") process" << process_index_ << "of group" - << graph_->getProcessGroupName().data(); + << graph_->getProcessGroupName(); //This will cause the graph to fail, we must report to SM (unless we have restart attempts left) if (0U == restart_counter_) { graph_->abort(execution_error_code, ControlClientCode::kFailedUnexpectedTerminationOnEnter); @@ -349,10 +349,10 @@ void ProcessInfoNode::handleProcessRunning(uint32_t execution_error_code) { if (osal::CommsType::kNoComms == config_->startup_config_.comms_type_) { LM_LOG_DEBUG() << "Considered kRunning for Non Reporting Process pid" << pid_ << "(" << config_->startup_config_.short_name_ << ") process" << process_index_ << "of group" - << graph_->getProcessGroupName().data(); + << graph_->getProcessGroupName(); } else { LM_LOG_DEBUG() << "Got kRunning for pid" << pid_ << "(" << config_->startup_config_.short_name_ << ") process" - << process_index_ << "of group" << graph_->getProcessGroupName().data(); + << process_index_ << "of group" << graph_->getProcessGroupName(); } // kRunning has already been reported (or assumed) @@ -403,7 +403,7 @@ void ProcessInfoNode::terminateProcess() { if (!graph_->isStarting() || (0 == status_)) { queueTerminationSuccessorJobs(); } - LM_LOG_DEBUG() << "terminateProcess for" << graph_->getProcessGroupName().data() << "process" << process_index_ + LM_LOG_DEBUG() << "terminateProcess for" << graph_->getProcessGroupName() << "process" << process_index_ << "(" << config_->startup_config_.short_name_ << ") done"; } @@ -413,7 +413,7 @@ inline void ProcessInfoNode::handleTerminationProcess() { terminator_.init(0U, false); has_semaphore_.store(true); LM_LOG_DEBUG() << "Requesting termination of process" << process_index_ << "of" - << graph_->getProcessGroupName().data() << "pid" << pid_ << "(" + << graph_->getProcessGroupName() << "pid" << pid_ << "(" << config_->startup_config_.short_name_ << ")"; //handle request termination diff --git a/tests/ut/identifier_hash_UT/BUILD b/tests/ut/identifier_hash_UT/BUILD new file mode 100644 index 00000000..866eedda --- /dev/null +++ b/tests/ut/identifier_hash_UT/BUILD @@ -0,0 +1,24 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_test") + +cc_test( + name = "identifier_hash_UT", + srcs = ["identifier_hash_UT.cpp"], + visibility = ["//tests:__subpackages__"], + deps = [ + "//src/launch_manager_daemon/common:identifier_hash", + "@googletest//:gtest_main", + ], +) diff --git a/tests/ut/identifier_hash_UT/identifier_hash_UT.cpp b/tests/ut/identifier_hash_UT/identifier_hash_UT.cpp new file mode 100644 index 00000000..c3dbb658 --- /dev/null +++ b/tests/ut/identifier_hash_UT/identifier_hash_UT.cpp @@ -0,0 +1,78 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#include +#include +#include +#include + +using namespace testing; +using std::stringstream; + +using score::lcm::IdentifierHash; + +TEST(IdentifierHashTest, IdentifierHash_with_string_view_created) +{ + std::string_view idStrView = "ProcessGroup1/Startup"; + IdentifierHash identifierHash(idStrView); + stringstream strStream; + strStream << identifierHash; + ASSERT_EQ(strStream.str(), idStrView); +} + +TEST(IdentifierHashTest, IdentifierHash_with_string_created) +{ + std::string idStr = "ProcessGroup1/Startup"; + IdentifierHash identifierHash(idStr); + stringstream strStream; + strStream << identifierHash; + ASSERT_EQ(strStream.str(), idStr); +} + +TEST(IdentifierHashTest, IdentifierHash_default_created) +{ + IdentifierHash identifierHash; + stringstream strStream; + strStream << identifierHash; + ASSERT_EQ(strStream.str(), ""); +} + +TEST(IdentifierHashTest, IdentifierHash_invalid_hash_no_string_representation) +{ + std::string idStr = "MainFG"; + IdentifierHash identifierHash(idStr); + + // Clear registry to simulate missing entry + IdentifierHash::get_registry().clear(); + + stringstream strStream; + strStream << identifierHash; + ASSERT_TRUE(strStream.str().find("Unknown IdentifierHash") != std::string::npos); + ASSERT_TRUE(strStream.str().find(std::to_string(identifierHash.data())) != std::string::npos); +} + +TEST(IdentifierHashTest, IdentifierHash_no_dangling_pointer_after_source_string_dies) +{ + std::unique_ptr hash_ptr; + std::string_view idStrView = "this string will be destroyed"; + + { + std::string tmpIdStr = std::string(idStrView); + hash_ptr = std::make_unique(tmpIdStr); // Registry stores an owned copy + // Do not read the registry yet; ensure we read after the source string is destroyed. + } + + stringstream strStream; + strStream << *(hash_ptr.get()); + + ASSERT_EQ(strStream.str(), idStrView); +}