Skip to content

test: sweep — consolidate duplication, cover real gaps#51

Merged
sbogomolov merged 3 commits into
mainfrom
tests/sweep
Jul 9, 2026
Merged

test: sweep — consolidate duplication, cover real gaps#51
sbogomolov merged 3 commits into
mainfrom
tests/sweep

Conversation

@sbogomolov

Copy link
Copy Markdown
Owner

Test-suite sweep: cut duplication that doesn't earn its keep, add coverage where real gaps existed.

Commits

  1. Consolidate duplicated matrices and drop dead test surface — value-parameterized suites replace hand-copied per-protocol cases (config dedup, application invalid-socket, udp moved-from), so every protocol stays deliberately covered from one source and stays robust if the shared template is ever split apart. Removes the unused LoopbackReceiver. Two would-be cuts are kept as sharper tests instead (per-byte MAC case-folding; the non-NUL-terminated logger-name branch).

  2. Cover the BSD getifaddrs helpers via a detail:: split — the macOS/FreeBSD resolver's pure helpers (MAC read at the name-length offset, the IPv6 source-flag decision, KAME embedded-scope-id clearing) had no coverage at any layer. Split into testable detail:: functions and unit-tested; behavior-preserving.

  3. Cover error and edge paths surfaced by the sweep — narrowly scoped cases, each pinned to a specific production line: the drain per-poll cap; SSDP/DIAL interface-change and session-cap behavior; raw-socket build/interface failures; config and http rejections; and three failed-registration fd-rollback paths (the signal-wakeup pipe, the address monitor, and the event-loop dispatcher's kernel-interest programming). Captured-output assertions match the log level or a short token, not full message text.

Verification

  • Native unit suite green (Debug, ASan/UBSan).
  • Docker/Linux unit suite green (Debug, ASan/UBSan).
  • Every non-obvious test was verified to fail when its production line is broken, then reverted.

The config and application suites re-instantiated one shared template's
behavior per protocol by hand-copying near-identical cases. Replace
those with value-parameterized suites over {wol, mdns, ssdp}, so every
protocol stays deliberately covered — robust to the template ever being
split apart — from one test source:

- config duplicate-rule matrix: one TEST_P suite × 3 protocols (the
  port-dependent corners stay WoL-only); the per-protocol smoke tests
  fold into it. ConfigCount fails loudly on an unhandled protocol.
- application invalid-socket tests: one TEST_P over {protocol × source
  /target}; drop the SSDP rollback duplicate (the clear() is one
  unconditional path already pinned by the mDNS case).
- udp_socket: the five moved-from/closed guards become one table test.

Dead surface removed: the unused LoopbackReceiver helper.

Two would-be cuts kept as sharper tests instead: the mixed-case MAC
parse now asserts every byte (pins per-nibble, not per-byte, case
folding), and the static-array logger name is retargeted to a
non-NUL-terminated array (the one StaticStringLength branch a literal
can't reach).
The macOS/FreeBSD resolver's pure helpers had no coverage at any layer —
only the whole resolver, which needs a real interface. Split the
testable logic into detail:: functions (mirroring SelectSourceAddresses)
and unit-test them:

- MacFromLinkSockaddr (was ReadMac): reads the MAC at the name-length-
  dependent sdl_data offset; tested for the offset skip, the no-address
  (alen 0) case, and refusing a MAC that runs past sa_len.
- Ipv6SourceFlagsUsable: the SIOCGIFAFLAG_IN6 bitmask decision extracted
  from IsUsableIpv6 (the ioctl wrapper keeps calling it); tested for a
  usable address and each unusable flag bit.
- CanonicalizeLinkLocalV6: the KAME embedded-scope-id clearing; tested
  that it zeroes only bytes 2-3 and leaves a canonical address alone.

Behavior-preserving — the resolver calls the same code through the new
seams. Tests are BSD-lane only (the helpers are non-Linux).
The sweep found live code with no test at any layer. Add narrowly
scoped cases, each pinned to a specific production line:

- dispatchers: the DrainReadableFd per-poll cap stops one bursty socket
  from starving the loop, then resumes on the next drain.
- SSDP: the session cap is global across groups, a repeat interface
  change with no capability change is a no-op, a transient bring-up
  failure on a later group retries, and DIAL still forwards the
  response Location when the listener mint fails.
- DIAL proxy: rediscovery and a spurious accept edge both refresh
  last_active past the original grace deadline; the closed guard stops
  minting for a later header once a prior one aborted; an interface
  change to a different live address drops and re-mints listeners.
- raw socket: send fails cleanly when the frame can't be built;
  RejectsInvalidInterface now runs on both platforms; family-fd reuse
  on join (RequiresRoot).
- config: env tags differing only by case both canonicalize to one
  name and are rejected. http: a Content-Length that overflows size_t
  is rejected.
- failed-registration rollback: three paths that acquire an fd, fail to
  register it with a dispatcher, and must release it -- Application's
  signal-wakeup pipe, DefaultAddressMonitor::Start (Watch fails -> the
  socket is closed so IsValid() reports false), and EventLoopDispatcher
  ::Register (kernel-interest programming fails -> the map entry is
  erased so no fd is stranded; epoll-lane only). None was covered; a
  leaked fd is invisible to LeakSanitizer.

Captured-output assertions match the log level or a short stable token,
not full message text. TestCaptureSocket sizes its socketpair buffers
so a full drain burst can be staged before the first read.
@sbogomolov
sbogomolov merged commit a0011e1 into main Jul 9, 2026
17 checks passed
@sbogomolov
sbogomolov deleted the tests/sweep branch July 9, 2026 03:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant