feature/Producer #3
@ -4,12 +4,14 @@
|
||||
// Author: Unai Blazquez <unaibg2000@gmail.com>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
#include "SysfsRead.hpp"
|
||||
|
||||
using RandomFn = std::function<int()>;
|
||||
using LogFn = std::function<void(const std::string&)>;
|
||||
using SleepFn = std::function<void(std::chrono::milliseconds)>;
|
||||
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<void(int)> 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<void(int)> m_send;
|
||||
std::chrono::milliseconds compute_delay(SysfsStatus status) const;
|
||||
};
|
||||
|
||||
@ -7,13 +7,32 @@
|
||||
#include "SysfsRead.hpp"
|
||||
|
||||
Producer::Producer(const std::filesystem::path& sysfs_path,
|
||||
std::function<void(int)> send_fn, RandomFn random_fn
|
||||
std::function<void(int)> 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
|
||||
}
|
||||
|
||||
@ -14,10 +14,14 @@ TEST(ProducerTest, ProducerCallsBackWhenEnabled)
|
||||
}
|
||||
// create a fake callback function
|
||||
std::vector<int> outputs;
|
||||
std::vector<std::string> 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<int> outputs;
|
||||
std::vector<std::string> 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<int> outputs;
|
||||
std::vector<std::string> 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<int> outputs;
|
||||
std::vector<std::string> 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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user