| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- package server
- import (
- "context"
- "testing"
- productModel "perms-system-server/internal/model/product"
- pub "perms-system-server/internal/logic/pub"
- "perms-system-server/internal/testutil/mocks"
- "perms-system-server/pb"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "github.com/zeromicro/go-zero/core/stores/sqlx"
- "go.uber.org/mock/gomock"
- "golang.org/x/crypto/bcrypt"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
- )
- // ---------------------------------------------------------------------------
- // 审计 M-2(第 8 轮)—— PermServer.SyncPermissions gRPC 侧必须把 SyncPermsError{Code:404}
- // 映射为 codes.NotFound;此前落到 default 分支时会被统一为 codes.Internal,使接入方 SDK
- // 把"产品不存在"当作系统故障触发重试/告警。
- //
- // TC 编号:TC-0981(404→NotFound),TC-0982(未识别 code 仍走 Internal 防止误收)。
- // ---------------------------------------------------------------------------
- // TC-0981: gRPC 404 → codes.NotFound(配合 permserver.go:81 的 case 404 分支)。
- func TestSyncPermissions_gRPC_LockByCodeTxNotFound_MapsToCodesNotFound(t *testing.T) {
- ctrl := gomock.NewController(t)
- defer ctrl.Finish()
- hashedSecret, err := bcrypt.GenerateFromPassword([]byte("m2_secret_grpc"), bcrypt.MinCost)
- require.NoError(t, err)
- mockProduct := mocks.NewMockSysProductModel(ctrl)
- mockProduct.EXPECT().FindOneByAppKey(gomock.Any(), "m2_grpc_key").
- Return(&productModel.SysProduct{
- Id: 1, Code: "m2_grpc_prod", AppKey: "m2_grpc_key",
- AppSecret: string(hashedSecret), Status: 1,
- }, nil)
- // LockByCodeTx 命中 sqlx.ErrNotFound → service 内部构造 SyncPermsError{Code:404}。
- mockProduct.EXPECT().LockByCodeTx(gomock.Any(), gomock.Any(), "m2_grpc_prod").
- Return((*productModel.SysProduct)(nil), sqlx.ErrNotFound)
- mockPerm := mocks.NewMockSysPermModel(ctrl)
- mockPerm.EXPECT().TransactCtx(gomock.Any(), gomock.Any()).
- DoAndReturn(func(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
- return fn(ctx, nil)
- })
- svcCtx := mocks.NewMockServiceContext(mocks.MockModels{Product: mockProduct, Perm: mockPerm})
- srv := NewPermServer(svcCtx)
- _, err = srv.SyncPermissions(context.Background(), &pb.SyncPermissionsReq{
- AppKey: "m2_grpc_key", AppSecret: "m2_secret_grpc",
- Perms: []*pb.PermItem{{Code: "p1", Name: "P1"}},
- })
- require.Error(t, err, "M-2:tx 内产品消失必须返回 gRPC 错误")
- st, ok := status.FromError(err)
- require.True(t, ok, "M-2:必须是 gRPC status.Error,不得为裸 error")
- assert.Equal(t, codes.NotFound, st.Code(),
- "M-2:SyncPermsError{Code:404} 必须映射为 codes.NotFound;若仍为 codes.Internal,"+
- "说明 permserver.go 的 switch 缺少 case 404,接入方 SDK 会把业务未命中当作系统故障重试")
- assert.Equal(t, "产品不存在", st.Message(), "M-2:保留原始语义文案")
- }
- // TC-0982: 未映射的 SyncPermsError.Code(例如 500)必须继续落到 codes.Internal。
- // 防御未来有人错误"兜底"把所有 SyncPermsError 全部变 NotFound。
- func TestSyncPermissions_gRPC_UnmappedCode_StaysInternal(t *testing.T) {
- ctrl := gomock.NewController(t)
- defer ctrl.Finish()
- hashedSecret, err := bcrypt.GenerateFromPassword([]byte("m2_secret_grpc"), bcrypt.MinCost)
- require.NoError(t, err)
- mockProduct := mocks.NewMockSysProductModel(ctrl)
- mockProduct.EXPECT().FindOneByAppKey(gomock.Any(), "m2_grpc_key2").
- Return(&productModel.SysProduct{
- Id: 1, Code: "m2_grpc_prod2", AppKey: "m2_grpc_key2",
- AppSecret: string(hashedSecret), Status: 1,
- }, nil)
- mockProduct.EXPECT().LockByCodeTx(gomock.Any(), gomock.Any(), "m2_grpc_prod2").
- Return(&productModel.SysProduct{Id: 1, Code: "m2_grpc_prod2"}, nil)
- mockPerm := mocks.NewMockSysPermModel(ctrl)
- mockPerm.EXPECT().FindMapByProductCodeWithTx(gomock.Any(), gomock.Any(), "m2_grpc_prod2").
- Return(nil, &pub.SyncPermsError{Code: 500, Message: "any low-level"})
- mockPerm.EXPECT().TransactCtx(gomock.Any(), gomock.Any()).
- DoAndReturn(func(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
- return fn(ctx, nil)
- })
- svcCtx := mocks.NewMockServiceContext(mocks.MockModels{Product: mockProduct, Perm: mockPerm})
- srv := NewPermServer(svcCtx)
- _, err = srv.SyncPermissions(context.Background(), &pb.SyncPermissionsReq{
- AppKey: "m2_grpc_key2", AppSecret: "m2_secret_grpc",
- Perms: []*pb.PermItem{{Code: "p1", Name: "P1"}},
- })
- require.Error(t, err)
- st, ok := status.FromError(err)
- require.True(t, ok)
- assert.Equal(t, codes.Internal, st.Code(),
- "M-2:未识别的 SyncPermsError.Code 必须仍落到 codes.Internal,不得被"+
- "一刀切映射成 codes.NotFound 掩盖真正的系统故障")
- }
|