lolly/internal/server/monitoring_registration_test.go
xfy dea5e28f5f test(server): fix data race in monitoring endpoint tests
Replace concurrent polling of srv.GetListeners() with pre-created
net.Listener injected via srv.SetListeners(). The previous approach
raced with the Start() goroutine writing to s.listeners and calling
net.Listen().

Also remove unused waitForServerRunning call.
2026-06-11 15:23:46 +08:00

125 lines
3.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package server
import (
"net"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"rua.plus/lolly/internal/config"
"rua.plus/lolly/internal/matcher"
)
func TestMonitoringEndpoints_OnlyRegisteredWhenEnabled(t *testing.T) {
// Case 1: monitoring 未启用时,/_status 不应注册
cfg := &config.Config{
Servers: []config.ServerConfig{{
Listen: "127.0.0.1:0",
Static: []config.StaticConfig{{
Path: "/",
Root: t.TempDir(),
}},
}},
}
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen failed: %v", err)
}
defer ln.Close()
addr := ln.Addr().String()
cfg.Servers[0].Listen = addr
srv := New(cfg)
srv.SetListeners([]net.Listener{ln})
go srv.Start()
defer srv.StopWithTimeout(5 * time.Second)
client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI("http://" + addr + "/_status")
req.Header.SetMethod("GET")
if err := client.Do(req, resp); err != nil {
t.Fatalf("request failed: %v", err)
}
// 未启用时应返回 404被 static handler 处理,找不到文件)
assert.Equal(t, fasthttp.StatusNotFound, resp.StatusCode(),
"status endpoint should NOT be registered when monitoring is disabled")
}
func TestMonitoringEndpoints_ReachableWhenEnabled(t *testing.T) {
cfg := &config.Config{
Monitoring: config.MonitoringConfig{
Status: config.StatusConfig{
Enabled: true,
Path: "/_status",
Allow: []string{"127.0.0.1"},
},
},
Servers: []config.ServerConfig{{
Listen: "127.0.0.1:0",
Static: []config.StaticConfig{{
Path: "/",
Root: t.TempDir(),
}},
}},
}
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen failed: %v", err)
}
defer ln.Close()
addr := ln.Addr().String()
cfg.Servers[0].Listen = addr
srv := New(cfg)
srv.SetListeners([]net.Listener{ln})
go srv.Start()
defer srv.StopWithTimeout(5 * time.Second)
client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI("http://" + addr + "/_status")
req.Header.SetMethod("GET")
if err := client.Do(req, resp); err != nil {
t.Fatalf("request failed: %v", err)
}
assert.Equal(t, fasthttp.StatusOK, resp.StatusCode(),
"status endpoint should be reachable when enabled, even with static handler on /")
}
func TestLocationEngine_StatusExactBeatsStaticPrefix(t *testing.T) {
// 独立验证 location engine 的优先级exact match 应该 beat prefix /
engine := matcher.NewLocationEngine()
engine.AddExact("/_status", func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(fasthttp.StatusOK)
}, false)
engine.AddPrefix("/", func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(fasthttp.StatusNotFound)
}, false)
engine.MarkInitialized()
result := engine.Match([]byte("/_status"))
if result == nil {
t.Fatal("expected match")
}
if result.LocationType != matcher.LocationTypeExact {
t.Errorf("expected exact match, got %s", result.LocationType)
}
}