From 261f0c0b92ac94fffde83685e04697f81cbe392d Mon Sep 17 00:00:00 2001 From: Nikita Nogovicyn Date: Sat, 17 Jan 2026 21:15:05 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=85=D1=83=D0=B5=D1=82=D0=B0=20=D0=BD=D0=B5=D0=BD=D1=83?= =?UTF-8?q?=D0=B6=D0=BD=D0=B0=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index bd15ce6..fb3eac5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,11 +21,8 @@ WORKDIR /root/ COPY --from=builder /app/server . COPY --from=builder /app/migrations ./migrations RUN mkdir -p ./config -COPY --from=builder /app/docker-entrypoint.sh /docker-entrypoint.sh - -RUN chmod +x /docker-entrypoint.sh EXPOSE 9091 -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["./server"] +ENTRYPOINT ["./server"] + From e7e9d620b86ac2214f41855b20ccd0ae5a70999c Mon Sep 17 00:00:00 2001 From: vallyenfail Date: Sun, 18 Jan 2026 00:33:27 +0300 Subject: [PATCH 2/5] add service --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fb3eac5..6d2e837 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ WORKDIR /root/ COPY --from=builder /app/server . COPY --from=builder /app/migrations ./migrations -RUN mkdir -p ./config +COPY --from=builder /app/config/boot.yaml ./config/boot.yaml EXPOSE 9091 From a1f28772f72210f757f0ad4125da748428432e93 Mon Sep 17 00:00:00 2001 From: vallyenfail Date: Sun, 18 Jan 2026 00:35:24 +0300 Subject: [PATCH 3/5] add service --- internal/grpc/tests/repository_test.go | 274 +++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 internal/grpc/tests/repository_test.go diff --git a/internal/grpc/tests/repository_test.go b/internal/grpc/tests/repository_test.go new file mode 100644 index 0000000..0476d92 --- /dev/null +++ b/internal/grpc/tests/repository_test.go @@ -0,0 +1,274 @@ +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) +} From 1dbdb820cda5ec99624e79e61b2acd7d9b149f8e Mon Sep 17 00:00:00 2001 From: vallyenfail Date: Sun, 18 Jan 2026 00:42:01 +0300 Subject: [PATCH 4/5] add service --- {internal/grpc/tests => tests}/auth_handler_test.go | 0 {internal/grpc/tests => tests}/concurrent_test.go | 0 {internal/grpc/tests => tests}/edge_cases_test.go | 0 {internal/grpc/tests => tests}/full_flow_test.go | 0 {internal/grpc/tests => tests}/integration_suite_test.go | 0 {internal/grpc/tests => tests}/invite_handler_test.go | 0 {internal/grpc/tests => tests}/repository_test.go | 0 {internal/grpc/tests => tests}/request_handler_test.go | 0 {internal/grpc/tests => tests}/supplier_handler_test.go | 0 {internal/grpc/tests => tests}/user_handler_test.go | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {internal/grpc/tests => tests}/auth_handler_test.go (100%) rename {internal/grpc/tests => tests}/concurrent_test.go (100%) rename {internal/grpc/tests => tests}/edge_cases_test.go (100%) rename {internal/grpc/tests => tests}/full_flow_test.go (100%) rename {internal/grpc/tests => tests}/integration_suite_test.go (100%) rename {internal/grpc/tests => tests}/invite_handler_test.go (100%) rename {internal/grpc/tests => tests}/repository_test.go (100%) rename {internal/grpc/tests => tests}/request_handler_test.go (100%) rename {internal/grpc/tests => tests}/supplier_handler_test.go (100%) rename {internal/grpc/tests => tests}/user_handler_test.go (100%) diff --git a/internal/grpc/tests/auth_handler_test.go b/tests/auth_handler_test.go similarity index 100% rename from internal/grpc/tests/auth_handler_test.go rename to tests/auth_handler_test.go diff --git a/internal/grpc/tests/concurrent_test.go b/tests/concurrent_test.go similarity index 100% rename from internal/grpc/tests/concurrent_test.go rename to tests/concurrent_test.go diff --git a/internal/grpc/tests/edge_cases_test.go b/tests/edge_cases_test.go similarity index 100% rename from internal/grpc/tests/edge_cases_test.go rename to tests/edge_cases_test.go diff --git a/internal/grpc/tests/full_flow_test.go b/tests/full_flow_test.go similarity index 100% rename from internal/grpc/tests/full_flow_test.go rename to tests/full_flow_test.go diff --git a/internal/grpc/tests/integration_suite_test.go b/tests/integration_suite_test.go similarity index 100% rename from internal/grpc/tests/integration_suite_test.go rename to tests/integration_suite_test.go diff --git a/internal/grpc/tests/invite_handler_test.go b/tests/invite_handler_test.go similarity index 100% rename from internal/grpc/tests/invite_handler_test.go rename to tests/invite_handler_test.go diff --git a/internal/grpc/tests/repository_test.go b/tests/repository_test.go similarity index 100% rename from internal/grpc/tests/repository_test.go rename to tests/repository_test.go diff --git a/internal/grpc/tests/request_handler_test.go b/tests/request_handler_test.go similarity index 100% rename from internal/grpc/tests/request_handler_test.go rename to tests/request_handler_test.go diff --git a/internal/grpc/tests/supplier_handler_test.go b/tests/supplier_handler_test.go similarity index 100% rename from internal/grpc/tests/supplier_handler_test.go rename to tests/supplier_handler_test.go diff --git a/internal/grpc/tests/user_handler_test.go b/tests/user_handler_test.go similarity index 100% rename from internal/grpc/tests/user_handler_test.go rename to tests/user_handler_test.go From b6f7323c58e7453e3c47471b5ea0356b7aa8e9d5 Mon Sep 17 00:00:00 2001 From: vallyenfail Date: Sun, 18 Jan 2026 00:47:16 +0300 Subject: [PATCH 5/5] add service --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bce8fc2..3272aa1 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ config/config.yaml # Build artifacts /bin/ -/dist/ \ No newline at end of file +/dist/ +.gitea \ No newline at end of file