package integration import ( "bytes" "context" "encoding/json" "fmt" "net/http/httptest" "testing" "time" "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" testcontainers_postgres "github.com/testcontainers/testcontainers-go/modules/postgres" "github.com/testcontainers/testcontainers-go/wait" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" "github.com/break/junhong_cmp_fiber/internal/bootstrap" "github.com/break/junhong_cmp_fiber/internal/handler/admin" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/routes" permissionService "github.com/break/junhong_cmp_fiber/internal/service/permission" postgresStore "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/middleware" "github.com/break/junhong_cmp_fiber/pkg/response" ) // permTestEnv 权限测试环境 type permTestEnv struct { db *gorm.DB app *fiber.App permissionService *permissionService.Service cleanup func() } // setupPermTestEnv 设置权限测试环境 func setupPermTestEnv(t *testing.T) *permTestEnv { t.Helper() ctx := context.Background() // 启动 PostgreSQL 容器 pgContainer, err := testcontainers_postgres.RunContainer(ctx, testcontainers.WithImage("postgres:14-alpine"), testcontainers_postgres.WithDatabase("testdb"), testcontainers_postgres.WithUsername("postgres"), testcontainers_postgres.WithPassword("password"), testcontainers.WithWaitStrategy( wait.ForLog("database system is ready to accept connections"). WithOccurrence(2). WithStartupTimeout(30*time.Second), ), ) require.NoError(t, err, "启动 PostgreSQL 容器失败") pgConnStr, err := pgContainer.ConnectionString(ctx, "sslmode=disable") require.NoError(t, err) // 连接数据库 db, err := gorm.Open(postgres.Open(pgConnStr), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) require.NoError(t, err) // 自动迁移 err = db.AutoMigrate( &model.Permission{}, ) require.NoError(t, err) // 初始化 Store permStore := postgresStore.NewPermissionStore(db) // 初始化 Service permSvc := permissionService.New(permStore) // 初始化 Handler permHandler := admin.NewPermissionHandler(permSvc) // 创建 Fiber App app := fiber.New(fiber.Config{ ErrorHandler: func(c *fiber.Ctx, err error) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) }, }) // 注册路由 services := &bootstrap.Handlers{ Permission: permHandler, } middlewares := &bootstrap.Middlewares{} routes.RegisterRoutes(app, services, middlewares) return &permTestEnv{ db: db, app: app, permissionService: permSvc, cleanup: func() { if err := pgContainer.Terminate(ctx); err != nil { t.Logf("终止 PostgreSQL 容器失败: %v", err) } }, } } // TestPermissionAPI_Create 测试创建权限 API func TestPermissionAPI_Create(t *testing.T) { env := setupPermTestEnv(t) defer env.cleanup() // 添加测试中间件 testUserID := uint(1) env.app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), testUserID, constants.UserTypeSuperAdmin, 0) c.SetUserContext(ctx) return c.Next() }) t.Run("成功创建权限", func(t *testing.T) { reqBody := model.CreatePermissionRequest{ PermName: "用户管理", PermCode: "user:manage", PermType: constants.PermissionTypeMenu, URL: "/admin/users", } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", "/api/admin/permissions", bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) // 验证数据库中权限已创建 var count int64 env.db.Model(&model.Permission{}).Where("perm_code = ?", "user:manage").Count(&count) assert.Equal(t, int64(1), count) }) t.Run("权限编码重复时返回错误", func(t *testing.T) { // 先创建一个权限 existingPerm := &model.Permission{ PermName: "已存在权限", PermCode: "existing:perm", PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(existingPerm) // 尝试创建相同编码的权限 reqBody := model.CreatePermissionRequest{ PermName: "新权限", PermCode: "existing:perm", PermType: constants.PermissionTypeMenu, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", "/api/admin/permissions", bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := env.app.Test(req) require.NoError(t, err) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, errors.CodePermCodeExists, result.Code) }) t.Run("创建子权限", func(t *testing.T) { // 先创建父权限 parentPerm := &model.Permission{ PermName: "系统管理", PermCode: "system:manage", PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(parentPerm) // 创建子权限 reqBody := model.CreatePermissionRequest{ PermName: "用户列表", PermCode: "system:user:list", PermType: constants.PermissionTypeButton, ParentID: &parentPerm.ID, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", "/api/admin/permissions", bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) // 验证父权限ID已设置 var child model.Permission env.db.Where("perm_code = ?", "system:user:list").First(&child) assert.NotNil(t, child.ParentID) assert.Equal(t, parentPerm.ID, *child.ParentID) }) } // TestPermissionAPI_Get 测试获取权限详情 API func TestPermissionAPI_Get(t *testing.T) { env := setupPermTestEnv(t) defer env.cleanup() // 添加测试中间件 testUserID := uint(1) env.app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), testUserID, constants.UserTypeSuperAdmin, 0) c.SetUserContext(ctx) return c.Next() }) // 创建测试权限 testPerm := &model.Permission{ PermName: "获取测试权限", PermCode: "get:test:perm", PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(testPerm) t.Run("成功获取权限详情", func(t *testing.T) { req := httptest.NewRequest("GET", fmt.Sprintf("/api/admin/permissions/%d", testPerm.ID), nil) resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) t.Run("权限不存在时返回错误", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/permissions/99999", nil) resp, err := env.app.Test(req) require.NoError(t, err) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, errors.CodePermissionNotFound, result.Code) }) } // TestPermissionAPI_Update 测试更新权限 API func TestPermissionAPI_Update(t *testing.T) { env := setupPermTestEnv(t) defer env.cleanup() // 添加测试中间件 testUserID := uint(1) env.app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), testUserID, constants.UserTypeSuperAdmin, 0) c.SetUserContext(ctx) return c.Next() }) // 创建测试权限 testPerm := &model.Permission{ PermName: "更新测试权限", PermCode: "update:test:perm", PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(testPerm) t.Run("成功更新权限", func(t *testing.T) { newName := "更新后权限" reqBody := model.UpdatePermissionRequest{ PermName: &newName, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("PUT", fmt.Sprintf("/api/admin/permissions/%d", testPerm.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) // 验证数据库已更新 var updated model.Permission env.db.First(&updated, testPerm.ID) assert.Equal(t, newName, updated.PermName) }) } // TestPermissionAPI_Delete 测试删除权限 API func TestPermissionAPI_Delete(t *testing.T) { env := setupPermTestEnv(t) defer env.cleanup() // 添加测试中间件 testUserID := uint(1) env.app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), testUserID, constants.UserTypeSuperAdmin, 0) c.SetUserContext(ctx) return c.Next() }) t.Run("成功软删除权限", func(t *testing.T) { // 创建测试权限 testPerm := &model.Permission{ PermName: "删除测试权限", PermCode: "delete:test:perm", PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(testPerm) req := httptest.NewRequest("DELETE", fmt.Sprintf("/api/admin/permissions/%d", testPerm.ID), nil) resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) // 验证权限已软删除 var deleted model.Permission err = env.db.Unscoped().First(&deleted, testPerm.ID).Error require.NoError(t, err) assert.NotNil(t, deleted.DeletedAt) }) } // TestPermissionAPI_List 测试权限列表 API func TestPermissionAPI_List(t *testing.T) { env := setupPermTestEnv(t) defer env.cleanup() // 添加测试中间件 testUserID := uint(1) env.app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), testUserID, constants.UserTypeSuperAdmin, 0) c.SetUserContext(ctx) return c.Next() }) // 创建多个测试权限 for i := 1; i <= 5; i++ { perm := &model.Permission{ PermName: fmt.Sprintf("列表测试权限_%d", i), PermCode: fmt.Sprintf("list:test:perm:%d", i), PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(perm) } t.Run("成功获取权限列表", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/permissions?page=1&page_size=10", nil) resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) t.Run("按类型过滤权限", func(t *testing.T) { req := httptest.NewRequest("GET", fmt.Sprintf("/api/admin/permissions?perm_type=%d", constants.PermissionTypeMenu), nil) resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) }) } // TestPermissionAPI_GetTree 测试获取权限树 API func TestPermissionAPI_GetTree(t *testing.T) { env := setupPermTestEnv(t) defer env.cleanup() // 添加测试中间件 testUserID := uint(1) env.app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), testUserID, constants.UserTypeSuperAdmin, 0) c.SetUserContext(ctx) return c.Next() }) // 创建层级权限结构 // 根权限 rootPerm := &model.Permission{ PermName: "系统管理", PermCode: "system", PermType: constants.PermissionTypeMenu, Status: constants.StatusEnabled, } env.db.Create(rootPerm) // 子权限 childPerm := &model.Permission{ PermName: "用户管理", PermCode: "system:user", PermType: constants.PermissionTypeMenu, ParentID: &rootPerm.ID, Status: constants.StatusEnabled, } env.db.Create(childPerm) // 孙子权限 grandchildPerm := &model.Permission{ PermName: "用户列表", PermCode: "system:user:list", PermType: constants.PermissionTypeButton, ParentID: &childPerm.ID, Status: constants.StatusEnabled, } env.db.Create(grandchildPerm) t.Run("成功获取权限树", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/permissions/tree", nil) resp, err := env.app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) }