Skip to content

Iox #27 client port implementation and test part 2 #863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3140e35
iox-#27 Add UML documentation for client and server service discovery
elBoberido Jun 23, 2021
07c0aa9
iox-#27 Add CaPro messages for request-response
elBoberido Jun 23, 2021
d5d666f
iox-#27 Implement ClientPortRouDi
elBoberido Jun 23, 2021
3e0a2f0
iox-#27 Use reference instead of not_null and update documentation
elBoberido Jun 24, 2021
d16c368
iox-#27 Test setup and initial tests for client port
elBoberido Jun 24, 2021
ed4c7a9
iox-#27 Fix typo and add U suffix
elBoberido Jun 28, 2021
23b1188
iox-#27 Add skeletons for ClientPortUserTests
elBoberido Jun 28, 2021
d1e8770
iox-#27 Simplify the service discovery for the client
elBoberido Jul 1, 2021
41ba185
iox-#27 Adjust client state machine according to new design
elBoberido Jul 1, 2021
26c3695
iox-#27 Make it more conveniet to output a CaproMessageType as string
elBoberido Jul 1, 2021
de1efff
iox-#27 Make it more conveniet to output a ConnectionState as string
elBoberido Jul 1, 2021
2c54884
iox-#27 Add missing return in switch
elBoberido Jul 1, 2021
a2d4b10
iox-#27 Make a bunch of tests pass
elBoberido Jul 1, 2021
2c21ef3
iox-#27 Make another bunch of tests pass
elBoberido Jul 2, 2021
eeebd96
iox-#27 Make condition variable related tests work
elBoberido Jul 2, 2021
242dfca
iox-#27 Finish ClientPortUser tests
elBoberido Jul 2, 2021
e6ef2fe
iox-#27 Rework ClientPortUser death test
elBoberido Jul 2, 2021
9516bfc
iox-#27 Implement stream operator for Error enum
elBoberido Jul 2, 2021
818a4a5
iox-#27 Check for nullptr access
elBoberido Jul 2, 2021
20e34c9
iox-#27 Fix build for ubuntu 16.04
elBoberido Jul 2, 2021
58b1474
iox-#27 Update copyright
elBoberido Jul 5, 2021
9317487
iox-#27 Code reuse in tests
elBoberido Jul 5, 2021
a2e43ba
iox-#27 Put all port related classes into a common struct
elBoberido Jul 6, 2021
c3710a1
iox-#27 Initial ClientPortRouDi tests
elBoberido Jul 6, 2021
86d7010
iox-#27 Add note regargint ClientPort thread safety
elBoberido Jul 6, 2021
64107a1
iox-#27 Add test for valid state transitions
elBoberido Jul 6, 2021
91db7a4
iox-#27 Add test for invalid state transitions
elBoberido Jul 6, 2021
5b0cd5b
iox-#27 Add option to set the LogLevel for the current scope
elBoberido Jul 6, 2021
44d3f64
iox-#27 Turn off logger for tests with invalid transitions
elBoberido Jul 6, 2021
2af5101
iox-#27 Fix typo
elBoberido Jul 12, 2021
41885ec
iox-#27 Fix typo and update copyright
elBoberido Jul 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@startuml

== Client tries to connect (Server not present) ==

PortManager -> ClientPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::CONNECT

PortManager -> PortManager ++ : sendToAllMatchingServerPorts

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::NACK)
return cxx::nullopt

return

...

== Server offers service (Client not present) ==

PortManager -> ServerPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::OFFER

PortManager -> PortManager ++ : sendToAllMatchingClientPorts

return

...

== Client tries to connect (Server present) ==

PortManager -> ClientPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::CONNECT

PortManager -> PortManager ++ : sendToAllMatchingServerPorts

PortManager -> ServerPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::CONNECT)
return CaproMessageType::ACK

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::ACK)
return cxx::nullopt

return

...

== Server offers service (Client present) ==

PortManager -> ServerPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::OFFER

PortManager -> PortManager ++ : sendToAllMatchingClientPorts

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::OFFER)
return CaproMessageType::CONNECT

PortManager -> ServerPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::CONNECT)
return CaproMessageType::ACK

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::ACK)
return cxx::nullopt

return

...

@enduml
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion doc/design/diagrams/request_response/client_port.puml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ class ClientPortUser {
hasNewResponses(): void
hasLostResponsesSinceLastCall(): bool
setConditionVariable(conditionVariable: ConditionVariableData&, notificationIndex: uint64_t): void
unsetConditionVariable: void
unsetConditionVariable(): void
isConditionVariableSet(): bool
}

class ClientPortRouDi {
getResponseQueueFullPolicy: QueueFullPolicy
tryGetCaProMessage(): optional<CaProMessage>
dispatchCaProMessageAndGetPossibleResponse(caProMessage: const CaProMessage): optional<CaProMessage>
releaseAllChunks(): void
Expand Down
12 changes: 6 additions & 6 deletions doc/design/diagrams/request_response/client_port.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions doc/design/diagrams/request_response/client_state_machine.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@startuml

[*] -down-> NOT_CONNECTED

NOT_CONNECTED -down-> CONNECT_REQUESTED : CONNECT
NOT_CONNECTED -right-> NOT_CONNECTED : OFFER

CONNECT_REQUESTED -down-> CONNECTED : ACK
CONNECT_REQUESTED -right-> WAIT_FOR_OFFER : NACK
CONNECT_REQUESTED : entry / CONNECT with response queue for server

WAIT_FOR_OFFER -left-> CONNECT_REQUESTED : OFFER
WAIT_FOR_OFFER -up-> NOT_CONNECTED : DISCONNECT

CONNECTED -up-> WAIT_FOR_OFFER : STOP_OFFER
CONNECTED -up-> DISCONNECT_REQUESTED : DISCONNECT
CONNECTED : entry / store received request queue
CONNECTED : exit / remove request queue

DISCONNECT_REQUESTED -up-> NOT_CONNECTED : ACK/NACK
DISCONNECT_REQUESTED : entry / DISCONNECT with response queue for server

@enduml
11 changes: 11 additions & 0 deletions doc/design/diagrams/request_response/client_state_machine.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions doc/design/request_response_communication.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ A client can ask a server to block if its response queue is full.
The server will obey if the corresponding `clientTooSlowPolicy` is set to `ConsumerTooSlowPolicy::WAIT_FOR_CONSUMER`.
If the options don't match, the client will not be connected to the server, similar to the behavior of publisher and subscriber.

#### Client Service Discovery
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To view this with rendered diagrams use the three dots on the right and select View file


The client is guided by the following state machine.

![client state machine](diagrams/request_response/client_state_machine.svg)

Similar to the subscriber state machine, the client passes it's response queue with the `CONNECT` CaPro message to the server.
The server will pass its request queue with the `ACK` CaPro message to the client.

Following is a sequence diagram which shows all this cases

![client and server service discovery](diagrams/request_response/client_and_server_service_discovery.svg)

### Code example

## Open issues
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ inline void Iceoryx2DDSGateway<channel_t, gateway_t>::loadConfiguration(const co
template <typename channel_t, typename gateway_t>
inline void Iceoryx2DDSGateway<channel_t, gateway_t>::discover(const capro::CaproMessage& msg) noexcept
{
LogDebug() << "[Iceoryx2DDSGateway] <CaproMessage> "
<< capro::CaproMessageTypeString[static_cast<uint8_t>(msg.m_type)]
LogDebug() << "[Iceoryx2DDSGateway] <CaproMessage> " << msg.m_type
<< " { Service: " << msg.m_serviceDescription.getServiceIDString()
<< ", Instance: " << msg.m_serviceDescription.getInstanceIDString()
<< ", Event: " << msg.m_serviceDescription.getEventIDString() << " }";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ namespace iox
error(POPO__CHUNK_LOCKING_ERROR) \
error(POPO__CHUNK_UNLOCKING_ERROR) \
error(POPO__CAPRO_PROTOCOL_ERROR) \
error(POPO__CLIENT_PORT_INVALID_REQUEST_TO_FREE_FROM_USER) \
error(POPO__CLIENT_PORT_INVALID_REQUEST_TO_SEND_FROM_USER) \
error(POPO__CLIENT_PORT_INVALID_RESPONSE_TO_RELEASE_FROM_USER) \
error(POPO__CONDITION_VARIABLE_DATA_FAILED_TO_CREATE_SEMAPHORE) \
error(POPO__CONDITION_LISTENER_SEMAPHORE_CORRUPTED_IN_WAS_TRIGGERED) \
error(POPO__CONDITION_LISTENER_SEMAPHORE_CORRUPTED_IN_WAIT) \
Expand Down Expand Up @@ -173,6 +176,12 @@ enum class Error : uint32_t
ICEORYX_ERRORS(CREATE_ICEORYX_ERROR_ENUM)
};

/// @brief Convenience stream operator to easily use the Error enum with std::ostream
/// @param[in] stream sink to write the message to
/// @param[in] value to convert to a string literal
/// @return the reference to `stream` which was provided as input parameter
std::ostream& operator<<(std::ostream& stream, Error value);

/// @brief the available error levels
/// FATAL
/// - Log message with FATAL
Expand Down
15 changes: 15 additions & 0 deletions iceoryx_hoofs/include/iceoryx_hoofs/log/logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef IOX_HOOFS_LOG_LOGGER_HPP
#define IOX_HOOFS_LOG_LOGGER_HPP

#include "iceoryx_hoofs/cxx/generic_raii.hpp"
#include "iceoryx_hoofs/log/logcommon.hpp"
#include "iceoryx_hoofs/log/logstream.hpp"

Expand Down Expand Up @@ -45,7 +46,20 @@ class Logger
Logger(const Logger& other) = delete;
Logger& operator=(const Logger& rhs) = delete;

/// @brief Getter method for the current LogLevel
/// @return the current LogLevel
LogLevel GetLogLevel() const noexcept;

/// @brief Sets the LogLevel for the Logger
/// @param[in] logLevel to be set
void SetLogLevel(const LogLevel logLevel) noexcept;

/// @brief Sets the LogLevel to the given level for the lifetime of the GenericRAII object and then sets it back to
/// the previous one
/// @param[in] logLevel to be set temporarily
/// @return a scope guard which resets the LogLevel to the value at the time when this method was called
cxx::GenericRAII SetLogLevelForScope(const LogLevel logLevel) noexcept;

void SetLogMode(const LogMode logMode) noexcept;
bool IsEnabled(const LogLevel logLevel) const noexcept;

Expand All @@ -66,6 +80,7 @@ class Logger
void Print(const LogEntry entry) const;

std::atomic<LogLevel> m_logLevel{LogLevel::kVerbose};
std::atomic<LogLevel> m_logLevelPredecessor{LogLevel::kVerbose};
std::atomic<LogMode> m_logMode{LogMode::kConsole};
};

Expand Down
8 changes: 7 additions & 1 deletion iceoryx_hoofs/source/error_handling/error_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ HandlerFunction ErrorHandler::handler = {ErrorHandler::DefaultHandler};

std::mutex ErrorHandler::handler_mutex;

std::ostream& operator<<(std::ostream& stream, Error value)
{
stream << ErrorHandler::ToString(value);
return stream;
}

void ErrorHandler::DefaultHandler(const Error error, const std::function<void()> errorCallBack, const ErrorLevel level)
{
if (errorCallBack)
Expand All @@ -41,7 +47,7 @@ void ErrorHandler::DefaultHandler(const Error error, const std::function<void()>
else
{
std::stringstream ss;
ss << "ICEORYX error! " << ErrorHandler::ToString(error);
ss << "ICEORYX error! " << error;

ReactOnErrorLevel(level, ss.str().c_str());
}
Expand Down
12 changes: 12 additions & 0 deletions iceoryx_hoofs/source/log/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,23 @@ Logger& Logger::operator=(Logger&& rhs)
return *this;
}

LogLevel Logger::GetLogLevel() const noexcept
{
return m_logLevel.load(std::memory_order_relaxed);
}

void Logger::SetLogLevel(const LogLevel logLevel) noexcept
{
m_logLevel.store(logLevel, std::memory_order_relaxed);
}

cxx::GenericRAII Logger::SetLogLevelForScope(const LogLevel logLevel) noexcept
{
m_logLevelPredecessor.store(m_logLevel.load(std::memory_order_relaxed), std::memory_order_relaxed);
SetLogLevel(logLevel);
return cxx::GenericRAII([] {}, [&] { this->SetLogLevel(m_logLevelPredecessor.load(std::memory_order_relaxed)); });
}

void Logger::SetLogMode(const LogMode logMode) noexcept
{
m_logMode.store(logMode, std::memory_order_relaxed);
Expand Down
22 changes: 22 additions & 0 deletions iceoryx_hoofs/test/moduletests/test_logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,28 @@ TEST_F(IoxLogger_test, Output)
EXPECT_THAT(output, Eq(expected));
}

TEST_F(IoxLogger_test, SettingTheLogLevelWorks)
{
constexpr auto LOG_LEVEL{iox::log::LogLevel::kInfo};
EXPECT_THAT(m_sut.GetLogLevel(), Ne(LOG_LEVEL));

m_sut.SetLogLevel(LOG_LEVEL);
EXPECT_THAT(m_sut.GetLogLevel(), Eq(LOG_LEVEL));
}

TEST_F(IoxLogger_test, SettingTheLogLevelForScopeResetsLogLevelAtEndOfScope)
{
constexpr auto LOG_LEVEL{iox::log::LogLevel::kInfo};
auto initialLogLevel{m_sut.GetLogLevel()};
EXPECT_THAT(initialLogLevel, Ne(LOG_LEVEL));

{
auto logLevelScopeGuard = m_sut.SetLogLevelForScope(LOG_LEVEL);
EXPECT_THAT(m_sut.GetLogLevel(), Eq(LOG_LEVEL));
}

EXPECT_THAT(m_sut.GetLogLevel(), Eq(initialLogLevel));
}

class IoxLoggerLogLevel_test : public TestWithParam<iox::log::LogLevel>, public IoxLogger_testBase
{
Expand Down
17 changes: 17 additions & 0 deletions iceoryx_posh/include/iceoryx_posh/iceoryx_posh_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,23 @@ enum class ConnectionState : uint32_t
WAIT_FOR_OFFER
};

/// @brief Converts the ConnectionState to a string literal
/// @param[in] value to convert to a string literal
/// @return pointer to a string literal
inline constexpr const char* asStringLiteral(ConnectionState value) noexcept;

/// @brief Convenience stream operator to easily use the `asStringLiteral` function with std::ostream
/// @param[in] stream sink to write the message to
/// @param[in] value to convert to a string literal
/// @return the reference to `stream` which was provided as input parameter
inline std::ostream& operator<<(std::ostream& stream, ConnectionState value);

/// @brief Convenience stream operator to easily use the `asStringLiteral` function with iox::log::LogStream
/// @param[in] stream sink to write the message to
/// @param[in] value to convert to a string literal
/// @return the reference to `stream` which was provided as input parameter
inline log::LogStream& operator<<(log::LogStream& stream, ConnectionState value);

// Default properties of ChunkDistributorData
struct DefaultChunkDistributorConfig
{
Expand Down
Loading