Record origin changes and show them on the prefix page (closes #161)
check / check (push) Successful in 4m6s
check / check (push) Successful in 4m6s
The routing table records each prefix and origin AS pair's origin changes: when it gains its first peer and when it loses its last. Each row holds the prefix, the origin AS, announced or withdrawn, the peer count and the time. The prefix handler writes them to a new origin_changes table, and the database maintainer prunes each prefix to its newest 500 rows and 72 hours. The prefix page lists them newest first, at most 5,000. Model: deepseek-v4-pro
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package routewatch
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/routewatch/internal/database"
|
||||
"git.eeqj.de/sneak/routewatch/internal/routetable"
|
||||
)
|
||||
|
||||
// TestPrefixHandlerWritesOriginChanges hands a running prefix handler an
|
||||
// announcement and flushes. The flush must write the origin change to the
|
||||
// database.
|
||||
func TestPrefixHandlerWritesOriginChanges(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := newTestDatabase(t)
|
||||
h := prefixHandlerWithoutTimer(db)
|
||||
|
||||
h.HandleMessage(peerAnnouncement(testPeerIP, testV4Prefix))
|
||||
h.flushBatch()
|
||||
|
||||
got, err := db.GetOriginChanges(t.Context(),
|
||||
netip.MustParsePrefix(testV4Prefix), 10)
|
||||
if err != nil {
|
||||
t.Fatalf("GetOriginChanges: %v", err)
|
||||
}
|
||||
|
||||
if len(got) != 1 || !got[0].Announced || got[0].OriginASN != testASNB {
|
||||
t.Errorf("GetOriginChanges = %+v, want one announced row for AS%d",
|
||||
got, testASNB)
|
||||
}
|
||||
}
|
||||
|
||||
// errTestOriginChangeWrite is the error a test store's failing write of the
|
||||
// origin changes returns.
|
||||
var errTestOriginChangeWrite = errors.New(
|
||||
"test: the write of the origin changes failed")
|
||||
|
||||
// originChangesFailsStore is a real database whose first write of the origin
|
||||
// changes fails, writing nothing. writes counts the writes asked for.
|
||||
type originChangesFailsStore struct {
|
||||
*database.Database
|
||||
|
||||
writes int
|
||||
}
|
||||
|
||||
func (s *originChangesFailsStore) WriteOriginChanges(
|
||||
changes []routetable.OriginChange,
|
||||
) error {
|
||||
s.writes++
|
||||
if s.writes == 1 {
|
||||
return errTestOriginChangeWrite
|
||||
}
|
||||
|
||||
return s.Database.WriteOriginChanges(changes)
|
||||
}
|
||||
|
||||
// TestPrefixHandlerWritesAFailedOriginChangeWriteAgain runs two flushes into a
|
||||
// database whose first write of the origin changes fails. The second write must
|
||||
// hold the change of the first.
|
||||
func TestPrefixHandlerWritesAFailedOriginChangeWriteAgain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := newTestDatabase(t)
|
||||
store := &originChangesFailsStore{Database: db}
|
||||
h := prefixHandlerWithoutTimer(store)
|
||||
|
||||
h.HandleMessage(peerAnnouncement(testPeerIP, testV4Prefix))
|
||||
h.flushBatch()
|
||||
h.flushBatch()
|
||||
|
||||
got, err := db.GetOriginChanges(t.Context(),
|
||||
netip.MustParsePrefix(testV4Prefix), 10)
|
||||
if err != nil {
|
||||
t.Fatalf("GetOriginChanges: %v", err)
|
||||
}
|
||||
|
||||
if len(got) != 1 || !got[0].Announced || got[0].OriginASN != testASNB {
|
||||
t.Errorf("GetOriginChanges = %+v, want one announced row for AS%d",
|
||||
got, testASNB)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user