All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
- 合并 customer_account 和 shop_account 路由到统一的 account 接口 - 新增统一认证接口 (auth handler) - 实现越权防护中间件和权限检查工具函数 - 新增操作审计日志模型和服务 - 更新数据库迁移 (版本 39: account_operation_log 表) - 补充集成测试覆盖权限检查和审计日志场景
360 lines
12 KiB
Go
360 lines
12 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
)
|
|
|
|
type MockShopStore struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockShopStore) GetByID(ctx context.Context, id uint) (*model.Shop, error) {
|
|
args := m.Called(ctx, id)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*model.Shop), args.Error(1)
|
|
}
|
|
|
|
func (m *MockShopStore) GetSubordinateShopIDs(ctx context.Context, shopID uint) ([]uint, error) {
|
|
args := m.Called(ctx, shopID)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).([]uint), args.Error(1)
|
|
}
|
|
|
|
type MockEnterpriseStore struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockEnterpriseStore) GetByID(ctx context.Context, id uint) (*model.Enterprise, error) {
|
|
args := m.Called(ctx, id)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*model.Enterprise), args.Error(1)
|
|
}
|
|
|
|
func TestCanManageShop_SuperAdmin(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeSuperAdmin)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageShop(ctx, 100, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageShop_Platform(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypePlatform)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageShop(ctx, 100, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageShop_AgentManageOwnShop(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return([]uint{100, 101, 102}, nil)
|
|
|
|
err := CanManageShop(ctx, 100, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageShop_AgentManageSubordinateShop(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return([]uint{100, 101, 102}, nil)
|
|
|
|
err := CanManageShop(ctx, 101, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageShop_AgentCannotManageOtherShop(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return([]uint{100, 101, 102}, nil)
|
|
|
|
err := CanManageShop(ctx, 200, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理该店铺的账号")
|
|
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageShop_AgentNoShopID(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageShop(ctx, 100, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理店铺账号")
|
|
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageShop_EnterpriseUser(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeEnterprise)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageShop(ctx, 100, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理店铺账号")
|
|
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageShop_GetSubordinateShopIDsError(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return(nil, errors.New("database error"))
|
|
|
|
err := CanManageShop(ctx, 100, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "查询下级店铺失败")
|
|
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageEnterprise_SuperAdmin(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeSuperAdmin)
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockEnterpriseStore.AssertNotCalled(t, "GetByID")
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageEnterprise_Platform(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypePlatform)
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockEnterpriseStore.AssertNotCalled(t, "GetByID")
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageEnterprise_AgentManageOwnShopEnterprise(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
ownerShopID := uint(100)
|
|
enterprise := &model.Enterprise{
|
|
OwnerShopID: &ownerShopID,
|
|
}
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(enterprise, nil)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return([]uint{100, 101, 102}, nil)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageEnterprise_AgentManageSubordinateShopEnterprise(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
ownerShopID := uint(101)
|
|
enterprise := &model.Enterprise{
|
|
OwnerShopID: &ownerShopID,
|
|
}
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(enterprise, nil)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return([]uint{100, 101, 102}, nil)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.NoError(t, err)
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageEnterprise_AgentCannotManageOtherShopEnterprise(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
ownerShopID := uint(200)
|
|
enterprise := &model.Enterprise{
|
|
OwnerShopID: &ownerShopID,
|
|
}
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(enterprise, nil)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return([]uint{100, 101, 102}, nil)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理该企业的账号")
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCanManageEnterprise_AgentCannotManagePlatformEnterprise(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
enterprise := &model.Enterprise{
|
|
OwnerShopID: nil,
|
|
}
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(enterprise, nil)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理平台级企业账号")
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageEnterprise_EnterpriseUser(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeEnterprise)
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理企业账号")
|
|
|
|
mockEnterpriseStore.AssertNotCalled(t, "GetByID")
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageEnterprise_GetEnterpriseError(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(nil, errors.New("database error"))
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限操作该资源或资源不存在")
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageEnterprise_AgentNoShopID(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
|
|
ownerShopID := uint(100)
|
|
enterprise := &model.Enterprise{
|
|
OwnerShopID: &ownerShopID,
|
|
}
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(enterprise, nil)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "无权限管理企业账号")
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertNotCalled(t, "GetSubordinateShopIDs")
|
|
}
|
|
|
|
func TestCanManageEnterprise_GetSubordinateShopIDsError(t *testing.T) {
|
|
ctx := context.Background()
|
|
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
|
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(100))
|
|
|
|
ownerShopID := uint(100)
|
|
enterprise := &model.Enterprise{
|
|
OwnerShopID: &ownerShopID,
|
|
}
|
|
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
mockEnterpriseStore.On("GetByID", ctx, uint(50)).Return(enterprise, nil)
|
|
|
|
mockShopStore := new(MockShopStore)
|
|
mockShopStore.On("GetSubordinateShopIDs", ctx, uint(100)).Return(nil, errors.New("database error"))
|
|
|
|
err := CanManageEnterprise(ctx, 50, mockEnterpriseStore, mockShopStore)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "查询下级店铺失败")
|
|
|
|
mockEnterpriseStore.AssertExpectations(t)
|
|
mockShopStore.AssertExpectations(t)
|
|
}
|
|
|
|
func TestPermissionHelperTestCoverage(t *testing.T) {
|
|
mockShopStore := new(MockShopStore)
|
|
mockEnterpriseStore := new(MockEnterpriseStore)
|
|
|
|
assert.Implements(t, (*ShopStoreInterface)(nil), mockShopStore)
|
|
assert.Implements(t, (*EnterpriseStoreInterface)(nil), mockEnterpriseStore)
|
|
}
|