Implemented full e2e testing

This commit is contained in:
Martino Ferrari
2026-07-02 10:10:57 +02:00
parent f8c79131c9
commit f2042d624b
35 changed files with 2419 additions and 78 deletions
+9 -13
View File
@@ -6,6 +6,7 @@
#include "StandardParser.h"
#include "StreamString.h"
#include "GlobalObjectsDatabase.h"
#include "TestCommon.h"
#include <assert.h>
#include <stdio.h>
@@ -150,15 +151,11 @@ void TestSchedulerControl() {
BasicUDPSocket listener;
listener.Open();
listener.Listen(8099);
GrowUDPRecvBuffer(listener);
// Read current value
uint32 valBeforePause = 0;
char buffer[2048];
uint32 size = 2048;
TimeoutType timeout(1000);
if (listener.Read(buffer, size, timeout)) {
// [Header][ID][Size][Value]
valBeforePause = *(uint32 *)(&buffer[sizeof(TraceHeader) + 16]);
if (ReadUDPSTraceScalar(listener, 1000, valBeforePause)) {
printf("Value before/at pause: %u\n", valBeforePause);
} else {
printf("WARNING: No data received before pause.\n");
@@ -194,10 +191,11 @@ void TestSchedulerControl() {
// Read again - should be same or very close if paused
uint32 valAfterWait = 0;
size = 2048; // Reset size
while (listener.Read(buffer, size, TimeoutType(100))) {
valAfterWait = *(uint32 *)(&buffer[sizeof(TraceHeader) + 16]);
size = 2048;
{
uint32 v;
while (ReadUDPSTraceScalar(listener, 100, v)) {
valAfterWait = v;
}
}
printf("Value after 2s wait (drained): %u\n", valAfterWait);
@@ -237,9 +235,7 @@ void TestSchedulerControl() {
// Check if increasing
uint32 valAfterResume = 0;
size = 2048;
if (listener.Read(buffer, size, timeout)) {
valAfterResume = *(uint32 *)(&buffer[sizeof(TraceHeader) + 16]);
if (ReadUDPSTraceScalar(listener, 1000, valAfterResume)) {
printf("Value after resume: %u\n", valAfterResume);
}
+42
View File
@@ -1,7 +1,10 @@
#include "TestCommon.h"
#include "BasicTCPSocket.h"
#include "HighResolutionTimer.h"
#include "StringHelper.h"
#include "TimeoutType.h"
#include "UDPSProtocol.h"
#include <sys/socket.h>
namespace MARTe {
@@ -71,4 +74,43 @@ bool SendCommandGAM(uint16 port, const char8* cmd, StreamString &reply) {
return false;
}
bool ReadUDPSTraceScalar(BasicUDPSocket &sock, uint32 overallTimeoutMs, uint32 &value) {
uint64 start = HighResolutionTimer::Counter();
float64 budgetS = (float64)overallTimeoutMs / 1000.0;
uint32 quantumMs = (overallTimeoutMs < 50u) ? overallTimeoutMs : 50u;
if (quantumMs == 0u) quantumMs = 1u;
for (;;) {
float64 elapsed = (float64)(HighResolutionTimer::Counter() - start) * HighResolutionTimer::Period();
if (elapsed >= budgetS) break;
char buffer[2048];
uint32 size = 2048;
TimeoutType timeout(quantumMs);
if (sock.Read(buffer, size, timeout)) {
if (size >= UDPS_HEADER_SIZE) {
UDPSPacketHeader hdr;
memcpy(&hdr, buffer, UDPS_HEADER_SIZE);
if (hdr.magic == UDPS_MAGIC && hdr.type == UDPS_TYPE_DATA) {
uint32 off = UDPS_HEADER_SIZE + 8u; // skip 8-byte HRT timestamp
if (size >= off + sizeof(uint32)) {
memcpy(&value, buffer + off, sizeof(uint32));
return true;
}
}
}
// CONFIG packet, undersized datagram, or bad magic — keep polling.
}
}
return false;
}
void GrowUDPRecvBuffer(BasicUDPSocket &sock, uint32 bytes) {
Handle fd = sock.GetReadHandle();
if (fd >= 0) {
int32 sz = static_cast<int32>(bytes);
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
}
}
}
+43
View File
@@ -1,6 +1,7 @@
#ifndef TESTCOMMON_H
#define TESTCOMMON_H
#include "BasicUDPSocket.h"
#include "CompilerTypes.h"
#include "StreamString.h"
@@ -8,6 +9,48 @@ namespace MARTe {
extern const char8 * const debug_test_config;
bool SendCommandGAM(uint16 port, const char8* cmd, StreamString &reply);
void TestMessageCommand();
/**
* @brief Reads DebugService trace telemetry off @p sock until a real
* UDPS DATA packet (Common/UDP/UDPSProtocol.h) is decoded or
* @p overallTimeoutMs elapses, and extracts the value of the first
* (and, for these single-signal integration tests, only) traced
* signal — a scalar at wire offset 0, right after the 8-byte HRT
* timestamp that opens every DATA payload.
*
* DebugService's real UDP telemetry (DebugService::Streamer) speaks the
* shared UDPS protocol, not the legacy TraceHeader format declared in
* DebugCore.h (that struct is now dead code, kept only for historical
* reference) — callers must not reinterpret raw datagrams as
* TraceHeader. CONFIG packets (sent once when the traced-signal set
* changes) are silently skipped so callers don't need to special-case
* them.
*
* @param sock DebugService's StreamPort/UdpPort listener, already Open()+Listen()ed.
* @param overallTimeoutMs total time budget across all read attempts.
* @param value output: the decoded scalar value.
* @return true if a DATA packet was decoded within the budget.
*/
bool ReadUDPSTraceScalar(BasicUDPSocket &sock, uint32 overallTimeoutMs, uint32 &value);
/**
* @brief Grows the OS receive buffer (SO_RCVBUF) on an already-Open()ed
* UDP socket.
*
* BasicUDPSocket never touches SO_RCVBUF, so listeners are left at the
* Linux default (net.core.rmem_default, ~208 KiB on most systems). At
* sustained 1 kHz+ trace rates a single scheduling delay in the test
* process (e.g. a printf, a GC pass, or just being descheduled) is
* enough to overflow that default buffer, causing silent kernel-level
* datagram drops (visible as RcvbufErrors in /proc/net/snmp) that show
* up as false "discontinuities" even though DebugService sent every
* sample. UDPSClient already works around this for production code
* (UDPSClient::SetRecvBufferSize); integration tests that Listen()
* directly on a raw BasicUDPSocket need the same treatment.
*
* Best-effort: a failure here just leaves the OS default in place.
*/
void GrowUDPRecvBuffer(BasicUDPSocket &sock, uint32 bytes = 4194304u);
}
#endif
+13 -26
View File
@@ -5,6 +5,7 @@
#include "StandardParser.h"
#include "StreamString.h"
#include "HighResolutionTimer.h"
#include "TestCommon.h"
#include <assert.h>
#include <stdio.h>
@@ -31,14 +32,19 @@ void TestFullTracePipeline() {
assert(sig != NULL_PTR(DebugSignalInfo*));
printf("Signal registered with ID: %u\n", sig->internalID);
// 3. Enable Trace manually
sig->isTracing = true;
sig->decimationFactor = 1;
// 3. Enable Trace via the real API (DebugService::TraceSignal), not by
// poking isTracing directly — DebugService's override also flags
// udpsConfigPending so the streamer thread rebuilds its UDPS slot table
// and CONFIG packet. Without that, the streamer's anyData/slot-match
// logic (DebugService.cpp Streamer()) never finds a slot for this
// signal's samples and silently never sends any DATA packet at all.
assert(service.TraceSignal("TraceTest.Signal", true, 1) == 1u);
// 4. Setup a local UDP listener
BasicUDPSocket listener;
assert(listener.Open());
assert(listener.Listen(8083));
GrowUDPRecvBuffer(listener);
// 5. Simulate cycles
printf("Simulating cycles...\n");
@@ -49,29 +55,10 @@ void TestFullTracePipeline() {
Sleep::MSec(10);
}
// 6. Try to read from UDP
char buffer[2048];
uint32 size = 2048;
TimeoutType timeout(1000); // 1s
if (listener.Read(buffer, size, timeout)) {
printf("SUCCESS: Received %u bytes over UDP!\n", size);
TraceHeader *h = (TraceHeader*)buffer;
printf("Header: Magic=0x%X, Count=%u, Seq=%u\n", h->magic, h->count, h->seq);
uint32 offset = sizeof(TraceHeader);
if (size >= offset + 16) {
uint32 recId = *(uint32*)(&buffer[offset]);
uint64 recTs = *(uint64*)(&buffer[offset + 4]);
uint32 recSize = *(uint32*)(&buffer[offset + 12]);
printf("Data: ID=%u, TS=%llu, Size=%u\n", recId, (unsigned long long)recTs, recSize);
if (size >= offset + 16 + recSize) {
if (recSize == 4) {
uint32 recVal = *(uint32*)(&buffer[offset + 16]);
printf("Value=%u\n", recVal);
}
}
}
// 6. Try to read a real UDPS DATA packet from UDP
uint32 val = 0;
if (ReadUDPSTraceScalar(listener, 2000, val)) {
printf("SUCCESS: Received UDPS DATA packet! Value=%u\n", val);
} else {
printf("FAILURE: No UDP packets received.\n");
}
+8 -17
View File
@@ -6,6 +6,7 @@
#include "StandardParser.h"
#include "StreamString.h"
#include "GlobalObjectsDatabase.h"
#include "TestCommon.h"
#include <assert.h>
#include <stdio.h>
@@ -111,6 +112,7 @@ void RunValidationTest() {
BasicUDPSocket listener;
listener.Open();
listener.Listen(8086);
GrowUDPRecvBuffer(listener);
printf("Validating for 10 seconds...\n");
uint32 totalPackets = 0;
@@ -121,25 +123,14 @@ void RunValidationTest() {
uint64 start = HighResolutionTimer::Counter();
float64 elapsed = 0;
while (elapsed < 10.0) {
char buffer[2048];
uint32 size = 2048;
if (listener.Read(buffer, size, TimeoutType(100))) {
uint32 val;
if (ReadUDPSTraceScalar(listener, 100, val)) {
totalPackets++;
TraceHeader *h = (TraceHeader*)buffer;
uint32 offset = sizeof(TraceHeader);
for (uint32 i=0; i<h->count; i++) {
uint32 recId = *(uint32*)(&buffer[offset]);
uint32 recSize = *(uint32*)(&buffer[offset + 12]);
if (recSize == 4) {
uint32 val = *(uint32*)(&buffer[offset + 16]);
totalSamples++;
if (lastValue != 0xFFFFFFFF && val != lastValue + 1) {
discontinuities++;
}
lastValue = val;
}
offset += (16 + recSize);
totalSamples++;
if (lastValue != 0xFFFFFFFF && val != lastValue + 1) {
discontinuities++;
}
lastValue = val;
}
elapsed = (float64)(HighResolutionTimer::Counter() - start) * HighResolutionTimer::Period();
}