Answer-time tests check the answer, not wall-clock milliseconds (closes #316)
check / check (push) Waiting to run
check / check (push) Waiting to run
Tests only. `TestWAFAnswersWithinTheTimeLimitWhileEveryOutsideSourceHangs` and `TestHangingRoutewatchNeverDelaysAndFailsTheQuery` run in a `synctest` bubble, whose clock load cannot move, instead of comparing wall-clock durations with fixed bounds. The first checks the answer comes after exactly `SWW_LOOKUP_TIMEOUT`, and that the DNS blocklist's query, held by a stand-in resolver, had not failed when it came. The second requires `no_answer_yet` after exactly zero time. The other wall-clock checks in the tests were already in bubbles or are bounds load cannot break. - The held DNS query still times out on the real clock after two seconds; a stall that long between question and check fails the test. Model: opus-5-5
This commit was merged in pull request #343.
This commit is contained in:
1 parent
1748a670f9
commit
b93bad5842
2 files changed
+153
-46
No files matched your search
@@ -12,6 +12,7 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"sneak.berlin/go/smallwebwaf/internal/routewatch"
|
||||
@@ -114,6 +115,28 @@ func answering(body string) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// silentURL is where a routewatch that never answers is: a query to it waits,
|
||||
// without the network, until it is abandoned. TestMain registers it with Go's
|
||||
// default transport, through which the Client asks.
|
||||
const silentURL = "silent://routewatch/"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
transport, _ := http.DefaultTransport.(*http.Transport)
|
||||
transport.RegisterProtocol("silent", silentRoutewatch{})
|
||||
|
||||
m.Run()
|
||||
}
|
||||
|
||||
// silentRoutewatch is the routewatch at silentURL.
|
||||
type silentRoutewatch struct{}
|
||||
|
||||
// RoundTrip waits until req is abandoned.
|
||||
func (silentRoutewatch) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
<-req.Context().Done()
|
||||
|
||||
return nil, req.Context().Err()
|
||||
}
|
||||
|
||||
func (f *fixture) route() (routewatch.Route, routewatch.Missing) {
|
||||
addr := netip.MustParseAddr(clientAddr)
|
||||
client := netip.PrefixFrom(addr, addr.BitLen())
|
||||
@@ -288,20 +311,29 @@ func TestFailureIsKeptForAMinuteSoRoutewatchIsNotAskedPerRequest(t *testing.T) {
|
||||
func TestHangingRoutewatchNeverDelaysAndFailsTheQuery(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := newFixture(t, func(_ http.ResponseWriter, r *http.Request) {
|
||||
<-r.Context().Done()
|
||||
// In a synctest bubble, time passes only while every goroutine in it waits,
|
||||
// so Route's wait is measured exactly, however busy the host is. routewatch
|
||||
// is the one at silentURL: one reached over the network would keep the
|
||||
// bubble's clock from moving.
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
// Without newFixture's stand-in, which is reached over the network.
|
||||
f := &fixture{t: t, log: &syncBuffer{}}
|
||||
f.client = routewatch.New(routewatch.Params{
|
||||
URL: silentURL, Now: time.Now,
|
||||
ProcessLog: slog.New(slog.NewTextHandler(f.log, nil)),
|
||||
})
|
||||
|
||||
began := time.Now()
|
||||
_, missing := f.route()
|
||||
|
||||
if waited := time.Since(began); missing != routewatch.NoAnswerYet || waited != 0 {
|
||||
t.Errorf("Route gave %q after %s while routewatch hangs, want %q at once",
|
||||
missing, waited, routewatch.NoAnswerYet)
|
||||
}
|
||||
|
||||
f.waitFor(routewatch.RequestFailed)
|
||||
f.wantFailureLoggedWithoutTheClient()
|
||||
})
|
||||
|
||||
start := time.Now()
|
||||
|
||||
f.route()
|
||||
|
||||
if elapsed := time.Since(start); elapsed > time.Second {
|
||||
t.Errorf("Route took %s while routewatch hangs", elapsed)
|
||||
}
|
||||
|
||||
f.waitFor(routewatch.RequestFailed)
|
||||
f.wantFailureLoggedWithoutTheClient()
|
||||
}
|
||||
|
||||
func TestRepeatedRequestsMakeOneQueryAndTheAnswerExpires(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user