test(handler/router): add handler_test.go (NewHandler, Init, Handle, Close)
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/handler"
|
||||
"github.com/go-gost/relay"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// newInitdHandler — convenience constructor with minimal Init
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func newInitdHandler(t *testing.T, opts ...handler.Option) *routerHandler {
|
||||
t.Helper()
|
||||
h := NewHandler(append([]handler.Option{
|
||||
handler.LoggerOption(&testLogger{}),
|
||||
}, opts...)...).(*routerHandler)
|
||||
if err := h.parseMetadata(testMD(nil)); err != nil {
|
||||
t.Fatalf("parseMetadata: %v", err)
|
||||
}
|
||||
h.id = uuid.New().String()
|
||||
h.log = &testLogger{}
|
||||
h.pool = NewConnectorPool(h.id)
|
||||
_, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
return h
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NewHandler tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestNewHandler_Minimal(t *testing.T) {
|
||||
h := NewHandler()
|
||||
if h == nil {
|
||||
t.Fatal("handler is nil")
|
||||
}
|
||||
rh := h.(*routerHandler)
|
||||
if rh.options.Service != "" {
|
||||
t.Errorf("Service = %q, want empty", rh.options.Service)
|
||||
}
|
||||
if rh.sdCache == nil {
|
||||
t.Error("sdCache is nil")
|
||||
}
|
||||
if rh.routeCache == nil {
|
||||
t.Error("routeCache is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewHandler_WithOptions(t *testing.T) {
|
||||
h := NewHandler(
|
||||
handler.LoggerOption(&testLogger{}),
|
||||
handler.ServiceOption("test-svc"),
|
||||
)
|
||||
rh := h.(*routerHandler)
|
||||
if rh.options.Logger == nil {
|
||||
t.Error("Logger not set")
|
||||
}
|
||||
if rh.options.Service != "test-svc" {
|
||||
t.Errorf("Service = %q, want test-svc", rh.options.Service)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Init tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestInit_Minimal(t *testing.T) {
|
||||
rh := NewHandler(handler.LoggerOption(&testLogger{})).(*routerHandler)
|
||||
if err := rh.Init(testMD(nil)); err != nil {
|
||||
t.Fatalf("Init: %v", err)
|
||||
}
|
||||
if rh.id == "" {
|
||||
t.Error("id is empty")
|
||||
}
|
||||
if rh.cancel == nil {
|
||||
t.Error("cancel is nil")
|
||||
}
|
||||
if rh.stats != nil {
|
||||
t.Error("stats should be nil (no observer)")
|
||||
}
|
||||
if rh.limiter != nil {
|
||||
t.Error("limiter should be nil (no limiter)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInit_WithObserver(t *testing.T) {
|
||||
obs := newFakeObserver(10)
|
||||
rh := NewHandler(
|
||||
handler.LoggerOption(&testLogger{}),
|
||||
handler.ObserverOption(obs),
|
||||
handler.ServiceOption("test-svc"),
|
||||
).(*routerHandler)
|
||||
|
||||
if err := rh.Init(testMD(nil)); err != nil {
|
||||
t.Fatalf("Init: %v", err)
|
||||
}
|
||||
if rh.stats == nil {
|
||||
t.Error("stats should be non-nil when observer is set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInit_WithLimiter(t *testing.T) {
|
||||
rh := NewHandler(
|
||||
handler.LoggerOption(&testLogger{}),
|
||||
handler.TrafficLimiterOption(&mockTrafficLimiter{}),
|
||||
).(*routerHandler)
|
||||
|
||||
if err := rh.Init(testMD(nil)); err != nil {
|
||||
t.Fatalf("Init: %v", err)
|
||||
}
|
||||
if rh.limiter == nil {
|
||||
t.Error("limiter should be non-nil when limiter is set")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handle tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestHandle_BadVersion(t *testing.T) {
|
||||
h := newInitdHandler(t)
|
||||
|
||||
req := relay.Request{
|
||||
Version: 0x02, // not Version1 — triggers error in ReadFrom
|
||||
Cmd: relay.CmdAssociate,
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
req.WriteTo(&buf)
|
||||
|
||||
conn := &fakeConn{buf: buf.Bytes()}
|
||||
err := h.Handle(context.Background(), conn)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for bad version")
|
||||
}
|
||||
|
||||
// The response is not written when ReadFrom fails, so we only verify
|
||||
// that the connection was closed (defer conn.Close in Handle).
|
||||
if !conn.closed {
|
||||
t.Error("connection was not closed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandle_UnknownCmd(t *testing.T) {
|
||||
h := newInitdHandler(t)
|
||||
|
||||
req := relay.Request{
|
||||
Version: relay.Version1,
|
||||
Cmd: 0xFF,
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
req.WriteTo(&buf)
|
||||
|
||||
conn := &fakeConn{buf: buf.Bytes()}
|
||||
err := h.Handle(context.Background(), conn)
|
||||
if err != ErrUnknownCmd {
|
||||
t.Errorf("err = %v, want ErrUnknownCmd", err)
|
||||
}
|
||||
|
||||
resp := readRelayResponse(t, conn.writeBuf.Bytes())
|
||||
if resp.Status != relay.StatusBadRequest {
|
||||
t.Errorf("status = %d, want BadRequest", resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandle_AuthSuccess(t *testing.T) {
|
||||
h := newInitdHandler(t,
|
||||
handler.AutherOption(&mockAuther{
|
||||
authenticateFn: func(ctx context.Context, user, pass string, opts ...auth.Option) (string, bool) {
|
||||
return "client-1", true
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
rid := relay.NewTunnelID([]byte("0123456789abcdef"))
|
||||
req := relay.Request{
|
||||
Version: relay.Version1,
|
||||
Cmd: relay.CmdAssociate,
|
||||
Features: []relay.Feature{
|
||||
&relay.UserAuthFeature{Username: "user", Password: "pass"},
|
||||
&relay.TunnelFeature{ID: rid},
|
||||
&relay.NetworkFeature{Network: relay.NetworkIP},
|
||||
},
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
req.WriteTo(&buf)
|
||||
|
||||
conn := &fakeConn{buf: buf.Bytes()}
|
||||
err := h.Handle(context.Background(), conn)
|
||||
if err != nil {
|
||||
t.Fatalf("Handle: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandle_AuthFailure(t *testing.T) {
|
||||
h := newInitdHandler(t,
|
||||
handler.AutherOption(&mockAuther{
|
||||
authenticateFn: func(ctx context.Context, user, pass string, opts ...auth.Option) (string, bool) {
|
||||
return "", false
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
rid := relay.NewTunnelID([]byte("0123456789abcdef"))
|
||||
req := relay.Request{
|
||||
Version: relay.Version1,
|
||||
Cmd: relay.CmdAssociate,
|
||||
Features: []relay.Feature{
|
||||
&relay.UserAuthFeature{Username: "user", Password: "wrong"},
|
||||
&relay.TunnelFeature{ID: rid},
|
||||
&relay.NetworkFeature{Network: relay.NetworkIP},
|
||||
},
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
req.WriteTo(&buf)
|
||||
|
||||
conn := &fakeConn{buf: buf.Bytes()}
|
||||
err := h.Handle(context.Background(), conn)
|
||||
if err != ErrUnauthorized {
|
||||
t.Errorf("err = %v, want ErrUnauthorized", err)
|
||||
}
|
||||
|
||||
resp := readRelayResponse(t, conn.writeBuf.Bytes())
|
||||
if resp.Status != relay.StatusUnauthorized {
|
||||
t.Errorf("status = %d, want Unauthorized", resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandle_AssociateValid(t *testing.T) {
|
||||
h := newInitdHandler(t)
|
||||
h.md.ingress = nil
|
||||
|
||||
rid := relay.NewTunnelID([]byte("0123456789abcdef"))
|
||||
reqData := buildRelayAssociateRequest(t, "10.0.0.1:0", rid, "ip")
|
||||
|
||||
conn := &fakeConn{buf: reqData}
|
||||
err := h.Handle(context.Background(), conn)
|
||||
if err != nil {
|
||||
t.Fatalf("Handle: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Close tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
h := newInitdHandler(t)
|
||||
h.Close()
|
||||
// should not panic
|
||||
}
|
||||
|
||||
func TestClose_Double(t *testing.T) {
|
||||
h := newInitdHandler(t)
|
||||
h.Close()
|
||||
h.Close() // should not panic
|
||||
}
|
||||
Reference in New Issue
Block a user