package pub import ( "context" "encoding/json" "errors" "net/http" "net/http/httptest" "testing" "time" "perms-system-server/internal/config" productmemberModel "perms-system-server/internal/model/productmember" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/testutil" "perms-system-server/internal/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func newCapMockServer(success bool) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]bool{"success": success}) })) } func newCapEnabledSvcCtx(endpointURL string) *svc.ServiceContext { cfg := testutil.GetTestConfig() cfg.Capjs = config.CapjsConf{ Enable: 1, EndpointURL: endpointURL, Key: "test-key", Secret: "test-secret", } return svc.NewServiceContext(cfg) } // TC-1219: cap.js 未启用时调用 LoginByCap func TestLoginByCap_CapDisabled(t *testing.T) { cfg := testutil.GetTestConfig() cfg.Capjs = config.CapjsConf{Enable: 0} svcCtx := svc.NewServiceContext(cfg) logic := NewLoginByCapLogic(context.Background(), svcCtx) resp, err := logic.LoginByCap(&types.LoginByCapReq{ Username: "user", Password: "pass", ProductCode: "pc", CapToken: "some-token", }) require.Nil(t, resp) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 400, codeErr.Code()) assert.Contains(t, codeErr.Error(), "当前未启用人机验证") } // TC-1220: capToken 为空 func TestLoginByCap_EmptyCapToken(t *testing.T) { server := newCapMockServer(true) defer server.Close() svcCtx := newCapEnabledSvcCtx(server.URL) logic := NewLoginByCapLogic(context.Background(), svcCtx) resp, err := logic.LoginByCap(&types.LoginByCapReq{ Username: "user", Password: "pass", ProductCode: "pc", CapToken: "", }) require.Nil(t, resp) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 400, codeErr.Code()) assert.Contains(t, codeErr.Error(), "人机验证不能为空") } // TC-1221: capToken 无效(远端校验失败) func TestLoginByCap_InvalidCapToken(t *testing.T) { server := newCapMockServer(false) defer server.Close() svcCtx := newCapEnabledSvcCtx(server.URL) logic := NewLoginByCapLogic(context.Background(), svcCtx) resp, err := logic.LoginByCap(&types.LoginByCapReq{ Username: "user", Password: "pass", ProductCode: "pc", CapToken: "invalid-token", }) require.Nil(t, resp) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 400, codeErr.Code()) assert.Contains(t, codeErr.Error(), "人机验证失败") } // TC-1222: capToken 有效 + 正常登录 func TestLoginByCap_ValidToken_Success(t *testing.T) { ctx := context.Background() server := newCapMockServer(true) defer server.Close() svcCtx := newCapEnabledSvcCtx(server.URL) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() password := "TestPass123" pc := testutil.UniqueId() now := time.Now().Unix() userId, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 2) t.Cleanup(cleanUser) _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret") t.Cleanup(cleanProduct) pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &productmemberModel.SysProductMember{ ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: now, UpdateTime: now, }) require.NoError(t, err) pmId, _ := pmRes.LastInsertId() t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId) }) logic := NewLoginByCapLogic(ctx, svcCtx) resp, err := logic.LoginByCap(&types.LoginByCapReq{ Username: username, Password: password, ProductCode: pc, CapToken: "valid-token", }) require.NoError(t, err) require.NotNil(t, resp) assert.NotEmpty(t, resp.AccessToken) assert.NotEmpty(t, resp.RefreshToken) assert.Equal(t, username, resp.UserInfo.Username) } // TC-1223: capToken 有效 + 密码错误 func TestLoginByCap_ValidToken_WrongPassword(t *testing.T) { ctx := context.Background() server := newCapMockServer(true) defer server.Close() svcCtx := newCapEnabledSvcCtx(server.URL) username := testutil.UniqueId() pc := testutil.UniqueId() _, cleanUser := insertTestUser(t, ctx, svcCtx, username, "RealPass123", 1, 2) t.Cleanup(cleanUser) _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret") t.Cleanup(cleanProduct) logic := NewLoginByCapLogic(ctx, svcCtx) resp, err := logic.LoginByCap(&types.LoginByCapReq{ Username: username, Password: "WrongPass", ProductCode: pc, CapToken: "valid-token", }) require.Nil(t, resp) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 401, codeErr.Code()) } // TC-1224: capToken 有效 + 超管被拒绝 func TestLoginByCap_ValidToken_SuperAdminRejected(t *testing.T) { ctx := context.Background() server := newCapMockServer(true) defer server.Close() svcCtx := newCapEnabledSvcCtx(server.URL) username := testutil.UniqueId() password := "TestPass123" pc := testutil.UniqueId() _, cleanUser := insertSuperAdmin(t, ctx, svcCtx, username, password) t.Cleanup(cleanUser) _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret") t.Cleanup(cleanProduct) logic := NewLoginByCapLogic(ctx, svcCtx) resp, err := logic.LoginByCap(&types.LoginByCapReq{ Username: username, Password: password, ProductCode: pc, CapToken: "valid-token", }) require.Nil(t, resp) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 403, codeErr.Code()) }