Files
smart-search-back/tests/concurrent_ownership_test.go
vallyenfail d3d004569e
Some checks failed
Deploy Smart Search Backend Test / deploy (push) Failing after 1m31s
add service
2026-01-19 23:50:42 +03:00

244 lines
6.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package tests
import (
"sync"
"sync/atomic"
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) TestConcurrentOwnership_User2TriesApproveTZ_WhileUser1Creates() {
email1, password1, _ := s.createUniqueTestUser("owner1", 1000.0)
email2, password2, _ := s.createUniqueTestUser("attacker1", 1000.0)
login1, err := s.authClient.Login(s.ctx, &authpb.LoginRequest{
Email: email1,
Password: password1,
Ip: "127.0.0.1",
UserAgent: "test-agent",
})
s.Require().NoError(err)
validate1, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: login1.AccessToken,
})
s.Require().NoError(err)
user1ID := validate1.UserId
login2, err := s.authClient.Login(s.ctx, &authpb.LoginRequest{
Email: email2,
Password: password2,
Ip: "127.0.0.1",
UserAgent: "test-agent",
})
s.Require().NoError(err)
validate2, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: login2.AccessToken,
})
s.Require().NoError(err)
user2ID := validate2.UserId
createResp, err := s.requestClient.CreateTZ(s.ctx, &requestpb.CreateTZRequest{
UserId: user1ID,
RequestTxt: "Request от User1 для теста ownership",
})
s.Require().NoError(err)
requestID := createResp.RequestId
var wg sync.WaitGroup
var user1Success, user2Denied int32
startBarrier := make(chan struct{})
wg.Add(1)
go func() {
defer wg.Done()
<-startBarrier
_, err := s.requestClient.ApproveTZ(s.ctx, &requestpb.ApproveTZRequest{
RequestId: requestID,
FinalTz: "User1 approves",
UserId: user1ID,
})
if err == nil {
atomic.AddInt32(&user1Success, 1)
}
}()
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
<-startBarrier
_, err := s.requestClient.ApproveTZ(s.ctx, &requestpb.ApproveTZRequest{
RequestId: requestID,
FinalTz: "User2 tries to approve",
UserId: user2ID,
})
if err != nil {
st, ok := status.FromError(err)
if ok && st.Code() == codes.PermissionDenied {
atomic.AddInt32(&user2Denied, 1)
}
}
}()
}
close(startBarrier)
wg.Wait()
s.T().Logf("User1 success: %d, User2 denied: %d", user1Success, user2Denied)
s.Equal(int32(5), user2Denied,
"Все попытки User2 должны быть отклонены с PermissionDenied")
}
func (s *IntegrationSuite) TestConcurrentOwnership_ConcurrentApproveTZ_SameRequest() {
email, password, _ := s.createUniqueTestUser("concurrent_approve", 1000.0)
loginResp, err := s.authClient.Login(s.ctx, &authpb.LoginRequest{
Email: email,
Password: password,
Ip: "127.0.0.1",
UserAgent: "test-agent",
})
s.Require().NoError(err)
validateResp, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: loginResp.AccessToken,
})
s.Require().NoError(err)
userID := validateResp.UserId
createResp, err := s.requestClient.CreateTZ(s.ctx, &requestpb.CreateTZRequest{
UserId: userID,
RequestTxt: "Request для concurrent ApproveTZ",
})
s.Require().NoError(err)
requestID := createResp.RequestId
var wg sync.WaitGroup
var successCount int32
goroutines := 5
startBarrier := make(chan struct{})
for i := 0; i < goroutines; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
<-startBarrier
_, err := s.requestClient.ApproveTZ(s.ctx, &requestpb.ApproveTZRequest{
RequestId: requestID,
FinalTz: "Concurrent approve attempt",
UserId: userID,
})
if err == nil {
atomic.AddInt32(&successCount, 1)
}
}(i)
}
close(startBarrier)
wg.Wait()
s.T().Logf("Concurrent ApproveTZ success count: %d", successCount)
suppliersCount := s.getRequestSuppliersCount(requestID)
s.T().Logf("Total suppliers for request: %d", suppliersCount)
}
func (s *IntegrationSuite) TestConcurrentOwnership_SessionIsolation_AfterLogout() {
email1, password1, _ := s.createUniqueTestUser("session_iso1", 1000.0)
email2, password2, _ := s.createUniqueTestUser("session_iso2", 1000.0)
login1, err := s.authClient.Login(s.ctx, &authpb.LoginRequest{
Email: email1,
Password: password1,
Ip: "127.0.0.1",
UserAgent: "test-agent",
})
s.Require().NoError(err)
user1Token := login1.AccessToken
validate1, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: user1Token,
})
s.Require().NoError(err)
s.True(validate1.Valid)
login2, err := s.authClient.Login(s.ctx, &authpb.LoginRequest{
Email: email2,
Password: password2,
Ip: "127.0.0.1",
UserAgent: "test-agent",
})
s.Require().NoError(err)
user2Token := login2.AccessToken
_, err = s.authClient.Logout(s.ctx, &authpb.LogoutRequest{
AccessToken: user1Token,
})
s.Require().NoError(err)
validate1After, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: user1Token,
})
s.NoError(err)
s.False(validate1After.Valid,
"Токен User1 должен быть невалиден после logout")
validate2After, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: user2Token,
})
s.NoError(err)
s.True(validate2After.Valid,
"Токен User2 должен оставаться валидным после logout User1")
var wg sync.WaitGroup
var user1Invalid, user2Valid int32
goroutines := 10
startBarrier := make(chan struct{})
for i := 0; i < goroutines; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
<-startBarrier
if idx%2 == 0 {
resp, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: user1Token,
})
if err == nil && !resp.Valid {
atomic.AddInt32(&user1Invalid, 1)
}
} else {
resp, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{
AccessToken: user2Token,
})
if err == nil && resp.Valid {
atomic.AddInt32(&user2Valid, 1)
}
}
}(i)
}
close(startBarrier)
wg.Wait()
s.T().Logf("Session isolation - User1 invalid: %d, User2 valid: %d", user1Invalid, user2Valid)
s.Equal(int32(goroutines/2), user1Invalid,
"Все проверки токена User1 должны показать invalid")
s.Equal(int32(goroutines/2), user2Valid,
"Все проверки токена User2 должны показать valid")
}