357 lines
8.8 KiB
Go
357 lines
8.8 KiB
Go
package go_web_gin
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
// AppTestSuite is the test suite for App
|
|
type AppTestSuite struct {
|
|
suite.Suite
|
|
app *App
|
|
}
|
|
|
|
// SetupSuite runs once before all tests
|
|
func (s *AppTestSuite) SetupSuite() {
|
|
gin.SetMode(gin.TestMode)
|
|
s.app = New()
|
|
}
|
|
|
|
// TearDownSuite runs once after all tests
|
|
func (s *AppTestSuite) TearDownSuite() {
|
|
// Cleanup if needed
|
|
}
|
|
|
|
// SetupTest runs before each test
|
|
func (s *AppTestSuite) SetupTest() {
|
|
// Reset state if needed
|
|
}
|
|
|
|
// TearDownTest runs after each test
|
|
func (s *AppTestSuite) TearDownTest() {
|
|
// Cleanup after each test if needed
|
|
}
|
|
|
|
// TestNew tests the New function
|
|
func (s *AppTestSuite) TestNew() {
|
|
app := New()
|
|
s.NotNil(app, "New should return a non-nil App")
|
|
s.NotNil(app.engine, "engine should be initialized")
|
|
s.NotNil(app.logger, "logger should be initialized")
|
|
}
|
|
|
|
// TestNewSingleton tests that svr.GetEngine returns the same instance
|
|
func (s *AppTestSuite) TestNewSingleton() {
|
|
app1 := New()
|
|
app2 := New()
|
|
s.Equal(app1.engine, app2.engine, "engine should be singleton")
|
|
}
|
|
|
|
// TestUseMiddleware tests the UseMiddleware method
|
|
func (s *AppTestSuite) TestUseMiddleware() {
|
|
middlewareCalled := false
|
|
middleware := func(c *gin.Context) {
|
|
middlewareCalled = true
|
|
c.Next()
|
|
}
|
|
|
|
s.app.UseMiddleware(middleware)
|
|
|
|
// Create a test route to verify middleware
|
|
s.app.engine.GET("/test-middleware", func(c *gin.Context) {
|
|
c.Status(http.StatusOK)
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/test-middleware", nil)
|
|
w := httptest.NewRecorder()
|
|
s.app.engine.ServeHTTP(w, req)
|
|
|
|
s.True(middlewareCalled, "middleware should be called")
|
|
}
|
|
|
|
// TestRegisterRoutes tests the RegisterRoutes method
|
|
func (s *AppTestSuite) TestRegisterRoutes() {
|
|
app := New()
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.GET("/test-route", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"message": "ok"})
|
|
})
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/test-route", nil)
|
|
w := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w, req)
|
|
|
|
s.Equal(http.StatusOK, w.Code)
|
|
s.Contains(w.Body.String(), "ok")
|
|
}
|
|
|
|
// TestRegisterRoutesMultiple tests registering multiple routes
|
|
func (s *AppTestSuite) TestRegisterRoutesMultiple() {
|
|
app := New()
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.GET("/route1", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"route": 1})
|
|
})
|
|
e.POST("/route2", func(c *gin.Context) {
|
|
c.JSON(http.StatusCreated, gin.H{"route": 2})
|
|
})
|
|
e.PUT("/route3", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"route": 3})
|
|
})
|
|
})
|
|
|
|
// Test GET
|
|
req1 := httptest.NewRequest("GET", "/route1", nil)
|
|
w1 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w1, req1)
|
|
s.Equal(http.StatusOK, w1.Code)
|
|
|
|
// Test POST
|
|
req2 := httptest.NewRequest("POST", "/route2", nil)
|
|
w2 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w2, req2)
|
|
s.Equal(http.StatusCreated, w2.Code)
|
|
|
|
// Test PUT
|
|
req3 := httptest.NewRequest("PUT", "/route3", nil)
|
|
w3 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w3, req3)
|
|
s.Equal(http.StatusOK, w3.Code)
|
|
}
|
|
|
|
// TestDB tests the DB method returns nil when not initialized
|
|
func (s *AppTestSuite) TestDB() {
|
|
app := New()
|
|
s.Nil(app.DB(), "DB should be nil when not initialized")
|
|
}
|
|
|
|
// TestRedis tests the Redis method returns nil when not initialized
|
|
func (s *AppTestSuite) TestRedis() {
|
|
app := New()
|
|
s.Nil(app.Redis(), "Redis should be nil when not initialized")
|
|
}
|
|
|
|
// TestLogger tests the Logger method
|
|
func (s *AppTestSuite) TestLogger() {
|
|
app := New()
|
|
logger := app.Logger()
|
|
s.NotNil(logger, "Logger should not be nil")
|
|
}
|
|
|
|
// TestLoggerNotNil tests that logger is always initialized
|
|
func (s *AppTestSuite) TestLoggerNotNil() {
|
|
s.NotNil(s.app.Logger(), "Logger should always be initialized in New()")
|
|
}
|
|
|
|
// TestLoggerMethods tests that logger methods work
|
|
func (s *AppTestSuite) TestLoggerMethods() {
|
|
s.NotPanics(func() {
|
|
s.app.Logger().Info(nil, "Test info message")
|
|
s.app.Logger().Debug(nil, "Test debug message")
|
|
s.app.Logger().Warn(nil, "Test warn message")
|
|
}, "Logger methods should not panic")
|
|
}
|
|
|
|
// TestLoggerWithContext tests logger with context
|
|
func (s *AppTestSuite) TestLoggerWithContext() {
|
|
ctx := context.Background()
|
|
s.NotPanics(func() {
|
|
s.app.Logger().Info(ctx, "Test with context")
|
|
}, "Logger should work with context")
|
|
}
|
|
|
|
// TestRunInvalidAddress tests Run with invalid address
|
|
func (s *AppTestSuite) TestRunInvalidAddress() {
|
|
app := New()
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.GET("/ping", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"pong": true})
|
|
})
|
|
})
|
|
|
|
// Use a channel to handle the async nature of Run
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- app.Run("invalid:address:format")
|
|
}()
|
|
|
|
select {
|
|
case err := <-errCh:
|
|
s.Error(err, "Run should return error for invalid address")
|
|
case <-time.After(2 * time.Second):
|
|
// Server might start, which is fine for this test
|
|
}
|
|
}
|
|
|
|
// TestHTTPMethod tests various HTTP methods
|
|
func (s *AppTestSuite) TestHTTPMethod() {
|
|
app := New()
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.DELETE("/delete", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"deleted": true})
|
|
})
|
|
e.PATCH("/patch", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"patched": true})
|
|
})
|
|
e.OPTIONS("/options", func(c *gin.Context) {
|
|
c.Status(http.StatusNoContent)
|
|
})
|
|
e.HEAD("/head", func(c *gin.Context) {
|
|
c.Status(http.StatusOK)
|
|
})
|
|
})
|
|
|
|
// Test DELETE
|
|
req := httptest.NewRequest("DELETE", "/delete", nil)
|
|
w := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w, req)
|
|
s.Equal(http.StatusOK, w.Code)
|
|
|
|
// Test PATCH
|
|
req2 := httptest.NewRequest("PATCH", "/patch", nil)
|
|
w2 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w2, req2)
|
|
s.Equal(http.StatusOK, w2.Code)
|
|
|
|
// Test OPTIONS
|
|
req3 := httptest.NewRequest("OPTIONS", "/options", nil)
|
|
w3 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w3, req3)
|
|
s.Equal(http.StatusNoContent, w3.Code)
|
|
|
|
// Test HEAD
|
|
req4 := httptest.NewRequest("HEAD", "/head", nil)
|
|
w4 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w4, req4)
|
|
s.Equal(http.StatusOK, w4.Code)
|
|
}
|
|
|
|
// TestRouteGroup tests route groups
|
|
func (s *AppTestSuite) TestRouteGroup() {
|
|
app := New()
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
api := e.Group("/api")
|
|
{
|
|
api.GET("/users", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"users": []string{}})
|
|
})
|
|
api.GET("/posts", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"posts": []string{}})
|
|
})
|
|
}
|
|
})
|
|
|
|
req1 := httptest.NewRequest("GET", "/api/users", nil)
|
|
w1 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w1, req1)
|
|
s.Equal(http.StatusOK, w1.Code)
|
|
|
|
req2 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
w2 := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w2, req2)
|
|
s.Equal(http.StatusOK, w2.Code)
|
|
}
|
|
|
|
// TestMiddlewareChain tests middleware chain
|
|
func (s *AppTestSuite) TestMiddlewareChain() {
|
|
app := New()
|
|
order := []string{}
|
|
|
|
app.UseMiddleware(func(c *gin.Context) {
|
|
order = append(order, "middleware1-before")
|
|
c.Next()
|
|
order = append(order, "middleware1-after")
|
|
})
|
|
|
|
app.UseMiddleware(func(c *gin.Context) {
|
|
order = append(order, "middleware2-before")
|
|
c.Next()
|
|
order = append(order, "middleware2-after")
|
|
})
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.GET("/chain", func(c *gin.Context) {
|
|
order = append(order, "handler")
|
|
c.Status(http.StatusOK)
|
|
})
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/chain", nil)
|
|
w := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w, req)
|
|
|
|
expected := []string{
|
|
"middleware1-before",
|
|
"middleware2-before",
|
|
"handler",
|
|
"middleware2-after",
|
|
"middleware1-after",
|
|
}
|
|
s.Equal(expected, order, "middleware should execute in correct order")
|
|
}
|
|
|
|
// TestQueryParam tests query parameters
|
|
func (s *AppTestSuite) TestQueryParam() {
|
|
app := New()
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.GET("/search", func(c *gin.Context) {
|
|
q := c.Query("q")
|
|
c.JSON(http.StatusOK, gin.H{"query": q})
|
|
})
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/search?q=test", nil)
|
|
w := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w, req)
|
|
|
|
s.Equal(http.StatusOK, w.Code)
|
|
s.Contains(w.Body.String(), "test")
|
|
}
|
|
|
|
// TestPathParam tests path parameters
|
|
func (s *AppTestSuite) TestPathParam() {
|
|
app := New()
|
|
|
|
app.RegisterRoutes(func(e *gin.Engine) {
|
|
e.GET("/users/:id", func(c *gin.Context) {
|
|
id := c.Param("id")
|
|
c.JSON(http.StatusOK, gin.H{"user_id": id})
|
|
})
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/users/123", nil)
|
|
w := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w, req)
|
|
|
|
s.Equal(http.StatusOK, w.Code)
|
|
s.Contains(w.Body.String(), "123")
|
|
}
|
|
|
|
// TestNotFound tests 404 handling
|
|
func (s *AppTestSuite) TestNotFound() {
|
|
app := New()
|
|
|
|
req := httptest.NewRequest("GET", "/nonexistent", nil)
|
|
w := httptest.NewRecorder()
|
|
app.engine.ServeHTTP(w, req)
|
|
|
|
s.Equal(http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
// TestAppRunSuite runs the test suite
|
|
func TestAppRunSuite(t *testing.T) {
|
|
suite.Run(t, new(AppTestSuite))
|
|
}
|