mirror of
https://github.com/Quad4-Software/Reticulum-Go
synced 2026-08-29 23:48:44 -04:00
110 lines
3.1 KiB
Go
110 lines
3.1 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (c) 2024-2026 Quad4.io
|
|
|
|
package discovery
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"sync/atomic"
|
|
"testing"
|
|
)
|
|
|
|
func TestInterfaceDiscoveryInvalidStampCache(t *testing.T) {
|
|
h := &interfaceAnnounceHandler{
|
|
requiredValue: 200,
|
|
validCache: make(map[string]*ReceivedAnnounceInfo),
|
|
invalidCache: make(map[string]struct{}),
|
|
}
|
|
app, err := BuildAppData(Info{
|
|
Type: "AutoInterface",
|
|
TransportID: bytes.Repeat([]byte{0x11}, 16),
|
|
Name: "node",
|
|
}, 2, WorkblockExpandRounds)
|
|
if err != nil {
|
|
t.Fatalf("BuildAppData: %v", err)
|
|
}
|
|
if err := h.ReceivedAnnounce(nil, nil, app, 0); err != nil {
|
|
t.Fatalf("first announce: %v", err)
|
|
}
|
|
sum := sha256.Sum256(app[1:])
|
|
key := string(sum[:])
|
|
if _, ok := h.invalidCache[key]; !ok {
|
|
t.Fatal("expected invalid stamp cache entry")
|
|
}
|
|
var validated atomic.Int32
|
|
h.requiredValue = 0
|
|
h.onDiscovered = func(*ReceivedAnnounceInfo) { validated.Add(1) }
|
|
if err := h.ReceivedAnnounce(nil, nil, app, 0); err != nil {
|
|
t.Fatalf("cached announce: %v", err)
|
|
}
|
|
if validated.Load() != 0 {
|
|
t.Fatal("invalid cache should short-circuit without callback")
|
|
}
|
|
}
|
|
|
|
func TestInterfaceDiscoveryValidStampCache(t *testing.T) {
|
|
var hits atomic.Int32
|
|
h := &interfaceAnnounceHandler{
|
|
requiredValue: 2,
|
|
onDiscovered: func(*ReceivedAnnounceInfo) { hits.Add(1) },
|
|
validCache: make(map[string]*ReceivedAnnounceInfo),
|
|
invalidCache: make(map[string]struct{}),
|
|
}
|
|
app, err := BuildAppData(Info{
|
|
Type: "AutoInterface",
|
|
TransportID: bytes.Repeat([]byte{0x11}, 16),
|
|
Name: "node",
|
|
}, 2, WorkblockExpandRounds)
|
|
if err != nil {
|
|
t.Fatalf("BuildAppData: %v", err)
|
|
}
|
|
if _, err := ValidateAndDecode(app, 2, WorkblockExpandRounds); err != nil {
|
|
t.Fatalf("precheck ValidateAndDecode: %v", err)
|
|
}
|
|
if err := h.ReceivedAnnounce(nil, nil, app, 0); err != nil {
|
|
t.Fatalf("first announce: %v", err)
|
|
}
|
|
if hits.Load() != 1 {
|
|
t.Fatalf("hits=%d want 1", hits.Load())
|
|
}
|
|
sum := sha256.Sum256(app[1:])
|
|
key := string(sum[:])
|
|
if _, ok := h.validCache[key]; !ok {
|
|
t.Fatal("expected valid stamp cache entry")
|
|
}
|
|
if err := h.ReceivedAnnounce(nil, nil, app, 0); err != nil {
|
|
t.Fatalf("second announce: %v", err)
|
|
}
|
|
if hits.Load() != 2 {
|
|
t.Fatalf("hits=%d want 2 from cache", hits.Load())
|
|
}
|
|
}
|
|
|
|
func TestInterfaceDiscoverySingleFlightDropsConcurrent(t *testing.T) {
|
|
var hits atomic.Int32
|
|
h := &interfaceAnnounceHandler{
|
|
requiredValue: 2,
|
|
onDiscovered: func(*ReceivedAnnounceInfo) { hits.Add(1) },
|
|
validCache: make(map[string]*ReceivedAnnounceInfo),
|
|
invalidCache: make(map[string]struct{}),
|
|
validating: true,
|
|
}
|
|
app, err := BuildAppData(Info{
|
|
Type: "AutoInterface",
|
|
TransportID: bytes.Repeat([]byte{0x22}, 16),
|
|
Name: "node2",
|
|
}, 2, WorkblockExpandRounds)
|
|
if err != nil {
|
|
t.Fatalf("BuildAppData: %v", err)
|
|
}
|
|
if err := h.ReceivedAnnounce(nil, nil, app, 0); err != nil {
|
|
t.Fatalf("concurrent announce: %v", err)
|
|
}
|
|
if hits.Load() != 0 {
|
|
t.Fatal("single-flight drop should not invoke callback")
|
|
}
|
|
if len(h.validCache) != 0 || len(h.invalidCache) != 0 {
|
|
t.Fatal("dropped announce must not populate caches")
|
|
}
|
|
}
|