diff --git a/include/Producer.hpp b/include/Producer.hpp index 52214bd..d21ba85 100644 --- a/include/Producer.hpp +++ b/include/Producer.hpp @@ -4,12 +4,14 @@ // Author: Unai Blazquez #include #include +#include #include #include #include "SysfsRead.hpp" using RandomFn = std::function; +using LogFn = std::function; using SleepFn = std::function; class Producer { @@ -17,11 +19,9 @@ class Producer /// @brief Construct a Producer bound to a sysfs-like control file. /// @param sysfs_path Path to the control file (e.g. "./fake_sysfs_input"). /// @param send_fn Function called whenever a new integer should be sent. - /// @param sleep_fn Stub for sleeping function, allows reducing sleep on - /// testing Producer(const std::filesystem::path& sysfs_path, std::function send_fn, RandomFn random_fn, - SleepFn sleep_fn = default_sleep); + LogFn log_fn = nullptr, SleepFn sleep_fn = default_sleep); /// @brief Start the worker thread. Safe to call only once. void start(); @@ -42,5 +42,7 @@ class Producer { std::this_thread::sleep_for(d); } + LogFn m_log; std::function m_send; + std::chrono::milliseconds compute_delay(SysfsStatus status) const; }; diff --git a/src/core/Producer.cxx b/src/core/Producer.cxx index 708808a..8833d8f 100644 --- a/src/core/Producer.cxx +++ b/src/core/Producer.cxx @@ -7,13 +7,32 @@ #include "SysfsRead.hpp" Producer::Producer(const std::filesystem::path& sysfs_path, - std::function send_fn, RandomFn random_fn + std::function send_fn, RandomFn random_fn, + LogFn log_fn, SleepFn sleep_fn) : m_reader(sysfs_path), m_send(std::move(send_fn)), m_random(std::move(random_fn)), + m_log(std::move(log_fn)), m_sleep(std::move(sleep_fn)) { } +std::chrono::milliseconds Producer::compute_delay(SysfsStatus status) const +{ + using namespace std::chrono_literals; + + auto standard = 1000ms; // example: 1s, must be < 7s + auto hot = 7000ms; // exactly 7s + + if (status == SysfsStatus::ErrorTempTooHigh) + { // when error = temp too high + return hot; + } + else + { + return standard; + } +} + void Producer::start() { m_running.store(true); @@ -28,28 +47,38 @@ void Producer::stop() m_thread.join(); } } + void Producer::run_loop() { - auto status = m_reader.read_status(); - switch (status) + while (m_running.load()) { - case SysfsStatus::Enabled: - m_send(m_random()); - break; + auto status = m_reader.read_status(); + switch (status) + { + case SysfsStatus::Enabled: + m_send(m_random()); + if (m_log) m_log("Producer: Enabled"); + break; - case SysfsStatus::Unreachable: - // do nothing for now - break; + case SysfsStatus::Unreachable: + // do nothing for now + if (m_log) m_log("Producer: SysfsFile Unreachable"); + break; - case SysfsStatus::Empty: - break; + case SysfsStatus::Empty: + if (m_log) m_log("Producer: SysfsFile Empty"); + break; - case SysfsStatus::ErrorTempTooHigh: - break; + case SysfsStatus::ErrorTempTooHigh: + if (m_log) m_log("Producer: Error temp too high!!"); + break; - case SysfsStatus::UnexpectedValue: - break; + case SysfsStatus::UnexpectedValue: + if (m_log) m_log("Producer: UnexpectedValue"); + break; + } + auto delay = compute_delay(status); + m_sleep(delay); + // Thread will end here (for now) stop will join it } - m_sleep(delay); - // Thread will end here (for now) stop will join it } diff --git a/tests/test_producer.cxx b/tests/test_producer.cxx index 81a33ac..6dae65f 100644 --- a/tests/test_producer.cxx +++ b/tests/test_producer.cxx @@ -14,10 +14,14 @@ TEST(ProducerTest, ProducerCallsBackWhenEnabled) } // create a fake callback function std::vector outputs; + std::vector logs; // construct a producer with fake file and callback - Producer producer{"fake_sysfs_input", [&outputs](int value) - { outputs.push_back(value); }, []() { return 42; }}; + Producer producer{"fake_sysfs_input", + [&outputs](int value) { outputs.push_back(value); }, + []() { return 42; }, + [&logs](const std::string& msg) { logs.push_back(msg); }, + [](std::chrono::milliseconds) {}}; // Act: initialize producer and stop it. producer.start(); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // ← 1ms window @@ -26,6 +30,7 @@ TEST(ProducerTest, ProducerCallsBackWhenEnabled) // Assert: we expect one output being 42 ASSERT_EQ(outputs.size(), 1u); EXPECT_EQ(outputs[0], 42); + EXPECT_NE(logs[0].find("Enabled"), std::string::npos); } TEST(ProducerTest, ProducerDoesNotCallWhenUnexpectedValue) @@ -37,10 +42,13 @@ TEST(ProducerTest, ProducerDoesNotCallWhenUnexpectedValue) } std::vector outputs; + std::vector logs; Producer producer{"fake_sysfs_input", [&outputs](int value) { outputs.push_back(value); }, - []() { return 42; }, [](std::chrono::milliseconds) {}}; + []() { return 42; }, + [&logs](const std::string& msg) { logs.push_back(msg); }, + [](std::chrono::milliseconds) {}}; producer.start(); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // ← 1ms window @@ -48,6 +56,7 @@ TEST(ProducerTest, ProducerDoesNotCallWhenUnexpectedValue) // Assert: we expect no output EXPECT_TRUE(outputs.empty()); + EXPECT_NE(logs[0].find("UnexpectedValue"), std::string::npos); } TEST(ProducerTest, ProducerDoesNotCallWhenEmpty) @@ -59,16 +68,20 @@ TEST(ProducerTest, ProducerDoesNotCallWhenEmpty) } std::vector outputs; + std::vector logs; Producer producer{"fake_sysfs_input", [&outputs](int value) { outputs.push_back(value); }, - []() { return 42; }, [](std::chrono::milliseconds) {}}; + []() { return 42; }, + [&logs](const std::string& msg) { logs.push_back(msg); }, + [](std::chrono::milliseconds) {}}; producer.start(); producer.stop(); // Assert: we expect no output EXPECT_TRUE(outputs.empty()); + EXPECT_NE(logs[0].find("Empty"), std::string::npos); } TEST(ProducerTest, ProducerDoesNotCallWhenUnreachable) @@ -78,7 +91,9 @@ TEST(ProducerTest, ProducerDoesNotCallWhenUnreachable) Producer producer{"nonexistant_sysfs_input", [&outputs](int value) { outputs.push_back(value); }, - []() { return 42; }, [](std::chrono::milliseconds) {}}; + []() { return 42; }, + [&logs](const std::string& msg) { logs.push_back(msg); }, + [](std::chrono::milliseconds) {}}; producer.start(); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // ← 1ms window @@ -86,6 +101,7 @@ TEST(ProducerTest, ProducerDoesNotCallWhenUnreachable) // Assert: we expect no output EXPECT_TRUE(outputs.empty()); + EXPECT_NE(logs[0].find("Unreachable"), std::string::npos); } TEST(ProducerTest, ProducerDoesNotCallWhenTempTooHigh) @@ -96,10 +112,13 @@ TEST(ProducerTest, ProducerDoesNotCallWhenTempTooHigh) out << "error: temp too high"; } std::vector outputs; + std::vector logs; Producer producer{"fake_sysfs_input", [&outputs](int value) { outputs.push_back(value); }, - []() { return 42; }, [](std::chrono::milliseconds) {}}; + []() { return 42; }, + [&logs](const std::string& msg) { logs.push_back(msg); }, + [](std::chrono::milliseconds) {}}; producer.start(); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // ← 1ms window @@ -107,4 +126,5 @@ TEST(ProducerTest, ProducerDoesNotCallWhenTempTooHigh) // Assert: we expect no output EXPECT_TRUE(outputs.empty()); + EXPECT_NE(logs[0].find("Error"), std::string::npos); }