Skip to content

test: beasting infra + raise coverage 47%→94%, fix silent watch event-drop bug - #309

Merged
shubhamranjan merged 5 commits into
mainfrom
tests/coverage-and-beasting
Jun 30, 2026
Merged

test: beasting infra + raise coverage 47%→94%, fix silent watch event-drop bug#309
shubhamranjan merged 5 commits into
mainfrom
tests/coverage-and-beasting

Conversation

@shubhamranjan

@shubhamranjan shubhamranjan commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Description

What & why

The test suite was green but shallow — combined coverage sat at 46.7%, most of it from integration tests the CI badge didn't even count, and there was no defense against timing/concurrency flakiness. This PR adds repeat-run "beasting", drives combined coverage to 93.8%, and — as a direct result of writing real delivery tests — uncovers and fixes a production bug that silently dropped watch events.

Beasting (flaky-test detection)

  • dotnet-etcd.Tests/beast.sh — builds once, then runs the suite N times with --no-build so only non-determinism can fail a run. Configurable iterations (-n), category (-f Unit|Integration|All), and stop-on-first vs keep-going (-k). Honors BEAST_LOG_DIR.
  • .github/workflows/beast-tests.yml — opt-in CI: manual workflow_dispatch (iterations/category inputs) and a nightly schedule (cron: '0 4 * * *'). Per-iteration logs upload as an artifact on failure so a nightly flake is reproducible.
  • Verified locally: 15× → 0 flaky, including the new timing-sensitive watch tests.

Coverage: 46.7% → 93.8%

Metric Before After
Line 46.7% 93.8%
Method 62.7% 96.7%
Branch 44% 79.6%
Tests 178 408 (341 unit + 67 integration)
  • All unary client methods/overloads (KV/Lease/Lock/Auth/Election/Cluster/Maintenance), sync + async, via the existing MockConnection/TestHelper pattern.
  • A controllable FakeDuplexStreamingCall mock unlocking the streaming paths: WatchManager (25%→93%), Watcher, the EtcdClient watch wrappers, duplex LeaseKeepAlive, and server-streaming Observe/Snapshot.
  • AsyncHelper (0%→100%), AsyncDuplexStreamingCallAdapter, constructor validation, and EtcdClient core.
  • CI coverage report now reflects combined unit + integration coverage (was unit-only).

Bug fix (TDD)

EtcdClient.Watch(WatchRequest[], Action<WatchEvent[]>[]) and its async twin captured the for-loop variable inside the event-conversion closure. When an event later arrived, the wrapper indexed methods[requests.Length]IndexOutOfRangeException on a background task, silently dropping every event. Reproduced with a failing delivery test (a=0, b=0), fixed with a per-iteration local index, confirmed green.

Adds beast.sh, which builds once then runs the suite N times with --no-build to
surface timing/race-driven flakiness in the watch/auth/lease streaming paths.
Configurable iterations, category filter (Unit|Integration|All), and stop-on-first
vs keep-going. Plus an opt-in beast-tests.yml workflow (manual dispatch + nightly).
…intenance + helpers

Adds unit tests covering all unary public methods and overloads (sync + async)
across the EtcdClient feature partials via the existing MockConnection/TestHelper
pattern, plus AsyncHelper (was 0%), AsyncDuplexStreamingCallAdapter, and EtcdClient
core methods (GetConnection/GetWatchManager/CancelWatch/Dispose). +142 unit tests
(111 -> 253). Streaming methods (KeepAlive/Observe/Snapshot/Watch) excluded; covered
separately.
Collect coverage from the integration test run too; reportgenerator already globs
./coverage/** and merges the cobertura files, so the badge/report now reflects
combined unit + integration coverage instead of unit-only.
…treaming coverage

Watch(WatchRequest[], Action<WatchEvent[]>[]) and the async variant captured the
for-loop variable inside the event-conversion closure, so when an event later arrived
the wrapper indexed methods[requests.Length] -> IndexOutOfRangeException on a background
task, silently dropping every event. Capture a per-iteration local index.

Adds a controllable FakeDuplexStreamingCall plus unit tests for WatchManager, the
EtcdClient watch wrappers (incl. delivery tests that fail without the fix), duplex
LeaseKeepAlive, server-streaming Observe/Snapshot, and constructor validation. Combined
line coverage 46.7% -> 93.8%.
The nightly beast schedule already runs, but per-iteration logs went to an ephemeral
mktemp dir lost when the runner tears down. beast.sh now honors BEAST_LOG_DIR; the
workflow points it at the workspace and uploads it as an artifact on failure, so a
nightly flake is diagnosable.
@github-actions

Copy link
Copy Markdown

Summary
Generated on: 06/30/2026 - 18:47:55
Coverage date: 06/30/2026 - 18:46:37 - 06/30/2026 - 18:47:54
Parser: MultiReport (2x Cobertura)
Assemblies: 1
Classes: 14
Files: 23
Line coverage: 94.4%
Covered lines: 1897
Uncovered lines: 112
Coverable lines: 2009
Total lines: 5299
Branch coverage: 79% (280 of 354)
Covered branches: 280
Total branches: 354
Method coverage: 96.7% (265 of 274)
Full method coverage: 85.7% (235 of 274)
Covered methods: 265
Fully covered methods: 235
Total methods: 274

dotnet-etcd 94.4%
dotnet_etcd.AsyncDuplexStreamingCallAdapter<T1, T2> 100%
dotnet_etcd.AsyncStreamCallFactory<T1, T2> 100%
dotnet_etcd.AuthenticationHttpHandler 96.1%
dotnet_etcd.ConnectionStringParser 100%
dotnet_etcd.DependencyInjection.EtcdClientOptions 76.1%
dotnet_etcd.DependencyInjection.EtcdClientOptionsValidator 100%
dotnet_etcd.DependencyInjection.ServiceCollectionExtensions 85.5%
dotnet_etcd.EtcdClient 95.5%
dotnet_etcd.GrpcChannelFactory 100%
dotnet_etcd.helper.AsyncHelper 100%
dotnet_etcd.multiplexer.Connection 100%
dotnet_etcd.Watcher 85.7%
dotnet_etcd.WatchEvent 100%
dotnet_etcd.WatchManager 92.7%

@shubhamranjan shubhamranjan changed the title fix(watch): deliver events in array Watch/WatchAsync overloads; add streaming coverage test: beasting infra + raise coverage 47%→94%, fix silent watch event-drop bug Jun 30, 2026
@shubhamranjan
shubhamranjan merged commit 4d7b128 into main Jun 30, 2026
6 checks passed
@shubhamranjan
shubhamranjan deleted the tests/coverage-and-beasting branch July 13, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant