coder/tailnet/derpmap_test.go

165 lines
4.6 KiB
Go

package tailnet_test
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
"github.com/coder/coder/v2/tailnet"
)
func TestNewDERPMap(t *testing.T) {
t.Parallel()
t.Run("WithoutRemoteURL", func(t *testing.T) {
t.Parallel()
derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{
RegionID: 1,
Nodes: []*tailcfg.DERPNode{{}},
}, []string{"stun.google.com:2345"}, "", "", false)
require.NoError(t, err)
require.Len(t, derpMap.Regions, 2)
require.Len(t, derpMap.Regions[1].Nodes, 1)
require.Len(t, derpMap.Regions[2].Nodes, 1)
})
t.Run("RemoteURL", func(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, _ := json.Marshal(&tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {
RegionID: 1,
Nodes: []*tailcfg.DERPNode{{}},
},
},
})
_, _ = w.Write(data)
}))
t.Cleanup(server.Close)
derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{
RegionID: 2,
}, []string{}, server.URL, "", false)
require.NoError(t, err)
require.Len(t, derpMap.Regions, 2)
})
t.Run("RemoteConflicts", func(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, _ := json.Marshal(&tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {},
},
})
_, _ = w.Write(data)
}))
t.Cleanup(server.Close)
_, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{
RegionID: 1,
}, []string{}, server.URL, "", false)
require.Error(t, err)
})
t.Run("LocalPath", func(t *testing.T) {
t.Parallel()
localPath := filepath.Join(t.TempDir(), "derp.json")
content, err := json.Marshal(&tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {
Nodes: []*tailcfg.DERPNode{{}},
},
},
})
require.NoError(t, err)
err = os.WriteFile(localPath, content, 0o600)
require.NoError(t, err)
derpMap, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{
RegionID: 2,
}, []string{}, "", localPath, false)
require.NoError(t, err)
require.Len(t, derpMap.Regions, 2)
})
t.Run("DisableSTUN", func(t *testing.T) {
t.Parallel()
localPath := filepath.Join(t.TempDir(), "derp.json")
content, err := json.Marshal(&tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {
Nodes: []*tailcfg.DERPNode{{
STUNPort: 1234,
}},
},
2: {
Nodes: []*tailcfg.DERPNode{
{
STUNPort: 1234,
},
{
STUNPort: 12345,
},
{
STUNOnly: true,
STUNPort: 54321,
},
},
},
},
})
require.NoError(t, err)
err = os.WriteFile(localPath, content, 0o600)
require.NoError(t, err)
region := &tailcfg.DERPRegion{
RegionID: 3,
Nodes: []*tailcfg.DERPNode{{
STUNPort: 1234,
}},
}
derpMap, err := tailnet.NewDERPMap(context.Background(), region, []string{"127.0.0.1:54321"}, "", localPath, true)
require.NoError(t, err)
require.Len(t, derpMap.Regions, 3)
require.Len(t, derpMap.Regions[1].Nodes, 1)
require.EqualValues(t, -1, derpMap.Regions[1].Nodes[0].STUNPort)
// The STUNOnly node should get removed.
require.Len(t, derpMap.Regions[2].Nodes, 2)
require.EqualValues(t, -1, derpMap.Regions[2].Nodes[0].STUNPort)
require.False(t, derpMap.Regions[2].Nodes[0].STUNOnly)
require.EqualValues(t, -1, derpMap.Regions[2].Nodes[1].STUNPort)
require.False(t, derpMap.Regions[2].Nodes[1].STUNOnly)
// We don't add any nodes ourselves if STUN is disabled.
require.Len(t, derpMap.Regions[3].Nodes, 1)
// ... but we still remove the STUN port from existing nodes in the
// region.
require.EqualValues(t, -1, derpMap.Regions[3].Nodes[0].STUNPort)
})
t.Run("RequireRegions", func(t *testing.T) {
t.Parallel()
_, err := tailnet.NewDERPMap(context.Background(), nil, nil, "", "", false)
require.Error(t, err)
require.ErrorContains(t, err, "DERP map has no regions")
})
t.Run("RequireDERPNodes", func(t *testing.T) {
t.Parallel()
// No nodes.
_, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{}, nil, "", "", false)
require.Error(t, err)
require.ErrorContains(t, err, "DERP map has no DERP nodes")
// No DERP nodes.
_, err = tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{
Nodes: []*tailcfg.DERPNode{
{
STUNOnly: true,
},
},
}, nil, "", "", false)
require.Error(t, err)
require.ErrorContains(t, err, "DERP map has no DERP nodes")
})
}