Files
EasyTier/easytier-go/examples/dial/main_test.go
KKRainbow 3d0c9c3ca5 chore(go): use lowercase module import path (#2560)
* chore(go): use lowercase module import path
* ci: scope checks for Go module changes
2026-09-10 15:13:55 +08:00

210 lines
5.1 KiB
Go

package main
import (
"bytes"
"context"
"encoding/binary"
"io"
"net"
"net/netip"
"strings"
"testing"
"time"
corehost "github.com/easytier/easytier/easytier-go"
"github.com/easytier/easytier/easytier-go/proto/common"
)
func TestParseOptions(t *testing.T) {
options, err := parseOptions([]string{
"-p", "tcp://198.51.100.10:11010",
"--network-name", "office",
"--network-secret", "secret",
"--ipv4", "10.144.0.10/24",
"--network", "udp4",
"--address", "10.144.0.20:7000",
"--connect-timeout", "3s",
})
if err != nil {
t.Fatalf("parse options: %v", err)
}
if options.network != "udp4" ||
options.address != "10.144.0.20:7000" ||
options.connectTimeout != 3*time.Second ||
len(options.peers) != 1 {
t.Fatalf("parsed options = %+v", options)
}
}
func TestParseOptionsRejectsInvalidArguments(t *testing.T) {
valid := []string{
"-p", "tcp://198.51.100.10:11010",
"--network-name", "office",
"--network-secret", "secret",
"--ipv4", "10.144.0.10/24",
"--address", "10.144.0.20:7000",
}
tests := []struct {
name string
arguments []string
want string
}{
{
name: "network",
arguments: append(append([]string(nil), valid...), "--network", "sctp"),
want: "--network",
},
{
name: "destination",
arguments: []string{
"-p", "tcp://198.51.100.10:11010",
"--network-name", "office",
"--network-secret", "secret",
"--ipv4", "10.144.0.10/24",
"--address", "[2001:db8::1]:7000",
},
want: "--address",
},
{
name: "connect timeout",
arguments: append(append([]string(nil), valid...), "--connect-timeout", "0s"),
want: "--connect-timeout",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := parseOptions(test.arguments)
if err == nil || !strings.Contains(err.Error(), test.want) {
t.Fatalf("parse error = %v, want containing %q", err, test.want)
}
})
}
}
func TestRoutesReachOverlayOrProxyDestination(t *testing.T) {
overlay := netip.MustParseAddr("10.144.0.20")
overlayOctets := overlay.As4()
routes := []*corehost.Route{
{
Ipv4Addr: &common.Ipv4Inet{
Address: &common.Ipv4Addr{
Addr: binary.BigEndian.Uint32(overlayOctets[:]),
},
},
},
{ProxyCidrs: []string{"10.200.0.0/24"}},
}
if !routesReach(routes, overlay) {
t.Fatal("overlay destination was not reachable")
}
if !routesReach(routes, netip.MustParseAddr("10.200.0.8")) {
t.Fatal("proxy destination was not reachable")
}
if routesReach(routes, netip.MustParseAddr("10.201.0.8")) {
t.Fatal("unknown destination was reachable")
}
}
func TestRelayTCP(t *testing.T) {
client, server := net.Pipe()
defer client.Close()
defer server.Close()
serverDone := make(chan error, 1)
go func() {
request := make([]byte, len("request"))
if _, err := io.ReadFull(server, request); err != nil {
serverDone <- err
return
}
if string(request) != "request" {
serverDone <- io.ErrUnexpectedEOF
return
}
if _, err := server.Write([]byte("response")); err != nil {
serverDone <- err
return
}
serverDone <- server.Close()
}()
var output bytes.Buffer
if err := relayTCP(client, strings.NewReader("request"), &output); err != nil {
t.Fatalf("relay TCP: %v", err)
}
if err := <-serverDone; err != nil {
t.Fatalf("serve TCP exchange: %v", err)
}
if output.String() != "response" {
t.Fatalf("TCP output = %q", output.String())
}
}
func TestExchangeUDP(t *testing.T) {
echo, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
if err != nil {
t.Fatalf("listen UDP echo: %v", err)
}
defer echo.Close()
echoDone := make(chan error, 1)
go func() {
packet := make([]byte, maxUDPPayload)
length, client, err := echo.ReadFromUDP(packet)
if err == nil {
_, err = echo.WriteToUDP(packet[:length], client)
}
echoDone <- err
}()
connection, err := net.DialUDP("udp4", nil, echo.LocalAddr().(*net.UDPAddr))
if err != nil {
t.Fatalf("dial UDP echo: %v", err)
}
defer connection.Close()
_ = connection.SetDeadline(time.Now().Add(5 * time.Second))
var output bytes.Buffer
if err := exchangeUDP(
context.Background(),
connection,
strings.NewReader("datagram"),
&output,
); err != nil {
t.Fatalf("exchange UDP: %v", err)
}
if err := <-echoDone; err != nil {
t.Fatalf("serve UDP exchange: %v", err)
}
if output.String() != "datagram" {
t.Fatalf("UDP output = %q", output.String())
}
}
func TestExchangeUDPRejectsOversizedInput(t *testing.T) {
connection, peer := net.Pipe()
defer connection.Close()
defer peer.Close()
err := exchangeUDP(
context.Background(),
connection,
strings.NewReader(strings.Repeat("x", maxUDPPayload+1)),
io.Discard,
)
if err == nil || !strings.Contains(err.Error(), "maximum payload") {
t.Fatalf("oversized UDP error = %v", err)
}
}
func TestExchangeUDPCanCancelInputRead(t *testing.T) {
connection, peer := net.Pipe()
defer connection.Close()
defer peer.Close()
input, inputWriter := io.Pipe()
defer input.Close()
defer inputWriter.Close()
ctx, cancel := context.WithCancel(context.Background())
cancel()
if err := exchangeUDP(ctx, connection, input, io.Discard); err != context.Canceled {
t.Fatalf("cancelled UDP exchange error = %v", err)
}
}