Make the routewatch tests pass on a loaded host (closes #213)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Five prefix handler tests gave HandleMessage two seconds to apply a full batch of 25,000 prefixes, which under the race detector on a loaded host takes longer. A test now waits up to stepTimeout, 15 seconds, for each step it expects. The slowest tests filled production limits, such as the peering handler's 500,000 paths. The peering handler now takes its path limit, and the prefix handler its limit on one write of the table's changes, as they take their timer interval. Those tests give small limits, and the tests of the maximum batch size lower it to one batch. This also fixes #215. The test helpers bound every wait, Stop included, so a test that hangs in one fails with its own message. Model: opus-5-5
This commit was merged in pull request #214.
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -20,6 +19,10 @@ const (
|
||||
testASNB = 64501
|
||||
testASNC = 64502
|
||||
testASND = 64503
|
||||
|
||||
// testMaxTrackedPaths is a limit of the path map that a test fills
|
||||
// quickly, in place of maxTrackedPaths.
|
||||
testMaxTrackedPaths = 10
|
||||
)
|
||||
|
||||
// recordingStore wraps mockStore to count every RecordPeering call, so a
|
||||
@@ -52,9 +55,10 @@ func (r *recordingStore) callCount() int {
|
||||
// processing goroutine, so tests drive processing explicitly.
|
||||
func newTestHandler(db database.Store) *PeeringHandler {
|
||||
return &PeeringHandler{
|
||||
db: db,
|
||||
logger: logger.New(),
|
||||
asPaths: make(map[string]database.SeenTimes),
|
||||
db: db,
|
||||
logger: logger.New(),
|
||||
asPaths: make(map[string]database.SeenTimes),
|
||||
maxPaths: maxTrackedPaths,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,25 +248,28 @@ func TestPeeringHandlerStopWritesTheRemainingPaths(t *testing.T) {
|
||||
|
||||
// TestPeeringHandlerCapDropsAndCounts verifies that a full map drops new paths
|
||||
// and counts them, while a path already tracked is refreshed rather than
|
||||
// dropped.
|
||||
// dropped. The handler's limit is small, and its timer does not fire.
|
||||
func TestPeeringHandlerCapDropsAndCounts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
store := &recordingStore{mockStore: newMockStore()}
|
||||
h := newTestHandler(store)
|
||||
h := newPeeringHandler(store, logger.New(), longerThanAnyTest,
|
||||
testMaxTrackedPaths)
|
||||
|
||||
defer stopInTime(t, h)
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
// Fill the map to exactly maxTrackedPaths, including one real path key so
|
||||
// the "already tracked" branch can be exercised. The filler keys are never
|
||||
// processed in this test, so their contents do not matter.
|
||||
// Fill the map to exactly its limit, including one real path key so the
|
||||
// "already tracked" branch can be exercised. The other paths are of one
|
||||
// AS, so they carry no peering.
|
||||
existing := pathKey(t, testASNA, testASNB)
|
||||
|
||||
h.mu.Lock()
|
||||
h.asPaths[existing] = database.SeenTimes{First: now, Last: now}
|
||||
|
||||
for i := 0; len(h.asPaths) < maxTrackedPaths; i++ {
|
||||
h.asPaths[strconv.Itoa(i)] = database.SeenTimes{First: now, Last: now}
|
||||
for asn := 1; len(h.asPaths) < testMaxTrackedPaths; asn++ {
|
||||
h.asPaths[pathKey(t, asn)] = database.SeenTimes{First: now, Last: now}
|
||||
}
|
||||
h.mu.Unlock()
|
||||
|
||||
@@ -270,8 +277,9 @@ func TestPeeringHandlerCapDropsAndCounts(t *testing.T) {
|
||||
handle(h, now.Add(time.Second), testASNA, testASNC)
|
||||
|
||||
tracked, dropped := snapshot(h)
|
||||
if tracked != maxTrackedPaths {
|
||||
t.Fatalf("want map size %d after drop, got %d", maxTrackedPaths, tracked)
|
||||
if tracked != testMaxTrackedPaths {
|
||||
t.Fatalf("want map size %d after drop, got %d", testMaxTrackedPaths,
|
||||
tracked)
|
||||
}
|
||||
|
||||
if dropped != 1 {
|
||||
@@ -283,8 +291,9 @@ func TestPeeringHandlerCapDropsAndCounts(t *testing.T) {
|
||||
handle(h, refreshed, testASNA, testASNB)
|
||||
|
||||
tracked, dropped = snapshot(h)
|
||||
if tracked != maxTrackedPaths {
|
||||
t.Fatalf("want map size %d after refresh, got %d", maxTrackedPaths, tracked)
|
||||
if tracked != testMaxTrackedPaths {
|
||||
t.Fatalf("want map size %d after refresh, got %d", testMaxTrackedPaths,
|
||||
tracked)
|
||||
}
|
||||
|
||||
if dropped != 1 {
|
||||
@@ -303,17 +312,21 @@ func TestPeeringHandlerCapDropsAndCounts(t *testing.T) {
|
||||
|
||||
// TestPeeringHandlerRunResetsTheDroppedCount fills the map, has the handler
|
||||
// drop one path, and runs the processing. The count of dropped paths is the
|
||||
// run's own, so it is 0 again after the run.
|
||||
// run's own, so it is 0 again after the run. The handler's limit is small, and
|
||||
// its timer does not fire.
|
||||
func TestPeeringHandlerRunResetsTheDroppedCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
h := newTestHandler(newMockStore())
|
||||
h := newPeeringHandler(newMockStore(), logger.New(), longerThanAnyTest,
|
||||
testMaxTrackedPaths)
|
||||
|
||||
defer stopInTime(t, h)
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
// Paths of one AS carry no peering, so the run records nothing.
|
||||
h.mu.Lock()
|
||||
for asn := 1; len(h.asPaths) < maxTrackedPaths; asn++ {
|
||||
for asn := 1; len(h.asPaths) < testMaxTrackedPaths; asn++ {
|
||||
h.asPaths[pathKey(t, asn)] = database.SeenTimes{First: now, Last: now}
|
||||
}
|
||||
h.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user