package integration import ( "bytes" "encoding/json" "fmt" "net/http/httptest" "testing" "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "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" accountService "github.com/break/junhong_cmp_fiber/internal/service/account" 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" "github.com/break/junhong_cmp_fiber/tests/testutils" ) func TestPlatformAccountAPI_ListPlatformAccounts(t *testing.T) { db, redisClient := testutils.SetupTestDB(t) defer testutils.TeardownTestDB(t, db, redisClient) accountStore := postgresStore.NewAccountStore(db, redisClient) roleStore := postgresStore.NewRoleStore(db) accountRoleStore := postgresStore.NewAccountRoleStore(db) accService := accountService.New(accountStore, roleStore, accountRoleStore) accountHandler := admin.NewAccountHandler(accService) app := fiber.New(fiber.Config{ ErrorHandler: errors.SafeErrorHandler(nil), }) testUserID := uint(1) app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), middleware.NewSimpleUserContext(testUserID, constants.UserTypeSuperAdmin, 0)) c.SetUserContext(ctx) return c.Next() }) services := &bootstrap.Handlers{Account: accountHandler} middlewares := &bootstrap.Middlewares{} routes.RegisterRoutes(app, services, middlewares) superAdmin := &model.Account{ Username: testutils.GenerateUsername("super_admin", 1), Phone: testutils.GeneratePhone("138", 1), Password: "hashedpassword", UserType: constants.UserTypeSuperAdmin, Status: constants.StatusEnabled, } db.Create(superAdmin) platformUser := &model.Account{ Username: testutils.GenerateUsername("platform_user", 2), Phone: testutils.GeneratePhone("138", 2), Password: "hashedpassword", UserType: constants.UserTypePlatform, Status: constants.StatusEnabled, } db.Create(platformUser) agentUser := &model.Account{ Username: testutils.GenerateUsername("agent_user", 3), Phone: testutils.GeneratePhone("138", 3), Password: "hashedpassword", UserType: constants.UserTypeAgent, Status: constants.StatusEnabled, } db.Create(agentUser) t.Run("列表只返回平台账号和超级管理员", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/platform-accounts?page=1&page_size=20", nil) resp, err := 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) data := result.Data.(map[string]interface{}) items := data["items"].([]interface{}) assert.GreaterOrEqual(t, len(items), 2) var count int64 db.Model(&model.Account{}).Where("user_type IN ?", []int{1, 2}).Count(&count) assert.GreaterOrEqual(t, count, int64(2)) }) t.Run("按用户名筛选", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/platform-accounts?username=platform_user", nil) resp, err := 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) data := result.Data.(map[string]interface{}) items := data["items"].([]interface{}) assert.GreaterOrEqual(t, len(items), 1) }) } func TestPlatformAccountAPI_UpdatePassword(t *testing.T) { db, redisClient := testutils.SetupTestDB(t) defer testutils.TeardownTestDB(t, db, redisClient) accountStore := postgresStore.NewAccountStore(db, redisClient) roleStore := postgresStore.NewRoleStore(db) accountRoleStore := postgresStore.NewAccountRoleStore(db) accService := accountService.New(accountStore, roleStore, accountRoleStore) accountHandler := admin.NewAccountHandler(accService) app := fiber.New(fiber.Config{ ErrorHandler: errors.SafeErrorHandler(nil), }) testUserID := uint(1) app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), middleware.NewSimpleUserContext(testUserID, constants.UserTypeSuperAdmin, 0)) c.SetUserContext(ctx) return c.Next() }) services := &bootstrap.Handlers{Account: accountHandler} middlewares := &bootstrap.Middlewares{} routes.RegisterRoutes(app, services, middlewares) testAccount := &model.Account{ Username: testutils.GenerateUsername("pwd_test", 10), Phone: testutils.GeneratePhone("139", 10), Password: "old_hashed_password", UserType: constants.UserTypePlatform, Status: constants.StatusEnabled, } db.Create(testAccount) t.Run("成功修改密码", func(t *testing.T) { reqBody := model.UpdatePasswordRequest{ NewPassword: "NewPassword@123", } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("PUT", fmt.Sprintf("/api/admin/platform-accounts/%d/password", testAccount.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := 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 updated model.Account db.First(&updated, testAccount.ID) assert.NotEqual(t, "old_hashed_password", updated.Password) }) t.Run("账号不存在返回错误", func(t *testing.T) { reqBody := model.UpdatePasswordRequest{ NewPassword: "NewPassword@123", } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("PUT", "/api/admin/platform-accounts/99999/password", bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := 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.CodeAccountNotFound, result.Code) }) } func TestPlatformAccountAPI_UpdateStatus(t *testing.T) { db, redisClient := testutils.SetupTestDB(t) defer testutils.TeardownTestDB(t, db, redisClient) accountStore := postgresStore.NewAccountStore(db, redisClient) roleStore := postgresStore.NewRoleStore(db) accountRoleStore := postgresStore.NewAccountRoleStore(db) accService := accountService.New(accountStore, roleStore, accountRoleStore) accountHandler := admin.NewAccountHandler(accService) app := fiber.New(fiber.Config{ ErrorHandler: errors.SafeErrorHandler(nil), }) testUserID := uint(1) app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), middleware.NewSimpleUserContext(testUserID, constants.UserTypeSuperAdmin, 0)) c.SetUserContext(ctx) return c.Next() }) services := &bootstrap.Handlers{Account: accountHandler} middlewares := &bootstrap.Middlewares{} routes.RegisterRoutes(app, services, middlewares) testAccount := &model.Account{ Username: testutils.GenerateUsername("status_test", 20), Phone: testutils.GeneratePhone("137", 20), Password: "hashedpassword", UserType: constants.UserTypePlatform, Status: constants.StatusEnabled, } db.Create(testAccount) t.Run("成功禁用账号", func(t *testing.T) { reqBody := model.UpdateStatusRequest{ Status: constants.StatusDisabled, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("PUT", fmt.Sprintf("/api/admin/platform-accounts/%d/status", testAccount.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var updated model.Account db.First(&updated, testAccount.ID) assert.Equal(t, constants.StatusDisabled, updated.Status) }) t.Run("成功启用账号", func(t *testing.T) { reqBody := model.UpdateStatusRequest{ Status: constants.StatusEnabled, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("PUT", fmt.Sprintf("/api/admin/platform-accounts/%d/status", testAccount.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var updated model.Account db.First(&updated, testAccount.ID) assert.Equal(t, constants.StatusEnabled, updated.Status) }) } func TestPlatformAccountAPI_AssignRoles(t *testing.T) { db, redisClient := testutils.SetupTestDB(t) defer testutils.TeardownTestDB(t, db, redisClient) accountStore := postgresStore.NewAccountStore(db, redisClient) roleStore := postgresStore.NewRoleStore(db) accountRoleStore := postgresStore.NewAccountRoleStore(db) accService := accountService.New(accountStore, roleStore, accountRoleStore) accountHandler := admin.NewAccountHandler(accService) app := fiber.New(fiber.Config{ ErrorHandler: errors.SafeErrorHandler(nil), }) testUserID := uint(1) app.Use(func(c *fiber.Ctx) error { ctx := middleware.SetUserContext(c.UserContext(), middleware.NewSimpleUserContext(testUserID, constants.UserTypeSuperAdmin, 0)) c.SetUserContext(ctx) return c.Next() }) services := &bootstrap.Handlers{Account: accountHandler} middlewares := &bootstrap.Middlewares{} routes.RegisterRoutes(app, services, middlewares) superAdmin := &model.Account{ Username: testutils.GenerateUsername("super_admin_role", 30), Phone: testutils.GeneratePhone("136", 30), Password: "hashedpassword", UserType: constants.UserTypeSuperAdmin, Status: constants.StatusEnabled, } db.Create(superAdmin) platformUser := &model.Account{ Username: testutils.GenerateUsername("platform_user_role", 31), Phone: testutils.GeneratePhone("136", 31), Password: "hashedpassword", UserType: constants.UserTypePlatform, Status: constants.StatusEnabled, } db.Create(platformUser) testRole := &model.Role{ RoleName: testutils.GenerateUsername("测试角色", 30), RoleType: constants.RoleTypePlatform, Status: constants.StatusEnabled, } db.Create(testRole) t.Run("超级管理员禁止分配角色", func(t *testing.T) { reqBody := model.AssignRolesRequest{ RoleIDs: []uint{testRole.ID}, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", fmt.Sprintf("/api/admin/platform-accounts/%d/roles", superAdmin.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := 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.CodeInvalidParam, result.Code) assert.Contains(t, result.Message, "超级管理员不允许分配角色") }) t.Run("平台用户成功分配角色", func(t *testing.T) { reqBody := model.AssignRolesRequest{ RoleIDs: []uint{testRole.ID}, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", fmt.Sprintf("/api/admin/platform-accounts/%d/roles", platformUser.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var count int64 db.Model(&model.AccountRole{}).Where("account_id = ? AND role_id = ?", platformUser.ID, testRole.ID).Count(&count) assert.Equal(t, int64(1), count) }) t.Run("空数组清空所有角色", func(t *testing.T) { reqBody := model.AssignRolesRequest{ RoleIDs: []uint{}, } jsonBody, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", fmt.Sprintf("/api/admin/platform-accounts/%d/roles", platformUser.ID), bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, fiber.StatusOK, resp.StatusCode) var count int64 db.Model(&model.AccountRole{}).Where("account_id = ?", platformUser.ID).Count(&count) assert.Equal(t, int64(0), count) }) }