From 2fe983d2886290dcc7ee64acc821053a41eb76b0 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 19:55:47 +0000 Subject: [PATCH] feat: added tests to check consumer resilience against corrupted data. All tests pased --- tests/test_consumer.cxx | 95 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/tests/test_consumer.cxx b/tests/test_consumer.cxx index d330570..610e6c0 100644 --- a/tests/test_consumer.cxx +++ b/tests/test_consumer.cxx @@ -1,7 +1,11 @@ #include +#include +#include +#include #include #include +#include #include "Consumer.hpp" #include "UnixIpcBridge.hpp" @@ -118,3 +122,94 @@ TEST(ConsumerThreadTest, StopsCleanlyWhenNeverStarted) // stop() on a consumer that was never started must not crash consumer.stop(); } + +// --------------------------------------------------------------------------- +// Requirement 2: Consumer receiving corrupted data (non-numeric) +// --------------------------------------------------------------------------- + +/// Helper: raw-connect to a UNIX socket and send arbitrary bytes. +static void send_raw_bytes(const std::string& path, const void* data, + size_t len) +{ + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + ASSERT_GE(fd, 0); + + struct sockaddr_un addr = {}; + addr.sun_family = AF_UNIX; + std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1); + + ASSERT_EQ( + connect(fd, reinterpret_cast(&addr), sizeof(addr)), 0); + + if (len > 0) + { + ::send(fd, data, len, 0); + } + close(fd); +} + +TEST(ConsumerThreadTest, DropsCorruptedShortMessage) +{ + const std::string sock = "/tmp/test_ct_corrupt_short.sock"; + + ConsumerThread consumer(sock); + QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); + consumer.start(); + + // Send only 2 bytes instead of sizeof(int)==4 — corrupted / partial message + uint16_t garbage = 0xBEEF; + send_raw_bytes(sock, &garbage, sizeof(garbage)); + + // Give the consumer time to process (or not) + spy.wait(500); + consumer.stop(); + + // No signal should have been emitted + EXPECT_EQ(spy.count(), 0); +} + +TEST(ConsumerThreadTest, DropsEmptyConnection) +{ + const std::string sock = "/tmp/test_ct_corrupt_empty.sock"; + + ConsumerThread consumer(sock); + QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); + consumer.start(); + + // Connect and immediately close — zero bytes sent + send_raw_bytes(sock, nullptr, 0); + + spy.wait(500); + consumer.stop(); + + EXPECT_EQ(spy.count(), 0); +} + +TEST(ConsumerThreadTest, SurvivesCorruptedThenReceivesValid) +{ + const std::string sock = "/tmp/test_ct_corrupt_then_valid.sock"; + + ConsumerThread consumer(sock); + QSignalSpy spy(&consumer, &ConsumerThread::valueReceived); + consumer.start(); + + // First: send corrupted (1 byte) + uint8_t one_byte = 0xFF; + send_raw_bytes(sock, &one_byte, sizeof(one_byte)); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + // Then: send a valid int via the normal bridge + UnixIpcBridge bridge(sock); + bridge.send(777); + + // Wait for the valid signal + for (int attempt = 0; spy.count() < 1 && attempt < 20; ++attempt) + { + spy.wait(100); + } + consumer.stop(); + + // The corrupted message must have been dropped, valid one received + ASSERT_EQ(spy.count(), 1); + EXPECT_EQ(spy.at(0).at(0).toInt(), 777); +}