You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
5.5 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package server
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
"github.com/noahlann/nnet/pkg/config"
ctxpkg "github.com/noahlann/nnet/pkg/context"
"github.com/noahlann/nnet/pkg/errors"
"github.com/noahlann/nnet/pkg/health"
routerpkg "github.com/noahlann/nnet/pkg/router"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestServerNew(t *testing.T) {
cfg := &config.Config{
Addr: "tcp://:8080", // 使用标准格式
}
server, err := NewServer(cfg)
require.NoError(t, err, "Expected no error when creating server")
assert.NotNil(t, server, "Expected server to be non-nil")
}
func TestServerNewInvalidAddr(t *testing.T) {
// Config.Validate() 只检查地址是否为空,不检查格式
// 所以即使地址格式无效NewServer也可能成功
// 实际的地址验证会在Start()时进行
cfg := &config.Config{
Addr: "invalid://address",
}
server, err := NewServer(cfg)
// NewServer可能成功因为Validate只检查非空
// 实际的错误会在Start()时发现
if err != nil {
assert.Nil(t, server, "Expected server to be nil on error")
} else {
// 如果NewServer成功服务器应该不为nil
assert.NotNil(t, server, "Expected server to be non-nil if no error")
}
}
func TestServerRouter(t *testing.T) {
cfg := &config.Config{
Addr: "tcp://:8080",
}
server, err := NewServer(cfg)
require.NoError(t, err)
router := server.Router()
assert.NotNil(t, router, "Expected router to be non-nil")
}
func TestServerStartStop(t *testing.T) {
t.Skip("Skipping start/stop test - requires actual network binding, may fail in some environments")
// 这个测试需要实际的网络绑定,可能会在某些环境中失败
// 可以放在集成测试中
}
func TestServerRegisterRoute(t *testing.T) {
cfg := &config.Config{
Addr: "tcp://:8080",
}
server, err := NewServer(cfg)
require.NoError(t, err)
// 注册路由使用router包的Handler类型Handler实际上是func(ctx Context) error
handler := routerpkg.Handler(func(ctx ctxpkg.Context) error {
// 简单的handler只验证可以注册
return nil
})
route := server.Router().RegisterString("/test", handler)
assert.NotNil(t, route, "Expected route to be returned")
// 验证路由已注册通过Router接口
router := server.Router()
assert.NotNil(t, router, "Expected router to be non-nil")
}
func TestServerConfig(t *testing.T) {
cfg := &config.Config{
Addr: "tcp://:8080",
}
server, err := NewServer(cfg)
require.NoError(t, err)
// 测试获取配置
serverConfig := server.Config()
assert.NotNil(t, serverConfig, "Expected config to be non-nil")
assert.Equal(t, cfg.Addr, serverConfig.Addr, "Expected address to match")
}
func TestServerStarted(t *testing.T) {
cfg := &config.Config{
Addr: "tcp://:8080",
}
server, err := NewServer(cfg)
require.NoError(t, err)
// 测试初始状态(不启动服务器,避免网络连接)
assert.False(t, server.Started(), "Expected server to not be started initially")
}
func TestServerMultipleStart(t *testing.T) {
t.Skip("Skipping multiple start test - requires actual server start")
// 这个测试需要实际的服务器启动,可能会失败
// 可以放在集成测试中
}
func TestServerStopBeforeStart(t *testing.T) {
cfg := &config.Config{
Addr: "tcp://:8080",
}
server, err := NewServer(cfg)
require.NoError(t, err)
// 在未启动时停止应该返回错误
err = server.Stop()
assert.Error(t, err, "Expected error when stopping server that hasn't started")
assert.Equal(t, errors.ErrServerNotStarted, err, "Expected ErrServerNotStarted")
}
func TestServerExportMetrics(t *testing.T) {
cfg := &config.Config{Addr: "tcp://:8080"}
srv, err := NewServer(cfg)
require.NoError(t, err)
metrics := srv.Metrics()
metrics.IncConnections()
metrics.IncRequests()
metrics.IncErrors()
metrics.AddBytesReceived(42)
metrics.AddBytesSent(24)
var buf bytes.Buffer
require.NoError(t, srv.ExportMetrics(&buf))
output := buf.String()
assert.Contains(t, output, "nnet_connections 1")
assert.Contains(t, output, "nnet_requests 1")
assert.Contains(t, output, "nnet_errors 1")
assert.Contains(t, output, "nnet_bytes_received 42")
assert.Contains(t, output, "nnet_bytes_sent 24")
}
func TestServerMetricsHandler(t *testing.T) {
cfg := &config.Config{Addr: "tcp://:8080"}
srv, err := NewServer(cfg)
require.NoError(t, err)
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
rr := httptest.NewRecorder()
srv.Metrics().IncConnections()
srv.MetricsHandler().ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, "text/plain; version=0.0.4", rr.Header().Get("Content-Type"))
assert.Contains(t, rr.Body.String(), "nnet_connections 1")
}
type stubHealthCheck struct {
status health.Status
message string
}
func (s stubHealthCheck) Check() (health.Status, string) {
return s.status, s.message
}
func TestServerHealthHandler(t *testing.T) {
cfg := &config.Config{Addr: "tcp://:8080"}
srv, err := NewServer(cfg)
require.NoError(t, err)
checker := srv.HealthChecker()
require.NoError(t, checker.Register("stub", stubHealthCheck{status: health.StatusHealthy, message: "ok"}))
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rr := httptest.NewRecorder()
srv.HealthHandler().ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, "application/json", rr.Header().Get("Content-Type"))
assert.Contains(t, rr.Body.String(), `"status":"healthy"`)
assert.Contains(t, rr.Body.String(), `"stub"`)
}