Implemented full e2e testing
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user