Skip to content

Commit

Permalink
iox-eclipse-iceoryx#1755 Add tests for the platform logging
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Mar 12, 2024
1 parent a97ddbe commit 93ff01e
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 6 deletions.
4 changes: 4 additions & 0 deletions iceoryx_platform/generic/include/iceoryx_platform/logging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ void iox_platform_set_log_backend(IceoryxPlatformLogBackend log_backend);
void iox_platform_detail_log(
const char* file, int line, const char* function, IceoryxPlatformLogLevel log_level, const char* msg);

/// @note Implementation detail! Do not use directly
void iox_platform_detail_default_log_backend(
const char* file, int line, const char* function, IceoryxPlatformLogLevel log_level, const char* msg);

// NOLINTJUSTIFICATION The functionality of the macro (obtaining the source location) cannot be achieved with C++17
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
/// @brief Frontend for logging in the iceoryx platform
Expand Down
11 changes: 5 additions & 6 deletions iceoryx_platform/generic/source/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@
#include <sstream>
#include <thread>

namespace
{
// NOLINTJUSTIFICATION only used in this file; should be fine
// NOLINTNEXTLINE(readability-function-size)
void default_log_backend(
void iox_platform_detail_default_log_backend(
const char* file, int line, const char* function, IceoryxPlatformLogLevel log_level, const char* msg)
{
if (log_level == IceoryxPlatformLogLevel::IOX_PLATFORM_LOG_LEVEL_OFF)
Expand All @@ -35,7 +33,6 @@ void default_log_backend(
}

std::stringstream stream;
stream << file << ":" << line << " (" << function << ") ";

switch (log_level)
{
Expand All @@ -62,13 +59,15 @@ void default_log_backend(
break;
}

stream << " " << msg;
stream << " " << file << ":" << line << " { " << function << " } " << msg;

// NOLINTJUSTIFICATION We want to flush the line with each log output; if performance matters a custom log backend can be used, e.g. the logger in hoofs
// NOLINTNEXTLINE(performance-avoid-endl)
std::cout << stream.str() << std::endl;
}

namespace
{
enum class LoggerExchangeState : uint8_t
{
DEFAULT,
Expand All @@ -78,7 +77,7 @@ enum class LoggerExchangeState : uint8_t

struct IceoryxPlatformLogger
{
std::atomic<IceoryxPlatformLogBackend> log_backend{&default_log_backend};
std::atomic<IceoryxPlatformLogBackend> log_backend{&iox_platform_detail_default_log_backend};
std::atomic<LoggerExchangeState> logger_exchange_state{LoggerExchangeState::DEFAULT};
};

Expand Down
155 changes: 155 additions & 0 deletions iceoryx_platform/test/moduletests/test_platform_logging.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) 2024 by Mathias Kraus <[email protected]>. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_platform/logging.hpp"

#include "test.hpp"

#include <atomic>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <utility>

namespace
{
using namespace ::testing;

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) for testing only
std::atomic<bool> has_custom_backend{false};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) for testing only
std::atomic<uint64_t> dummy_backend_output_counter{0};

class LogOutput
{
public:
void set(IceoryxPlatformLogLevel log_level, const char* msg) noexcept
{
std::lock_guard<std::mutex> lock(m_mtx);

m_log_level = log_level;
m_log_msg = msg;
}

void clear() noexcept
{
std::lock_guard<std::mutex> lock(m_mtx);

m_log_level = IceoryxPlatformLogLevel::IOX_PLATFORM_LOG_LEVEL_TRACE;
m_log_msg.clear();
}

std::pair<IceoryxPlatformLogLevel, std::string> get() const noexcept
{
std::lock_guard<std::mutex> lock(m_mtx);

return std::make_pair(m_log_level, m_log_msg);
}

private:
mutable std::mutex m_mtx;
IceoryxPlatformLogLevel m_log_level{IceoryxPlatformLogLevel::IOX_PLATFORM_LOG_LEVEL_TRACE};
std::string m_log_msg;
};

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) for testing only
LogOutput last_log_output;

// NOLINTNEXTLINE(readability-function-size) not directly called; just for testing
void custom_log_backend(
const char* file, int line, const char* function, IceoryxPlatformLogLevel log_level, const char* msg)
{
has_custom_backend = true;
last_log_output.set(log_level, msg);
iox_platform_detail_default_log_backend(file, line, function, log_level, msg);
}

// NOLINTNEXTLINE(readability-function-size) not directly called; just for testing
void dummy_log_backend(
const char* file, int line, const char* function, IceoryxPlatformLogLevel log_level, const char* msg)
{
dummy_backend_output_counter.fetch_add(1);
last_log_output.set(log_level, msg);
iox_platform_detail_default_log_backend(file, line, function, log_level, msg);
}

TEST(Logging_test, DefaultBackendLogsToCout)
{
::testing::Test::RecordProperty("TEST_ID", "a1d5fbb5-38e3-4829-bf1a-4ea312115f12");

ASSERT_FALSE(has_custom_backend);

std::stringstream buffer;
std::streambuf* original_cout_buffer = std::cout.rdbuf(buffer.rdbuf());

constexpr const char* MESSAGE{"Hypnotoad will rock you"};

IOX_PLATFORM_LOG(IOX_PLATFORM_LOG_LEVEL_INFO, MESSAGE);

std::string log = buffer.str();
EXPECT_THAT(log, HasSubstr(MESSAGE));

std::cout.rdbuf(original_cout_buffer);
}

TEST(Logging_test, SettingBackendWithNullptrFails)
{
::testing::Test::RecordProperty("TEST_ID", "85029c9d-3be2-463c-838a-9fce01e10640");

ASSERT_FALSE(has_custom_backend);

iox_platform_set_log_backend(nullptr);

IOX_PLATFORM_LOG(IOX_PLATFORM_LOG_LEVEL_INFO, "Hypnotoad");
ASSERT_FALSE(has_custom_backend);
}

TEST(Logging_test, SettingCustomBackendWorks)
{
::testing::Test::RecordProperty("TEST_ID", "9348e6ef-30a4-4cd7-a3d3-264efe378fba");

ASSERT_FALSE(has_custom_backend);

iox_platform_set_log_backend(&custom_log_backend);

last_log_output.clear();

constexpr const char* MESSAGE{"Who will rock you?"};
IOX_PLATFORM_LOG(IOX_PLATFORM_LOG_LEVEL_INFO, MESSAGE);

auto [log_level, log_msg] = last_log_output.get();
EXPECT_THAT(log_level, Eq(IOX_PLATFORM_LOG_LEVEL_INFO));
EXPECT_THAT(log_msg, StrEq(MESSAGE));
}

TEST(Logging_test, SettingCustomBackendTwiceFails)
{
::testing::Test::RecordProperty("TEST_ID", "cbc3446e-5c02-4f46-933f-c91627f669d3");

ASSERT_TRUE(has_custom_backend);

constexpr uint64_t DUMMY_MESSAGE_COUNT_AFTER_FAILED_SETUP{1};
ASSERT_THAT(dummy_backend_output_counter, Eq(0));
iox_platform_set_log_backend(&dummy_log_backend);
ASSERT_THAT(dummy_backend_output_counter, Eq(DUMMY_MESSAGE_COUNT_AFTER_FAILED_SETUP));

IOX_PLATFORM_LOG(IOX_PLATFORM_LOG_LEVEL_INFO, "Hypnotoad");

ASSERT_THAT(dummy_backend_output_counter, Eq(DUMMY_MESSAGE_COUNT_AFTER_FAILED_SETUP));
}

} // namespace

0 comments on commit 93ff01e

Please sign in to comment.