Keep a trailing AS set out of the origin and the peerings (closes #75)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
A path ending in an AS set, such as [64496, 64497, [64498, 64499]], was flattened into the sequence, so the route was stored as originated by the last set member and the peering handler recorded peerings the path does not show. ASPath now keeps the sequence and a trailing set of several members apart; Origin() gives the last AS of the sequence, or 0 (no known origin) for such a set. The handlers use it; peerings come from the sequence only. The pages show origin 0 as no known origin, and the IP lookup asks no WHOIS lookup for it. Empty paths are unchanged. Model: opus-5-5
This commit was merged in pull request #91.
This commit is contained in:
@@ -2,6 +2,9 @@ package routewatch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -16,6 +19,7 @@ const (
|
||||
testASNA = 64500
|
||||
testASNB = 64501
|
||||
testASNC = 64502
|
||||
testASND = 64503
|
||||
)
|
||||
|
||||
// recordingStore wraps mockStore to count every RecordPeering call, so a
|
||||
@@ -64,7 +68,7 @@ func snapshot(h *PeeringHandler) (int, int) {
|
||||
func pathKey(t *testing.T, asns ...int) string {
|
||||
t.Helper()
|
||||
|
||||
b, err := json.Marshal(ristypes.ASPath(asns))
|
||||
b, err := json.Marshal(asns)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal path: %v", err)
|
||||
}
|
||||
@@ -74,11 +78,80 @@ func pathKey(t *testing.T, asns ...int) string {
|
||||
|
||||
func handle(h *PeeringHandler, ts time.Time, asns ...int) {
|
||||
h.HandleMessage(&ristypes.RISMessage{
|
||||
Path: ristypes.ASPath(asns),
|
||||
Path: ristypes.ASPath{Sequence: asns},
|
||||
ParsedTimestamp: ts,
|
||||
})
|
||||
}
|
||||
|
||||
// decodePath decodes an AS path from the JSON the feed writes for it, in which
|
||||
// an AS set is an array inside the path: decodePath(t, 1, 2, []int{3, 4})
|
||||
// decodes [1, 2, [3, 4]].
|
||||
func decodePath(t *testing.T, elements ...any) ristypes.ASPath {
|
||||
t.Helper()
|
||||
|
||||
data, err := json.Marshal(elements)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal path: %v", err)
|
||||
}
|
||||
|
||||
var path ristypes.ASPath
|
||||
|
||||
err = json.Unmarshal(data, &path)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode path %s: %v", data, err)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// TestPeeringHandlerLeavesATrailingASSetOutOfThePeerings handles AS paths that
|
||||
// end in an AS set. The members of a set are not neighbours of each other or of
|
||||
// the AS before the set, so a set of several members is in no peering; a set of
|
||||
// one member counts as that AS.
|
||||
func TestPeeringHandlerLeavesATrailingASSetOutOfThePeerings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
path []any
|
||||
// The peerings recorded, keyed as the mock store keys them.
|
||||
wantPeerings []string
|
||||
}{
|
||||
{
|
||||
name: "a set of several members",
|
||||
path: []any{testASNA, testASNB, []int{testASNC, testASND}},
|
||||
wantPeerings: []string{fmt.Sprintf("%d_%d", testASNA, testASNB)},
|
||||
},
|
||||
{
|
||||
name: "a set of one member",
|
||||
path: []any{testASNA, testASNB, []int{testASNC}},
|
||||
wantPeerings: []string{
|
||||
fmt.Sprintf("%d_%d", testASNA, testASNB),
|
||||
fmt.Sprintf("%d_%d", testASNB, testASNC),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
store := newMockStore()
|
||||
h := newTestHandler(store)
|
||||
h.HandleMessage(&ristypes.RISMessage{
|
||||
Path: decodePath(t, tt.path...),
|
||||
ParsedTimestamp: time.Now().UTC(),
|
||||
})
|
||||
h.ProcessPeeringsNow()
|
||||
|
||||
got := slices.Sorted(maps.Keys(store.Peerings))
|
||||
if !slices.Equal(got, tt.wantPeerings) {
|
||||
t.Errorf("peerings recorded = %v, want %v", got, tt.wantPeerings)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPeeringHandlerProcessesEachRunAndEmpties verifies that a processing run
|
||||
// empties the path map (the swap) and that a path seen again after a run is
|
||||
// recorded in the next run too.
|
||||
|
||||
Reference in New Issue
Block a user