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
219 lines
5.3 KiB
Go
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
|
|
}
|