add service
All checks were successful
Deploy Smart Search Backend Test / deploy (push) Successful in 1m25s
All checks were successful
Deploy Smart Search Backend Test / deploy (push) Successful in 1m25s
This commit is contained in:
@@ -1,158 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_LoginWithNonExistentUser() {
|
||||
req := &authpb.LoginRequest{
|
||||
Email: "nonexistent@example.com",
|
||||
Password: "password123",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "test-agent",
|
||||
}
|
||||
|
||||
resp, err := s.authClient.Login(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.NotFound, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_ValidateWithInvalidToken() {
|
||||
req := &authpb.ValidateRequest{
|
||||
AccessToken: "invalid-token",
|
||||
}
|
||||
|
||||
resp, err := s.authClient.Validate(context.Background(), req)
|
||||
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.False(resp.Valid)
|
||||
s.Equal(int64(0), resp.UserId)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_ValidateWithEmptyToken() {
|
||||
req := &authpb.ValidateRequest{
|
||||
AccessToken: "",
|
||||
}
|
||||
|
||||
resp, err := s.authClient.Validate(context.Background(), req)
|
||||
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.False(resp.Valid)
|
||||
s.Equal(int64(0), resp.UserId)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_RefreshWithInvalidToken() {
|
||||
req := &authpb.RefreshRequest{
|
||||
RefreshToken: "invalid-refresh-token",
|
||||
}
|
||||
|
||||
resp, err := s.authClient.Refresh(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.Unauthenticated, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_LogoutWithInvalidToken() {
|
||||
req := &authpb.LogoutRequest{
|
||||
AccessToken: "invalid-token",
|
||||
}
|
||||
|
||||
resp, err := s.authClient.Logout(context.Background(), req)
|
||||
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.True(resp.Success)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_RefreshTokenFlow() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(loginResp)
|
||||
s.NotEmpty(loginResp.AccessToken)
|
||||
s.NotEmpty(loginResp.RefreshToken)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(validateResp)
|
||||
s.True(validateResp.Valid)
|
||||
|
||||
refreshReq := &authpb.RefreshRequest{
|
||||
RefreshToken: loginResp.RefreshToken,
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
refreshResp, err := s.authClient.Refresh(ctx, refreshReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(refreshResp)
|
||||
s.NotEmpty(refreshResp.AccessToken)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: refreshResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(logoutResp)
|
||||
s.True(logoutResp.Success)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestAuthHandler_LogoutInvalidatesSession() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
s.NotEmpty(loginResp.AccessToken)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp.Success)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(validateResp)
|
||||
s.False(validateResp.Valid)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,285 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
invitepb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/invite"
|
||||
requestpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_CreateTZWithEmptyRequestText() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &requestpb.CreateTZRequest{
|
||||
UserId: validateResp.UserId,
|
||||
RequestTxt: "",
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.CreateTZ(ctx, req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.InvalidArgument, codes.Internal}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_GenerateInviteWithZeroMaxUses() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &invitepb.GenerateRequest{
|
||||
UserId: validateResp.UserId,
|
||||
TtlDays: 30,
|
||||
MaxUses: 0,
|
||||
}
|
||||
|
||||
resp, err := s.inviteClient.Generate(ctx, req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.InvalidArgument, codes.Internal}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_GenerateInviteWithZeroTTL() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &invitepb.GenerateRequest{
|
||||
UserId: validateResp.UserId,
|
||||
TtlDays: 0,
|
||||
MaxUses: 10,
|
||||
}
|
||||
|
||||
resp, err := s.inviteClient.Generate(ctx, req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.InvalidArgument, codes.Internal}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_ApproveTZWithEmptyFinalTZ() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
createReq := &requestpb.CreateTZRequest{
|
||||
UserId: validateResp.UserId,
|
||||
RequestTxt: "Test request",
|
||||
}
|
||||
|
||||
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||
if err != nil {
|
||||
s.T().Skip("Cannot test ApproveTZ without CreateTZ")
|
||||
return
|
||||
}
|
||||
|
||||
approveReq := &requestpb.ApproveTZRequest{
|
||||
RequestId: createResp.RequestId,
|
||||
FinalTz: "",
|
||||
UserId: validateResp.UserId,
|
||||
}
|
||||
|
||||
approveResp, err := s.requestClient.ApproveTZ(ctx, approveReq)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.InvalidArgument, codes.Internal}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(approveResp)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_DoubleLogout() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp1, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp1.Success)
|
||||
|
||||
logoutResp2, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp2.Success)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_ValidateAfterLogout() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp.Success)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
s.False(validateResp.Valid)
|
||||
s.Equal(int64(0), validateResp.UserId)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_RefreshAfterLogout() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp.Success)
|
||||
|
||||
refreshReq := &authpb.RefreshRequest{
|
||||
RefreshToken: loginResp.RefreshToken,
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
refreshResp, err := s.authClient.Refresh(ctx, refreshReq)
|
||||
s.Error(err)
|
||||
s.Nil(refreshResp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.Unauthenticated, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestEdgeCase_LoginWithWrongPassword() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "wrongpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.Error(err)
|
||||
s.Nil(loginResp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.Unauthenticated, st.Code())
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
invitepb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/invite"
|
||||
requestpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"
|
||||
supplierpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplier"
|
||||
userpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/user"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestFullFlow_CompleteRequestLifecycle() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
s.NotEmpty(loginResp.AccessToken)
|
||||
s.NotEmpty(loginResp.RefreshToken)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
s.True(validateResp.Valid)
|
||||
userID := validateResp.UserId
|
||||
|
||||
getUserInfoReq := &userpb.GetInfoRequest{
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
userInfoResp, err := s.userClient.GetInfo(ctx, getUserInfoReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(userInfoResp)
|
||||
s.Equal("test@example.com", userInfoResp.Email)
|
||||
|
||||
getBalanceReq := &userpb.GetBalanceRequest{
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
balanceResp, err := s.userClient.GetBalance(ctx, getBalanceReq)
|
||||
s.NoError(err)
|
||||
s.GreaterOrEqual(balanceResp.Balance, 0.0)
|
||||
|
||||
createTZReq := &requestpb.CreateTZRequest{
|
||||
UserId: userID,
|
||||
RequestTxt: "Нужны поставщики металлоконструкций",
|
||||
}
|
||||
|
||||
createTZResp, err := s.requestClient.CreateTZ(ctx, createTZReq)
|
||||
if err != nil {
|
||||
s.T().Logf("CreateTZ failed: %v", err)
|
||||
return
|
||||
}
|
||||
s.NotEmpty(createTZResp.RequestId)
|
||||
s.NotEmpty(createTZResp.TzText)
|
||||
requestID := createTZResp.RequestId
|
||||
|
||||
approveTZReq := &requestpb.ApproveTZRequest{
|
||||
RequestId: requestID,
|
||||
FinalTz: "Утвержденное ТЗ для поставщиков металлоконструкций",
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
approveTZResp, err := s.requestClient.ApproveTZ(ctx, approveTZReq)
|
||||
if err != nil {
|
||||
s.T().Logf("ApproveTZ failed: %v", err)
|
||||
return
|
||||
}
|
||||
s.True(approveTZResp.Success)
|
||||
|
||||
getMailingListReq := &requestpb.GetMailingListRequest{
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
mailingListResp, err := s.requestClient.GetMailingList(ctx, getMailingListReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(mailingListResp.Items)
|
||||
s.GreaterOrEqual(len(mailingListResp.Items), 1)
|
||||
|
||||
getMailingListByIDReq := &requestpb.GetMailingListByIDRequest{
|
||||
RequestId: requestID,
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
mailingListByIDResp, err := s.requestClient.GetMailingListByID(ctx, getMailingListByIDReq)
|
||||
if err != nil {
|
||||
s.T().Logf("GetMailingListByID failed: %v", err)
|
||||
return
|
||||
}
|
||||
s.NotNil(mailingListByIDResp.Item)
|
||||
s.Equal(requestID, mailingListByIDResp.Item.RequestId)
|
||||
|
||||
exportExcelReq := &supplierpb.ExportExcelRequest{
|
||||
RequestId: requestID,
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
exportExcelResp, err := s.supplierClient.ExportExcel(ctx, exportExcelReq)
|
||||
if err != nil {
|
||||
s.T().Logf("ExportExcel failed (expected if no suppliers): %v", err)
|
||||
} else {
|
||||
s.NotNil(exportExcelResp)
|
||||
s.NotEmpty(exportExcelResp.FileName)
|
||||
}
|
||||
|
||||
getStatisticsReq := &userpb.GetStatisticsRequest{
|
||||
UserId: userID,
|
||||
}
|
||||
|
||||
statisticsResp, err := s.userClient.GetStatistics(ctx, getStatisticsReq)
|
||||
s.NoError(err)
|
||||
s.GreaterOrEqual(statisticsResp.TotalRequests, int32(0))
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp.Success)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestFullFlow_InviteCodeLifecycle() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
userID := validateResp.UserId
|
||||
|
||||
generateInviteReq := &invitepb.GenerateRequest{
|
||||
UserId: userID,
|
||||
TtlDays: 7,
|
||||
MaxUses: 5,
|
||||
}
|
||||
|
||||
generateInviteResp, err := s.inviteClient.Generate(ctx, generateInviteReq)
|
||||
s.NoError(err)
|
||||
s.NotEmpty(generateInviteResp.Code)
|
||||
s.Greater(generateInviteResp.MaxUses, int32(0))
|
||||
inviteCode := generateInviteResp.Code
|
||||
|
||||
getInviteInfoReq := &invitepb.GetInfoRequest{
|
||||
Code: inviteCode,
|
||||
}
|
||||
|
||||
inviteInfoResp, err := s.inviteClient.GetInfo(ctx, getInviteInfoReq)
|
||||
s.NoError(err)
|
||||
s.Equal(inviteCode, inviteInfoResp.Code)
|
||||
s.Equal(userID, inviteInfoResp.UserId)
|
||||
s.Equal(generateInviteResp.MaxUses, inviteInfoResp.CanBeUsedCount)
|
||||
s.Equal(int32(0), inviteInfoResp.UsedCount)
|
||||
s.True(inviteInfoResp.IsActive)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp.Success)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestFullFlow_MultipleRefresh() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
s.NotEmpty(loginResp.AccessToken)
|
||||
s.NotEmpty(loginResp.RefreshToken)
|
||||
|
||||
refreshToken := loginResp.RefreshToken
|
||||
|
||||
refreshReq1 := &authpb.RefreshRequest{
|
||||
RefreshToken: refreshToken,
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
refreshResp1, err := s.authClient.Refresh(ctx, refreshReq1)
|
||||
s.NoError(err)
|
||||
s.NotEmpty(refreshResp1.AccessToken)
|
||||
|
||||
refreshReq2 := &authpb.RefreshRequest{
|
||||
RefreshToken: refreshToken,
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
refreshResp2, err := s.authClient.Refresh(ctx, refreshReq2)
|
||||
s.NoError(err)
|
||||
s.NotEmpty(refreshResp2.AccessToken)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: refreshResp2.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
s.True(validateResp.Valid)
|
||||
|
||||
logoutReq := &authpb.LogoutRequest{
|
||||
AccessToken: refreshResp2.AccessToken,
|
||||
}
|
||||
|
||||
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||
s.NoError(err)
|
||||
s.True(logoutResp.Success)
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/modules/postgres"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
|
||||
"git.techease.ru/Smart-search/smart-search-back/internal/database"
|
||||
grpchandlers "git.techease.ru/Smart-search/smart-search-back/internal/grpc"
|
||||
"git.techease.ru/Smart-search/smart-search-back/pkg/crypto"
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
invitepb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/invite"
|
||||
requestpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"
|
||||
supplierpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplier"
|
||||
userpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/user"
|
||||
)
|
||||
|
||||
const (
|
||||
testJWTSecret = "test-jwt-secret-key-for-integration-tests"
|
||||
testCryptoSecret = "test-crypto-secret-key-for-integration"
|
||||
bufSize = 1024 * 1024
|
||||
)
|
||||
|
||||
type IntegrationSuite struct {
|
||||
suite.Suite
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
pgContainer *postgres.PostgresContainer
|
||||
pool *pgxpool.Pool
|
||||
grpcServer *grpc.Server
|
||||
listener *bufconn.Listener
|
||||
authClient authpb.AuthServiceClient
|
||||
userClient userpb.UserServiceClient
|
||||
inviteClient invitepb.InviteServiceClient
|
||||
requestClient requestpb.RequestServiceClient
|
||||
supplierClient supplierpb.SupplierServiceClient
|
||||
testUserEmail string
|
||||
testUserPassword string
|
||||
testAccessToken string
|
||||
testRefreshToken string
|
||||
}
|
||||
|
||||
func TestIntegrationSuite(t *testing.T) {
|
||||
suite.Run(t, new(IntegrationSuite))
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) SetupSuite() {
|
||||
s.ctx, s.cancel = context.WithCancel(context.Background())
|
||||
|
||||
s.T().Log("Starting PostgreSQL container...")
|
||||
pgContainer, err := postgres.Run(s.ctx,
|
||||
"postgres:15-alpine",
|
||||
postgres.WithDatabase("test_db"),
|
||||
postgres.WithUsername("test_user"),
|
||||
postgres.WithPassword("test_password"),
|
||||
testcontainers.WithWaitStrategy(
|
||||
wait.ForLog("database system is ready to accept connections").
|
||||
WithOccurrence(2).
|
||||
WithStartupTimeout(60*time.Second)),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.pgContainer = pgContainer
|
||||
|
||||
connStr, err := pgContainer.ConnectionString(s.ctx, "sslmode=disable")
|
||||
s.Require().NoError(err)
|
||||
s.T().Logf("PostgreSQL connection string: %s", connStr)
|
||||
|
||||
s.T().Log("Running migrations...")
|
||||
err = database.RunMigrationsFromPath(connStr, "../../../migrations")
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.T().Log("Creating connection pool...")
|
||||
poolConfig, err := pgxpool.ParseConfig(connStr)
|
||||
s.Require().NoError(err)
|
||||
poolConfig.MaxConns = 10
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(s.ctx, poolConfig)
|
||||
s.Require().NoError(err)
|
||||
s.pool = pool
|
||||
|
||||
err = pool.Ping(s.ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.T().Log("Creating gRPC server...")
|
||||
logger, _ := zap.NewDevelopment()
|
||||
|
||||
authHandler, userHandler, inviteHandler, requestHandler, supplierHandler := grpchandlers.NewHandlers(
|
||||
pool,
|
||||
testJWTSecret,
|
||||
testCryptoSecret,
|
||||
"",
|
||||
"",
|
||||
logger,
|
||||
)
|
||||
|
||||
s.listener = bufconn.Listen(bufSize)
|
||||
s.grpcServer = grpc.NewServer()
|
||||
|
||||
grpchandlers.RegisterServices(s.grpcServer, authHandler, userHandler, inviteHandler, requestHandler, supplierHandler)
|
||||
|
||||
go func() {
|
||||
if err := s.grpcServer.Serve(s.listener); err != nil {
|
||||
s.T().Logf("gRPC server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
s.T().Log("Creating gRPC clients...")
|
||||
conn, err := grpc.NewClient("passthrough://bufnet",
|
||||
grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
|
||||
return s.listener.Dial()
|
||||
}),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.authClient = authpb.NewAuthServiceClient(conn)
|
||||
s.userClient = userpb.NewUserServiceClient(conn)
|
||||
s.inviteClient = invitepb.NewInviteServiceClient(conn)
|
||||
s.requestClient = requestpb.NewRequestServiceClient(conn)
|
||||
s.supplierClient = supplierpb.NewSupplierServiceClient(conn)
|
||||
|
||||
s.testUserEmail = fmt.Sprintf("test_%d@example.com", time.Now().Unix())
|
||||
s.testUserPassword = "testpassword123"
|
||||
|
||||
s.T().Log("Creating test user...")
|
||||
s.createTestUser("test@example.com", "testpassword")
|
||||
|
||||
s.T().Log("Integration suite setup completed")
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) createTestUser(email, password string) {
|
||||
cryptoHelper := crypto.NewCrypto(testCryptoSecret)
|
||||
|
||||
encryptedEmail, err := cryptoHelper.Encrypt(email)
|
||||
s.Require().NoError(err)
|
||||
|
||||
encryptedPhone, err := cryptoHelper.Encrypt("+1234567890")
|
||||
s.Require().NoError(err)
|
||||
|
||||
encryptedUserName, err := cryptoHelper.Encrypt("Test User")
|
||||
s.Require().NoError(err)
|
||||
|
||||
emailHash := cryptoHelper.EmailHash(email)
|
||||
passwordHash := crypto.PasswordHash(password)
|
||||
|
||||
query := `
|
||||
INSERT INTO users (email, email_hash, password_hash, phone, user_name, company_name, balance, payment_status, invites_issued, invites_limit)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
ON CONFLICT (email_hash) DO NOTHING
|
||||
`
|
||||
|
||||
_, err = s.pool.Exec(s.ctx, query,
|
||||
encryptedEmail,
|
||||
emailHash,
|
||||
passwordHash,
|
||||
encryptedPhone,
|
||||
encryptedUserName,
|
||||
"Test Company",
|
||||
1000.0,
|
||||
"active",
|
||||
0,
|
||||
10,
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TearDownSuite() {
|
||||
s.T().Log("Tearing down integration suite...")
|
||||
|
||||
if s.grpcServer != nil {
|
||||
s.grpcServer.Stop()
|
||||
}
|
||||
|
||||
if s.pool != nil {
|
||||
s.pool.Close()
|
||||
}
|
||||
|
||||
if s.pgContainer != nil {
|
||||
if err := s.pgContainer.Terminate(s.ctx); err != nil {
|
||||
s.T().Logf("Failed to terminate PostgreSQL container: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if s.cancel != nil {
|
||||
s.cancel()
|
||||
}
|
||||
|
||||
s.T().Log("Integration suite teardown completed")
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TearDownTest() {
|
||||
s.testAccessToken = ""
|
||||
s.testRefreshToken = ""
|
||||
|
||||
_, _ = s.pool.Exec(s.ctx, "DELETE FROM sessions")
|
||||
_, _ = s.pool.Exec(s.ctx, "DELETE FROM invite_codes")
|
||||
_, _ = s.pool.Exec(s.ctx, "DELETE FROM suppliers")
|
||||
_, _ = s.pool.Exec(s.ctx, "DELETE FROM requests_for_suppliers")
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
invitepb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/invite"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestInviteHandler_GenerateWithNonExistentUser() {
|
||||
req := &invitepb.GenerateRequest{
|
||||
UserId: 999999,
|
||||
TtlDays: 30,
|
||||
MaxUses: 10,
|
||||
}
|
||||
|
||||
resp, err := s.inviteClient.Generate(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal, codes.Unknown}, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestInviteHandler_GetInfoWithInvalidCode() {
|
||||
req := &invitepb.GetInfoRequest{
|
||||
Code: "999999999",
|
||||
}
|
||||
|
||||
resp, err := s.inviteClient.GetInfo(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.NotFound, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestInviteHandler_GetInfoWithInvalidCodeFormat() {
|
||||
req := &invitepb.GetInfoRequest{
|
||||
Code: "invalid-code",
|
||||
}
|
||||
|
||||
resp, err := s.inviteClient.GetInfo(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestInviteHandler_GenerateAndGetInfoFlow() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
s.True(validateResp.Valid)
|
||||
|
||||
generateReq := &invitepb.GenerateRequest{
|
||||
UserId: validateResp.UserId,
|
||||
TtlDays: 30,
|
||||
MaxUses: 10,
|
||||
}
|
||||
|
||||
generateResp, err := s.inviteClient.Generate(ctx, generateReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(generateResp)
|
||||
s.NotEmpty(generateResp.Code)
|
||||
s.Greater(generateResp.MaxUses, int32(0))
|
||||
s.NotNil(generateResp.ExpiresAt)
|
||||
|
||||
getInfoReq := &invitepb.GetInfoRequest{
|
||||
Code: generateResp.Code,
|
||||
}
|
||||
|
||||
infoResp, err := s.inviteClient.GetInfo(ctx, getInfoReq)
|
||||
s.NoError(err)
|
||||
s.NotNil(infoResp)
|
||||
s.Equal(generateResp.Code, infoResp.Code)
|
||||
s.Equal(validateResp.UserId, infoResp.UserId)
|
||||
s.Equal(generateResp.MaxUses, infoResp.CanBeUsedCount)
|
||||
s.Equal(int32(0), infoResp.UsedCount)
|
||||
s.True(infoResp.IsActive)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestInviteHandler_GenerateWithInvalidTTL() {
|
||||
ctx := context.Background()
|
||||
|
||||
req := &invitepb.GenerateRequest{
|
||||
UserId: 1,
|
||||
TtlDays: -1,
|
||||
MaxUses: 10,
|
||||
}
|
||||
|
||||
resp, err := s.inviteClient.Generate(ctx, req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.InvalidArgument, codes.Internal, codes.Unknown}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.techease.ru/Smart-search/smart-search-back/internal/model"
|
||||
"git.techease.ru/Smart-search/smart-search-back/internal/repository"
|
||||
"git.techease.ru/Smart-search/smart-search-back/pkg/crypto"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_InviteIncrementUsedCount() {
|
||||
inviteRepo := repository.NewInviteRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
invite := &model.InviteCode{
|
||||
UserID: userID,
|
||||
Code: time.Now().UnixNano(),
|
||||
CanBeUsedCount: 10,
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
err = inviteRepo.Create(ctx, invite)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = inviteRepo.IncrementUsedCount(ctx, invite.Code)
|
||||
s.NoError(err)
|
||||
|
||||
found, err := inviteRepo.FindByCode(ctx, invite.Code)
|
||||
s.NoError(err)
|
||||
s.Equal(1, found.UsedCount)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_InviteDeactivateExpired() {
|
||||
inviteRepo := repository.NewInviteRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
expiredCode := time.Now().UnixNano()
|
||||
_, err = s.pool.Exec(ctx, `
|
||||
INSERT INTO invite_codes (user_id, code, can_be_used_count, expires_at, is_active)
|
||||
VALUES ($1, $2, 10, now() - interval '1 hour', true)
|
||||
`, userID, expiredCode)
|
||||
s.Require().NoError(err)
|
||||
|
||||
count, err := inviteRepo.DeactivateExpired(ctx)
|
||||
s.NoError(err)
|
||||
s.GreaterOrEqual(count, 1)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_InviteGetUserInvites() {
|
||||
inviteRepo := repository.NewInviteRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
invite := &model.InviteCode{
|
||||
UserID: userID,
|
||||
Code: time.Now().UnixNano(),
|
||||
CanBeUsedCount: 10,
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
err = inviteRepo.Create(ctx, invite)
|
||||
s.Require().NoError(err)
|
||||
|
||||
invites, err := inviteRepo.GetUserInvites(ctx, userID)
|
||||
s.NoError(err)
|
||||
s.GreaterOrEqual(len(invites), 1)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_SessionRevoke() {
|
||||
sessionRepo := repository.NewSessionRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
session := &model.Session{
|
||||
UserID: userID,
|
||||
AccessToken: "test-access-token-" + uuid.New().String(),
|
||||
RefreshToken: "test-refresh-token-" + uuid.New().String(),
|
||||
IP: "127.0.0.1",
|
||||
UserAgent: "test-agent",
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
err = sessionRepo.Create(ctx, session)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = sessionRepo.Revoke(ctx, session.RefreshToken)
|
||||
s.NoError(err)
|
||||
|
||||
_, err = sessionRepo.FindByRefreshToken(ctx, session.RefreshToken)
|
||||
s.Error(err)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_SessionDeleteExpired() {
|
||||
sessionRepo := repository.NewSessionRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
_, err = s.pool.Exec(ctx, `
|
||||
INSERT INTO sessions (user_id, access_token, refresh_token, ip, user_agent, expires_at)
|
||||
VALUES ($1, $2, $3, '127.0.0.1', 'test', now() - interval '1 hour')
|
||||
`, userID, "expired-access-"+uuid.New().String(), "expired-refresh-"+uuid.New().String())
|
||||
s.Require().NoError(err)
|
||||
|
||||
count, err := sessionRepo.DeleteExpired(ctx)
|
||||
s.NoError(err)
|
||||
s.GreaterOrEqual(count, 1)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_RequestUpdateWithTZ() {
|
||||
requestRepo := repository.NewRequestRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
req := &model.Request{
|
||||
UserID: userID,
|
||||
RequestTxt: "Test request for TZ update",
|
||||
}
|
||||
err = requestRepo.Create(ctx, req)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = requestRepo.UpdateWithTZ(ctx, req.ID, "Generated TZ text", true)
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_RequestGetByID() {
|
||||
requestRepo := repository.NewRequestRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var reqID uuid.UUID
|
||||
err = s.pool.QueryRow(ctx, `
|
||||
INSERT INTO requests_for_suppliers (user_id, request_txt, final_tz, final_update_tz, mailling_status_id)
|
||||
VALUES ($1, 'Test request', 'TZ text', 'Final TZ', 1)
|
||||
RETURNING id
|
||||
`, userID).Scan(&reqID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
found, err := requestRepo.GetByID(ctx, reqID)
|
||||
s.NoError(err)
|
||||
s.Equal(reqID, found.ID)
|
||||
s.Equal("Test request", found.RequestTxt)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_SupplierBulkInsertAndDelete() {
|
||||
supplierRepo := repository.NewSupplierRepository(s.pool)
|
||||
requestRepo := repository.NewRequestRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
req := &model.Request{
|
||||
UserID: userID,
|
||||
RequestTxt: "Test request for suppliers",
|
||||
}
|
||||
err = requestRepo.Create(ctx, req)
|
||||
s.Require().NoError(err)
|
||||
|
||||
suppliers := []*model.Supplier{
|
||||
{Name: "Supplier 1", Email: "s1@test.com"},
|
||||
{Name: "Supplier 2", Email: "s2@test.com"},
|
||||
}
|
||||
err = supplierRepo.BulkInsert(ctx, req.ID, suppliers)
|
||||
s.NoError(err)
|
||||
|
||||
found, err := supplierRepo.GetByRequestID(ctx, req.ID)
|
||||
s.NoError(err)
|
||||
s.Equal(2, len(found))
|
||||
|
||||
err = supplierRepo.DeleteByRequestID(ctx, req.ID)
|
||||
s.NoError(err)
|
||||
|
||||
found, err = supplierRepo.GetByRequestID(ctx, req.ID)
|
||||
s.NoError(err)
|
||||
s.Equal(0, len(found))
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_TokenUsageCreate() {
|
||||
tokenRepo := repository.NewTokenUsageRepository(s.pool)
|
||||
requestRepo := repository.NewRequestRepository(s.pool)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
req := &model.Request{
|
||||
UserID: userID,
|
||||
RequestTxt: "Test request for token usage",
|
||||
}
|
||||
err = requestRepo.Create(ctx, req)
|
||||
s.Require().NoError(err)
|
||||
|
||||
usage := &model.TokenUsage{
|
||||
RequestID: req.ID,
|
||||
RequestTokenCount: 100,
|
||||
ResponseTokenCount: 50,
|
||||
TokenCost: 0.005,
|
||||
Type: "openai",
|
||||
}
|
||||
err = tokenRepo.Create(ctx, usage)
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_UserCreate() {
|
||||
userRepo := repository.NewUserRepository(s.pool, testCryptoSecret)
|
||||
ctx := context.Background()
|
||||
|
||||
cryptoHelper := crypto.NewCrypto(testCryptoSecret)
|
||||
email := fmt.Sprintf("newuser_%d@test.com", time.Now().UnixNano())
|
||||
|
||||
user := &model.User{
|
||||
Email: email,
|
||||
EmailHash: cryptoHelper.EmailHash(email),
|
||||
PasswordHash: crypto.PasswordHash("password123"),
|
||||
Phone: "+1234567890",
|
||||
UserName: "New User",
|
||||
CompanyName: "Test Company",
|
||||
Balance: 100.0,
|
||||
PaymentStatus: "active",
|
||||
}
|
||||
|
||||
err := userRepo.Create(ctx, user)
|
||||
s.NoError(err)
|
||||
s.NotZero(user.ID)
|
||||
|
||||
_, err = s.pool.Exec(ctx, "DELETE FROM users WHERE id = $1", user.ID)
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_UserCheckInviteLimit() {
|
||||
userRepo := repository.NewUserRepository(s.pool, testCryptoSecret)
|
||||
ctx := context.Background()
|
||||
|
||||
var userID int
|
||||
err := s.pool.QueryRow(ctx, "SELECT id FROM users LIMIT 1").Scan(&userID)
|
||||
s.Require().NoError(err)
|
||||
|
||||
canInvite, err := userRepo.CheckInviteLimit(ctx, userID)
|
||||
s.NoError(err)
|
||||
s.True(canInvite)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRepository_TxManagerPool() {
|
||||
txManager := repository.NewTxManager(s.pool)
|
||||
|
||||
pool := txManager.Pool()
|
||||
s.NotNil(pool)
|
||||
s.Equal(s.pool, pool)
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
requestpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestRequestHandler_CreateTZWithNonExistentUser() {
|
||||
req := &requestpb.CreateTZRequest{
|
||||
UserId: 999999,
|
||||
RequestTxt: "Нужны поставщики металлоконструкций",
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.CreateTZ(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal, codes.Unknown}, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRequestHandler_GetMailingListByIDWithNonExistent() {
|
||||
req := &requestpb.GetMailingListByIDRequest{
|
||||
RequestId: "999999",
|
||||
UserId: 1,
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.GetMailingListByID(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal, codes.Unknown}, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRequestHandler_GetMailingListWithNonExistentUser() {
|
||||
req := &requestpb.GetMailingListRequest{
|
||||
UserId: 999999,
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.GetMailingList(context.Background(), req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
s.Equal(0, len(resp.Items))
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRequestHandler_ApproveTZWithInvalidRequest() {
|
||||
req := &requestpb.ApproveTZRequest{
|
||||
RequestId: "999999",
|
||||
FinalTz: "Approved TZ",
|
||||
UserId: 1,
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.ApproveTZ(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal, codes.Unknown, codes.InvalidArgument}, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRequestHandler_CreateTZWithValidUser() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &requestpb.CreateTZRequest{
|
||||
UserId: validateResp.UserId,
|
||||
RequestTxt: "Нужны поставщики металлоконструкций",
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.CreateTZ(ctx, req)
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.NotEmpty(resp.RequestId)
|
||||
s.NotEmpty(resp.TzText)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestRequestHandler_GetMailingListWithValidUser() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &requestpb.GetMailingListRequest{
|
||||
UserId: validateResp.UserId,
|
||||
}
|
||||
|
||||
resp, err := s.requestClient.GetMailingList(ctx, req)
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
requestpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"
|
||||
supplierpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplier"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestSupplierHandler_ExportExcelWithNonExistentRequest() {
|
||||
req := &supplierpb.ExportExcelRequest{
|
||||
RequestId: "999999",
|
||||
UserId: 1,
|
||||
}
|
||||
|
||||
resp, err := s.supplierClient.ExportExcel(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal, codes.Unknown, codes.InvalidArgument}, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestSupplierHandler_ExportExcelWithInvalidUser() {
|
||||
req := &supplierpb.ExportExcelRequest{
|
||||
RequestId: "1",
|
||||
UserId: 999999,
|
||||
}
|
||||
|
||||
resp, err := s.supplierClient.ExportExcel(context.Background(), req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.PermissionDenied, codes.Internal, codes.Unknown, codes.InvalidArgument}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestSupplierHandler_ExportExcelWithValidRequest() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
createReq := &requestpb.CreateTZRequest{
|
||||
UserId: validateResp.UserId,
|
||||
RequestTxt: "Нужны поставщики кирпича",
|
||||
}
|
||||
|
||||
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||
if err != nil {
|
||||
s.T().Skip("Cannot test ExportExcel without CreateTZ")
|
||||
return
|
||||
}
|
||||
|
||||
exportReq := &supplierpb.ExportExcelRequest{
|
||||
RequestId: createResp.RequestId,
|
||||
UserId: validateResp.UserId,
|
||||
}
|
||||
|
||||
exportResp, err := s.supplierClient.ExportExcel(ctx, exportReq)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Contains([]codes.Code{codes.NotFound, codes.Internal}, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(exportResp)
|
||||
s.NotEmpty(exportResp.FileName)
|
||||
s.Equal("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", exportResp.MimeType)
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||
userpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/user"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetInfoWithNonExistentUser() {
|
||||
req := &userpb.GetInfoRequest{
|
||||
UserId: 999999,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetInfo(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.NotFound, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetBalanceWithNonExistentUser() {
|
||||
req := &userpb.GetBalanceRequest{
|
||||
UserId: 999999,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetBalance(context.Background(), req)
|
||||
|
||||
s.Error(err)
|
||||
s.Nil(resp)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.NotFound, st.Code())
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetStatisticsWithNonExistentUser() {
|
||||
req := &userpb.GetStatisticsRequest{
|
||||
UserId: 999999,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetStatistics(context.Background(), req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.NotFound, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
s.Equal(int32(0), resp.TotalRequests)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetBalanceStatistics() {
|
||||
req := &userpb.GetBalanceStatisticsRequest{
|
||||
UserId: 1,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetBalanceStatistics(context.Background(), req)
|
||||
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
s.True(ok)
|
||||
s.Equal(codes.NotFound, st.Code())
|
||||
return
|
||||
}
|
||||
|
||||
s.NotNil(resp)
|
||||
s.GreaterOrEqual(resp.Balance, 0.0)
|
||||
s.GreaterOrEqual(resp.TotalRequests, int32(0))
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetInfoWithValidUser() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &userpb.GetInfoRequest{
|
||||
UserId: validateResp.UserId,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetInfo(ctx, req)
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.Equal("test@example.com", resp.Email)
|
||||
s.Equal("Test User", resp.Name)
|
||||
s.Equal("+1234567890", resp.Phone)
|
||||
s.Equal("Test Company", resp.CompanyName)
|
||||
s.Equal("active", resp.PaymentStatus)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetBalanceWithValidUser() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &userpb.GetBalanceRequest{
|
||||
UserId: validateResp.UserId,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetBalance(ctx, req)
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.GreaterOrEqual(resp.Balance, 0.0)
|
||||
}
|
||||
|
||||
func (s *IntegrationSuite) TestUserHandler_GetStatisticsWithValidUser() {
|
||||
ctx := context.Background()
|
||||
|
||||
loginReq := &authpb.LoginRequest{
|
||||
Email: "test@example.com",
|
||||
Password: "testpassword",
|
||||
Ip: "127.0.0.1",
|
||||
UserAgent: "integration-test",
|
||||
}
|
||||
|
||||
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||
s.NoError(err)
|
||||
|
||||
validateReq := &authpb.ValidateRequest{
|
||||
AccessToken: loginResp.AccessToken,
|
||||
}
|
||||
|
||||
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||
s.NoError(err)
|
||||
|
||||
req := &userpb.GetStatisticsRequest{
|
||||
UserId: validateResp.UserId,
|
||||
}
|
||||
|
||||
resp, err := s.userClient.GetStatistics(ctx, req)
|
||||
s.NoError(err)
|
||||
s.NotNil(resp)
|
||||
s.GreaterOrEqual(resp.TotalRequests, int32(0))
|
||||
s.GreaterOrEqual(resp.SuccessfulRequests, int32(0))
|
||||
s.GreaterOrEqual(resp.FailedRequests, int32(0))
|
||||
s.GreaterOrEqual(resp.TotalSpent, 0.0)
|
||||
}
|
||||
Reference in New Issue
Block a user