package integration
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"your-project/controller"
"your-project/middleware"
"your-project/model"
"your-project/router"
"your-project/service"
)
// API集成测试套件
type APIIntegrationTestSuite struct {
suite.Suite
app *gin.Engine
db *gorm.DB
server *httptest.Server
}
// 设置测试环境
func (suite *APIIntegrationTestSuite) SetupSuite() {
gin.SetMode(gin.TestMode)
// 设置测试数据库
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
suite.Require().NoError(err)
err = db.AutoMigrate(&model.User{}, &model.Token{}, &model.Channel{})
suite.Require().NoError(err)
suite.db = db
// 创建服务
userService := service.NewUserService(db, nil, nil)
tokenService := service.NewTokenService(db, nil)
// 创建控制器
userController := controller.NewUserController(userService)
tokenController := controller.NewTokenController(tokenService)
// 设置路由
app := gin.New()
app.Use(gin.Recovery())
// 公开路由
public := app.Group("/api/v1")
public.POST("/register", userController.Register)
public.POST("/login", userController.Login)
// 需要认证的路由
auth := app.Group("/api/v1")
auth.Use(middleware.AuthMiddleware(tokenService))
auth.GET("/profile", userController.GetProfile)
auth.PUT("/profile", userController.UpdateProfile)
auth.GET("/tokens", tokenController.ListTokens)
auth.POST("/tokens", tokenController.CreateToken)
auth.DELETE("/tokens/:id", tokenController.DeleteToken)
suite.app = app
suite.server = httptest.NewServer(app)
}
// 清理测试数据
func (suite *APIIntegrationTestSuite) SetupTest() {
suite.db.Exec("DELETE FROM users")
suite.db.Exec("DELETE FROM tokens")
}
// 清理资源
func (suite *APIIntegrationTestSuite) TearDownSuite() {
if suite.server != nil {
suite.server.Close()
}
}
// 测试用户注册和登录流程
func (suite *APIIntegrationTestSuite) TestUserRegistrationAndLogin() {
// 注册用户
registerData := map[string]interface{}{
"username": "testuser",
"email": "[email protected]",
"password": "password123",
}
registerResp := suite.makeRequest("POST", "/api/v1/register", registerData, "")
assert.Equal(suite.T(), http.StatusCreated, registerResp.Code)
var registerResult map[string]interface{}
err := json.Unmarshal(registerResp.Body.Bytes(), ®isterResult)
assert.NoError(suite.T(), err)
assert.True(suite.T(), registerResult["success"].(bool))
// 登录用户
loginData := map[string]interface{}{
"username": "testuser",
"password": "password123",
}
loginResp := suite.makeRequest("POST", "/api/v1/login", loginData, "")
assert.Equal(suite.T(), http.StatusOK, loginResp.Code)
var loginResult map[string]interface{}
err = json.Unmarshal(loginResp.Body.Bytes(), &loginResult)
assert.NoError(suite.T(), err)
assert.True(suite.T(), loginResult["success"].(bool))
data := loginResult["data"].(map[string]interface{})
token := data["token"].(string)
assert.NotEmpty(suite.T(), token)
}
// 测试令牌管理流程
func (suite *APIIntegrationTestSuite) TestTokenManagement() {
// 先注册和登录用户
token := suite.createUserAndGetToken()
// 创建令牌
createTokenData := map[string]interface{}{
"name": "测试令牌",
"quota": 1000000,
}
createResp := suite.makeRequest("POST", "/api/v1/tokens", createTokenData, token)
assert.Equal(suite.T(), http.StatusCreated, createResp.Code)
var createResult map[string]interface{}
err := json.Unmarshal(createResp.Body.Bytes(), &createResult)
assert.NoError(suite.T(), err)
assert.True(suite.T(), createResult["success"].(bool))
data := createResult["data"].(map[string]interface{})
tokenID := data["id"].(float64)
// 列出令牌
listResp := suite.makeRequest("GET", "/api/v1/tokens", nil, token)
assert.Equal(suite.T(), http.StatusOK, listResp.Code)
var listResult map[string]interface{}
err = json.Unmarshal(listResp.Body.Bytes(), &listResult)
assert.NoError(suite.T(), err)
assert.True(suite.T(), listResult["success"].(bool))
tokens := listResult["data"].([]interface{})
assert.Len(suite.T(), tokens, 1)
// 删除令牌
deleteResp := suite.makeRequest("DELETE", fmt.Sprintf("/api/v1/tokens/%d", int(tokenID)), nil, token)
assert.Equal(suite.T(), http.StatusOK, deleteResp.Code)
// 验证令牌已删除
listResp2 := suite.makeRequest("GET", "/api/v1/tokens", nil, token)
assert.Equal(suite.T(), http.StatusOK, listResp2.Code)
var listResult2 map[string]interface{}
err = json.Unmarshal(listResp2.Body.Bytes(), &listResult2)
assert.NoError(suite.T(), err)
tokens2 := listResult2["data"].([]interface{})
assert.Len(suite.T(), tokens2, 0)
}
// 测试认证中间件
func (suite *APIIntegrationTestSuite) TestAuthMiddleware() {
// 未提供令牌
resp := suite.makeRequest("GET", "/api/v1/profile", nil, "")
assert.Equal(suite.T(), http.StatusUnauthorized, resp.Code)
// 无效令牌
resp = suite.makeRequest("GET", "/api/v1/profile", nil, "invalid-token")
assert.Equal(suite.T(), http.StatusUnauthorized, resp.Code)
// 有效令牌
token := suite.createUserAndGetToken()
resp = suite.makeRequest("GET", "/api/v1/profile", nil, token)
assert.Equal(suite.T(), http.StatusOK, resp.Code)
}
// 辅助方法:创建用户并获取令牌
func (suite *APIIntegrationTestSuite) createUserAndGetToken() string {
// 注册用户
registerData := map[string]interface{}{
"username": "testuser",
"email": "[email protected]",
"password": "password123",
}
suite.makeRequest("POST", "/api/v1/register", registerData, "")
// 登录获取令牌
loginData := map[string]interface{}{
"username": "testuser",
"password": "password123",
}
loginResp := suite.makeRequest("POST", "/api/v1/login", loginData, "")
var loginResult map[string]interface{}
json.Unmarshal(loginResp.Body.Bytes(), &loginResult)
data := loginResult["data"].(map[string]interface{})
return data["token"].(string)
}
// 辅助方法:发送HTTP请求
func (suite *APIIntegrationTestSuite) makeRequest(method, path string, body interface{}, token string) *httptest.ResponseRecorder {
var reqBody *bytes.Buffer
if body != nil {
jsonBody, _ := json.Marshal(body)
reqBody = bytes.NewBuffer(jsonBody)
} else {
reqBody = bytes.NewBuffer(nil)
}
req := httptest.NewRequest(method, path, reqBody)
req.Header.Set("Content-Type", "application/json")
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
w := httptest.NewRecorder()
suite.app.ServeHTTP(w, req)
return w
}
// 运行API集成测试套件
func TestAPIIntegrationSuite(t *testing.T) {
suite.Run(t, new(APIIntegrationTestSuite))
}