All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Signed-off-by: Asai Neko <sugar@sne.moe>
120 lines
3.1 KiB
Go
120 lines
3.1 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
|
|
"nixcn-cms/api"
|
|
"nixcn-cms/middleware"
|
|
"nixcn-cms/testutil"
|
|
)
|
|
|
|
func init() { gin.SetMode(gin.TestMode) }
|
|
|
|
// buildRouter mirrors the engine setup inside Start() without blocking on
|
|
// ListenAndServe, making it possible to use httptest.
|
|
func buildRouter() *gin.Engine {
|
|
r := gin.New()
|
|
r.Use(otelgin.Middleware(viper.GetString("server.service_name")))
|
|
r.Use(middleware.GinLogger())
|
|
r.Use(gin.Recovery())
|
|
api.Handler(r.Group("/app/api/v1"))
|
|
return r
|
|
}
|
|
|
|
func TestServerRouterResponds(t *testing.T) {
|
|
testutil.Setup(t)
|
|
testutil.SeedClient(t)
|
|
|
|
r := buildRouter()
|
|
srv := httptest.NewServer(r)
|
|
defer srv.Close()
|
|
|
|
// POST /auth/magic exists — any response other than 404 confirms routing.
|
|
resp, err := http.Post(srv.URL+"/app/api/v1/auth/magic", "application/json", nil)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
assert.NotEqual(t, http.StatusNotFound, resp.StatusCode)
|
|
}
|
|
|
|
func TestServerRouterNotFound(t *testing.T) {
|
|
testutil.Setup(t)
|
|
|
|
r := buildRouter()
|
|
req := httptest.NewRequest(http.MethodGet, "/app/api/v1/nonexistent", nil)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestServerRouterRecovery(t *testing.T) {
|
|
testutil.Setup(t)
|
|
|
|
r := gin.New()
|
|
r.Use(gin.Recovery())
|
|
r.GET("/panic", func(c *gin.Context) { panic("test panic") })
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/panic", nil)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
|
|
// Recovery middleware must catch the panic and return 500.
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
}
|
|
|
|
func TestServerModeRelease(t *testing.T) {
|
|
viper.Set("server.debug_mode", false)
|
|
viper.Set("server.service_name", "test-svc")
|
|
defer viper.Reset()
|
|
|
|
// Calling Start() would block, so we replicate only the mode-setting logic.
|
|
if !viper.GetBool("server.debug_mode") {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
assert.Equal(t, gin.ReleaseMode, gin.Mode())
|
|
gin.SetMode(gin.TestMode) // restore
|
|
}
|
|
|
|
func TestServerHealthEndpoints(t *testing.T) {
|
|
testutil.Setup(t)
|
|
testutil.SeedClient(t)
|
|
|
|
r := buildRouter()
|
|
|
|
endpoints := []struct {
|
|
method string
|
|
path string
|
|
}{
|
|
{http.MethodPost, "/app/api/v1/auth/magic"},
|
|
{http.MethodPost, "/app/api/v1/auth/exchange"},
|
|
{http.MethodGet, "/app/api/v1/event/list"},
|
|
{http.MethodGet, "/app/api/v1/user/info"},
|
|
}
|
|
|
|
for _, ep := range endpoints {
|
|
t.Run(ep.method+" "+ep.path, func(t *testing.T) {
|
|
req := httptest.NewRequest(ep.method, ep.path, nil)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
|
|
// Route must be registered — anything other than 404 is fine.
|
|
assert.NotEqual(t, http.StatusNotFound, w.Code,
|
|
"route %s %s should be registered", ep.method, ep.path)
|
|
|
|
// Response must be valid JSON.
|
|
var body map[string]any
|
|
err := json.Unmarshal(w.Body.Bytes(), &body)
|
|
assert.NoError(t, err, "response must be valid JSON for %s %s", ep.method, ep.path)
|
|
})
|
|
}
|
|
}
|