Skip to content

hl2_tx_loopback_test depends on a hardcoded IP on a foreign subnet (192.168.1.12) — passes or fails by accident of network #4815

Description

@nigelfenton

Raised because the review on #4799 asked for it — hl2_tx_loopback_test was reported failing identically on a clean tree, "so it stops shadowing other work."

I could not reproduce that failure, and the reason is itself the bug: whether this test runs at all depends on what happens to answer at a hardcoded address on a subnet the developer may not even be on.

What it does

const QString simHost = QStringLiteral("192.168.1.12");
if (!simPresent(simHost)) {
    std::fprintf(stderr, "hl2_tx_loopback_test: SKIPPED — no simulator answering at %s\n", ...);
    return 0;
}

192.168.1.12 is hardcoded, on 192.168.1.0/24. There is no environment override and no way to point it elsewhere without a rebuild.

So the test has three possible behaviours on a given machine, and nothing in the name or the output distinguishes the second from the third:

Situation Result
Nothing answers (my box — different subnet) SKIPPED, exit 0 — looks like a pass
A real HL2 simulator answers genuinely runs
Something else entirely answers runs against the wrong device and fails

On this machine (10.0.0.0/24) it exits 0 every time, having tested nothing.

The probe is looser than it looks

static bool simPresent(const QString& host)
{
    QUdpSocket s;
    ...
    s.writeDatagram(..., QHostAddress(host), kMetisPort);
    return s.waitForReadyRead(1500);
}

waitForReadyRead() is true if any datagram arrives on that unbound-port socket within 1.5 s. It does not check the sender address and does not parse the reply as a Metis discovery response. An ICMP-adjacent stray, a broadcast, or an unrelated device on 192.168.1.12 all read as "the simulator is present" — and then the test proceeds to key a transmit path against it.

That last part matters: past the gate the test does qunsetenv("AETHER_AUTOMATION") deliberately to open the TX gate, then asserts canTransmit. It is a transmit test being pointed at whatever answered.

Why it shadows other work

A test that is green because it silently skipped is indistinguishable, from CI or a terminal, from one that is green because it passed. And when it does fail, the failure is about the reviewer's LAN rather than the code under review — which is exactly what happened on #4799, where it had to be explained away before the real findings could be discussed.

Suggested fix

  1. Make the target configurable — an env var (AETHER_HL2_SIM_HOST or similar) with the current IP as a documented default, so it can be pointed at a real simulator or deliberately disabled.
  2. Verify the reply, not merely that a packet arrived: check the sender is the host asked, and that the payload parses as a Metis discovery response.
  3. Make the skip visible as a skip. Exit 0 with a message on stderr reads as a pass to every automated consumer. If the suite has a skip convention, use it; if not, this is a good reason to have one.
  4. Consider whether a test that needs a live device on a specific subnet belongs in the default target at all, or should be opt-in like the other hardware-dependent checks.

Point 3 is the one that costs least and buys most — it turns a silent no-op into an honest one.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmaintainer-reviewRequires maintainer review before any action is takenpriority: mediumMedium priorityprotocolSmartSDR protocolsafetyEquipment protection concern

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions