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>
280 lines
9.1 KiB
Go
280 lines
9.1 KiB
Go
package integration
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/gofiber/fiber/v2"
|
||
"github.com/stretchr/testify/assert"
|
||
"github.com/stretchr/testify/require"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||
"github.com/break/junhong_cmp_fiber/tests/testutils/integ"
|
||
)
|
||
|
||
// TestAccountAPI_Create 测试创建账号 API
|
||
func TestAccountAPI_Create(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
t.Run("成功创建平台账号", func(t *testing.T) {
|
||
username := fmt.Sprintf("platform_user_%d", time.Now().UnixNano())
|
||
phone := fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000)
|
||
|
||
reqBody := dto.CreateAccountRequest{
|
||
Username: username,
|
||
Phone: phone,
|
||
Password: "Password123",
|
||
UserType: constants.UserTypePlatform,
|
||
}
|
||
|
||
jsonBody, _ := json.Marshal(reqBody)
|
||
resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/accounts", jsonBody)
|
||
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.RawDB().Model(&model.Account{}).Where("username = ?", username).Count(&count)
|
||
assert.Equal(t, int64(1), count)
|
||
})
|
||
|
||
t.Run("用户名重复时返回错误", func(t *testing.T) {
|
||
// 先创建一个账号
|
||
existingUsername := fmt.Sprintf("existing_user_%d", time.Now().UnixNano())
|
||
existingAccount := env.CreateTestAccount(existingUsername, "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
// 尝试创建同名账号
|
||
phone := fmt.Sprintf("138%08d", time.Now().UnixNano()%100000000)
|
||
reqBody := dto.CreateAccountRequest{
|
||
Username: existingAccount.Username,
|
||
Phone: phone,
|
||
Password: "Password123",
|
||
UserType: constants.UserTypePlatform,
|
||
}
|
||
|
||
jsonBody, _ := json.Marshal(reqBody)
|
||
resp, err := env.AsSuperAdmin().Request("POST", "/api/admin/accounts", jsonBody)
|
||
require.NoError(t, err)
|
||
|
||
var result response.Response
|
||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, errors.CodeUsernameExists, result.Code)
|
||
})
|
||
|
||
// TODO: 当前代码允许平台账号不提供 parent_id,此测试预期的业务规则已变更
|
||
// t.Run("非root用户缺少parent_id时返回错误", func(t *testing.T) { ... })
|
||
}
|
||
|
||
// TestAccountAPI_Get 测试获取账号详情 API
|
||
func TestAccountAPI_Get(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
// 创建测试账号
|
||
testAccount := env.CreateTestAccount("test_user", "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
t.Run("成功获取账号详情", func(t *testing.T) {
|
||
resp, err := env.AsSuperAdmin().Request("GET", fmt.Sprintf("/api/admin/accounts/%d", testAccount.ID), nil)
|
||
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) {
|
||
resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/accounts/99999", nil)
|
||
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)
|
||
})
|
||
|
||
t.Run("无效ID返回错误", func(t *testing.T) {
|
||
resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/accounts/invalid", nil)
|
||
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)
|
||
})
|
||
}
|
||
|
||
// TestAccountAPI_Update 测试更新账号 API
|
||
func TestAccountAPI_Update(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
// 创建测试账号
|
||
testAccount := env.CreateTestAccount("update_test", "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
t.Run("成功更新账号", func(t *testing.T) {
|
||
newUsername := "updated_user"
|
||
reqBody := dto.UpdateAccountRequest{
|
||
Username: &newUsername,
|
||
}
|
||
|
||
jsonBody, _ := json.Marshal(reqBody)
|
||
resp, err := env.AsSuperAdmin().Request("PUT", fmt.Sprintf("/api/admin/accounts/%d", testAccount.ID), jsonBody)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||
|
||
// 验证数据库已更新
|
||
var updated model.Account
|
||
env.RawDB().First(&updated, testAccount.ID)
|
||
assert.Equal(t, newUsername, updated.Username)
|
||
})
|
||
}
|
||
|
||
// TestAccountAPI_Delete 测试删除账号 API
|
||
func TestAccountAPI_Delete(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
t.Run("成功软删除账号", func(t *testing.T) {
|
||
// 创建测试账号
|
||
testAccount := env.CreateTestAccount("delete_test", "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
resp, err := env.AsSuperAdmin().Request("DELETE", fmt.Sprintf("/api/admin/accounts/%d", testAccount.ID), nil)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||
|
||
// 验证账号已软删除
|
||
var deleted model.Account
|
||
err = env.RawDB().Unscoped().First(&deleted, testAccount.ID).Error
|
||
require.NoError(t, err)
|
||
assert.NotNil(t, deleted.DeletedAt)
|
||
})
|
||
}
|
||
|
||
// TestAccountAPI_List 测试账号列表 API
|
||
func TestAccountAPI_List(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
// 创建多个测试账号
|
||
for i := 1; i <= 5; i++ {
|
||
env.CreateTestAccount(fmt.Sprintf("list_test_%d", i), "password123", constants.UserTypePlatform, nil, nil)
|
||
}
|
||
|
||
t.Run("成功获取账号列表", func(t *testing.T) {
|
||
resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/accounts?page=1&page_size=10", nil)
|
||
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) {
|
||
resp, err := env.AsSuperAdmin().Request("GET", "/api/admin/accounts?page=1&page_size=2", nil)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||
})
|
||
}
|
||
|
||
// TestAccountAPI_AssignRoles 测试分配角色 API
|
||
func TestAccountAPI_AssignRoles(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
// 创建测试账号
|
||
testAccount := env.CreateTestAccount("role_test", "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
// 创建测试角色
|
||
testRole := env.CreateTestRole("测试角色", constants.RoleTypePlatform)
|
||
|
||
t.Run("成功分配角色", func(t *testing.T) {
|
||
reqBody := dto.AssignRolesRequest{
|
||
RoleIDs: []uint{testRole.ID},
|
||
}
|
||
|
||
jsonBody, _ := json.Marshal(reqBody)
|
||
resp, err := env.AsSuperAdmin().Request("POST", fmt.Sprintf("/api/admin/accounts/%d/roles", testAccount.ID), jsonBody)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||
|
||
// 验证关联已创建
|
||
var count int64
|
||
env.RawDB().Model(&model.AccountRole{}).Where("account_id = ? AND role_id = ?", testAccount.ID, testRole.ID).Count(&count)
|
||
assert.Equal(t, int64(1), count)
|
||
})
|
||
}
|
||
|
||
// TestAccountAPI_GetRoles 测试获取账号角色 API
|
||
func TestAccountAPI_GetRoles(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
// 创建测试账号
|
||
testAccount := env.CreateTestAccount("get_roles_test", "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
// 创建并分配角色
|
||
testRole := env.CreateTestRole("获取角色测试", constants.RoleTypePlatform)
|
||
|
||
accountRole := &model.AccountRole{
|
||
AccountID: testAccount.ID,
|
||
RoleID: testRole.ID,
|
||
Status: constants.StatusEnabled,
|
||
Creator: 1,
|
||
Updater: 1,
|
||
}
|
||
env.TX.Create(accountRole)
|
||
|
||
t.Run("成功获取账号角色", func(t *testing.T) {
|
||
resp, err := env.AsSuperAdmin().Request("GET", fmt.Sprintf("/api/admin/accounts/%d/roles", testAccount.ID), nil)
|
||
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)
|
||
})
|
||
}
|
||
|
||
// TestAccountAPI_RemoveRole 测试移除角色 API
|
||
func TestAccountAPI_RemoveRole(t *testing.T) {
|
||
env := integ.NewIntegrationTestEnv(t)
|
||
|
||
// 创建测试账号
|
||
testAccount := env.CreateTestAccount("remove_role_test", "password123", constants.UserTypePlatform, nil, nil)
|
||
|
||
// 创建并分配角色
|
||
testRole := env.CreateTestRole("移除角色测试", constants.RoleTypePlatform)
|
||
|
||
accountRole := &model.AccountRole{
|
||
AccountID: testAccount.ID,
|
||
RoleID: testRole.ID,
|
||
Status: constants.StatusEnabled,
|
||
Creator: 1,
|
||
Updater: 1,
|
||
}
|
||
env.TX.Create(accountRole)
|
||
|
||
t.Run("成功移除角色", func(t *testing.T) {
|
||
resp, err := env.AsSuperAdmin().Request("DELETE", fmt.Sprintf("/api/admin/accounts/%d/roles/%d", testAccount.ID, testRole.ID), nil)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||
|
||
// 验证关联已软删除
|
||
var ar model.AccountRole
|
||
err = env.RawDB().Unscoped().Where("account_id = ? AND role_id = ?", testAccount.ID, testRole.ID).First(&ar).Error
|
||
require.NoError(t, err)
|
||
assert.NotNil(t, ar.DeletedAt)
|
||
})
|
||
}
|