Files
mc-gateway/cmd/gateway/tcp_web_port_reuse_test.go
tursom f508ecc1b9
Some checks failed
Go / build (.exe, 386, windows, windows-386) (push) Has been cancelled
Go / build (.exe, amd64, windows, windows-amd64) (push) Has been cancelled
Go / build (.exe, arm64, windows, windows-arm64) (push) Has been cancelled
Go / build (386, freebsd, freebsd-386) (push) Has been cancelled
Go / build (386, linux, linux-386) (push) Has been cancelled
Go / build (386, netbsd, netbsd-386) (push) Has been cancelled
Go / build (386, openbsd, openbsd-386) (push) Has been cancelled
Go / build (386, plan9, plan9-386) (push) Has been cancelled
Go / build (amd64, darwin, darwin-amd64) (push) Has been cancelled
Go / build (amd64, dragonfly, dragonfly-amd64) (push) Has been cancelled
Go / build (amd64, freebsd, freebsd-amd64) (push) Has been cancelled
Go / build (amd64, illumos, illumos-amd64) (push) Has been cancelled
Go / build (amd64, linux, linux-amd64) (push) Has been cancelled
Go / build (amd64, netbsd, netbsd-amd64) (push) Has been cancelled
Go / build (amd64, openbsd, openbsd-amd64) (push) Has been cancelled
Go / build (amd64, plan9, plan9-amd64) (push) Has been cancelled
Go / build (amd64, solaris, solaris-amd64) (push) Has been cancelled
Go / build (arm, 6, linux, linux-armv6) (push) Has been cancelled
Go / build (arm, 7, linux, linux-armv7) (push) Has been cancelled
Go / build (arm, freebsd, freebsd-arm) (push) Has been cancelled
Go / build (arm, netbsd, netbsd-arm) (push) Has been cancelled
Go / build (arm, openbsd, openbsd-arm) (push) Has been cancelled
Go / build (arm, plan9, plan9-arm) (push) Has been cancelled
Go / build (arm64, darwin, darwin-arm64) (push) Has been cancelled
Go / build (arm64, freebsd, freebsd-arm64) (push) Has been cancelled
Go / build (arm64, linux, linux-arm64) (push) Has been cancelled
Go / build (arm64, netbsd, netbsd-arm64) (push) Has been cancelled
Go / build (arm64, openbsd, openbsd-arm64) (push) Has been cancelled
Go / build (loong64, linux, linux-loong64) (push) Has been cancelled
Go / build (mips, linux, linux-mips) (push) Has been cancelled
Go / build (mips64, linux, linux-mips64) (push) Has been cancelled
Go / build (mips64le, linux, linux-mips64le) (push) Has been cancelled
Go / build (mipsle, linux, linux-mipsle) (push) Has been cancelled
Go / build (ppc64, aix, aix-ppc64) (push) Has been cancelled
Go / build (ppc64, linux, linux-ppc64) (push) Has been cancelled
Go / build (ppc64, openbsd, openbsd-ppc64) (push) Has been cancelled
Go / build (ppc64le, linux, linux-ppc64le) (push) Has been cancelled
Go / build (riscv64, freebsd, freebsd-riscv64) (push) Has been cancelled
Go / build (riscv64, linux, linux-riscv64) (push) Has been cancelled
Go / build (riscv64, openbsd, openbsd-riscv64) (push) Has been cancelled
Go / build (s390x, linux, linux-s390x) (push) Has been cancelled
Docker Image / docker (push) Has been cancelled
Go / merge-artifacts (push) Has been cancelled
docs: 补充中文代码注释
2026-06-27 20:15:29 +08:00

219 lines
5.3 KiB
Go

// cmd/gateway/tcp_web_port_reuse_test.go 包含用于约束 tcp web port reuse 行为的测试。
package main
import (
"errors"
"net"
"net/http"
"testing"
"time"
"github.com/gorilla/websocket"
"github.com/tursom/mc-gateway/internal/gatewayconfig"
"github.com/tursom/mc-gateway/protocol"
)
func TestTCPWebPortReuseEnabledUsesNormalizedPorts(t *testing.T) {
tests := []struct {
name string
tcp gatewayconfig.ProtocolConfig
websocket gatewayconfig.WebSocketConfig
want bool
}{
{
name: "explicit same port",
tcp: gatewayconfig.ProtocolConfig{Enable: true, Port: 25565},
websocket: gatewayconfig.WebSocketConfig{Enable: true, Port: 25565},
want: true,
},
{
name: "websocket default port",
tcp: gatewayconfig.ProtocolConfig{Enable: true, Port: defaultWebSocketPort},
websocket: gatewayconfig.WebSocketConfig{Enable: true},
want: true,
},
{
name: "tcp default port",
tcp: gatewayconfig.ProtocolConfig{Enable: true},
websocket: gatewayconfig.WebSocketConfig{Enable: true, Port: defaultTCPPort},
want: true,
},
{
name: "different ports",
tcp: gatewayconfig.ProtocolConfig{Enable: true, Port: 25565},
websocket: gatewayconfig.WebSocketConfig{Enable: true, Port: 25566},
want: false,
},
{
name: "tcp disabled",
tcp: gatewayconfig.ProtocolConfig{Enable: false, Port: 25565},
websocket: gatewayconfig.WebSocketConfig{Enable: true, Port: 25565},
want: false,
},
{
name: "websocket disabled",
tcp: gatewayconfig.ProtocolConfig{Enable: true, Port: 25565},
websocket: gatewayconfig.WebSocketConfig{Enable: false, Port: 25565},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer saveGatewayState(t)()
config.Tcp = tt.tcp
config.WebSocket = tt.websocket
if got := tcpWebPortReuseEnabled(); got != tt.want {
t.Fatalf("tcpWebPortReuseEnabled() = %v, want %v", got, tt.want)
}
})
}
}
func TestServeTcpWebPortReuseServesHTTPOnSharedPort(t *testing.T) {
defer saveGatewayState(t)()
requested := make(chan string, 1)
addr, stop := startPortReuseTestServer(
t,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requested <- r.URL.Path
w.WriteHeader(http.StatusNoContent)
}),
func(conn net.Conn) {
conn.Close()
},
)
defer stop()
client := &http.Client{
Timeout: 2 * time.Second,
Transport: &http.Transport{Proxy: nil},
}
resp, err := client.Get("http://" + addr + "/status")
if err != nil {
t.Fatalf("Get() error = %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent {
t.Fatalf("HTTP status = %d, want %d", resp.StatusCode, http.StatusNoContent)
}
select {
case got := <-requested:
if got != "/status" {
t.Fatalf("request path = %q, want /status", got)
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for HTTP request")
}
}
func TestServeTcpWebPortReuseUpgradesWebSocketOnSharedPort(t *testing.T) {
defer saveGatewayState(t)()
config.WebSocket.Path = "/gateway"
webSocketHandler := newWebSocketHandler()
handlerDone := make(chan struct{})
addr, stop := startPortReuseTestServer(
t,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer close(handlerDone)
webSocketHandler.ServeHTTP(w, r)
}),
func(conn net.Conn) {
conn.Close()
},
)
defer stop()
conn, _, err := websocket.DefaultDialer.Dial("ws://"+addr+"/gateway", nil)
if err != nil {
t.Fatalf("Dial() error = %v", err)
}
conn.Close()
select {
case <-handlerDone:
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for WebSocket handler")
}
}
func TestServeTcpWebPortReusePreservesMinecraftInitialPacket(t *testing.T) {
defer saveGatewayState(t)()
hostCh := make(chan string, 1)
addr, stop := startPortReuseTestServer(
t,
http.NotFoundHandler(),
func(conn net.Conn) {
defer conn.Close()
buf := getProxyBuffer()
defer putProxyBuffer(buf)
n, err := conn.Read(buf)
if err != nil {
hostCh <- ""
return
}
hostCh <- protocol.GetMcHost(buf[:n])
},
)
defer stop()
conn, err := net.Dial("tcp", addr)
if err != nil {
t.Fatalf("Dial() error = %v", err)
}
defer conn.Close()
if _, err := conn.Write(gatewayTestPacket("play.example")); err != nil {
t.Fatalf("Write() error = %v", err)
}
select {
case got := <-hostCh:
if got != "play.example" {
t.Fatalf("Minecraft host = %q, want play.example", got)
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for Minecraft branch")
}
}
func startPortReuseTestServer(t *testing.T, handler http.Handler, tcpHandler func(net.Conn)) (string, func()) {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("Listen() error = %v", err)
}
done := make(chan error, 1)
go func() {
done <- serveTcpWebPortReuse(listener, handler, tcpHandler)
}()
stop := func() {
if err := listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
t.Fatalf("Close(listener) error = %v", err)
}
select {
case err := <-done:
if err != nil && !errors.Is(err, net.ErrClosed) {
t.Fatalf("serveTcpWebPortReuse() error = %v", err)
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for port reuse server shutdown")
}
}
return listener.Addr().String(), stop
}