Files
geo/server/internal/tenant/transport/router_test.go
T
root acf7738bdd feat(tenant-api): add desktop content asset endpoint scoped by tenant
Lets desktop clients fetch tenant images/articles assets via Bearer-auth
without requiring the public asset signature, so stale-signed assets
served from existing articles still load on the desktop side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 12:20:54 +08:00

111 lines
3.4 KiB
Go

package transport
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func init() {
gin.SetMode(gin.TestMode)
}
func TestProtectedRoutes_RequireAuth(t *testing.T) {
// Build a minimal Gin engine with just the auth middleware and a mock handler
// to verify that unauthenticated requests are rejected at the middleware level.
// We can't fully test RegisterRoutes without a bootstrap.App (needs DB/Redis),
// so we test the middleware behavior directly.
routes := []struct {
method string
path string
}{
{http.MethodGet, "/api/auth/me"},
{http.MethodPost, "/api/auth/logout"},
{http.MethodPost, "/api/desktop/clients/register"},
{http.MethodGet, "/api/tenant/accounts"},
{http.MethodPost, "/api/tenant/accounts/:id/request-delete"},
{http.MethodPost, "/api/tenant/tasks/:id/reconcile"},
{http.MethodPost, "/api/tenant/tasks/:id/cancel"},
{http.MethodPost, "/api/tenant/publish-jobs"},
{http.MethodGet, "/api/tenant/media/platforms"},
{http.MethodGet, "/api/tenant/workspace/overview"},
{http.MethodGet, "/api/tenant/templates"},
{http.MethodGet, "/api/tenant/articles"},
{http.MethodGet, "/api/tenant/brands"},
{http.MethodGet, "/api/tenant/brands/library-summary"},
{http.MethodGet, "/api/tenant/monitoring/brands/:brand_id/questions/:question_id/detail"},
{http.MethodPost, "/api/tenant/brands"},
}
for _, rt := range routes {
t.Run(rt.method+" "+rt.path, func(t *testing.T) {
// A real engine with auth middleware would reject these.
// Here we verify the route patterns are what we expect.
// This is a documentation-style test that pins the API surface.
assert.NotEmpty(t, rt.path)
})
}
}
func TestPublicRoutes_NoAuth(t *testing.T) {
// Verify public routes don't need auth by checking expected paths
publicRoutes := []struct {
method string
path string
}{
{http.MethodPost, "/api/auth/login"},
{http.MethodPost, "/api/auth/refresh"},
{http.MethodGet, "/api/health/live"},
{http.MethodGet, "/api/health/ready"},
}
for _, rt := range publicRoutes {
t.Run(rt.method+" "+rt.path, func(t *testing.T) {
assert.NotEmpty(t, rt.path)
})
}
}
func TestDesktopClientRoutes_ClientTokenAuth(t *testing.T) {
routes := []struct {
method string
path string
}{
{http.MethodGet, "/api/desktop/dispatch"},
{http.MethodGet, "/api/desktop/accounts"},
{http.MethodGet, "/api/desktop/content/assets/:token"},
{http.MethodPost, "/api/desktop/clients/offline"},
{http.MethodPost, "/api/desktop/tasks/lease"},
{http.MethodPost, "/api/desktop/tasks/:id/result"},
{http.MethodPost, "/api/desktop/monitoring/tasks/lease"},
{http.MethodPost, "/api/desktop/monitoring/tasks/resume"},
{http.MethodPost, "/api/desktop/monitoring/tasks/:id/result"},
{http.MethodPost, "/api/desktop/monitoring/tasks/:id/skip"},
{http.MethodPost, "/api/desktop/monitoring/tasks/:id/cancel"},
}
for _, rt := range routes {
t.Run(rt.method+" "+rt.path, func(t *testing.T) {
assert.NotEmpty(t, rt.path)
})
}
}
func TestHealthEndpoint_Live(t *testing.T) {
r := gin.New()
r.GET("/api/health/live", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "ok", "data": gin.H{"status": "alive"}})
})
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/health/live", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "alive")
}