| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- package product
- import (
- "errors"
- "sync"
- "testing"
- productModel "perms-system-server/internal/model/product"
- "perms-system-server/internal/response"
- "perms-system-server/internal/svc"
- "perms-system-server/internal/testutil"
- "perms-system-server/internal/testutil/ctxhelper"
- "perms-system-server/internal/types"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "golang.org/x/crypto/bcrypt"
- )
- // TC-0060: 正常创建
- func TestCreateProduct_Success(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- code := testutil.UniqueId()
- logic := NewCreateProductLogic(ctx, svcCtx)
- resp, err := logic.CreateProduct(&types.CreateProductReq{
- Code: code,
- Name: "测试产品",
- Remark: "集成测试",
- })
- require.NoError(t, err)
- require.NotNil(t, resp)
- t.Cleanup(func() {
- testutil.CleanTableByField(ctx, conn, "`sys_product_member`", "productCode", code)
- testutil.CleanTableByField(ctx, conn, "`sys_user`", "username", "admin_"+code)
- testutil.CleanTable(ctx, conn, "`sys_product`", resp.Id)
- })
- assert.True(t, resp.Id > 0)
- assert.Equal(t, code, resp.Code)
- assert.NotEmpty(t, resp.AppKey)
- assert.NotEmpty(t, resp.AppSecret)
- assert.Equal(t, "admin_"+code, resp.AdminUser)
- assert.NotEmpty(t, resp.AdminPassword)
- }
- // TC-0060: 正常创建
- func TestCreateProduct_VerifyDB(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- code := testutil.UniqueId()
- logic := NewCreateProductLogic(ctx, svcCtx)
- resp, err := logic.CreateProduct(&types.CreateProductReq{
- Code: code,
- Name: "DB验证产品",
- Remark: "验证数据库记录",
- })
- require.NoError(t, err)
- t.Cleanup(func() {
- testutil.CleanTableByField(ctx, conn, "`sys_product_member`", "productCode", code)
- testutil.CleanTableByField(ctx, conn, "`sys_user`", "username", "admin_"+code)
- testutil.CleanTable(ctx, conn, "`sys_product`", resp.Id)
- })
- product, err := svcCtx.SysProductModel.FindOne(ctx, resp.Id)
- require.NoError(t, err)
- assert.Equal(t, code, product.Code)
- assert.Equal(t, "DB验证产品", product.Name)
- assert.Equal(t, resp.AppKey, product.AppKey)
- require.NoError(t, bcrypt.CompareHashAndPassword([]byte(product.AppSecret), []byte(resp.AppSecret)),
- "DB should store bcrypt hash of appSecret, verifiable with plaintext from response")
- assert.Equal(t, int64(1), product.Status)
- var userCount int64
- err = conn.QueryRowCtx(ctx, &userCount,
- "SELECT COUNT(*) FROM `sys_user` WHERE `username` = ?", "admin_"+code)
- require.NoError(t, err)
- assert.Equal(t, int64(1), userCount)
- var memberCount int64
- err = conn.QueryRowCtx(ctx, &memberCount,
- "SELECT COUNT(*) FROM `sys_product_member` WHERE `productCode` = ? AND `memberType` = 'ADMIN'", code)
- require.NoError(t, err)
- assert.Equal(t, int64(1), memberCount)
- }
- // TC-0063: 编码已存在
- func TestCreateProduct_DuplicateCode(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- code := testutil.UniqueId()
- logic := NewCreateProductLogic(ctx, svcCtx)
- resp, err := logic.CreateProduct(&types.CreateProductReq{
- Code: code,
- Name: "第一个产品",
- })
- require.NoError(t, err)
- t.Cleanup(func() {
- testutil.CleanTableByField(ctx, conn, "`sys_product_member`", "productCode", code)
- testutil.CleanTableByField(ctx, conn, "`sys_user`", "username", "admin_"+code)
- testutil.CleanTable(ctx, conn, "`sys_product`", resp.Id)
- })
- logic2 := NewCreateProductLogic(ctx, svcCtx)
- _, err = logic2.CreateProduct(&types.CreateProductReq{
- Code: code,
- Name: "重复产品",
- })
- require.Error(t, err)
- var codeErr *response.CodeError
- require.True(t, errors.As(err, &codeErr))
- assert.Equal(t, 409, codeErr.Code())
- assert.Equal(t, "产品编码已存在", codeErr.Error())
- }
- // TC-0064: 并发创建同编码
- func TestCreateProduct_ConcurrentSameCode(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- code := testutil.UniqueId()
- t.Cleanup(func() {
- testutil.CleanTableByField(ctx, conn, "`sys_product_member`", "productCode", code)
- testutil.CleanTableByField(ctx, conn, "`sys_user`", "username", "admin_"+code)
- testutil.CleanTableByField(ctx, conn, "`sys_product`", "code", code)
- })
- var wg sync.WaitGroup
- results := make(chan error, 2)
- for i := 0; i < 2; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- logic := NewCreateProductLogic(ctx, svcCtx)
- _, err := logic.CreateProduct(&types.CreateProductReq{
- Code: code,
- Name: "并发测试产品",
- })
- results <- err
- }()
- }
- wg.Wait()
- close(results)
- var errs []error
- for err := range results {
- errs = append(errs, err)
- }
- require.Len(t, errs, 2)
- successCount := 0
- failCount := 0
- for _, err := range errs {
- if err == nil {
- successCount++
- } else {
- failCount++
- }
- }
- assert.Equal(t, 1, successCount, "exactly one goroutine should succeed")
- assert.Equal(t, 1, failCount, "exactly one goroutine should fail (409 or DB duplicate)")
- }
- // TC-0514: createProduct非超管拒绝
- func TestCreateProduct_NonSuperAdminRejected(t *testing.T) {
- ctx := ctxhelper.AdminCtx("test_product")
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- logic := NewCreateProductLogic(ctx, svcCtx)
- _, err := logic.CreateProduct(&types.CreateProductReq{Code: "test", Name: "test"})
- require.Error(t, err)
- var ce *response.CodeError
- require.True(t, errors.As(err, &ce))
- assert.Equal(t, 403, ce.Code())
- }
- // suppress unused import
- var _ = (*productModel.SysProduct)(nil)
|