refactor(handler/tunnel): split 794-line entrypoint.go into 6 files, fix 3 bugs, add 48 tests
Breaking Change: moves Connector, ConnectorPool, parseTunnelID from tunnel.go into dedicated connector.go and id.go. Bug Fixes: - dialer.go: clear stale retry err so SD fallback is not masked (nil err from pool.Get() left previous iteration's error live) - connect.go: check WriteTo errors in both mux and non-mux paths - eprelay.go: use fresh relay.Response for features sent over mux (previously reused same resp struct after resp.WriteTo(muxConn)) Refactor: - entrypoint.go: split ~790 lines into 6 files (ephttp, eptls, eprelay, epwebsocket, eplistener, entrypointsvc), moved to dedicated package - handler.go: moved initEntrypoints/createEntrypointService to entrypointsvc.go - tunnel.go: moved Connector/ConnectorPool/parseTunnelID to connector.go and id.go - connect.go: moved entrypoint-originated handleConnect to eprelay.go (handler-side handleConnect kept in connect.go) Tests (48 new, 88 total): - id_test.go: parseTunnelID variants (empty, UUID, private '$', invalid) - tunnel_test.go: Tunnel lifecycle (AddConnector, GetConnector weighted/closed filtering, CloseOnIdle, clean), Connector (NewConnector nil-opts, GetConn nil/closed session, Close, IsClosed), ConnectorPool (Add/Get/Close, idle cleanup, concurrency) - dialer_test.go: SD error paths (sd.Get error, empty address) - handler_test.go: observeStats (nil observer, cancelled context loop), initEntrypoints (no entrypoints configured) - helpers_test.go: testLogger, fakeConn for handler tests - eprelay_test.go: handleConnect ingress/dial/SD round-trip
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-gost/relay"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestParseTunnelID(t *testing.T) {
|
||||
t.Run("empty string", func(t *testing.T) {
|
||||
tid := parseTunnelID("")
|
||||
if !tid.IsZero() {
|
||||
t.Error("expected zero tunnel ID for empty string")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("valid uuid", func(t *testing.T) {
|
||||
tid := parseTunnelID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
if tid.IsZero() {
|
||||
t.Error("expected non-zero tunnel ID")
|
||||
}
|
||||
if tid.IsPrivate() {
|
||||
t.Error("expected non-private tunnel ID")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("valid uuid with $ prefix", func(t *testing.T) {
|
||||
tid := parseTunnelID("$6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
if tid.IsZero() {
|
||||
t.Error("expected non-zero tunnel ID")
|
||||
}
|
||||
if !tid.IsPrivate() {
|
||||
t.Error("expected private tunnel ID")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid uuid", func(t *testing.T) {
|
||||
tid := parseTunnelID("not-a-uuid")
|
||||
if !tid.IsZero() {
|
||||
t.Error("expected zero tunnel ID for invalid input")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid uuid with $ prefix", func(t *testing.T) {
|
||||
tid := parseTunnelID("$not-a-uuid")
|
||||
if !tid.IsZero() {
|
||||
t.Error("expected zero tunnel ID for invalid input")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseTunnelID_PrivateMarker(t *testing.T) {
|
||||
t.Run("dollar not at start", func(t *testing.T) {
|
||||
tid := parseTunnelID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
if tid.IsPrivate() {
|
||||
t.Error("expected non-private when $ is not at start")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseTunnelID_RoundTrip(t *testing.T) {
|
||||
original := parseTunnelID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
t.Logf("original string: %s", original.String())
|
||||
|
||||
reparsed := parseTunnelID(original.String())
|
||||
if !original.Equal(reparsed) {
|
||||
t.Errorf("round-trip failed: original=%v reparsed=%v", original, reparsed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTunnelID_PrivateRoundTrip(t *testing.T) {
|
||||
original := parseTunnelID("$6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
if !original.IsPrivate() {
|
||||
t.Fatal("expected private tunnel ID")
|
||||
}
|
||||
t.Logf("original string: %s", original.String())
|
||||
|
||||
// The private flag is carried in the struct, not in the string representation.
|
||||
// Reparsing from String() gives a non-private ID because the $ prefix is not
|
||||
// part of the relay.TunnelID.String() output.
|
||||
reparsed := parseTunnelID(original.String())
|
||||
if !original.Equal(reparsed) {
|
||||
t.Errorf("round-trip failed: original=%v reparsed=%v", original, reparsed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTunnelID_RelayCompatibility(t *testing.T) {
|
||||
id := parseTunnelID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
u, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
var raw [16]byte
|
||||
copy(raw[:], u[:])
|
||||
expected := relay.NewTunnelID(raw[:])
|
||||
if !id.Equal(expected) {
|
||||
t.Error("parseTunnelID result should match relay.NewTunnelID")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user