tailscale/prober/derp_test.go
Anton Tolchanov 69f61dcad8 prober: add a DERP probe manager based on derpprobe
This ensures that each DERP server is probed individually (TLS and STUN)
and also manages per-region mesh probing. Actual probing code has been
copied from cmd/derpprobe.

Signed-off-by: Anton Tolchanov <anton@tailscale.com>
2022-10-20 13:54:34 +01:00

107 lines
2.9 KiB
Go

// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package prober
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"tailscale.com/tailcfg"
)
func TestDerpProber(t *testing.T) {
dm := &tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
0: {
RegionID: 0,
RegionCode: "zero",
Nodes: []*tailcfg.DERPNode{
{
Name: "n1",
RegionID: 0,
HostName: "derpn1.tailscale.test",
IPv4: "1.1.1.1",
IPv6: "::1",
},
{
Name: "n2",
RegionID: 0,
HostName: "derpn2.tailscale.test",
IPv4: "1.1.1.1",
IPv6: "::1",
},
},
},
},
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp, err := json.Marshal(dm)
if err != nil {
t.Fatal(err)
}
w.Write(resp)
}))
defer srv.Close()
clk := newFakeTime()
p := newForTest(clk.Now, clk.NewTicker)
dp := &derpProber{
p: p,
derpMapURL: srv.URL,
tlsProbeFn: func(_ string) ProbeFunc { return func(context.Context) error { return nil } },
udpProbeFn: func(_ string, _ int) ProbeFunc { return func(context.Context) error { return nil } },
meshProbeFn: func(_, _ string) ProbeFunc { return func(context.Context) error { return nil } },
nodes: make(map[string]*tailcfg.DERPNode),
probes: make(map[string]*Probe),
}
if err := dp.ProbeMap(context.Background()); err != nil {
t.Errorf("unexpected ProbeMap() error: %s", err)
}
if len(dp.nodes) != 2 || dp.nodes["derpn1.tailscale.test"] == nil || dp.nodes["derpn2.tailscale.test"] == nil {
t.Errorf("unexpected nodes: %+v", dp.nodes)
}
// Probes expected for two nodes:
// - 3 regular probes per node (TLS, UDPv4, UDPv6)
// - 4 mesh probes (N1->N2, N1->N1, N2->N1, N2->N2)
if len(dp.probes) != 10 {
t.Errorf("unexpected probes: %+v", dp.probes)
}
// Add one more node and check that probes got created.
dm.Regions[0].Nodes = append(dm.Regions[0].Nodes, &tailcfg.DERPNode{
Name: "n3",
RegionID: 0,
HostName: "derpn3.tailscale.test",
IPv4: "1.1.1.1",
IPv6: "::1",
})
if err := dp.ProbeMap(context.Background()); err != nil {
t.Errorf("unexpected ProbeMap() error: %s", err)
}
if len(dp.nodes) != 3 {
t.Errorf("unexpected nodes: %+v", dp.nodes)
}
// 9 regular probes + 9 mesh probes
if len(dp.probes) != 18 {
t.Errorf("unexpected probes: %+v", dp.probes)
}
// Remove 2 nodes and check that probes have been destroyed.
dm.Regions[0].Nodes = dm.Regions[0].Nodes[:1]
if err := dp.ProbeMap(context.Background()); err != nil {
t.Errorf("unexpected ProbeMap() error: %s", err)
}
if len(dp.nodes) != 1 {
t.Errorf("unexpected nodes: %+v", dp.nodes)
}
// 3 regular probes + 1 mesh probe
if len(dp.probes) != 4 {
t.Errorf("unexpected probes: %+v", dp.probes)
}
}