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_InviteDecrementCanBeUsedCount() { 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) tx, err := s.pool.Begin(ctx) s.Require().NoError(err) defer func() { _ = tx.Rollback(ctx) }() err = inviteRepo.DecrementCanBeUsedCountTx(ctx, tx, invite.Code) s.NoError(err) err = tx.Commit(ctx) s.NoError(err) found, err := inviteRepo.FindByCode(ctx, invite.Code) s.NoError(err) s.Equal(9, found.CanBeUsedCount) } 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_InviteFindActiveByUserID() { 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) _, err = s.pool.Exec(ctx, "UPDATE invite_codes SET is_active = false WHERE user_id = $1", userID) s.Require().NoError(err) invite := &model.InviteCode{ UserID: userID, Code: time.Now().UnixNano(), CanBeUsedCount: 5, ExpiresAt: time.Now().Add(24 * time.Hour), } err = inviteRepo.Create(ctx, invite) s.Require().NoError(err) found, err := inviteRepo.FindActiveByUserID(ctx, userID) s.NoError(err) s.NotNil(found) s.Equal(invite.Code, found.Code) s.Equal(userID, found.UserID) s.True(found.IsActive) } func (s *IntegrationSuite) TestRepository_InviteFindActiveByUserIDNotFound() { inviteRepo := repository.NewInviteRepository(s.pool) ctx := context.Background() found, err := inviteRepo.FindActiveByUserID(ctx, 999999) s.Error(err) s.Nil(found) } 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_TokenUsageGetBalanceStatistics() { 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 balance statistics", } err = requestRepo.Create(ctx, req) s.Require().NoError(err) usage1 := &model.TokenUsage{ RequestID: req.ID, RequestTokenCount: 100, ResponseTokenCount: 50, TokenCost: 10.0, Type: "openai", } err = tokenRepo.Create(ctx, usage1) s.Require().NoError(err) usage2 := &model.TokenUsage{ RequestID: req.ID, RequestTokenCount: 200, ResponseTokenCount: 100, TokenCost: 20.0, Type: "perplexity", } err = tokenRepo.Create(ctx, usage2) s.Require().NoError(err) averageCost, history, err := tokenRepo.GetBalanceStatistics(ctx, userID) s.NoError(err) s.Greater(averageCost, 0.0) s.GreaterOrEqual(len(history), 2) for _, item := range history { s.NotEmpty(item.OperationID) s.NotEmpty(item.Data) s.GreaterOrEqual(item.Amount, 0.0) } } func (s *IntegrationSuite) TestRepository_TokenUsageGetBalanceStatisticsEmpty() { tokenRepo := repository.NewTokenUsageRepository(s.pool) ctx := context.Background() averageCost, history, err := tokenRepo.GetBalanceStatistics(ctx, 999999) s.NoError(err) s.Equal(0.0, averageCost) s.Empty(history) } 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) }