check / check (push) Failing after 2m14s
Hold the 100,000-row cap after a failed write's rows are put back, dropping and counting the oldest rows past it. Stop counts the unwritten origin changes. The prefix handler's per-write origin change limit is a field, so a test checks that one write leaves the rest. The server and README now say where origin changes come from. README, TODO and schema say 72 hours or 500 rows, whichever keeps more. The prefix page and TODO list the origin change columns and say what the peer count counts. The page takes its 5,000-row note from the constant. Model: deepseek-v4-pro
149 lines
4.3 KiB
Go
149 lines
4.3 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/netip"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.eeqj.de/sneak/routewatch/internal/config"
|
|
"git.eeqj.de/sneak/routewatch/internal/database"
|
|
"git.eeqj.de/sneak/routewatch/internal/logger"
|
|
"git.eeqj.de/sneak/routewatch/internal/metrics"
|
|
"git.eeqj.de/sneak/routewatch/internal/ristypes"
|
|
"git.eeqj.de/sneak/routewatch/internal/routetable"
|
|
"git.eeqj.de/sneak/routewatch/internal/streamer"
|
|
)
|
|
|
|
// newPrefixDetailServer returns a server whose routing table holds testPrefixV4
|
|
// with origin AS 64500, and whose database holds the given origin changes.
|
|
func newPrefixDetailServer(
|
|
t *testing.T, changes []routetable.OriginChange,
|
|
) *Server {
|
|
t.Helper()
|
|
|
|
db, err := database.New(&config.Config{StateDir: t.TempDir()}, logger.New())
|
|
if err != nil {
|
|
t.Fatalf("database.New: %v", err)
|
|
}
|
|
|
|
t.Cleanup(func() { _ = db.Close() })
|
|
|
|
table := emptyTable()
|
|
announce(table, testPrefixV4, 64500, testPeer(1), testRouteTime(0))
|
|
|
|
err = db.WriteOriginChanges(changes)
|
|
if err != nil {
|
|
t.Fatalf("WriteOriginChanges: %v", err)
|
|
}
|
|
|
|
return New(db, table, streamer.New(logger.New(), metrics.New()),
|
|
logger.New(), &config.Config{})
|
|
}
|
|
|
|
// TestPrefixDetailShowsOriginChanges checks that the prefix page shows the
|
|
// origin changes newest first, with the announced and withdrawn rows and the
|
|
// AS link.
|
|
func TestPrefixDetailShowsOriginChanges(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
prefix := netip.MustParsePrefix(testPrefixV4)
|
|
|
|
s := newPrefixDetailServer(t, []routetable.OriginChange{
|
|
{Prefix: prefix, OriginASN: 64500, Announced: true, PeerCount: 1,
|
|
Time: testRouteTime(1)},
|
|
{Prefix: prefix, OriginASN: 64500, Announced: false, PeerCount: 0,
|
|
Time: testRouteTime(2)},
|
|
})
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.router.ServeHTTP(rec, httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/prefix/"+testPrefixV4, nil))
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status %d, want %d; body %s", rec.Code, http.StatusOK, rec.Body)
|
|
}
|
|
|
|
page := rec.Body.String()
|
|
|
|
withdrawn := strings.Index(page, "Withdrawn")
|
|
announced := strings.Index(page, "Announced")
|
|
|
|
if withdrawn < 0 || announced < 0 {
|
|
t.Fatalf("page does not show the announced and withdrawn rows")
|
|
}
|
|
|
|
// The withdrawn row is newer, so it comes first.
|
|
if withdrawn > announced {
|
|
t.Errorf("the withdrawn row is not shown before the announced row")
|
|
}
|
|
|
|
if !strings.Contains(page, `href="/as/64500"`) {
|
|
t.Errorf("page does not link to AS64500")
|
|
}
|
|
}
|
|
|
|
// TestPrefixDetailShowsOriginZeroAsNoKnownOrigin checks that the origin
|
|
// changes table shows AS 0 as no known origin, without a link to AS0.
|
|
func TestPrefixDetailShowsOriginZeroAsNoKnownOrigin(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
prefix := netip.MustParsePrefix(testPrefixV4)
|
|
|
|
s := newPrefixDetailServer(t, []routetable.OriginChange{
|
|
{Prefix: prefix, OriginASN: ristypes.NoOrigin, Announced: true,
|
|
PeerCount: 1, Time: testRouteTime(1)},
|
|
})
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.router.ServeHTTP(rec, httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/prefix/"+testPrefixV4, nil))
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status %d, want %d; body %s", rec.Code, http.StatusOK, rec.Body)
|
|
}
|
|
|
|
page := rec.Body.String()
|
|
|
|
if !strings.Contains(page, "No known origin") {
|
|
t.Errorf("page does not say the origin change has no known origin")
|
|
}
|
|
|
|
if strings.Contains(page, `href="/as/0"`) {
|
|
t.Errorf("page links to AS0")
|
|
}
|
|
}
|
|
|
|
// TestPrefixDetailSaysWhenMoreThan5000Changes checks that the prefix page says
|
|
// so when a prefix has more than 5,000 origin changes.
|
|
func TestPrefixDetailSaysWhenMoreThan5000Changes(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
prefix := netip.MustParsePrefix(testPrefixV4)
|
|
|
|
changes := make([]routetable.OriginChange, 0, 5001)
|
|
for i := range 5001 {
|
|
changes = append(changes, routetable.OriginChange{
|
|
Prefix: prefix, OriginASN: 64500, Announced: true, PeerCount: 1,
|
|
Time: testRouteTime(i),
|
|
})
|
|
}
|
|
|
|
s := newPrefixDetailServer(t, changes)
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.router.ServeHTTP(rec, httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/prefix/"+testPrefixV4, nil))
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status %d, want %d; body %s", rec.Code, http.StatusOK, rec.Body)
|
|
}
|
|
|
|
page := rec.Body.String()
|
|
|
|
if !strings.Contains(page, "more than 5000 changes") {
|
|
t.Errorf("page does not say there are more than 5000 changes")
|
|
}
|
|
}
|