All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m30s
新增功能: - 门店套餐分配管理(shop_package_allocation):支持门店套餐库存管理 - 门店套餐系列分配管理(shop_series_allocation):支持套餐系列分配和佣金层级设置 - 我的套餐查询(my_package):支持门店查询自己的套餐分配情况 测试改进: - 统一集成测试基础设施,新增 testutils.NewIntegrationTestEnv - 重构所有集成测试使用新的测试环境设置 - 移除旧的测试辅助函数和冗余测试文件 - 新增 test_helpers_test.go 统一任务测试辅助 技术细节: - 新增数据库迁移 000025_create_shop_allocation_tables - 新增 3 个 Handler、Service、Store 和对应的单元测试 - 更新 OpenAPI 文档和文档生成器 - 测试覆盖率:Service 层 > 90% Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
385 lines
13 KiB
Go
385 lines
13 KiB
Go
package integration
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"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/model/dto"
|
|
"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"
|
|
pkgGorm "github.com/break/junhong_cmp_fiber/pkg/gorm"
|
|
"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) {
|
|
tx := testutils.NewTestTransaction(t)
|
|
rdb := testutils.GetTestRedis(t)
|
|
testutils.CleanTestRedisKeys(t, rdb)
|
|
|
|
accountStore := postgresStore.NewAccountStore(tx, rdb)
|
|
roleStore := postgresStore.NewRoleStore(tx)
|
|
accountRoleStore := postgresStore.NewAccountRoleStore(tx, rdb)
|
|
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{
|
|
AdminAuth: func(c *fiber.Ctx) error { return c.Next() },
|
|
H5Auth: func(c *fiber.Ctx) error { return c.Next() },
|
|
}
|
|
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,
|
|
}
|
|
tx.Create(superAdmin)
|
|
|
|
platformUser := &model.Account{
|
|
Username: testutils.GenerateUsername("platform_user", 2),
|
|
Phone: testutils.GeneratePhone("138", 2),
|
|
Password: "hashedpassword",
|
|
UserType: constants.UserTypePlatform,
|
|
Status: constants.StatusEnabled,
|
|
}
|
|
tx.Create(platformUser)
|
|
|
|
agentUser := &model.Account{
|
|
Username: testutils.GenerateUsername("agent_user", 3),
|
|
Phone: testutils.GeneratePhone("138", 3),
|
|
Password: "hashedpassword",
|
|
UserType: constants.UserTypeAgent,
|
|
Status: constants.StatusEnabled,
|
|
}
|
|
tx.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
|
|
ctx := pkgGorm.SkipDataPermission(context.Background())
|
|
tx.WithContext(ctx).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) {
|
|
tx := testutils.NewTestTransaction(t)
|
|
rdb := testutils.GetTestRedis(t)
|
|
testutils.CleanTestRedisKeys(t, rdb)
|
|
|
|
accountStore := postgresStore.NewAccountStore(tx, rdb)
|
|
roleStore := postgresStore.NewRoleStore(tx)
|
|
accountRoleStore := postgresStore.NewAccountRoleStore(tx, rdb)
|
|
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{
|
|
AdminAuth: func(c *fiber.Ctx) error { return c.Next() },
|
|
H5Auth: func(c *fiber.Ctx) error { return c.Next() },
|
|
}
|
|
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,
|
|
}
|
|
tx.Create(testAccount)
|
|
|
|
t.Run("成功修改密码", func(t *testing.T) {
|
|
reqBody := dto.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
|
|
ctx := pkgGorm.SkipDataPermission(context.Background())
|
|
tx.WithContext(ctx).First(&updated, testAccount.ID)
|
|
assert.NotEqual(t, "old_hashed_password", updated.Password)
|
|
})
|
|
|
|
t.Run("账号不存在返回错误", func(t *testing.T) {
|
|
reqBody := dto.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) {
|
|
tx := testutils.NewTestTransaction(t)
|
|
rdb := testutils.GetTestRedis(t)
|
|
testutils.CleanTestRedisKeys(t, rdb)
|
|
|
|
accountStore := postgresStore.NewAccountStore(tx, rdb)
|
|
roleStore := postgresStore.NewRoleStore(tx)
|
|
accountRoleStore := postgresStore.NewAccountRoleStore(tx, rdb)
|
|
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{
|
|
AdminAuth: func(c *fiber.Ctx) error { return c.Next() },
|
|
H5Auth: func(c *fiber.Ctx) error { return c.Next() },
|
|
}
|
|
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,
|
|
}
|
|
tx.Create(testAccount)
|
|
|
|
t.Run("成功禁用账号", func(t *testing.T) {
|
|
reqBody := dto.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
|
|
ctx := pkgGorm.SkipDataPermission(context.Background())
|
|
tx.WithContext(ctx).First(&updated, testAccount.ID)
|
|
assert.Equal(t, constants.StatusDisabled, updated.Status)
|
|
})
|
|
|
|
t.Run("成功启用账号", func(t *testing.T) {
|
|
reqBody := dto.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
|
|
ctx := pkgGorm.SkipDataPermission(context.Background())
|
|
tx.WithContext(ctx).First(&updated, testAccount.ID)
|
|
assert.Equal(t, constants.StatusEnabled, updated.Status)
|
|
})
|
|
}
|
|
|
|
func TestPlatformAccountAPI_AssignRoles(t *testing.T) {
|
|
tx := testutils.NewTestTransaction(t)
|
|
rdb := testutils.GetTestRedis(t)
|
|
testutils.CleanTestRedisKeys(t, rdb)
|
|
|
|
accountStore := postgresStore.NewAccountStore(tx, rdb)
|
|
roleStore := postgresStore.NewRoleStore(tx)
|
|
accountRoleStore := postgresStore.NewAccountRoleStore(tx, rdb)
|
|
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{
|
|
AdminAuth: func(c *fiber.Ctx) error { return c.Next() },
|
|
H5Auth: func(c *fiber.Ctx) error { return c.Next() },
|
|
}
|
|
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,
|
|
}
|
|
tx.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,
|
|
}
|
|
tx.Create(platformUser)
|
|
|
|
testRole := &model.Role{
|
|
RoleName: testutils.GenerateUsername("测试角色", 30),
|
|
RoleType: constants.RoleTypePlatform,
|
|
Status: constants.StatusEnabled,
|
|
}
|
|
tx.Create(testRole)
|
|
|
|
t.Run("超级管理员禁止分配角色", func(t *testing.T) {
|
|
reqBody := dto.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 := dto.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
|
|
ctx := pkgGorm.SkipDataPermission(context.Background())
|
|
tx.WithContext(ctx).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 := dto.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
|
|
ctx := pkgGorm.SkipDataPermission(context.Background())
|
|
tx.WithContext(ctx).Model(&model.AccountRole{}).Where("account_id = ?", platformUser.ID).Count(&count)
|
|
assert.Equal(t, int64(0), count)
|
|
})
|
|
}
|