check / check (push) Successful in 4m59s
The tests that have GeoJS asked now run in a synctest bubble, so a wait lasts exactly as long as it should however slowly the test process runs: a new client's wait is checked to be exactly one second, and its next request exactly no wait. A request waiting on the network would stop the bubble's clock, so the stand-in for GeoJS now answers in place of the network, through a transport that a test-only file lets the tests set. The test of the failure log uses an abandoned request instead of a closed port. Model: opus-5-5
100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
package lookup_test
|
|
|
|
import (
|
|
"net/netip"
|
|
"slices"
|
|
"testing"
|
|
"testing/synctest"
|
|
"time"
|
|
|
|
"sneak.berlin/go/smallwebwaf/internal/lookup"
|
|
)
|
|
|
|
func TestSnapshotHoldsEachAnswerAndWhenItWasLastUsed(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
synctest.Test(t, func(t *testing.T) {
|
|
_, clock, g := start()
|
|
placed := netip.MustParsePrefix("203.0.113.9/32")
|
|
notPlaced := netip.MustParsePrefix(unplaced + "/32")
|
|
asked := clock.Now()
|
|
|
|
wantCountry(t, g, placed, germany)
|
|
wantCountry(t, g, notPlaced, "")
|
|
|
|
clock.advance(time.Hour)
|
|
wantCountry(t, g, placed, germany)
|
|
|
|
want := []lookup.Answer{
|
|
{Client: notPlaced, Country: "", Answered: asked, Used: asked},
|
|
{Client: placed, Country: germany, Answered: asked, Used: asked.Add(time.Hour)},
|
|
}
|
|
if got := g.Snapshot(); !slices.Equal(got, want) {
|
|
t.Errorf("snapshot\n%+v\nwant\n%+v", got, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestLoadedAnswersAreKeptFor7DaysFromWhenGeoJSGaveThem(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
geojs, clock, g := start()
|
|
now := clock.Now()
|
|
kept := lookup.Answer{
|
|
Client: netip.MustParsePrefix("203.0.113.9/32"),
|
|
Country: "FR",
|
|
Answered: now.Add(-week + time.Second),
|
|
Used: now.Add(-time.Hour),
|
|
}
|
|
stale := lookup.Answer{
|
|
Client: netip.MustParsePrefix("203.0.113.10/32"),
|
|
Country: "FR",
|
|
Answered: now.Add(-week),
|
|
Used: now.Add(-time.Hour),
|
|
}
|
|
|
|
g.Load([]lookup.Answer{kept, stale})
|
|
|
|
if got := g.Snapshot(); !slices.Equal(got, []lookup.Answer{kept}) {
|
|
t.Errorf("kept %+v, want only the answer GeoJS gave less than 7 days ago", got)
|
|
}
|
|
|
|
wantCountry(t, g, kept.Client, "FR")
|
|
wantRequests(t, geojs, 0)
|
|
}
|
|
|
|
func TestLoadDropsTheAnswerUsedLongestAgoFirst(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const maxAnswers = 100000
|
|
|
|
_, clock, g := start()
|
|
now := clock.Now()
|
|
|
|
// lookups.json lists the answers by client. Here each was last used a
|
|
// second before the one listed before it, so the last listed is the
|
|
// one used longest ago, and the one dropped.
|
|
answers := make([]lookup.Answer, maxAnswers+1)
|
|
addr := netip.MustParseAddr("10.0.0.0")
|
|
|
|
for i := range answers {
|
|
answers[i] = lookup.Answer{
|
|
Client: netip.PrefixFrom(addr, addr.BitLen()),
|
|
Country: germany,
|
|
Answered: now,
|
|
Used: now.Add(-time.Duration(i) * time.Second),
|
|
}
|
|
addr = addr.Next()
|
|
}
|
|
|
|
g.Load(answers)
|
|
|
|
got := g.Snapshot()
|
|
if len(got) != maxAnswers || got[0] != answers[0] ||
|
|
got[maxAnswers-1] != answers[maxAnswers-1] {
|
|
t.Errorf("%d answers kept, from %s to %s; want %d, from %s to %s",
|
|
len(got), got[0].Client, got[len(got)-1].Client, maxAnswers,
|
|
answers[0].Client, answers[maxAnswers-1].Client)
|
|
}
|
|
}
|