From 6b9faa0c2f6f9a65fb989596273e6c360ab24e86 Mon Sep 17 00:00:00 2001 From: Arjen <18398758+Origami74@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:23:07 +0100 Subject: [PATCH] fix(test): correct the dummy-carrier assertion, and pin Darwin's presence probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The carrier assertion added in d6240698 was wrong and would have failed both Linux legs. A `dummy` interface brought up reports `` — `IFF_RUNNING` is set, so it *has* carrier. Verified against the exact fixture CI builds, `addrgenmode none` and all, rather than against the comment: the original code discarded the result and its comment claimed "up but not running", which is what made asserting it look safe. So the fixture pins address-less *presence* and cannot demonstrate the presence-vs-carrier split at all — an interface up with no carrier is a bridge with nothing plugged in, which no fixture here creates. `carrier_is_reported_separately_from_presence` pins that split from the other side. The corrected assertion is Linux-only, because the expected answer is a property of the fixture device rather than of the code. That is also what lets the macOS fixture land. The Linux legs pin the address-less contract on glibc and musl, but the BSD-derived `getifaddrs` the macOS backend actually calls had no coverage — the test skipped itself silently on that runner, which is precisely the shape the previous commit was removing. `feth` is macOS's fake-Ethernet pseudo-interface and is created address-less; the step fails the leg rather than testing the wrong thing if the runner hands it an address anyway, mirroring why the Linux step needs `addrgenmode none`. Both branches of the fixture guard were exercised: unset skips and passes, and declared-but-missing fails loudly. The corrected test was run against a real Linux dummy inside a container, not reasoned about. --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ src/transport/ethernet/mod.rs | 29 +++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d307afd9..604d3817 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -327,6 +327,31 @@ jobs: - name: Install cargo-nextest uses: taiki-e/install-action@nextest + # The Darwin half of the address-less presence contract. The Linux legs + # pin that `getifaddrs` reports an interface with no addresses as + # present, on both glibc and musl; without this the same claim on the + # BSD-derived implementation the macOS backend actually calls was + # untested, and the test skipped itself silently on this runner. + # + # `feth` is macOS's fake-Ethernet pseudo-interface. It is created + # address-less, and the check below fails the leg rather than testing the + # wrong thing if this runner hands it one anyway — the same shape as the + # Linux fixture step, which needs `addrgenmode none` for exactly that + # reason. + - name: Create an address-less interface for the presence probe + run: | + sudo ifconfig feth0 create + sudo ifconfig feth0 up + ifconfig feth0 + if ifconfig feth0 | grep -qE "^[[:space:]]*inet6? "; then + echo "feth0 has an address; it cannot test the address-less case" >&2 + exit 1 + fi + echo "FIPS_TEST_ADDRLESS_IFACE=feth0" >> "$GITHUB_ENV" + # Declare that this runner has fixtures, so a test that depends on + # one fails when the fixture is missing instead of skipping silently. + echo "FIPS_TEST_REQUIRE_FIXTURES=1" >> "$GITHUB_ENV" + - name: Run unit tests run: cargo nextest run --all --profile ci diff --git a/src/transport/ethernet/mod.rs b/src/transport/ethernet/mod.rs index 84348e2f..48c8433a 100644 --- a/src/transport/ethernet/mod.rs +++ b/src/transport/ethernet/mod.rs @@ -1899,15 +1899,28 @@ mod tests { the presence probe; if this fails on musl, every address-less \ interface on OpenWrt is invisible to interface binding" ); - // It has no carrier either — a dummy device is up but not running — - // which pins that presence and carrier really are separate reads. - // Asserted rather than discarded: if these two ever collapsed into the - // same read, a carrier-less bridge would report absent and the whole - // IFF_UP-not-IFF_RUNNING decision would be silently undone. + // Carrier is asserted rather than discarded, but the expected answer + // is `true`, not `false`: a Linux `dummy` brought up reports + // `UP,LOWER_UP`, so `IFF_RUNNING` is set and it has carrier. The + // comment this replaces claimed the opposite — "up but not running" — + // which is why the result was discarded rather than checked. + // + // So this fixture pins address-less *presence*, and cannot demonstrate + // the presence-vs-carrier split; an interface that is up with no + // carrier is a bridge with nothing plugged in, which no fixture here + // creates. `carrier_is_reported_separately_from_presence` pins that + // split from the other side, on a missing interface having neither. + // + // Linux only, because the expected answer is a property of the fixture + // device rather than of the code: a `dummy` that is up reports + // `IFF_RUNNING`, and macOS's `feth` has its own semantics that are not + // pinned here. What both platforms do assert is the part that matters + // — an interface with no addresses is still *present*. + #[cfg(target_os = "linux")] assert!( - !io::interface_carrier(&iface), - "{iface} is up with no carrier, so presence and carrier must \ - disagree here — if they agree, they are the same read" + io::interface_carrier(&iface), + "a dummy interface that is up reports IFF_RUNNING; if this fails, \ + the fixture is no longer a dummy and what it pins has changed" ); // And it resolves to an index, which is what a bind would attach to. assert!(io::interface_index(&iface).is_some());