e2e/qa: stop counting devices that cannot accept users as failures - #4168
Conversation
nikw9944
left a comment
There was a problem hiding this comment.
The exclusion is well-targeted and the premise checks out — is_device_eligible_for_provisioning is enforced client-side in the CLI before the onchain qa_allowlist can exempt the connect, so a max_users=0 device genuinely proves nothing. One gap in the new fail-open guard: it only fires at zero eligible devices, so a large partial drain still goes green over a fraction of the fleet with no durable signal of the lost coverage.
nikw9944
left a comment
There was a problem hiding this comment.
Re-checked at 89dec13: the coverage gap is closed and verified in code, not just claimed. SkippedRate() now gates fleet-wide and per host against -skipped-threshold, zero tested devices still fails independently of that threshold, Errorf replaces Fatalf so the publishers below it run, and devices_skipped lands in both InfluxDB and ClickHouse. The per-host gate is strictly more lenient than the 20% failure gate it displaces for skipped devices, so it adds no new false reds. No further findings.
The all-devices unicast test checked device readiness at four sites and logged "Ignoring <x> failure for device not ready for users", but each site incremented FailedTests before the check, so the carve-out only suppressed the log line while the device still counted as failed. Devices left activated with max_users=0 are drained on purpose and the CLI refuses the connect, so exclude them from ComputeFailureStats entirely rather than gating the counter: Success() also requires PacketsSent > 0 && PacketsReceived > 0, which a device that never connected can never satisfy. Also fix the ping failure message, which wrapped an always-nil lastErr and rendered as "failed to ping after 3 retries: %!w(<nil>)" for every connectivity failure. Report the packet counts instead.
Excluding not-ready devices from the failure stats opened a fail-open path: with every device excluded, totalDevices is 0, the overall rate is NaN, and NaN > threshold is false, so a run that tested nothing passed. Reachable when a fleet is drained metro-wide or newly created (devices are created with max_users=0 and unlocked on activation). Report which devices were skipped so an operator can tell "3 devices skipped" from "3 devices tested and fine", and fail when nothing was left to rate.
The zero-eligible-devices guard only caught a total drain: with 10 of a 13-device host pool refusing users, the run reported green over the remaining 3 and the skipped set reached only the test log. Coverage is now gated on the skipped rate at both resolutions against -skipped-threshold (default 0.5) — fleet-wide misses a single metro draining, which is a few percent of the fleet but all of one host's pool. Testing nothing at all still fails independently of the threshold, which -skipped-threshold=1 would otherwise switch off. The gate reports through Errorf rather than Fatalf so the publishers below it still run, and the skipped count publishes as devices_skipped next to devices_tested in InfluxDB and ClickHouse, so a collapse that stays under the threshold is visible on the dashboard.
89dec13 to
c4a722b
Compare
Summary of Changes
Mainnet Beta QA failed 7 times over Aug 8-10; three (infra runs 31248009915, 31266248546, 31286128831) had one cause.
qa_alldevices_unicast_test.gochecks device readiness at five sites, but each incrementsFailedTestsbefore that check, so the carve-out suppressed only the log line.laconic-{dfw,mia,was}-sw01have been activated atmax_users=0since Aug 6 and the CLI refuses those connects outright; againstcmh-mn-qa01's 13-device pool that read as 21-29% on a 20% per-host gate.Gating that counter is not enough:
Success()also requires non-zero packet counts, which a device that never connected cannot produce. Not-ready devices are therefore excluded fromComputeFailureStatsentirely — per-host denominator included — behind a newDevice.Ready()replacing the condition previously spelled out at six call sites.Exclusion opens a fail-open path worth reviewing closely: the rate is then measured over a shrinking pool, and with every device excluded it is
0/0, whereNaN > thresholdis false. Coverage is now gated on the skipped rate against-skipped-threshold(default 0.5), fleet-wide and per host — one metro draining is a few percent of the fleet but all of a host's pool, and per-host is the gate that fires in practice. Testing nothing fails independently of that threshold, which-skipped-threshold=1would otherwise switch off. The gate usest.Errorf, nott.Fatalf, so the publishers still run: the skipped count lands asdevices_skippedbesidedevices_testedin InfluxDB and ClickHouse, the latter via an idempotentADD COLUMN IF NOT EXISTS, best-effort so a writer without ALTER rights still gets its per-device rows in.Ready()is deliberately a subset ofis_device_eligible_for_provisioning: a device atusers_count + reserved_seats >= max_usershits the same CLI rejection and still counts as a failure, but fixing that means re-adding the capacity check #3697 removed, so it is a follow-up.Separately,
client_unicast.gowrapped an always-nillastErr, so every failure this weekend readfailed to ping after 3 retries: %!w(<nil>). It now reports packet counts.Testing Verification
go test ./e2e/internal/qa/...andgolangci-lint run --build-tags=qa ./e2e/...pass. The new subtests fail against the unfixed aggregation: the mainnet shape reportstotal=6 failed=3fortotal=3 failed=0, and a host whose whole pool is drained was absent fromPerHostrather than visible there as zero coverage.Not verified: the
qa-tagged tests need live fleet access, so nothing here runs against the real fleet and no run has written adevices_skippedrow yet. Mainnet has 5 of ~92 non-transit devices unusable today, well under the 0.5 default.Two pre-existing holes on the same axis go to separate PRs: a not-ready device still consumes a batch host slot, which on the two-host devnet run can trip the
fewer than 2 clients connectedfatal, and the Grafana active-device filter fails open on a query error but not on an empty successful response.