Skip to content

test: add connPool, rttTracker, delegationCache tests and fix cache benchmark - #5

Merged
PhantomInTheWire merged 1 commit into
masterfrom
fix/tests-benchmarks
Feb 25, 2026
Merged

PhantomInTheWire merged 1 commit into
masterfrom
fix/tests-benchmarks

Conversation

@PhantomInTheWire

@PhantomInTheWire PhantomInTheWire commented Feb 25, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Tests
    • Added comprehensive test coverage for connection pooling, including normal operation, error handling, capacity limits, and idle expiry scenarios.
    • Added unit tests for delegation cache behavior, including TTL clamping and longest-zone matching logic.
    • Added test suite for RTT tracking functionality, covering retrieval, updates, failures, and sorting logic.
    • Improved cache resolution benchmark with more realistic cache initialization and performance measurement refinements.

@coderabbitai

coderabbitai Bot commented Feb 25, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds comprehensive unit test coverage for resolver package components including cache resolution benchmarking, connection pool management, delegation cache operations, and RTT tracking behavior. Modifies existing cache benchmark to use real cache store infrastructure.

Changes

Cohort / File(s) Summary
Cache Resolution Benchmarking
internal/resolver/cache_bench_test.go
Reworks benchmark to use real cache store and stub resolver; adds cache population, switches to test ResolveFromCache with cache hits, and introduces performance measurement refinements including context usage and allocation reporting.
Resolver Component Tests
internal/resolver/conn_pool_test.go, internal/resolver/delegation_cache_test.go, internal/resolver/rtt_tracker_test.go
Adds three new comprehensive test files covering connection pool behavior (acquire/release/eviction), delegation cache operations (Set/Get/TTL clamping/zone matching), and RTT tracker functionality (EWMA updates/sorting/failure handling).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through tests so neat,
With pools and caches—what a treat!
From cache hits fast to RTT's dance,
Delegation zones get their chance.
Benchmarks run and coverage grows,
Our testing prowess brightly glows! 🐰✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding three new test files and fixing a cache benchmark. It is concise, specific, and clearly indicates the primary work.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/tests-benchmarks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@PhantomInTheWire
PhantomInTheWire merged commit 52dca50 into master Feb 25, 2026
5 of 6 checks passed
@PhantomInTheWire
PhantomInTheWire deleted the fix/tests-benchmarks branch February 25, 2026 19:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
internal/resolver/conn_pool_test.go (2)

77-103: TestConnPoolIdleExpiry doesn't verify the expired connection was actually pruned.

The test only checks require.NotNil(t, conn2) but never confirms conn2 is a different connection from conn1. If prune silently fails (e.g., the internal conns[0].lastUsed manipulation had no effect), the test would still pass because Get would return the old connection. Add an address-inequality check, or inspect pool length before and after the forced prune to confirm an entry was actually evicted.

🔍 Suggested strengthening
 conn2, release2, err := p.get(ctx)
 require.NoError(t, err)
 require.NotNil(t, conn2)
+// Confirm a fresh connection was created, not the expired one
+require.NotEqual(t, conn1.LocalAddr().String(), conn2.LocalAddr().String(),
+    "expected pruned connection to be replaced with a fresh one")
 release2(false)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/resolver/conn_pool_test.go` around lines 77 - 103, Update
TestConnPoolIdleExpiry to assert the expired connection was actually evicted:
after obtaining conn1 from p.get and forcing the prune (by setting p.lastPrune =
time.Time{} and manipulating p.conns[0].lastUsed), capture an identity for conn1
(e.g., the pointer value or a unique field), then call p.get again and assert
that conn2's identity is different from conn1's; alternatively, inspect p.conns
length before and after forcing prune to confirm an entry was removed. Reference
TestConnPoolIdleExpiry, p.conns, lastUsed, ConnPoolIdleTimeout, get and prune
when adding the assertion.

50-75: Acquiring 128 real network connections in a unit test is resource-intensive.

ConnPoolMaxConns = 128 means this test opens 129 real UDP sockets. In constrained CI environments (low fd limits, shared sandbox) this may cause fd exhaustion or measurable slowdown. Consider either mocking the dial function or using t.Parallel() awareness so this test doesn't run alongside other heavy tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/resolver/conn_pool_test.go` around lines 50 - 75,
TestConnPoolMaxConns opens 129 real UDP sockets which can exhaust fds in CI;
instead inject or override the dialer used by newConnPool to return a
lightweight mock connection (implementing the minimal methods used by
p.get/release) or add a constructor newConnPoolWithDial(dialFunc) so the test
can pass a fake dial that returns in-memory/net.Pipe connections; update
TestConnPoolMaxConns to use that mocked dial (or reduce the loop count for unit
tests) and optionally mark the test with t.Parallel() if safe. Ensure you change
references to newConnPool and p.get in the test to use the injected dial so no
real sockets are created.
internal/resolver/delegation_cache_test.go (1)

19-33: TestDelegationCacheTTLClamping doesn't actually verify clamping behavior.

Both sub-cases call Get immediately after Set, so the assertions pass regardless of whether TTL clamping is applied:

  • The 48h → 24h case: an un-clamped 48h TTL wouldn't have expired either, so ok==true tells you nothing.
  • The 1s → 5s case: the test returns within 1s, so even a truly 1s TTL is still valid when Get is called.

To actually exercise clamping, inspect the internal expiry field after Set, or use a fake/controllable clock. For the lower-bound case specifically, a time-manipulation approach like advancing a synthetic clock past 1s (but before 5s) would give a real signal.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/resolver/delegation_cache_test.go` around lines 19 - 33,
TestDelegationCacheTTLClamping currently calls DelegationCache.Set then Get
immediately so it never observes clamping; modify the test to either (A) expose
or inspect the internal expiry timestamp set by newDelegationCache()/Set (e.g.,
verify that the stored expiry for "com." is now time.Now()+24h and for "net." is
time.Now()+5s) or (B) inject/initialize the cache with a controllable clock and
advance it: after setting "net." with a 1s TTL advance the fake clock to >1s but
<5s and assert Get("net.") still returns true, and for "com." assert the expiry
corresponds to 24h not 48h. Target symbols: TestDelegationCacheTTLClamping,
newDelegationCache, (DelegationCache).Set, (DelegationCache).Get and the
internal expiry field or clock used by the cache.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/resolver/conn_pool_test.go`:
- Around line 77-103: Update TestConnPoolIdleExpiry to assert the expired
connection was actually evicted: after obtaining conn1 from p.get and forcing
the prune (by setting p.lastPrune = time.Time{} and manipulating
p.conns[0].lastUsed), capture an identity for conn1 (e.g., the pointer value or
a unique field), then call p.get again and assert that conn2's identity is
different from conn1's; alternatively, inspect p.conns length before and after
forcing prune to confirm an entry was removed. Reference TestConnPoolIdleExpiry,
p.conns, lastUsed, ConnPoolIdleTimeout, get and prune when adding the assertion.
- Around line 50-75: TestConnPoolMaxConns opens 129 real UDP sockets which can
exhaust fds in CI; instead inject or override the dialer used by newConnPool to
return a lightweight mock connection (implementing the minimal methods used by
p.get/release) or add a constructor newConnPoolWithDial(dialFunc) so the test
can pass a fake dial that returns in-memory/net.Pipe connections; update
TestConnPoolMaxConns to use that mocked dial (or reduce the loop count for unit
tests) and optionally mark the test with t.Parallel() if safe. Ensure you change
references to newConnPool and p.get in the test to use the injected dial so no
real sockets are created.

In `@internal/resolver/delegation_cache_test.go`:
- Around line 19-33: TestDelegationCacheTTLClamping currently calls
DelegationCache.Set then Get immediately so it never observes clamping; modify
the test to either (A) expose or inspect the internal expiry timestamp set by
newDelegationCache()/Set (e.g., verify that the stored expiry for "com." is now
time.Now()+24h and for "net." is time.Now()+5s) or (B) inject/initialize the
cache with a controllable clock and advance it: after setting "net." with a 1s
TTL advance the fake clock to >1s but <5s and assert Get("net.") still returns
true, and for "com." assert the expiry corresponds to 24h not 48h. Target
symbols: TestDelegationCacheTTLClamping, newDelegationCache,
(DelegationCache).Set, (DelegationCache).Get and the internal expiry field or
clock used by the cache.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee990ce and ebe9f68.

📒 Files selected for processing (4)
  • internal/resolver/cache_bench_test.go
  • internal/resolver/conn_pool_test.go
  • internal/resolver/delegation_cache_test.go
  • internal/resolver/rtt_tracker_test.go

Comment on lines +30 to +48
func TestConnPoolBadRelease(t *testing.T) {
p := newConnPool()
ctx := context.Background()

conn1, release1, err := p.get(ctx)
require.NoError(t, err)
require.NotNil(t, conn1)
localAddr1 := conn1.LocalAddr().String()

// Release as bad - should close and remove from pool
release1(true)

// Next get should create a new connection (different local addr)
conn2, release2, err := p.get(ctx)
require.NoError(t, err)
require.NotNil(t, conn2)
require.NotEqual(t, localAddr1, conn2.LocalAddr().String())
release2(false)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

require.NotEqual(localAddr1, conn2.LocalAddr()) is a potentially flaky assertion.

After a bad release the pool dials a new UDP socket, but the OS may reassign the same ephemeral port if the kernel's port-reuse window kicks in (or the process exhausts the port space in a tight loop). This makes the assertion non-deterministic. A more robust approach is to assert the pool's internal state (e.g., the old entry is absent) rather than relying on an OS-level side effect.

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