From e2968722eda9be4f271d1b073324244eeeb3b134 Mon Sep 17 00:00:00 2001 From: vallyenfail Date: Sat, 17 Jan 2026 20:41:37 +0300 Subject: [PATCH] add service --- CONTRIBUTING.md | 347 +++++ Makefile | 41 +- README.md | 42 + api/proto/auth/auth.proto | 2 +- api/proto/invite/invite.proto | 2 +- api/proto/request/request.proto | 2 +- api/proto/supplier/supplier.proto | 2 +- api/proto/user/user.proto | 2 +- cmd/server/main.go | 41 +- go.mod | 46 +- go.sum | 125 +- internal/ai/openai.go | 4 +- internal/ai/perplexity.go | 6 +- internal/database/migrations.go | 16 +- internal/grpc/auth_handler.go | 4 +- internal/grpc/invite_handler.go | 4 +- internal/grpc/request_handler.go | 4 +- internal/grpc/server.go | 22 +- internal/grpc/supplier_handler.go | 4 +- internal/grpc/tests/auth_handler_test.go | 158 +++ internal/grpc/tests/concurrent_test.go | 1105 +++++++++++++++ internal/grpc/tests/edge_cases_test.go | 285 ++++ internal/grpc/tests/full_flow_test.go | 239 ++++ internal/grpc/tests/integration_suite_test.go | 211 +++ internal/grpc/tests/invite_handler_test.go | 122 ++ internal/grpc/tests/request_handler_test.go | 138 ++ internal/grpc/tests/supplier_handler_test.go | 95 ++ internal/grpc/tests/user_handler_test.go | 174 +++ internal/grpc/user_handler.go | 4 +- internal/mocks/auth_service_mock.go | 58 +- internal/mocks/invite_repository_mock.go | 391 +++++- internal/mocks/invite_service_mock.go | 4 +- internal/mocks/request_repository_mock.go | 455 ++++++- internal/mocks/request_service_mock.go | 4 +- internal/mocks/session_repository_mock.go | 715 +++++++++- internal/mocks/supplier_repository_mock.go | 422 +++++- internal/mocks/supplier_service_mock.go | 2 +- internal/mocks/token_usage_repository_mock.go | 393 +++++- internal/mocks/user_repository_mock.go | 1197 ++++++++++++++++- internal/mocks/user_service_mock.go | 4 +- internal/repository/interfaces.go | 12 +- internal/repository/invite.go | 15 +- internal/repository/request.go | 15 +- internal/repository/session.go | 45 +- internal/repository/supplier.go | 16 +- internal/repository/token_usage.go | 16 +- internal/repository/tx.go | 48 + internal/repository/user.go | 54 +- internal/service/auth.go | 23 +- internal/service/interfaces.go | 4 +- internal/service/invite.go | 45 +- internal/service/request.go | 58 +- internal/service/supplier.go | 30 +- internal/service/tests/auth_suite_test.go | 52 +- internal/service/user.go | 4 +- internal/worker/invite_cleaner.go | 2 +- internal/worker/session_cleaner.go | 2 +- internal/worker/worker_test.go | 213 +++ .../00008_add_balance_check_constraint.sql | 10 + pkg/jwt/jwt.go | 3 + pkg/pb/{api/proto => }/auth/auth.pb.go | 96 +- pkg/pb/{api/proto => }/auth/auth_grpc.pb.go | 4 +- pkg/pb/{api/proto => }/invite/invite.pb.go | 72 +- .../{api/proto => }/invite/invite_grpc.pb.go | 4 +- pkg/pb/{api/proto => }/request/request.pb.go | 102 +- .../proto => }/request/request_grpc.pb.go | 4 +- .../{api/proto => }/supplier/supplier.pb.go | 60 +- .../proto => }/supplier/supplier_grpc.pb.go | 4 +- pkg/pb/{api/proto => }/user/user.pb.go | 96 +- pkg/pb/{api/proto => }/user/user_grpc.pb.go | 4 +- 70 files changed, 7542 insertions(+), 463 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 internal/grpc/tests/auth_handler_test.go create mode 100644 internal/grpc/tests/concurrent_test.go create mode 100644 internal/grpc/tests/edge_cases_test.go create mode 100644 internal/grpc/tests/full_flow_test.go create mode 100644 internal/grpc/tests/integration_suite_test.go create mode 100644 internal/grpc/tests/invite_handler_test.go create mode 100644 internal/grpc/tests/request_handler_test.go create mode 100644 internal/grpc/tests/supplier_handler_test.go create mode 100644 internal/grpc/tests/user_handler_test.go create mode 100644 internal/repository/tx.go create mode 100644 internal/worker/worker_test.go create mode 100644 migrations/00008_add_balance_check_constraint.sql rename pkg/pb/{api/proto => }/auth/auth.pb.go (82%) rename pkg/pb/{api/proto => }/auth/auth_grpc.pb.go (99%) rename pkg/pb/{api/proto => }/invite/invite.pb.go (80%) rename pkg/pb/{api/proto => }/invite/invite_grpc.pb.go (98%) rename pkg/pb/{api/proto => }/request/request.pb.go (83%) rename pkg/pb/{api/proto => }/request/request_grpc.pb.go (99%) rename pkg/pb/{api/proto => }/supplier/supplier.pb.go (68%) rename pkg/pb/{api/proto => }/supplier/supplier_grpc.pb.go (98%) rename pkg/pb/{api/proto => }/user/user.pb.go (83%) rename pkg/pb/{api/proto => }/user/user_grpc.pb.go (99%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..27a3db6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,347 @@ +# Руководство по разработке + +Спасибо за участие в разработке Smart Search! Этот документ описывает процесс разработки и правила работы с проектом. + +## 🚨 Обязательные проверки перед коммитом + +Перед каждым коммитом **ОБЯЗАТЕЛЬНО** выполнять в указанном порядке: + +### 1. Unit тесты ✅ +```bash +cd /Users/vallyenfail/Work/smart-search-back +go test ./internal/service/tests/... -v +``` + +Все тесты должны проходить без ошибок. + +### 2. E2E тесты ✅ +```bash +cd /Users/vallyenfail/Work/e2e-tests +go test -v +``` + +**Важно**: Перед запуском e2e тестов убедитесь, что Docker контейнеры запущены: +```bash +cd /Users/vallyenfail/Work +docker-compose up -d +``` + +### 3. Линтер ✅ +```bash +cd /Users/vallyenfail/Work/smart-search-back +make lint +``` + +Линтер должен показывать `0 issues`. + +### Автоматизация + +Рекомендуется использовать git pre-commit hook для автоматической проверки. Создайте файл `.git/hooks/pre-commit`: + +```bash +#!/bin/sh + +echo "🧪 Запуск unit тестов..." +cd /Users/vallyenfail/Work/smart-search-back +go test ./internal/service/tests/... -v +if [ $? -ne 0 ]; then + echo "❌ Unit тесты провалились" + exit 1 +fi + +echo "🧪 Запуск e2e тестов..." +cd /Users/vallyenfail/Work/e2e-tests +go test -v +if [ $? -ne 0 ]; then + echo "❌ E2E тесты провалились" + exit 1 +fi + +echo "🔍 Запуск линтера..." +cd /Users/vallyenfail/Work/smart-search-back +make lint +if [ $? -ne 0 ]; then + echo "❌ Линтер нашел проблемы" + exit 1 +fi + +echo "✅ Все проверки пройдены!" +exit 0 +``` + +Не забудьте сделать hook исполняемым: +```bash +chmod +x .git/hooks/pre-commit +``` + +## 📝 Процесс разработки + +### 1. Создание новой функциональности + +1. Создайте новую ветку от `main`: + ```bash + git checkout main + git pull + git checkout -b feature/название-фичи + ``` + +2. Внесите изменения в код + +3. Напишите/обновите unit тесты для новой функциональности + +4. Запустите все проверки (см. раздел "Обязательные проверки") + +5. Создайте коммит: + ```bash + git add . + git commit -m "feat: описание новой функциональности" + ``` + +6. Отправьте изменения: + ```bash + git push origin feature/название-фичи + ``` + +### 2. Исправление бага + +1. Создайте ветку: + ```bash + git checkout -b fix/описание-бага + ``` + +2. Воспроизведите баг в тесте (TDD подход) + +3. Исправьте баг + +4. Убедитесь, что тест проходит + +5. Запустите все проверки + +6. Создайте коммит: + ```bash + git commit -m "fix: описание исправления" + ``` + +## 🏗️ Архитектура проекта + +``` +smart-search-back/ +├── cmd/server/ # Точка входа приложения +├── internal/ +│ ├── ai/ # Интеграция с AI сервисами (OpenAI, Perplexity) +│ ├── config/ # Конфигурация приложения +│ ├── database/ # Миграции БД +│ ├── grpc/ # gRPC handlers +│ ├── mocks/ # Автогенерированные моки (minimock) +│ ├── model/ # Доменные модели +│ ├── repository/ # Слой работы с БД +│ │ ├── interfaces.go +│ │ └── *.go +│ ├── service/ # Бизнес-логика +│ │ ├── interfaces.go +│ │ ├── tests/ # Unit тесты сервисов +│ │ └── *.go +│ └── worker/ # Фоновые задачи (cleaners) +├── migrations/ # SQL миграции +└── pkg/ # Переиспользуемые пакеты + ├── crypto/ # Шифрование и хэширование + ├── errors/ # Система ошибок + ├── jwt/ # JWT токены + └── pb/ # Сгенерированные protobuf файлы +``` + +## 🧪 Тестирование + +Подробнее о тестировании смотрите в [TESTING.md](./TESTING.md). + +### Быстрые команды + +```bash +# Unit тесты +go test ./internal/service/tests/... -v + +# Unit тесты с покрытием +go test ./internal/service/tests/... -cover + +# E2E тесты +cd /Users/vallyenfail/Work/e2e-tests && go test -v + +# Линтер +make lint + +# Генерация моков +make generate-mock +``` + +## 📐 Стандарты кода + +### 1. Именование + +- **Интерфейсы**: `UserService`, `AuthService` (без суффикса `Interface`) +- **Структуры реализации**: `userService`, `authService` (private) +- **Переменные**: camelCase для private, PascalCase для public +- **Константы**: UPPER_CASE или PascalCase для экспортируемых + +### 2. Обработка ошибок + +Всегда используйте кастомные ошибки из `pkg/errors`: + +```go +if user == nil { + return errors.NewBusinessError(errors.UserNotFound, "user not found") +} + +if err := db.Query(); err != nil { + return errors.NewInternalError(errors.DatabaseError, "failed to query", err) +} +``` + +### 3. Context + +- Context всегда первый параметр +- Context создается только один раз в `main.go` +- Пробрасывается через все слои: `main → worker → handler → service → repository` + +```go +func (s *userService) GetUser(ctx context.Context, userID int) (*model.User, error) { + return s.userRepo.FindByID(ctx, userID) +} +``` + +### 4. Закрытие ресурсов + +Всегда проверяйте ошибки при закрытии ресурсов: + +```go +// ❌ Плохо +defer file.Close() + +// ✅ Хорошо +defer func() { _ = file.Close() }() + +// ✅ Если нужна обработка +defer func() { + if err := file.Close(); err != nil { + log.Printf("failed to close file: %v", err) + } +}() +``` + +## 🔧 Работа с базой данных + +### Миграции + +Миграции находятся в `migrations/` и нумеруются последовательно: + +``` +migrations/ +├── 00001_create_users.sql +├── 00002_create_sessions.sql +└── 00003_create_invite_codes.sql +``` + +Для создания новой миграции: + +```bash +# Формат: 0000X_название_миграции.sql +touch migrations/00008_add_new_table.sql +``` + +Миграции применяются автоматически при запуске приложения через `goose`. + +## 🐳 Docker и локальная разработка + +### Запуск всех сервисов + +```bash +cd /Users/vallyenfail/Work +docker-compose up -d +``` + +### Просмотр логов + +```bash +# Backend +docker logs smart-search-back --tail 50 -f + +# Gateway +docker logs smart-search-gateway --tail 50 -f + +# PostgreSQL +docker logs smart-search-postgres --tail 50 -f +``` + +### Пересборка после изменений + +```bash +cd /Users/vallyenfail/Work +docker-compose down +docker-compose up -d --build +``` + +### Подключение к БД + +```bash +docker exec -it smart-search-postgres psql -U postgres -d b2b_search +``` + +## 🔄 Git Flow + +### Ветки + +- `main` - основная стабильная ветка +- `feature/*` - новая функциональность +- `fix/*` - исправления багов +- `refactor/*` - рефакторинг без изменения функциональности + +### Commit Messages + +Используйте conventional commits: + +- `feat:` - новая функциональность +- `fix:` - исправление бага +- `refactor:` - рефакторинг кода +- `test:` - добавление/изменение тестов +- `docs:` - документация +- `chore:` - рутинные задачи (обновление зависимостей и т.д.) + +Примеры: +``` +feat: добавлена функция экспорта поставщиков в Excel +fix: исправлена ошибка при валидации токена +refactor: упрощена логика создания сессии +test: добавлены тесты для InviteService +docs: обновлена документация по тестированию +``` + +## 📚 Дополнительная документация + +- [TESTING.md](./TESTING.md) - подробное руководство по тестированию +- [GRPC_SERVICES.md](./GRPC_SERVICES.md) - описание gRPC сервисов +- [DEPLOYMENT.md](./DEPLOYMENT.md) - инструкции по деплою +- [README.md](./README.md) - общая информация о проекте + +## 🆘 Помощь + +Если у вас возникли вопросы или проблемы: + +1. Проверьте документацию в репозитории +2. Убедитесь, что все зависимости установлены +3. Проверьте, что Docker контейнеры запущены +4. Убедитесь, что используете правильные версии Go (1.21+) и зависимостей + +## ⚡ Чеклист перед коммитом + +- [ ] Код проходит линтер (`make lint`) +- [ ] Все unit тесты проходят +- [ ] Все e2e тесты проходят +- [ ] Добавлены/обновлены тесты для нового кода +- [ ] Документация обновлена (если нужно) +- [ ] Commit message следует conventional commits +- [ ] Нет закомментированного кода +- [ ] Нет debug логов +- [ ] Секреты не попали в репозиторий + +--- + +**Важно**: Соблюдение этих правил обеспечивает качество кода и стабильность проекта. Спасибо за вклад! 🚀 diff --git a/Makefile b/Makefile index b77ff55..8efb2cb 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,18 @@ -.PHONY: help build run migrate-up migrate-down migrate-create lint test proto clean +.PHONY: help build run migrate-up migrate-down migrate-create lint test test-integration proto clean help: @echo "Available commands:" - @echo " make build - Build the service" - @echo " make run - Run the service" - @echo " make migrate-up - Apply migrations" - @echo " make migrate-down - Rollback migrations" - @echo " make migrate-create - Create new migration (usage: make migrate-create name=migration_name)" - @echo " make lint - Run golangci-lint" - @echo " make proto - Generate proto files" - @echo " make generate-mock - Generate mocks for all interfaces (minimock)" - @echo " make test - Run tests" - @echo " make clean - Clean build artifacts" + @echo " make build - Build the service" + @echo " make run - Run the service" + @echo " make migrate-up - Apply migrations" + @echo " make migrate-down - Rollback migrations" + @echo " make migrate-create - Create new migration (usage: make migrate-create name=migration_name)" + @echo " make lint - Run golangci-lint" + @echo " make proto - Generate proto files" + @echo " make generate-mock - Generate mocks for all interfaces (minimock)" + @echo " make test - Run unit tests" + @echo " make test-integration - Run integration tests with testcontainers" + @echo " make clean - Clean build artifacts" build: @echo "Building server..." @@ -42,12 +43,19 @@ lint: proto: @echo "Generating proto files..." @mkdir -p pkg/pb - @find api/proto -name "*.proto" -exec protoc --go_out=pkg/pb --go_opt=paths=source_relative --go-grpc_out=pkg/pb --go-grpc_opt=paths=source_relative {} \; + @cd api/proto && protoc --go_out=../../pkg/pb --go_opt=paths=source_relative \ + --go-grpc_out=../../pkg/pb --go-grpc_opt=paths=source_relative \ + auth/auth.proto \ + user/user.proto \ + invite/invite.proto \ + request/request.proto \ + supplier/supplier.proto @echo "Proto generation complete" clean: @echo "Cleaning build artifacts..." rm -rf bin/ + rm -rf pkg/pb/ @echo "Clean complete" .PHONY: generate-mock @@ -71,8 +79,13 @@ generate-mock: @echo "Mocks generated in internal/mocks/" test: - @echo "Running tests..." - go test -v ./... + @echo "Running unit tests..." + go test -v -short ./... + +test-integration: + @echo "Running integration tests with testcontainers..." + @echo "This may take several minutes..." + go test -v -timeout=10m ./internal/grpc/tests/... # Default DB URL for local development DB_URL ?= postgres://postgres:password@localhost:5432/b2b_search?sslmode=disable diff --git a/README.md b/README.md index 8bc0e35..33d422a 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,48 @@ make migrate-up make migrate-down ``` +## Proto файлы + +⚠️ **Важно:** Директория `api/proto/` является **единственным источником истины** для всех Proto-контрактов. + +**Структура:** + +``` +smart-search-back/ +├── api/proto/ # Исходные .proto (источник истины) +│ ├── auth/auth.proto +│ ├── user/user.proto +│ └── ... +└── pkg/pb/ # Сгенерированные .pb.go + ├── auth/ + ├── user/ + └── ... +``` + +**Генерация proto кода:** + +```bash +make proto +``` + +Генерирует в `pkg/pb/`: +- `*.pb.go` - Protocol Buffers структуры +- `*_grpc.pb.go` - gRPC server/client код + +**Импорты в коде:** + +```go +import ( + authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth" + userpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/user" +) +``` + +**При изменении proto файлов:** +1. Внесите изменения в `api/proto/**/*.proto` +2. Запустите `make proto` для регенерации +3. Клиентские сервисы (gateway) синхронизируют изменения через `make proto` + ## Разработка ```bash diff --git a/api/proto/auth/auth.proto b/api/proto/auth/auth.proto index fca54e0..9b08765 100644 --- a/api/proto/auth/auth.proto +++ b/api/proto/auth/auth.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package auth; -option go_package = "github.com/smart-search-gateway/api/proto/auth/auth"; +option go_package = "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"; service AuthService { rpc Login(LoginRequest) returns (LoginResponse); diff --git a/api/proto/invite/invite.proto b/api/proto/invite/invite.proto index 4a5cce3..846d0b7 100644 --- a/api/proto/invite/invite.proto +++ b/api/proto/invite/invite.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package invite; -option go_package = "github.com/smart-search-gateway/api/proto/invite/invite"; +option go_package = "git.techease.ru/Smart-search/smart-search-back/pkg/pb/invite"; import "google/protobuf/timestamp.proto"; diff --git a/api/proto/request/request.proto b/api/proto/request/request.proto index 4ef0adf..ed359d1 100644 --- a/api/proto/request/request.proto +++ b/api/proto/request/request.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package request; -option go_package = "github.com/smart-search-gateway/api/proto/request/request"; +option go_package = "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"; import "google/protobuf/timestamp.proto"; diff --git a/api/proto/supplier/supplier.proto b/api/proto/supplier/supplier.proto index 484bd8e..d0fbc7b 100644 --- a/api/proto/supplier/supplier.proto +++ b/api/proto/supplier/supplier.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package supplier; -option go_package = "github.com/smart-search-gateway/api/proto/supplier/supplier"; +option go_package = "git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplier"; service SupplierService { rpc ExportExcel(ExportExcelRequest) returns (ExportExcelResponse); diff --git a/api/proto/user/user.proto b/api/proto/user/user.proto index d505160..d884374 100644 --- a/api/proto/user/user.proto +++ b/api/proto/user/user.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package user; -option go_package = "github.com/smart-search-gateway/api/proto/user/user"; +option go_package = "git.techease.ru/Smart-search/smart-search-back/pkg/pb/user"; service UserService { rpc GetInfo(GetInfoRequest) returns (GetInfoResponse); diff --git a/cmd/server/main.go b/cmd/server/main.go index 8e22013..90d88a0 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -7,15 +7,15 @@ import ( "github.com/jackc/pgx/v5/pgxpool" _ "github.com/jackc/pgx/v5/stdlib" rkboot "github.com/rookie-ninja/rk-boot/v2" - "github.com/rookie-ninja/rk-entry/v2/entry" + rkentry "github.com/rookie-ninja/rk-entry/v2/entry" rkgrpc "github.com/rookie-ninja/rk-grpc/v2/boot" "google.golang.org/grpc" - "smart-search-back/internal/config" - "smart-search-back/internal/database" - grpcServer "smart-search-back/internal/grpc" - "smart-search-back/internal/repository" - "smart-search-back/internal/worker" + "git.techease.ru/Smart-search/smart-search-back/internal/config" + "git.techease.ru/Smart-search/smart-search-back/internal/database" + grpcServer "git.techease.ru/Smart-search/smart-search-back/internal/grpc" + "git.techease.ru/Smart-search/smart-search-back/internal/repository" + "git.techease.ru/Smart-search/smart-search-back/internal/worker" ) func main() { @@ -24,21 +24,7 @@ func main() { log.Fatalf("Failed to load config: %v", err) } - boot := rkboot.NewBoot(rkboot.WithBootConfigPath("config/boot.yaml", nil)) - ctx := context.Background() - boot.Bootstrap(ctx) - - grpcEntry := rkgrpc.GetGrpcEntry("smart-search-service") - if grpcEntry == nil { - log.Fatal("Failed to get gRPC entry from rk-boot") - } - - loggerEntry := rkentry.GlobalAppCtx.GetLoggerEntry("smart-search-service") - if loggerEntry == nil { - loggerEntry = rkentry.GlobalAppCtx.GetLoggerEntryDefault() - } - logger := loggerEntry.Logger if err := database.RunMigrations(cfg.DatabaseURL()); err != nil { log.Fatalf("Failed to run migrations: %v", err) @@ -56,6 +42,19 @@ func main() { log.Println("Successfully connected to database") + boot := rkboot.NewBoot(rkboot.WithBootConfigPath("config/boot.yaml", nil)) + + grpcEntry := rkgrpc.GetGrpcEntry("smart-search-service") + if grpcEntry == nil { + log.Fatal("Failed to get gRPC entry from rk-boot") + } + + loggerEntry := rkentry.GlobalAppCtx.GetLoggerEntry("smart-search-service") + if loggerEntry == nil { + loggerEntry = rkentry.GlobalAppCtx.GetLoggerEntryDefault() + } + logger := loggerEntry.Logger + sessionRepo := repository.NewSessionRepository(pool) inviteRepo := repository.NewInviteRepository(pool) @@ -80,6 +79,8 @@ func main() { grpcServer.RegisterServices(s, authHandler, userHandler, inviteHandler, requestHandler, supplierHandler) }) + boot.Bootstrap(ctx) + log.Println("gRPC server started via rk-boot on port 9091") boot.WaitForShutdownSig(ctx) diff --git a/go.mod b/go.mod index 66e8ac5..3178d64 100644 --- a/go.mod +++ b/go.mod @@ -8,26 +8,45 @@ require ( github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.8.0 + github.com/pressly/goose/v3 v3.26.0 github.com/rookie-ninja/rk-boot/v2 v2.2.22 github.com/rookie-ninja/rk-entry/v2 v2.2.22 github.com/rookie-ninja/rk-grpc/v2 v2.2.22 github.com/stretchr/testify v1.11.1 + github.com/testcontainers/testcontainers-go v0.40.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 github.com/xuri/excelize/v2 v2.10.0 go.uber.org/zap v1.27.1 google.golang.org/grpc v1.78.0 google.golang.org/protobuf v1.36.11 + gopkg.in/yaml.v3 v3.0.1 ) require ( + dario.cat/mergo v1.0.2 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.1+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect @@ -38,13 +57,26 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/openzipkin/zipkin-go v0.4.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/pressly/goose/v3 v3.26.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect @@ -56,19 +88,26 @@ require ( github.com/rs/cors v1.7.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect + github.com/shirou/gopsutil/v4 v4.25.6 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tiendc/go-deepcopy v1.7.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/xuri/efp v0.0.1 // indirect github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib v1.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 // indirect go.opentelemetry.io/otel/exporters/zipkin v1.18.0 // indirect @@ -90,6 +129,5 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index 3e2f8d9..a9f6e38 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,19 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -34,8 +42,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -45,11 +53,23 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -57,10 +77,22 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= +github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -68,6 +100,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -92,6 +126,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -148,6 +184,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -239,16 +276,25 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= +github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -261,6 +307,22 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -268,6 +330,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -281,6 +345,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -288,6 +354,10 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -308,12 +378,15 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM= github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -347,6 +420,8 @@ github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= @@ -376,11 +451,15 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= +github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= +github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -413,8 +492,16 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= +github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0/go.mod h1:h+u/2KoREGTnTl9UwrQ/g+XhasAT8E6dClclAADeXoQ= github.com/tiendc/go-deepcopy v1.7.1 h1:LnubftI6nYaaMOcaz0LphzwraqN8jiWTwm416sitff4= github.com/tiendc/go-deepcopy v1.7.1/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -429,6 +516,8 @@ github.com/xuri/excelize/v2 v2.10.0 h1:8aKsP7JD39iKLc6dH5Tw3dgV3sPRh8uRVXu/fMstf github.com/xuri/excelize/v2 v2.10.0/go.mod h1:SC5TzhQkaOsTWpANfm+7bJCldzcnU/jrhqkTi/iBHBU= github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE= github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -438,12 +527,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib v1.19.0 h1:rnYI7OEPMWFeM4QCqWQ3InMJ0arWMR1i0Cx9A5hcjYM= go.opentelemetry.io/contrib v1.19.0/go.mod h1:gIzjwWFoGazJmtCaDgViqOSJPde2mCWzv60o0bWPcZs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 h1:hSWWvDjXHVLq9DkmB+77fl8v7+t+yYiS+eNkiplDK54= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0/go.mod h1:zG7KQql1WjZCaUJd+L/ReSYx4bjbYJxg5ws9ws+mYes= go.opentelemetry.io/otel/exporters/zipkin v1.18.0 h1:ZqrHgvega5NIiScTiVrtpZSpEmjUdwzkhuuCEIMAp+s= @@ -492,6 +585,8 @@ golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= @@ -552,6 +647,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -563,11 +659,18 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -576,6 +679,8 @@ golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -667,10 +772,20 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek= +modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/internal/ai/openai.go b/internal/ai/openai.go index ada0794..7278e29 100644 --- a/internal/ai/openai.go +++ b/internal/ai/openai.go @@ -9,7 +9,7 @@ import ( "regexp" "strings" - "smart-search-back/pkg/errors" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" ) type OpenAIClient struct { @@ -122,7 +122,7 @@ func (c *OpenAIClient) GenerateTZ(requestTxt string) (string, error) { if err != nil { return "", errors.NewInternalError(errors.AIAPIError, "failed to send request", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { diff --git a/internal/ai/perplexity.go b/internal/ai/perplexity.go index cf2f9ff..4b778e4 100644 --- a/internal/ai/perplexity.go +++ b/internal/ai/perplexity.go @@ -9,8 +9,8 @@ import ( "regexp" "strings" - "smart-search-back/internal/model" - "smart-search-back/pkg/errors" + "git.techease.ru/Smart-search/smart-search-back/internal/model" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" ) type PerplexityClient struct { @@ -149,7 +149,7 @@ func (c *PerplexityClient) FindSuppliers(tzText string) ([]*model.Supplier, int, if err != nil { return nil, 0, 0, errors.NewInternalError(errors.AIAPIError, "failed to send request", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { diff --git a/internal/database/migrations.go b/internal/database/migrations.go index 455fb10..97a8d6c 100644 --- a/internal/database/migrations.go +++ b/internal/database/migrations.go @@ -3,17 +3,22 @@ package database import ( "database/sql" "fmt" + "path/filepath" _ "github.com/jackc/pgx/v5/stdlib" "github.com/pressly/goose/v3" ) func RunMigrations(databaseURL string) error { + return RunMigrationsFromPath(databaseURL, "migrations") +} + +func RunMigrationsFromPath(databaseURL, migrationsDir string) error { db, err := sql.Open("pgx", databaseURL) if err != nil { return fmt.Errorf("failed to open database connection for migrations: %w", err) } - defer db.Close() + defer func() { _ = db.Close() }() if err := db.Ping(); err != nil { return fmt.Errorf("failed to ping database before migrations: %w", err) @@ -23,8 +28,13 @@ func RunMigrations(databaseURL string) error { return fmt.Errorf("failed to set goose dialect: %w", err) } - if err := goose.Up(db, "migrations"); err != nil { - return fmt.Errorf("failed to run migrations: %w", err) + absPath, err := filepath.Abs(migrationsDir) + if err != nil { + return fmt.Errorf("failed to resolve migrations path: %w", err) + } + + if err := goose.Up(db, absPath); err != nil { + return fmt.Errorf("failed to run migrations from %s: %w", absPath, err) } return nil diff --git a/internal/grpc/auth_handler.go b/internal/grpc/auth_handler.go index 43ae712..837c48f 100644 --- a/internal/grpc/auth_handler.go +++ b/internal/grpc/auth_handler.go @@ -3,8 +3,8 @@ package grpc import ( "context" - "smart-search-back/pkg/errors" - pb "smart-search-back/pkg/pb/api/proto/auth" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + pb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth" "go.uber.org/zap" ) diff --git a/internal/grpc/invite_handler.go b/internal/grpc/invite_handler.go index 09efc5e..df490d4 100644 --- a/internal/grpc/invite_handler.go +++ b/internal/grpc/invite_handler.go @@ -4,9 +4,9 @@ import ( "context" "strconv" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + pb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/invite" "google.golang.org/protobuf/types/known/timestamppb" - "smart-search-back/pkg/errors" - pb "smart-search-back/pkg/pb/api/proto/invite" ) func (h *InviteHandler) Generate(ctx context.Context, req *pb.GenerateRequest) (*pb.GenerateResponse, error) { diff --git a/internal/grpc/request_handler.go b/internal/grpc/request_handler.go index e53730f..352989c 100644 --- a/internal/grpc/request_handler.go +++ b/internal/grpc/request_handler.go @@ -4,10 +4,10 @@ import ( "context" "time" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + pb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request" "github.com/google/uuid" "google.golang.org/protobuf/types/known/timestamppb" - "smart-search-back/pkg/errors" - pb "smart-search-back/pkg/pb/api/proto/request" ) func (h *RequestHandler) CreateTZ(ctx context.Context, req *pb.CreateTZRequest) (*pb.CreateTZResponse, error) { diff --git a/internal/grpc/server.go b/internal/grpc/server.go index e41c0a1..2b61c3a 100644 --- a/internal/grpc/server.go +++ b/internal/grpc/server.go @@ -1,14 +1,14 @@ package grpc import ( - "smart-search-back/internal/ai" - "smart-search-back/internal/repository" - "smart-search-back/internal/service" - authpb "smart-search-back/pkg/pb/api/proto/auth" - invitepb "smart-search-back/pkg/pb/api/proto/invite" - requestpb "smart-search-back/pkg/pb/api/proto/request" - supplierpb "smart-search-back/pkg/pb/api/proto/supplier" - userpb "smart-search-back/pkg/pb/api/proto/user" + "git.techease.ru/Smart-search/smart-search-back/internal/ai" + "git.techease.ru/Smart-search/smart-search-back/internal/repository" + "git.techease.ru/Smart-search/smart-search-back/internal/service" + 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" "github.com/jackc/pgx/v5/pgxpool" "go.uber.org/zap" @@ -53,13 +53,15 @@ func NewHandlers(pool *pgxpool.Pool, jwtSecret, cryptoSecret, openAIKey, perplex supplierRepo := repository.NewSupplierRepository(pool) tokenUsageRepo := repository.NewTokenUsageRepository(pool) + txManager := repository.NewTxManager(pool) + openAIClient := ai.NewOpenAIClient(openAIKey) perplexityClient := ai.NewPerplexityClient(perplexityKey) authService := service.NewAuthService(userRepo, sessionRepo, jwtSecret, cryptoSecret) userService := service.NewUserService(userRepo, requestRepo, cryptoSecret) - inviteService := service.NewInviteService(inviteRepo, userRepo) - requestService := service.NewRequestService(requestRepo, supplierRepo, tokenUsageRepo, userRepo, openAIClient, perplexityClient) + inviteService := service.NewInviteService(inviteRepo, userRepo, txManager) + requestService := service.NewRequestService(requestRepo, supplierRepo, tokenUsageRepo, userRepo, openAIClient, perplexityClient, txManager) supplierService := service.NewSupplierService(supplierRepo) return &AuthHandler{authService: authService, logger: logger}, diff --git a/internal/grpc/supplier_handler.go b/internal/grpc/supplier_handler.go index 7e4bd26..83b8652 100644 --- a/internal/grpc/supplier_handler.go +++ b/internal/grpc/supplier_handler.go @@ -3,9 +3,9 @@ package grpc import ( "context" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + pb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplier" "github.com/google/uuid" - "smart-search-back/pkg/errors" - pb "smart-search-back/pkg/pb/api/proto/supplier" ) func (h *SupplierHandler) ExportExcel(ctx context.Context, req *pb.ExportExcelRequest) (*pb.ExportExcelResponse, error) { diff --git a/internal/grpc/tests/auth_handler_test.go b/internal/grpc/tests/auth_handler_test.go new file mode 100644 index 0000000..0005023 --- /dev/null +++ b/internal/grpc/tests/auth_handler_test.go @@ -0,0 +1,158 @@ +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) +} diff --git a/internal/grpc/tests/concurrent_test.go b/internal/grpc/tests/concurrent_test.go new file mode 100644 index 0000000..858840b --- /dev/null +++ b/internal/grpc/tests/concurrent_test.go @@ -0,0 +1,1105 @@ +package tests + +import ( + "context" + "fmt" + "sync" + "sync/atomic" + "time" + + "git.techease.ru/Smart-search/smart-search-back/internal/repository" + "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" + "github.com/jackc/pgx/v5" +) + +func (s *IntegrationSuite) TestConcurrent_GenerateInvites_ExceedsLimit() { + email := "invite_limit_test@example.com" + password := "testpassword" + inviteLimit := 5 + + s.createTestUserWithLimit(email, password, inviteLimit) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int64 + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + _, err := s.inviteClient.Generate(s.ctx, &invitepb.GenerateRequest{ + UserId: userID, + MaxUses: 1, + TtlDays: 7, + }) + + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Success: %d, Errors: %d", successCount, errorCount) + + s.LessOrEqual(int(successCount), inviteLimit, + "Количество успешных генераций (%d) не должно превышать лимит (%d)", successCount, inviteLimit) + + var invitesIssued int + err = s.pool.QueryRow(s.ctx, + "SELECT invites_issued FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&invitesIssued) + s.Require().NoError(err) + + s.LessOrEqual(invitesIssued, inviteLimit, + "invites_issued (%d) не должен превышать invites_limit (%d)", invitesIssued, inviteLimit) +} + +func (s *IntegrationSuite) TestConcurrent_UpdateBalance_GoesNegative() { + email := "balance_test@example.com" + password := "testpassword" + initialBalance := 100.0 + + s.createTestUserWithBalance(email, password, initialBalance) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + debitAmount := 50.0 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + result, err := s.pool.Exec(s.ctx, + "UPDATE users SET balance = balance - $1 WHERE email_hash = $2 AND balance - $1 >= 0", + debitAmount, emailHash, + ) + + if err == nil && result.RowsAffected() > 0 { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Success: %d, Errors: %d", successCount, errorCount) + + var finalBalance float64 + err := s.pool.QueryRow(s.ctx, + "SELECT balance FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&finalBalance) + s.Require().NoError(err) + + s.T().Logf("Final balance: %.2f", finalBalance) + + s.GreaterOrEqual(finalBalance, 0.0, + "Баланс (%f) не должен быть отрицательным", finalBalance) + + maxPossibleDebits := int(initialBalance / debitAmount) + s.Equal(maxPossibleDebits, int(successCount), + "Должно быть ровно %d успешных списаний при балансе %.0f и списании %.0f", + maxPossibleDebits, initialBalance, debitAmount) +} + +func (s *IntegrationSuite) TestConcurrent_UpdateBalance_ViaRepository() { + email := "balance_repo_test@example.com" + password := "testpassword" + initialBalance := 1000.0 + + s.createTestUserWithBalance(email, password, initialBalance) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + debitAmount := 200.0 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + result, err := s.pool.Exec(s.ctx, + "UPDATE users SET balance = balance + $1 WHERE id = $2 AND balance + $1 >= 0", + -debitAmount, userID, + ) + + if err == nil && result.RowsAffected() > 0 { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Success: %d, Errors: %d", successCount, errorCount) + + var finalBalance float64 + err = s.pool.QueryRow(s.ctx, + "SELECT balance FROM users WHERE id = $1", + userID, + ).Scan(&finalBalance) + s.Require().NoError(err) + + s.T().Logf("Final balance: %.2f", finalBalance) + + s.GreaterOrEqual(finalBalance, 0.0, + "Баланс (%f) не должен быть отрицательным", finalBalance) + + expectedMaxDebits := int(initialBalance / debitAmount) + s.Equal(expectedMaxDebits, int(successCount), + "Должно быть ровно %d успешных списаний при балансе %.0f и списании %.0f", + expectedMaxDebits, initialBalance, debitAmount) + + expectedFinalBalance := initialBalance - float64(successCount)*debitAmount + s.Equal(expectedFinalBalance, finalBalance, + "Финальный баланс должен быть %.2f", expectedFinalBalance) +} + +func (s *IntegrationSuite) TestConcurrent_IncrementInvitesIssued() { + email := "increment_test@example.com" + password := "testpassword" + inviteLimit := 5 + + s.createTestUserWithLimit(email, password, inviteLimit) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + goroutines := 20 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + result, err := s.pool.Exec(s.ctx, + "UPDATE users SET invites_issued = invites_issued + 1 WHERE id = $1 AND invites_issued < invites_limit", + userID, + ) + + if err == nil && result.RowsAffected() > 0 { + atomic.AddInt32(&successCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Success increments: %d", successCount) + + var invitesIssued int + err = s.pool.QueryRow(s.ctx, + "SELECT invites_issued FROM users WHERE id = $1", + userID, + ).Scan(&invitesIssued) + s.Require().NoError(err) + + s.Equal(inviteLimit, invitesIssued, + "invites_issued должен быть равен лимиту %d", inviteLimit) + + s.Equal(inviteLimit, int(successCount), + "Количество успешных инкрементов должно быть равно лимиту %d", inviteLimit) +} + +func (s *IntegrationSuite) createTestUserWithLimit(email, password string, inviteLimit int) { + 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 UPDATE SET invites_issued = 0, invites_limit = $10 + ` + + _, err = s.pool.Exec(s.ctx, query, + encryptedEmail, + emailHash, + passwordHash, + encryptedPhone, + encryptedUserName, + "Test Company", + 1000.0, + "active", + 0, + inviteLimit, + ) + s.Require().NoError(err) +} + +func (s *IntegrationSuite) createTestUserWithBalance(email, password string, balance float64) { + 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 UPDATE SET balance = $7 + ` + + _, err = s.pool.Exec(s.ctx, query, + encryptedEmail, + emailHash, + passwordHash, + encryptedPhone, + encryptedUserName, + "Test Company", + balance, + "active", + 0, + 10, + ) + s.Require().NoError(err) +} + +func (s *IntegrationSuite) TestConcurrent_UpdateBalance_ViaUserRepository() { + email := "balance_repo_real_test@example.com" + password := "testpassword" + initialBalance := 1000.0 + + s.createTestUserWithBalance(email, password, initialBalance) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + userRepo := repository.NewUserRepository(s.pool, testCryptoSecret) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + debitAmount := 200.0 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + err := userRepo.UpdateBalance(s.ctx, userID, -debitAmount) + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Success: %d, Errors: %d", successCount, errorCount) + + finalBalance, err := userRepo.GetBalance(s.ctx, userID) + s.Require().NoError(err) + + s.T().Logf("Final balance: %.2f", finalBalance) + + s.GreaterOrEqual(finalBalance, 0.0, + "Баланс (%f) не должен быть отрицательным", finalBalance) + + expectedMaxDebits := int(initialBalance / debitAmount) + s.Equal(expectedMaxDebits, int(successCount), + "Должно быть ровно %d успешных списаний", expectedMaxDebits) +} + +func (s *IntegrationSuite) TestConcurrent_RefreshToken_SameSession() { + email := "refresh_concurrent@example.com" + password := "testpassword" + s.createTestUser(email, password) + + 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) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 10 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + _, err := s.authClient.Refresh(s.ctx, &authpb.RefreshRequest{ + RefreshToken: loginResp.RefreshToken, + }) + + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Refresh success: %d, errors: %d", successCount, errorCount) + + s.GreaterOrEqual(int(successCount), 1, "Как минимум один refresh должен быть успешным") +} + +func (s *IntegrationSuite) TestConcurrent_Login_SameUser() { + email := "login_concurrent@example.com" + password := "testpassword" + s.createTestUser(email, password) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + _, err := s.authClient.Login(s.ctx, &authpb.LoginRequest{ + Email: email, + Password: password, + Ip: "127.0.0.1", + UserAgent: "test-agent", + }) + + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Login success: %d, errors: %d", successCount, errorCount) + + s.Equal(int32(goroutines), successCount, + "Все %d login запросов должны быть успешными", goroutines) + + var sessionsCount int + err := s.pool.QueryRow(s.ctx, + "SELECT COUNT(*) FROM sessions WHERE user_id = (SELECT id FROM users WHERE email_hash = $1)", + emailHash, + ).Scan(&sessionsCount) + s.Require().NoError(err) + + s.Equal(goroutines, sessionsCount, + "Должно быть создано %d сессий", goroutines) +} + +func (s *IntegrationSuite) TestConcurrent_Logout_SameSession() { + email := "logout_concurrent@example.com" + password := "testpassword" + s.createTestUser(email, password) + + 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) + + var wg sync.WaitGroup + var successCount int32 + goroutines := 10 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + _, err := s.authClient.Logout(s.ctx, &authpb.LogoutRequest{ + AccessToken: loginResp.AccessToken, + }) + + if err == nil { + atomic.AddInt32(&successCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Logout success: %d", successCount) + + s.GreaterOrEqual(int(successCount), 1, "Как минимум один logout должен быть успешным") +} + +func (s *IntegrationSuite) TestConcurrent_Validate_AfterLogout() { + email := "validate_concurrent@example.com" + password := "testpassword" + s.createTestUser(email, password) + + 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) + + var wg sync.WaitGroup + var validateSuccess int32 + var validateFailed int32 + var logoutDone int32 + goroutines := 20 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func(idx int) { + defer wg.Done() + + if idx == 0 { + time.Sleep(5 * time.Millisecond) + _, err := s.authClient.Logout(s.ctx, &authpb.LogoutRequest{ + AccessToken: loginResp.AccessToken, + }) + if err == nil { + atomic.AddInt32(&logoutDone, 1) + } + } else { + _, err := s.authClient.Validate(s.ctx, &authpb.ValidateRequest{ + AccessToken: loginResp.AccessToken, + }) + + if err == nil { + atomic.AddInt32(&validateSuccess, 1) + } else { + atomic.AddInt32(&validateFailed, 1) + } + } + }(i) + } + + wg.Wait() + + s.T().Logf("Validate success: %d, failed: %d, logout done: %d", validateSuccess, validateFailed, logoutDone) + + s.Equal(int32(1), logoutDone, "Logout должен быть выполнен") +} + +func (s *IntegrationSuite) TestConcurrent_IncrementInvites_ViaRepository() { + email := "increment_repo_test@example.com" + password := "testpassword" + inviteLimit := 5 + + s.createTestUserWithLimit(email, password, inviteLimit) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + userRepo := repository.NewUserRepository(s.pool, testCryptoSecret) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + err := userRepo.IncrementInvitesIssued(s.ctx, userID) + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Success: %d, Errors: %d", successCount, errorCount) + + var invitesIssued int + err = s.pool.QueryRow(s.ctx, + "SELECT invites_issued FROM users WHERE id = $1", + userID, + ).Scan(&invitesIssued) + s.Require().NoError(err) + + s.Equal(inviteLimit, invitesIssued, + "invites_issued должен быть равен лимиту %d", inviteLimit) + + s.Equal(inviteLimit, int(successCount), + "Количество успешных инкрементов должно быть равно лимиту %d", inviteLimit) +} + +func (s *IntegrationSuite) TestConcurrent_WithTransaction_InviteGenerate() { + email := "tx_invite_test@example.com" + password := "testpassword" + inviteLimit := 3 + + s.createTestUserWithLimit(email, password, inviteLimit) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int64 + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 50 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + _, err := s.inviteClient.Generate(s.ctx, &invitepb.GenerateRequest{ + UserId: userID, + MaxUses: 1, + TtlDays: 7, + }) + + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Transaction test - Success: %d, Errors: %d", successCount, errorCount) + + s.LessOrEqual(int(successCount), inviteLimit, + "Количество успешных генераций (%d) не должно превышать лимит (%d)", successCount, inviteLimit) + + var invitesIssued int + var inviteCodesCount int + err = s.pool.QueryRow(s.ctx, + "SELECT invites_issued FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&invitesIssued) + s.Require().NoError(err) + + err = s.pool.QueryRow(s.ctx, + "SELECT COUNT(*) FROM invite_codes WHERE user_id = $1", + userID, + ).Scan(&inviteCodesCount) + s.Require().NoError(err) + + s.Equal(invitesIssued, inviteCodesCount, + "invites_issued (%d) должен соответствовать количеству кодов (%d)", invitesIssued, inviteCodesCount) +} + +func (s *IntegrationSuite) TestConcurrent_CheckInviteLimit_WithForUpdate() { + email := "check_limit_test@example.com" + password := "testpassword" + inviteLimit := 2 + + s.createTestUserWithLimit(email, password, inviteLimit) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + goroutines := 30 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + tx, err := s.pool.Begin(s.ctx) + if err != nil { + return + } + defer func() { _ = tx.Rollback(s.ctx) }() + + var issued, limit int + err = tx.QueryRow(s.ctx, + "SELECT invites_issued, invites_limit FROM users WHERE id = $1 FOR UPDATE", + userID, + ).Scan(&issued, &limit) + if err != nil { + return + } + + if issued < limit { + atomic.AddInt32(&successCount, 1) + } + + _ = tx.Commit(s.ctx) + }() + } + + wg.Wait() + + s.T().Logf("CheckInviteLimit success count: %d", successCount) +} + +func (s *IntegrationSuite) TestConcurrent_CreateTZ_BalanceDeduction() { + email := "create_tz_concurrent@example.com" + password := "testpassword" + initialBalance := 100.0 + + s.createTestUserWithBalance(email, password, initialBalance) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 10 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + _, err := s.pool.Exec(s.ctx, ` + INSERT INTO requests_for_suppliers (user_id, request_txt) + VALUES ($1, $2) + `, userID, "Test request") + + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("CreateTZ success: %d, errors: %d", successCount, errorCount) + + s.Equal(int32(goroutines), successCount, + "Все %d запросов должны быть успешными", goroutines) + + var requestCount int + err = s.pool.QueryRow(s.ctx, + "SELECT COUNT(*) FROM requests_for_suppliers WHERE user_id = $1", + userID, + ).Scan(&requestCount) + s.Require().NoError(err) + + s.Equal(goroutines, requestCount, + "Должно быть создано %d запросов", goroutines) +} + +func (s *IntegrationSuite) TestConcurrent_BalanceDeduction_WithTransaction() { + email := "balance_tx_concurrent@example.com" + password := "testpassword" + initialBalance := 50.0 + costPerOperation := 10.0 + + s.createTestUserWithBalance(email, password, initialBalance) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + userRepo := repository.NewUserRepository(s.pool, testCryptoSecret) + txManager := repository.NewTxManager(s.pool) + + var wg sync.WaitGroup + var successCount int32 + var errorCount int32 + goroutines := 20 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + err := txManager.WithTx(s.ctx, func(tx pgx.Tx) error { + return userRepo.UpdateBalanceTx(s.ctx, tx, userID, -costPerOperation) + }) + + if err == nil { + atomic.AddInt32(&successCount, 1) + } else { + atomic.AddInt32(&errorCount, 1) + } + }() + } + + wg.Wait() + + s.T().Logf("Transaction balance deduction - Success: %d, Errors: %d", successCount, errorCount) + + finalBalance, err := userRepo.GetBalance(s.ctx, userID) + s.Require().NoError(err) + + s.T().Logf("Final balance: %.2f", finalBalance) + + s.GreaterOrEqual(finalBalance, 0.0, + "Баланс не должен быть отрицательным") + + expectedMaxOperations := int(initialBalance / costPerOperation) + s.Equal(expectedMaxOperations, int(successCount), + "Должно быть ровно %d успешных операций", expectedMaxOperations) +} + +func (s *IntegrationSuite) TestConcurrent_SessionCleanup_WithExpiredSessions() { + email := "session_cleanup@example.com" + password := "testpassword" + s.createTestUser(email, password) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + expiredTime := time.Now().Add(-24 * time.Hour) + for i := 0; i < 10; i++ { + _, err := s.pool.Exec(s.ctx, ` + INSERT INTO sessions (user_id, access_token, refresh_token, ip, user_agent, expires_at) + VALUES ($1, $2, $3, $4, $5, $6) + `, userID, fmt.Sprintf("expired_access_%d", i), fmt.Sprintf("expired_refresh_%d", i), + "127.0.0.1", "test-agent", expiredTime) + s.Require().NoError(err) + } + + validTime := time.Now().Add(24 * time.Hour) + for i := 0; i < 5; i++ { + _, err := s.pool.Exec(s.ctx, ` + INSERT INTO sessions (user_id, access_token, refresh_token, ip, user_agent, expires_at) + VALUES ($1, $2, $3, $4, $5, $6) + `, userID, fmt.Sprintf("valid_access_%d", i), fmt.Sprintf("valid_refresh_%d", i), + "127.0.0.1", "test-agent", validTime) + s.Require().NoError(err) + } + + var wg sync.WaitGroup + var cleanupCount int32 + goroutines := 5 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + result, err := s.pool.Exec(s.ctx, ` + DELETE FROM sessions + WHERE expires_at < now() + OR (revoked_at IS NOT NULL AND revoked_at < now() - interval '30 days') + `) + + if err == nil { + atomic.AddInt32(&cleanupCount, int32(result.RowsAffected())) + } + }() + } + + wg.Wait() + + s.T().Logf("Total cleaned up: %d", cleanupCount) + + s.GreaterOrEqual(int(cleanupCount), 10, + "Должно быть удалено как минимум 10 истекших сессий") + + var remainingCount int + err = s.pool.QueryRow(s.ctx, + "SELECT COUNT(*) FROM sessions WHERE user_id = $1", + userID, + ).Scan(&remainingCount) + s.Require().NoError(err) + + s.Equal(5, remainingCount, + "Должно остаться 5 валидных сессий") +} + +func (s *IntegrationSuite) TestConcurrent_InviteCleanup_WithExpiredInvites() { + email := "invite_cleanup@example.com" + password := "testpassword" + inviteLimit := 20 + + s.createTestUserWithLimit(email, password, inviteLimit) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + expiredTime := time.Now().Add(-24 * time.Hour) + for i := 0; i < 10; i++ { + code := int64(10000000 + i) + _, err := s.pool.Exec(s.ctx, ` + INSERT INTO invite_codes (user_id, code, can_be_used_count, expires_at, is_active) + VALUES ($1, $2, $3, $4, $5) + `, userID, code, 5, expiredTime, true) + s.Require().NoError(err) + } + + validTime := time.Now().Add(24 * time.Hour) + for i := 0; i < 5; i++ { + code := int64(20000000 + i) + _, err := s.pool.Exec(s.ctx, ` + INSERT INTO invite_codes (user_id, code, can_be_used_count, expires_at, is_active) + VALUES ($1, $2, $3, $4, $5) + `, userID, code, 5, validTime, true) + s.Require().NoError(err) + } + + var wg sync.WaitGroup + var deactivatedCount int32 + goroutines := 5 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + result, err := s.pool.Exec(s.ctx, ` + UPDATE invite_codes + SET is_active = false + WHERE expires_at < now() AND is_active = true + `) + + if err == nil { + atomic.AddInt32(&deactivatedCount, int32(result.RowsAffected())) + } + }() + } + + wg.Wait() + + s.T().Logf("Total deactivated: %d", deactivatedCount) + + s.GreaterOrEqual(int(deactivatedCount), 10, + "Должно быть деактивировано как минимум 10 истекших инвайтов") + + var activeCount int + err = s.pool.QueryRow(s.ctx, + "SELECT COUNT(*) FROM invite_codes WHERE user_id = $1 AND is_active = true", + userID, + ).Scan(&activeCount) + s.Require().NoError(err) + + s.Equal(5, activeCount, + "Должно остаться 5 активных инвайтов") +} + +func (s *IntegrationSuite) TestConcurrent_TransactionTimeout_Simulation() { + email := "tx_timeout@example.com" + password := "testpassword" + initialBalance := 1000.0 + + s.createTestUserWithBalance(email, password, initialBalance) + + cryptoHelper := crypto.NewCrypto(testCryptoSecret) + emailHash := cryptoHelper.EmailHash(email) + + var userID int + err := s.pool.QueryRow(s.ctx, + "SELECT id FROM users WHERE email_hash = $1", + emailHash, + ).Scan(&userID) + s.Require().NoError(err) + + var wg sync.WaitGroup + var successCount int32 + var blockedCount int32 + goroutines := 10 + + startBarrier := make(chan struct{}) + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func(idx int) { + defer wg.Done() + + <-startBarrier + + ctx, cancel := context.WithTimeout(s.ctx, 100*time.Millisecond) + defer cancel() + + tx, err := s.pool.Begin(ctx) + if err != nil { + atomic.AddInt32(&blockedCount, 1) + return + } + defer func() { _ = tx.Rollback(ctx) }() + + var balance float64 + err = tx.QueryRow(ctx, + "SELECT balance FROM users WHERE id = $1 FOR UPDATE", + userID, + ).Scan(&balance) + + if err != nil { + atomic.AddInt32(&blockedCount, 1) + return + } + + if idx%2 == 0 { + time.Sleep(50 * time.Millisecond) + } + + _, err = tx.Exec(ctx, + "UPDATE users SET balance = balance - 10 WHERE id = $1", + userID, + ) + + if err != nil { + atomic.AddInt32(&blockedCount, 1) + return + } + + err = tx.Commit(ctx) + if err != nil { + atomic.AddInt32(&blockedCount, 1) + return + } + + atomic.AddInt32(&successCount, 1) + }(i) + } + + close(startBarrier) + + wg.Wait() + + s.T().Logf("Transaction timeout test - Success: %d, Blocked/Timeout: %d", successCount, blockedCount) + + s.Greater(int(successCount), 0, "Должна быть хотя бы одна успешная транзакция") + + var finalBalance float64 + err = s.pool.QueryRow(s.ctx, + "SELECT balance FROM users WHERE id = $1", + userID, + ).Scan(&finalBalance) + s.Require().NoError(err) + + expectedBalance := initialBalance - float64(successCount)*10 + s.Equal(expectedBalance, finalBalance, + "Баланс должен соответствовать количеству успешных транзакций") +} diff --git a/internal/grpc/tests/edge_cases_test.go b/internal/grpc/tests/edge_cases_test.go new file mode 100644 index 0000000..42fe9a7 --- /dev/null +++ b/internal/grpc/tests/edge_cases_test.go @@ -0,0 +1,285 @@ +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()) +} diff --git a/internal/grpc/tests/full_flow_test.go b/internal/grpc/tests/full_flow_test.go new file mode 100644 index 0000000..e71fe59 --- /dev/null +++ b/internal/grpc/tests/full_flow_test.go @@ -0,0 +1,239 @@ +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) +} diff --git a/internal/grpc/tests/integration_suite_test.go b/internal/grpc/tests/integration_suite_test.go new file mode 100644 index 0000000..1ab5ba5 --- /dev/null +++ b/internal/grpc/tests/integration_suite_test.go @@ -0,0 +1,211 @@ +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") +} diff --git a/internal/grpc/tests/invite_handler_test.go b/internal/grpc/tests/invite_handler_test.go new file mode 100644 index 0000000..235228d --- /dev/null +++ b/internal/grpc/tests/invite_handler_test.go @@ -0,0 +1,122 @@ +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) +} diff --git a/internal/grpc/tests/request_handler_test.go b/internal/grpc/tests/request_handler_test.go new file mode 100644 index 0000000..b9f9cd0 --- /dev/null +++ b/internal/grpc/tests/request_handler_test.go @@ -0,0 +1,138 @@ +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) +} diff --git a/internal/grpc/tests/supplier_handler_test.go b/internal/grpc/tests/supplier_handler_test.go new file mode 100644 index 0000000..0ff0ed8 --- /dev/null +++ b/internal/grpc/tests/supplier_handler_test.go @@ -0,0 +1,95 @@ +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) +} diff --git a/internal/grpc/tests/user_handler_test.go b/internal/grpc/tests/user_handler_test.go new file mode 100644 index 0000000..dbf90d9 --- /dev/null +++ b/internal/grpc/tests/user_handler_test.go @@ -0,0 +1,174 @@ +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) +} diff --git a/internal/grpc/user_handler.go b/internal/grpc/user_handler.go index 186ac2e..81862ec 100644 --- a/internal/grpc/user_handler.go +++ b/internal/grpc/user_handler.go @@ -3,8 +3,8 @@ package grpc import ( "context" - "smart-search-back/pkg/errors" - pb "smart-search-back/pkg/pb/api/proto/user" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + pb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/user" ) func (h *UserHandler) GetInfo(ctx context.Context, req *pb.GetInfoRequest) (*pb.GetInfoResponse, error) { diff --git a/internal/mocks/auth_service_mock.go b/internal/mocks/auth_service_mock.go index 0fce24f..af3898d 100644 --- a/internal/mocks/auth_service_mock.go +++ b/internal/mocks/auth_service_mock.go @@ -2,7 +2,7 @@ package mocks -//go:generate minimock -i smart-search-back/internal/service.AuthService -o auth_service_mock.go -n AuthServiceMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/service.AuthService -o auth_service_mock.go -n AuthServiceMock -p mocks import ( "context" @@ -25,9 +25,9 @@ type AuthServiceMock struct { beforeLoginCounter uint64 LoginMock mAuthServiceMockLogin - funcLogout func(ctx context.Context, refreshToken string) (err error) + funcLogout func(ctx context.Context, accessToken string) (err error) funcLogoutOrigin string - inspectFuncLogout func(ctx context.Context, refreshToken string) + inspectFuncLogout func(ctx context.Context, accessToken string) afterLogoutCounter uint64 beforeLogoutCounter uint64 LogoutMock mAuthServiceMockLogout @@ -535,14 +535,14 @@ type AuthServiceMockLogoutExpectation struct { // AuthServiceMockLogoutParams contains parameters of the AuthService.Logout type AuthServiceMockLogoutParams struct { - ctx context.Context - refreshToken string + ctx context.Context + accessToken string } // AuthServiceMockLogoutParamPtrs contains pointers to parameters of the AuthService.Logout type AuthServiceMockLogoutParamPtrs struct { - ctx *context.Context - refreshToken *string + ctx *context.Context + accessToken *string } // AuthServiceMockLogoutResults contains results of the AuthService.Logout @@ -552,9 +552,9 @@ type AuthServiceMockLogoutResults struct { // AuthServiceMockLogoutOrigins contains origins of expectations of the AuthService.Logout type AuthServiceMockLogoutExpectationOrigins struct { - origin string - originCtx string - originRefreshToken string + origin string + originCtx string + originAccessToken string } // Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning @@ -568,7 +568,7 @@ func (mmLogout *mAuthServiceMockLogout) Optional() *mAuthServiceMockLogout { } // Expect sets up expected params for AuthService.Logout -func (mmLogout *mAuthServiceMockLogout) Expect(ctx context.Context, refreshToken string) *mAuthServiceMockLogout { +func (mmLogout *mAuthServiceMockLogout) Expect(ctx context.Context, accessToken string) *mAuthServiceMockLogout { if mmLogout.mock.funcLogout != nil { mmLogout.mock.t.Fatalf("AuthServiceMock.Logout mock is already set by Set") } @@ -581,7 +581,7 @@ func (mmLogout *mAuthServiceMockLogout) Expect(ctx context.Context, refreshToken mmLogout.mock.t.Fatalf("AuthServiceMock.Logout mock is already set by ExpectParams functions") } - mmLogout.defaultExpectation.params = &AuthServiceMockLogoutParams{ctx, refreshToken} + mmLogout.defaultExpectation.params = &AuthServiceMockLogoutParams{ctx, accessToken} mmLogout.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) for _, e := range mmLogout.expectations { if minimock.Equal(e.params, mmLogout.defaultExpectation.params) { @@ -615,8 +615,8 @@ func (mmLogout *mAuthServiceMockLogout) ExpectCtxParam1(ctx context.Context) *mA return mmLogout } -// ExpectRefreshTokenParam2 sets up expected param refreshToken for AuthService.Logout -func (mmLogout *mAuthServiceMockLogout) ExpectRefreshTokenParam2(refreshToken string) *mAuthServiceMockLogout { +// ExpectAccessTokenParam2 sets up expected param accessToken for AuthService.Logout +func (mmLogout *mAuthServiceMockLogout) ExpectAccessTokenParam2(accessToken string) *mAuthServiceMockLogout { if mmLogout.mock.funcLogout != nil { mmLogout.mock.t.Fatalf("AuthServiceMock.Logout mock is already set by Set") } @@ -632,14 +632,14 @@ func (mmLogout *mAuthServiceMockLogout) ExpectRefreshTokenParam2(refreshToken st if mmLogout.defaultExpectation.paramPtrs == nil { mmLogout.defaultExpectation.paramPtrs = &AuthServiceMockLogoutParamPtrs{} } - mmLogout.defaultExpectation.paramPtrs.refreshToken = &refreshToken - mmLogout.defaultExpectation.expectationOrigins.originRefreshToken = minimock.CallerInfo(1) + mmLogout.defaultExpectation.paramPtrs.accessToken = &accessToken + mmLogout.defaultExpectation.expectationOrigins.originAccessToken = minimock.CallerInfo(1) return mmLogout } // Inspect accepts an inspector function that has same arguments as the AuthService.Logout -func (mmLogout *mAuthServiceMockLogout) Inspect(f func(ctx context.Context, refreshToken string)) *mAuthServiceMockLogout { +func (mmLogout *mAuthServiceMockLogout) Inspect(f func(ctx context.Context, accessToken string)) *mAuthServiceMockLogout { if mmLogout.mock.inspectFuncLogout != nil { mmLogout.mock.t.Fatalf("Inspect function is already set for AuthServiceMock.Logout") } @@ -664,7 +664,7 @@ func (mmLogout *mAuthServiceMockLogout) Return(err error) *AuthServiceMock { } // Set uses given function f to mock the AuthService.Logout method -func (mmLogout *mAuthServiceMockLogout) Set(f func(ctx context.Context, refreshToken string) (err error)) *AuthServiceMock { +func (mmLogout *mAuthServiceMockLogout) Set(f func(ctx context.Context, accessToken string) (err error)) *AuthServiceMock { if mmLogout.defaultExpectation != nil { mmLogout.mock.t.Fatalf("Default expectation is already set for the AuthService.Logout method") } @@ -680,14 +680,14 @@ func (mmLogout *mAuthServiceMockLogout) Set(f func(ctx context.Context, refreshT // When sets expectation for the AuthService.Logout which will trigger the result defined by the following // Then helper -func (mmLogout *mAuthServiceMockLogout) When(ctx context.Context, refreshToken string) *AuthServiceMockLogoutExpectation { +func (mmLogout *mAuthServiceMockLogout) When(ctx context.Context, accessToken string) *AuthServiceMockLogoutExpectation { if mmLogout.mock.funcLogout != nil { mmLogout.mock.t.Fatalf("AuthServiceMock.Logout mock is already set by Set") } expectation := &AuthServiceMockLogoutExpectation{ mock: mmLogout.mock, - params: &AuthServiceMockLogoutParams{ctx, refreshToken}, + params: &AuthServiceMockLogoutParams{ctx, accessToken}, expectationOrigins: AuthServiceMockLogoutExpectationOrigins{origin: minimock.CallerInfo(1)}, } mmLogout.expectations = append(mmLogout.expectations, expectation) @@ -722,17 +722,17 @@ func (mmLogout *mAuthServiceMockLogout) invocationsDone() bool { } // Logout implements mm_service.AuthService -func (mmLogout *AuthServiceMock) Logout(ctx context.Context, refreshToken string) (err error) { +func (mmLogout *AuthServiceMock) Logout(ctx context.Context, accessToken string) (err error) { mm_atomic.AddUint64(&mmLogout.beforeLogoutCounter, 1) defer mm_atomic.AddUint64(&mmLogout.afterLogoutCounter, 1) mmLogout.t.Helper() if mmLogout.inspectFuncLogout != nil { - mmLogout.inspectFuncLogout(ctx, refreshToken) + mmLogout.inspectFuncLogout(ctx, accessToken) } - mm_params := AuthServiceMockLogoutParams{ctx, refreshToken} + mm_params := AuthServiceMockLogoutParams{ctx, accessToken} // Record call args mmLogout.LogoutMock.mutex.Lock() @@ -751,7 +751,7 @@ func (mmLogout *AuthServiceMock) Logout(ctx context.Context, refreshToken string mm_want := mmLogout.LogoutMock.defaultExpectation.params mm_want_ptrs := mmLogout.LogoutMock.defaultExpectation.paramPtrs - mm_got := AuthServiceMockLogoutParams{ctx, refreshToken} + mm_got := AuthServiceMockLogoutParams{ctx, accessToken} if mm_want_ptrs != nil { @@ -760,9 +760,9 @@ func (mmLogout *AuthServiceMock) Logout(ctx context.Context, refreshToken string mmLogout.LogoutMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) } - if mm_want_ptrs.refreshToken != nil && !minimock.Equal(*mm_want_ptrs.refreshToken, mm_got.refreshToken) { - mmLogout.t.Errorf("AuthServiceMock.Logout got unexpected parameter refreshToken, expected at\n%s:\nwant: %#v\n got: %#v%s\n", - mmLogout.LogoutMock.defaultExpectation.expectationOrigins.originRefreshToken, *mm_want_ptrs.refreshToken, mm_got.refreshToken, minimock.Diff(*mm_want_ptrs.refreshToken, mm_got.refreshToken)) + if mm_want_ptrs.accessToken != nil && !minimock.Equal(*mm_want_ptrs.accessToken, mm_got.accessToken) { + mmLogout.t.Errorf("AuthServiceMock.Logout got unexpected parameter accessToken, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmLogout.LogoutMock.defaultExpectation.expectationOrigins.originAccessToken, *mm_want_ptrs.accessToken, mm_got.accessToken, minimock.Diff(*mm_want_ptrs.accessToken, mm_got.accessToken)) } } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { @@ -777,9 +777,9 @@ func (mmLogout *AuthServiceMock) Logout(ctx context.Context, refreshToken string return (*mm_results).err } if mmLogout.funcLogout != nil { - return mmLogout.funcLogout(ctx, refreshToken) + return mmLogout.funcLogout(ctx, accessToken) } - mmLogout.t.Fatalf("Unexpected call to AuthServiceMock.Logout. %v %v", ctx, refreshToken) + mmLogout.t.Fatalf("Unexpected call to AuthServiceMock.Logout. %v %v", ctx, accessToken) return } diff --git a/internal/mocks/invite_repository_mock.go b/internal/mocks/invite_repository_mock.go index 6e45f36..70cfb51 100644 --- a/internal/mocks/invite_repository_mock.go +++ b/internal/mocks/invite_repository_mock.go @@ -2,16 +2,17 @@ package mocks -//go:generate minimock -i smart-search-back/internal/repository.InviteRepository -o invite_repository_mock.go -n InviteRepositoryMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/repository.InviteRepository -o invite_repository_mock.go -n InviteRepositoryMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" + "github.com/jackc/pgx/v5" ) // InviteRepositoryMock implements mm_repository.InviteRepository @@ -26,6 +27,13 @@ type InviteRepositoryMock struct { beforeCreateCounter uint64 CreateMock mInviteRepositoryMockCreate + funcCreateTx func(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) (err error) + funcCreateTxOrigin string + inspectFuncCreateTx func(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) + afterCreateTxCounter uint64 + beforeCreateTxCounter uint64 + CreateTxMock mInviteRepositoryMockCreateTx + funcDeactivateExpired func(ctx context.Context) (i1 int, err error) funcDeactivateExpiredOrigin string inspectFuncDeactivateExpired func(ctx context.Context) @@ -66,6 +74,9 @@ func NewInviteRepositoryMock(t minimock.Tester) *InviteRepositoryMock { m.CreateMock = mInviteRepositoryMockCreate{mock: m} m.CreateMock.callArgs = []*InviteRepositoryMockCreateParams{} + m.CreateTxMock = mInviteRepositoryMockCreateTx{mock: m} + m.CreateTxMock.callArgs = []*InviteRepositoryMockCreateTxParams{} + m.DeactivateExpiredMock = mInviteRepositoryMockDeactivateExpired{mock: m} m.DeactivateExpiredMock.callArgs = []*InviteRepositoryMockDeactivateExpiredParams{} @@ -425,6 +436,379 @@ func (m *InviteRepositoryMock) MinimockCreateInspect() { } } +type mInviteRepositoryMockCreateTx struct { + optional bool + mock *InviteRepositoryMock + defaultExpectation *InviteRepositoryMockCreateTxExpectation + expectations []*InviteRepositoryMockCreateTxExpectation + + callArgs []*InviteRepositoryMockCreateTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// InviteRepositoryMockCreateTxExpectation specifies expectation struct of the InviteRepository.CreateTx +type InviteRepositoryMockCreateTxExpectation struct { + mock *InviteRepositoryMock + params *InviteRepositoryMockCreateTxParams + paramPtrs *InviteRepositoryMockCreateTxParamPtrs + expectationOrigins InviteRepositoryMockCreateTxExpectationOrigins + results *InviteRepositoryMockCreateTxResults + returnOrigin string + Counter uint64 +} + +// InviteRepositoryMockCreateTxParams contains parameters of the InviteRepository.CreateTx +type InviteRepositoryMockCreateTxParams struct { + ctx context.Context + tx pgx.Tx + invite *model.InviteCode +} + +// InviteRepositoryMockCreateTxParamPtrs contains pointers to parameters of the InviteRepository.CreateTx +type InviteRepositoryMockCreateTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + invite **model.InviteCode +} + +// InviteRepositoryMockCreateTxResults contains results of the InviteRepository.CreateTx +type InviteRepositoryMockCreateTxResults struct { + err error +} + +// InviteRepositoryMockCreateTxOrigins contains origins of expectations of the InviteRepository.CreateTx +type InviteRepositoryMockCreateTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originInvite string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmCreateTx *mInviteRepositoryMockCreateTx) Optional() *mInviteRepositoryMockCreateTx { + mmCreateTx.optional = true + return mmCreateTx +} + +// Expect sets up expected params for InviteRepository.CreateTx +func (mmCreateTx *mInviteRepositoryMockCreateTx) Expect(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) *mInviteRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &InviteRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.paramPtrs != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by ExpectParams functions") + } + + mmCreateTx.defaultExpectation.params = &InviteRepositoryMockCreateTxParams{ctx, tx, invite} + mmCreateTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmCreateTx.expectations { + if minimock.Equal(e.params, mmCreateTx.defaultExpectation.params) { + mmCreateTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmCreateTx.defaultExpectation.params) + } + } + + return mmCreateTx +} + +// ExpectCtxParam1 sets up expected param ctx for InviteRepository.CreateTx +func (mmCreateTx *mInviteRepositoryMockCreateTx) ExpectCtxParam1(ctx context.Context) *mInviteRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &InviteRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.params != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Expect") + } + + if mmCreateTx.defaultExpectation.paramPtrs == nil { + mmCreateTx.defaultExpectation.paramPtrs = &InviteRepositoryMockCreateTxParamPtrs{} + } + mmCreateTx.defaultExpectation.paramPtrs.ctx = &ctx + mmCreateTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmCreateTx +} + +// ExpectTxParam2 sets up expected param tx for InviteRepository.CreateTx +func (mmCreateTx *mInviteRepositoryMockCreateTx) ExpectTxParam2(tx pgx.Tx) *mInviteRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &InviteRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.params != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Expect") + } + + if mmCreateTx.defaultExpectation.paramPtrs == nil { + mmCreateTx.defaultExpectation.paramPtrs = &InviteRepositoryMockCreateTxParamPtrs{} + } + mmCreateTx.defaultExpectation.paramPtrs.tx = &tx + mmCreateTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmCreateTx +} + +// ExpectInviteParam3 sets up expected param invite for InviteRepository.CreateTx +func (mmCreateTx *mInviteRepositoryMockCreateTx) ExpectInviteParam3(invite *model.InviteCode) *mInviteRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &InviteRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.params != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Expect") + } + + if mmCreateTx.defaultExpectation.paramPtrs == nil { + mmCreateTx.defaultExpectation.paramPtrs = &InviteRepositoryMockCreateTxParamPtrs{} + } + mmCreateTx.defaultExpectation.paramPtrs.invite = &invite + mmCreateTx.defaultExpectation.expectationOrigins.originInvite = minimock.CallerInfo(1) + + return mmCreateTx +} + +// Inspect accepts an inspector function that has same arguments as the InviteRepository.CreateTx +func (mmCreateTx *mInviteRepositoryMockCreateTx) Inspect(f func(ctx context.Context, tx pgx.Tx, invite *model.InviteCode)) *mInviteRepositoryMockCreateTx { + if mmCreateTx.mock.inspectFuncCreateTx != nil { + mmCreateTx.mock.t.Fatalf("Inspect function is already set for InviteRepositoryMock.CreateTx") + } + + mmCreateTx.mock.inspectFuncCreateTx = f + + return mmCreateTx +} + +// Return sets up results that will be returned by InviteRepository.CreateTx +func (mmCreateTx *mInviteRepositoryMockCreateTx) Return(err error) *InviteRepositoryMock { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &InviteRepositoryMockCreateTxExpectation{mock: mmCreateTx.mock} + } + mmCreateTx.defaultExpectation.results = &InviteRepositoryMockCreateTxResults{err} + mmCreateTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmCreateTx.mock +} + +// Set uses given function f to mock the InviteRepository.CreateTx method +func (mmCreateTx *mInviteRepositoryMockCreateTx) Set(f func(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) (err error)) *InviteRepositoryMock { + if mmCreateTx.defaultExpectation != nil { + mmCreateTx.mock.t.Fatalf("Default expectation is already set for the InviteRepository.CreateTx method") + } + + if len(mmCreateTx.expectations) > 0 { + mmCreateTx.mock.t.Fatalf("Some expectations are already set for the InviteRepository.CreateTx method") + } + + mmCreateTx.mock.funcCreateTx = f + mmCreateTx.mock.funcCreateTxOrigin = minimock.CallerInfo(1) + return mmCreateTx.mock +} + +// When sets expectation for the InviteRepository.CreateTx which will trigger the result defined by the following +// Then helper +func (mmCreateTx *mInviteRepositoryMockCreateTx) When(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) *InviteRepositoryMockCreateTxExpectation { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("InviteRepositoryMock.CreateTx mock is already set by Set") + } + + expectation := &InviteRepositoryMockCreateTxExpectation{ + mock: mmCreateTx.mock, + params: &InviteRepositoryMockCreateTxParams{ctx, tx, invite}, + expectationOrigins: InviteRepositoryMockCreateTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmCreateTx.expectations = append(mmCreateTx.expectations, expectation) + return expectation +} + +// Then sets up InviteRepository.CreateTx return parameters for the expectation previously defined by the When method +func (e *InviteRepositoryMockCreateTxExpectation) Then(err error) *InviteRepositoryMock { + e.results = &InviteRepositoryMockCreateTxResults{err} + return e.mock +} + +// Times sets number of times InviteRepository.CreateTx should be invoked +func (mmCreateTx *mInviteRepositoryMockCreateTx) Times(n uint64) *mInviteRepositoryMockCreateTx { + if n == 0 { + mmCreateTx.mock.t.Fatalf("Times of InviteRepositoryMock.CreateTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmCreateTx.expectedInvocations, n) + mmCreateTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmCreateTx +} + +func (mmCreateTx *mInviteRepositoryMockCreateTx) invocationsDone() bool { + if len(mmCreateTx.expectations) == 0 && mmCreateTx.defaultExpectation == nil && mmCreateTx.mock.funcCreateTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmCreateTx.mock.afterCreateTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmCreateTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// CreateTx implements mm_repository.InviteRepository +func (mmCreateTx *InviteRepositoryMock) CreateTx(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) (err error) { + mm_atomic.AddUint64(&mmCreateTx.beforeCreateTxCounter, 1) + defer mm_atomic.AddUint64(&mmCreateTx.afterCreateTxCounter, 1) + + mmCreateTx.t.Helper() + + if mmCreateTx.inspectFuncCreateTx != nil { + mmCreateTx.inspectFuncCreateTx(ctx, tx, invite) + } + + mm_params := InviteRepositoryMockCreateTxParams{ctx, tx, invite} + + // Record call args + mmCreateTx.CreateTxMock.mutex.Lock() + mmCreateTx.CreateTxMock.callArgs = append(mmCreateTx.CreateTxMock.callArgs, &mm_params) + mmCreateTx.CreateTxMock.mutex.Unlock() + + for _, e := range mmCreateTx.CreateTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmCreateTx.CreateTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmCreateTx.CreateTxMock.defaultExpectation.Counter, 1) + mm_want := mmCreateTx.CreateTxMock.defaultExpectation.params + mm_want_ptrs := mmCreateTx.CreateTxMock.defaultExpectation.paramPtrs + + mm_got := InviteRepositoryMockCreateTxParams{ctx, tx, invite} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmCreateTx.t.Errorf("InviteRepositoryMock.CreateTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmCreateTx.t.Errorf("InviteRepositoryMock.CreateTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.invite != nil && !minimock.Equal(*mm_want_ptrs.invite, mm_got.invite) { + mmCreateTx.t.Errorf("InviteRepositoryMock.CreateTx got unexpected parameter invite, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.originInvite, *mm_want_ptrs.invite, mm_got.invite, minimock.Diff(*mm_want_ptrs.invite, mm_got.invite)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmCreateTx.t.Errorf("InviteRepositoryMock.CreateTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmCreateTx.CreateTxMock.defaultExpectation.results + if mm_results == nil { + mmCreateTx.t.Fatal("No results are set for the InviteRepositoryMock.CreateTx") + } + return (*mm_results).err + } + if mmCreateTx.funcCreateTx != nil { + return mmCreateTx.funcCreateTx(ctx, tx, invite) + } + mmCreateTx.t.Fatalf("Unexpected call to InviteRepositoryMock.CreateTx. %v %v %v", ctx, tx, invite) + return +} + +// CreateTxAfterCounter returns a count of finished InviteRepositoryMock.CreateTx invocations +func (mmCreateTx *InviteRepositoryMock) CreateTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmCreateTx.afterCreateTxCounter) +} + +// CreateTxBeforeCounter returns a count of InviteRepositoryMock.CreateTx invocations +func (mmCreateTx *InviteRepositoryMock) CreateTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmCreateTx.beforeCreateTxCounter) +} + +// Calls returns a list of arguments used in each call to InviteRepositoryMock.CreateTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmCreateTx *mInviteRepositoryMockCreateTx) Calls() []*InviteRepositoryMockCreateTxParams { + mmCreateTx.mutex.RLock() + + argCopy := make([]*InviteRepositoryMockCreateTxParams, len(mmCreateTx.callArgs)) + copy(argCopy, mmCreateTx.callArgs) + + mmCreateTx.mutex.RUnlock() + + return argCopy +} + +// MinimockCreateTxDone returns true if the count of the CreateTx invocations corresponds +// the number of defined expectations +func (m *InviteRepositoryMock) MinimockCreateTxDone() bool { + if m.CreateTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.CreateTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.CreateTxMock.invocationsDone() +} + +// MinimockCreateTxInspect logs each unmet expectation +func (m *InviteRepositoryMock) MinimockCreateTxInspect() { + for _, e := range m.CreateTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to InviteRepositoryMock.CreateTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterCreateTxCounter := mm_atomic.LoadUint64(&m.afterCreateTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.CreateTxMock.defaultExpectation != nil && afterCreateTxCounter < 1 { + if m.CreateTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to InviteRepositoryMock.CreateTx at\n%s", m.CreateTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to InviteRepositoryMock.CreateTx at\n%s with params: %#v", m.CreateTxMock.defaultExpectation.expectationOrigins.origin, *m.CreateTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcCreateTx != nil && afterCreateTxCounter < 1 { + m.t.Errorf("Expected call to InviteRepositoryMock.CreateTx at\n%s", m.funcCreateTxOrigin) + } + + if !m.CreateTxMock.invocationsDone() && afterCreateTxCounter > 0 { + m.t.Errorf("Expected %d calls to InviteRepositoryMock.CreateTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.CreateTxMock.expectedInvocations), m.CreateTxMock.expectedInvocationsOrigin, afterCreateTxCounter) + } +} + type mInviteRepositoryMockDeactivateExpired struct { optional bool mock *InviteRepositoryMock @@ -1771,6 +2155,8 @@ func (m *InviteRepositoryMock) MinimockFinish() { if !m.minimockDone() { m.MinimockCreateInspect() + m.MinimockCreateTxInspect() + m.MinimockDeactivateExpiredInspect() m.MinimockFindByCodeInspect() @@ -1802,6 +2188,7 @@ func (m *InviteRepositoryMock) minimockDone() bool { done := true return done && m.MinimockCreateDone() && + m.MinimockCreateTxDone() && m.MinimockDeactivateExpiredDone() && m.MinimockFindByCodeDone() && m.MinimockGetUserInvitesDone() && diff --git a/internal/mocks/invite_service_mock.go b/internal/mocks/invite_service_mock.go index a0dedb9..beee5c7 100644 --- a/internal/mocks/invite_service_mock.go +++ b/internal/mocks/invite_service_mock.go @@ -2,15 +2,15 @@ package mocks -//go:generate minimock -i smart-search-back/internal/service.InviteService -o invite_service_mock.go -n InviteServiceMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/service.InviteService -o invite_service_mock.go -n InviteServiceMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" ) diff --git a/internal/mocks/request_repository_mock.go b/internal/mocks/request_repository_mock.go index ad7a6a4..1bef473 100644 --- a/internal/mocks/request_repository_mock.go +++ b/internal/mocks/request_repository_mock.go @@ -2,17 +2,18 @@ package mocks -//go:generate minimock -i smart-search-back/internal/repository.RequestRepository -o request_repository_mock.go -n RequestRepositoryMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/repository.RequestRepository -o request_repository_mock.go -n RequestRepositoryMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" "github.com/google/uuid" + "github.com/jackc/pgx/v5" ) // RequestRepositoryMock implements mm_repository.RequestRepository @@ -68,6 +69,13 @@ type RequestRepositoryMock struct { afterUpdateWithTZCounter uint64 beforeUpdateWithTZCounter uint64 UpdateWithTZMock mRequestRepositoryMockUpdateWithTZ + + funcUpdateWithTZTx func(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) (err error) + funcUpdateWithTZTxOrigin string + inspectFuncUpdateWithTZTx func(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) + afterUpdateWithTZTxCounter uint64 + beforeUpdateWithTZTxCounter uint64 + UpdateWithTZTxMock mRequestRepositoryMockUpdateWithTZTx } // NewRequestRepositoryMock returns a mock for mm_repository.RequestRepository @@ -99,6 +107,9 @@ func NewRequestRepositoryMock(t minimock.Tester) *RequestRepositoryMock { m.UpdateWithTZMock = mRequestRepositoryMockUpdateWithTZ{mock: m} m.UpdateWithTZMock.callArgs = []*RequestRepositoryMockUpdateWithTZParams{} + m.UpdateWithTZTxMock = mRequestRepositoryMockUpdateWithTZTx{mock: m} + m.UpdateWithTZTxMock.callArgs = []*RequestRepositoryMockUpdateWithTZTxParams{} + t.Cleanup(m.MinimockFinish) return m @@ -2597,6 +2608,441 @@ func (m *RequestRepositoryMock) MinimockUpdateWithTZInspect() { } } +type mRequestRepositoryMockUpdateWithTZTx struct { + optional bool + mock *RequestRepositoryMock + defaultExpectation *RequestRepositoryMockUpdateWithTZTxExpectation + expectations []*RequestRepositoryMockUpdateWithTZTxExpectation + + callArgs []*RequestRepositoryMockUpdateWithTZTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// RequestRepositoryMockUpdateWithTZTxExpectation specifies expectation struct of the RequestRepository.UpdateWithTZTx +type RequestRepositoryMockUpdateWithTZTxExpectation struct { + mock *RequestRepositoryMock + params *RequestRepositoryMockUpdateWithTZTxParams + paramPtrs *RequestRepositoryMockUpdateWithTZTxParamPtrs + expectationOrigins RequestRepositoryMockUpdateWithTZTxExpectationOrigins + results *RequestRepositoryMockUpdateWithTZTxResults + returnOrigin string + Counter uint64 +} + +// RequestRepositoryMockUpdateWithTZTxParams contains parameters of the RequestRepository.UpdateWithTZTx +type RequestRepositoryMockUpdateWithTZTxParams struct { + ctx context.Context + tx pgx.Tx + id uuid.UUID + tz string + generated bool +} + +// RequestRepositoryMockUpdateWithTZTxParamPtrs contains pointers to parameters of the RequestRepository.UpdateWithTZTx +type RequestRepositoryMockUpdateWithTZTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + id *uuid.UUID + tz *string + generated *bool +} + +// RequestRepositoryMockUpdateWithTZTxResults contains results of the RequestRepository.UpdateWithTZTx +type RequestRepositoryMockUpdateWithTZTxResults struct { + err error +} + +// RequestRepositoryMockUpdateWithTZTxOrigins contains origins of expectations of the RequestRepository.UpdateWithTZTx +type RequestRepositoryMockUpdateWithTZTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originId string + originTz string + originGenerated string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Optional() *mRequestRepositoryMockUpdateWithTZTx { + mmUpdateWithTZTx.optional = true + return mmUpdateWithTZTx +} + +// Expect sets up expected params for RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Expect(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{} + } + + if mmUpdateWithTZTx.defaultExpectation.paramPtrs != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by ExpectParams functions") + } + + mmUpdateWithTZTx.defaultExpectation.params = &RequestRepositoryMockUpdateWithTZTxParams{ctx, tx, id, tz, generated} + mmUpdateWithTZTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmUpdateWithTZTx.expectations { + if minimock.Equal(e.params, mmUpdateWithTZTx.defaultExpectation.params) { + mmUpdateWithTZTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmUpdateWithTZTx.defaultExpectation.params) + } + } + + return mmUpdateWithTZTx +} + +// ExpectCtxParam1 sets up expected param ctx for RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) ExpectCtxParam1(ctx context.Context) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{} + } + + if mmUpdateWithTZTx.defaultExpectation.params != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Expect") + } + + if mmUpdateWithTZTx.defaultExpectation.paramPtrs == nil { + mmUpdateWithTZTx.defaultExpectation.paramPtrs = &RequestRepositoryMockUpdateWithTZTxParamPtrs{} + } + mmUpdateWithTZTx.defaultExpectation.paramPtrs.ctx = &ctx + mmUpdateWithTZTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmUpdateWithTZTx +} + +// ExpectTxParam2 sets up expected param tx for RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) ExpectTxParam2(tx pgx.Tx) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{} + } + + if mmUpdateWithTZTx.defaultExpectation.params != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Expect") + } + + if mmUpdateWithTZTx.defaultExpectation.paramPtrs == nil { + mmUpdateWithTZTx.defaultExpectation.paramPtrs = &RequestRepositoryMockUpdateWithTZTxParamPtrs{} + } + mmUpdateWithTZTx.defaultExpectation.paramPtrs.tx = &tx + mmUpdateWithTZTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmUpdateWithTZTx +} + +// ExpectIdParam3 sets up expected param id for RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) ExpectIdParam3(id uuid.UUID) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{} + } + + if mmUpdateWithTZTx.defaultExpectation.params != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Expect") + } + + if mmUpdateWithTZTx.defaultExpectation.paramPtrs == nil { + mmUpdateWithTZTx.defaultExpectation.paramPtrs = &RequestRepositoryMockUpdateWithTZTxParamPtrs{} + } + mmUpdateWithTZTx.defaultExpectation.paramPtrs.id = &id + mmUpdateWithTZTx.defaultExpectation.expectationOrigins.originId = minimock.CallerInfo(1) + + return mmUpdateWithTZTx +} + +// ExpectTzParam4 sets up expected param tz for RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) ExpectTzParam4(tz string) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{} + } + + if mmUpdateWithTZTx.defaultExpectation.params != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Expect") + } + + if mmUpdateWithTZTx.defaultExpectation.paramPtrs == nil { + mmUpdateWithTZTx.defaultExpectation.paramPtrs = &RequestRepositoryMockUpdateWithTZTxParamPtrs{} + } + mmUpdateWithTZTx.defaultExpectation.paramPtrs.tz = &tz + mmUpdateWithTZTx.defaultExpectation.expectationOrigins.originTz = minimock.CallerInfo(1) + + return mmUpdateWithTZTx +} + +// ExpectGeneratedParam5 sets up expected param generated for RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) ExpectGeneratedParam5(generated bool) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{} + } + + if mmUpdateWithTZTx.defaultExpectation.params != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Expect") + } + + if mmUpdateWithTZTx.defaultExpectation.paramPtrs == nil { + mmUpdateWithTZTx.defaultExpectation.paramPtrs = &RequestRepositoryMockUpdateWithTZTxParamPtrs{} + } + mmUpdateWithTZTx.defaultExpectation.paramPtrs.generated = &generated + mmUpdateWithTZTx.defaultExpectation.expectationOrigins.originGenerated = minimock.CallerInfo(1) + + return mmUpdateWithTZTx +} + +// Inspect accepts an inspector function that has same arguments as the RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Inspect(f func(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool)) *mRequestRepositoryMockUpdateWithTZTx { + if mmUpdateWithTZTx.mock.inspectFuncUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("Inspect function is already set for RequestRepositoryMock.UpdateWithTZTx") + } + + mmUpdateWithTZTx.mock.inspectFuncUpdateWithTZTx = f + + return mmUpdateWithTZTx +} + +// Return sets up results that will be returned by RequestRepository.UpdateWithTZTx +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Return(err error) *RequestRepositoryMock { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + if mmUpdateWithTZTx.defaultExpectation == nil { + mmUpdateWithTZTx.defaultExpectation = &RequestRepositoryMockUpdateWithTZTxExpectation{mock: mmUpdateWithTZTx.mock} + } + mmUpdateWithTZTx.defaultExpectation.results = &RequestRepositoryMockUpdateWithTZTxResults{err} + mmUpdateWithTZTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmUpdateWithTZTx.mock +} + +// Set uses given function f to mock the RequestRepository.UpdateWithTZTx method +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Set(f func(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) (err error)) *RequestRepositoryMock { + if mmUpdateWithTZTx.defaultExpectation != nil { + mmUpdateWithTZTx.mock.t.Fatalf("Default expectation is already set for the RequestRepository.UpdateWithTZTx method") + } + + if len(mmUpdateWithTZTx.expectations) > 0 { + mmUpdateWithTZTx.mock.t.Fatalf("Some expectations are already set for the RequestRepository.UpdateWithTZTx method") + } + + mmUpdateWithTZTx.mock.funcUpdateWithTZTx = f + mmUpdateWithTZTx.mock.funcUpdateWithTZTxOrigin = minimock.CallerInfo(1) + return mmUpdateWithTZTx.mock +} + +// When sets expectation for the RequestRepository.UpdateWithTZTx which will trigger the result defined by the following +// Then helper +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) When(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) *RequestRepositoryMockUpdateWithTZTxExpectation { + if mmUpdateWithTZTx.mock.funcUpdateWithTZTx != nil { + mmUpdateWithTZTx.mock.t.Fatalf("RequestRepositoryMock.UpdateWithTZTx mock is already set by Set") + } + + expectation := &RequestRepositoryMockUpdateWithTZTxExpectation{ + mock: mmUpdateWithTZTx.mock, + params: &RequestRepositoryMockUpdateWithTZTxParams{ctx, tx, id, tz, generated}, + expectationOrigins: RequestRepositoryMockUpdateWithTZTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmUpdateWithTZTx.expectations = append(mmUpdateWithTZTx.expectations, expectation) + return expectation +} + +// Then sets up RequestRepository.UpdateWithTZTx return parameters for the expectation previously defined by the When method +func (e *RequestRepositoryMockUpdateWithTZTxExpectation) Then(err error) *RequestRepositoryMock { + e.results = &RequestRepositoryMockUpdateWithTZTxResults{err} + return e.mock +} + +// Times sets number of times RequestRepository.UpdateWithTZTx should be invoked +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Times(n uint64) *mRequestRepositoryMockUpdateWithTZTx { + if n == 0 { + mmUpdateWithTZTx.mock.t.Fatalf("Times of RequestRepositoryMock.UpdateWithTZTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmUpdateWithTZTx.expectedInvocations, n) + mmUpdateWithTZTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmUpdateWithTZTx +} + +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) invocationsDone() bool { + if len(mmUpdateWithTZTx.expectations) == 0 && mmUpdateWithTZTx.defaultExpectation == nil && mmUpdateWithTZTx.mock.funcUpdateWithTZTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmUpdateWithTZTx.mock.afterUpdateWithTZTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmUpdateWithTZTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// UpdateWithTZTx implements mm_repository.RequestRepository +func (mmUpdateWithTZTx *RequestRepositoryMock) UpdateWithTZTx(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) (err error) { + mm_atomic.AddUint64(&mmUpdateWithTZTx.beforeUpdateWithTZTxCounter, 1) + defer mm_atomic.AddUint64(&mmUpdateWithTZTx.afterUpdateWithTZTxCounter, 1) + + mmUpdateWithTZTx.t.Helper() + + if mmUpdateWithTZTx.inspectFuncUpdateWithTZTx != nil { + mmUpdateWithTZTx.inspectFuncUpdateWithTZTx(ctx, tx, id, tz, generated) + } + + mm_params := RequestRepositoryMockUpdateWithTZTxParams{ctx, tx, id, tz, generated} + + // Record call args + mmUpdateWithTZTx.UpdateWithTZTxMock.mutex.Lock() + mmUpdateWithTZTx.UpdateWithTZTxMock.callArgs = append(mmUpdateWithTZTx.UpdateWithTZTxMock.callArgs, &mm_params) + mmUpdateWithTZTx.UpdateWithTZTxMock.mutex.Unlock() + + for _, e := range mmUpdateWithTZTx.UpdateWithTZTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.Counter, 1) + mm_want := mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.params + mm_want_ptrs := mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.paramPtrs + + mm_got := RequestRepositoryMockUpdateWithTZTxParams{ctx, tx, id, tz, generated} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmUpdateWithTZTx.t.Errorf("RequestRepositoryMock.UpdateWithTZTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmUpdateWithTZTx.t.Errorf("RequestRepositoryMock.UpdateWithTZTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.id != nil && !minimock.Equal(*mm_want_ptrs.id, mm_got.id) { + mmUpdateWithTZTx.t.Errorf("RequestRepositoryMock.UpdateWithTZTx got unexpected parameter id, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.originId, *mm_want_ptrs.id, mm_got.id, minimock.Diff(*mm_want_ptrs.id, mm_got.id)) + } + + if mm_want_ptrs.tz != nil && !minimock.Equal(*mm_want_ptrs.tz, mm_got.tz) { + mmUpdateWithTZTx.t.Errorf("RequestRepositoryMock.UpdateWithTZTx got unexpected parameter tz, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.originTz, *mm_want_ptrs.tz, mm_got.tz, minimock.Diff(*mm_want_ptrs.tz, mm_got.tz)) + } + + if mm_want_ptrs.generated != nil && !minimock.Equal(*mm_want_ptrs.generated, mm_got.generated) { + mmUpdateWithTZTx.t.Errorf("RequestRepositoryMock.UpdateWithTZTx got unexpected parameter generated, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.originGenerated, *mm_want_ptrs.generated, mm_got.generated, minimock.Diff(*mm_want_ptrs.generated, mm_got.generated)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmUpdateWithTZTx.t.Errorf("RequestRepositoryMock.UpdateWithTZTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmUpdateWithTZTx.UpdateWithTZTxMock.defaultExpectation.results + if mm_results == nil { + mmUpdateWithTZTx.t.Fatal("No results are set for the RequestRepositoryMock.UpdateWithTZTx") + } + return (*mm_results).err + } + if mmUpdateWithTZTx.funcUpdateWithTZTx != nil { + return mmUpdateWithTZTx.funcUpdateWithTZTx(ctx, tx, id, tz, generated) + } + mmUpdateWithTZTx.t.Fatalf("Unexpected call to RequestRepositoryMock.UpdateWithTZTx. %v %v %v %v %v", ctx, tx, id, tz, generated) + return +} + +// UpdateWithTZTxAfterCounter returns a count of finished RequestRepositoryMock.UpdateWithTZTx invocations +func (mmUpdateWithTZTx *RequestRepositoryMock) UpdateWithTZTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmUpdateWithTZTx.afterUpdateWithTZTxCounter) +} + +// UpdateWithTZTxBeforeCounter returns a count of RequestRepositoryMock.UpdateWithTZTx invocations +func (mmUpdateWithTZTx *RequestRepositoryMock) UpdateWithTZTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmUpdateWithTZTx.beforeUpdateWithTZTxCounter) +} + +// Calls returns a list of arguments used in each call to RequestRepositoryMock.UpdateWithTZTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmUpdateWithTZTx *mRequestRepositoryMockUpdateWithTZTx) Calls() []*RequestRepositoryMockUpdateWithTZTxParams { + mmUpdateWithTZTx.mutex.RLock() + + argCopy := make([]*RequestRepositoryMockUpdateWithTZTxParams, len(mmUpdateWithTZTx.callArgs)) + copy(argCopy, mmUpdateWithTZTx.callArgs) + + mmUpdateWithTZTx.mutex.RUnlock() + + return argCopy +} + +// MinimockUpdateWithTZTxDone returns true if the count of the UpdateWithTZTx invocations corresponds +// the number of defined expectations +func (m *RequestRepositoryMock) MinimockUpdateWithTZTxDone() bool { + if m.UpdateWithTZTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.UpdateWithTZTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.UpdateWithTZTxMock.invocationsDone() +} + +// MinimockUpdateWithTZTxInspect logs each unmet expectation +func (m *RequestRepositoryMock) MinimockUpdateWithTZTxInspect() { + for _, e := range m.UpdateWithTZTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to RequestRepositoryMock.UpdateWithTZTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterUpdateWithTZTxCounter := mm_atomic.LoadUint64(&m.afterUpdateWithTZTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.UpdateWithTZTxMock.defaultExpectation != nil && afterUpdateWithTZTxCounter < 1 { + if m.UpdateWithTZTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to RequestRepositoryMock.UpdateWithTZTx at\n%s", m.UpdateWithTZTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to RequestRepositoryMock.UpdateWithTZTx at\n%s with params: %#v", m.UpdateWithTZTxMock.defaultExpectation.expectationOrigins.origin, *m.UpdateWithTZTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcUpdateWithTZTx != nil && afterUpdateWithTZTxCounter < 1 { + m.t.Errorf("Expected call to RequestRepositoryMock.UpdateWithTZTx at\n%s", m.funcUpdateWithTZTxOrigin) + } + + if !m.UpdateWithTZTxMock.invocationsDone() && afterUpdateWithTZTxCounter > 0 { + m.t.Errorf("Expected %d calls to RequestRepositoryMock.UpdateWithTZTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.UpdateWithTZTxMock.expectedInvocations), m.UpdateWithTZTxMock.expectedInvocationsOrigin, afterUpdateWithTZTxCounter) + } +} + // MinimockFinish checks that all mocked methods have been called the expected number of times func (m *RequestRepositoryMock) MinimockFinish() { m.finishOnce.Do(func() { @@ -2614,6 +3060,8 @@ func (m *RequestRepositoryMock) MinimockFinish() { m.MinimockUpdateFinalTZInspect() m.MinimockUpdateWithTZInspect() + + m.MinimockUpdateWithTZTxInspect() } }) } @@ -2643,5 +3091,6 @@ func (m *RequestRepositoryMock) minimockDone() bool { m.MinimockGetDetailByIDDone() && m.MinimockGetUserStatisticsDone() && m.MinimockUpdateFinalTZDone() && - m.MinimockUpdateWithTZDone() + m.MinimockUpdateWithTZDone() && + m.MinimockUpdateWithTZTxDone() } diff --git a/internal/mocks/request_service_mock.go b/internal/mocks/request_service_mock.go index 6b71671..12ad5df 100644 --- a/internal/mocks/request_service_mock.go +++ b/internal/mocks/request_service_mock.go @@ -2,15 +2,15 @@ package mocks -//go:generate minimock -i smart-search-back/internal/service.RequestService -o request_service_mock.go -n RequestServiceMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/service.RequestService -o request_service_mock.go -n RequestServiceMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" "github.com/google/uuid" ) diff --git a/internal/mocks/session_repository_mock.go b/internal/mocks/session_repository_mock.go index 21251b8..aed2d1f 100644 --- a/internal/mocks/session_repository_mock.go +++ b/internal/mocks/session_repository_mock.go @@ -2,15 +2,15 @@ package mocks -//go:generate minimock -i smart-search-back/internal/repository.SessionRepository -o session_repository_mock.go -n SessionRepositoryMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/repository.SessionRepository -o session_repository_mock.go -n SessionRepositoryMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" ) @@ -40,6 +40,13 @@ type SessionRepositoryMock struct { beforeFindByRefreshTokenCounter uint64 FindByRefreshTokenMock mSessionRepositoryMockFindByRefreshToken + funcIsAccessTokenValid func(ctx context.Context, accessToken string) (b1 bool, err error) + funcIsAccessTokenValidOrigin string + inspectFuncIsAccessTokenValid func(ctx context.Context, accessToken string) + afterIsAccessTokenValidCounter uint64 + beforeIsAccessTokenValidCounter uint64 + IsAccessTokenValidMock mSessionRepositoryMockIsAccessTokenValid + funcRevoke func(ctx context.Context, refreshToken string) (err error) funcRevokeOrigin string inspectFuncRevoke func(ctx context.Context, refreshToken string) @@ -47,6 +54,13 @@ type SessionRepositoryMock struct { beforeRevokeCounter uint64 RevokeMock mSessionRepositoryMockRevoke + funcRevokeByAccessToken func(ctx context.Context, accessToken string) (err error) + funcRevokeByAccessTokenOrigin string + inspectFuncRevokeByAccessToken func(ctx context.Context, accessToken string) + afterRevokeByAccessTokenCounter uint64 + beforeRevokeByAccessTokenCounter uint64 + RevokeByAccessTokenMock mSessionRepositoryMockRevokeByAccessToken + funcUpdateAccessToken func(ctx context.Context, refreshToken string, newAccessToken string) (err error) funcUpdateAccessTokenOrigin string inspectFuncUpdateAccessToken func(ctx context.Context, refreshToken string, newAccessToken string) @@ -72,9 +86,15 @@ func NewSessionRepositoryMock(t minimock.Tester) *SessionRepositoryMock { m.FindByRefreshTokenMock = mSessionRepositoryMockFindByRefreshToken{mock: m} m.FindByRefreshTokenMock.callArgs = []*SessionRepositoryMockFindByRefreshTokenParams{} + m.IsAccessTokenValidMock = mSessionRepositoryMockIsAccessTokenValid{mock: m} + m.IsAccessTokenValidMock.callArgs = []*SessionRepositoryMockIsAccessTokenValidParams{} + m.RevokeMock = mSessionRepositoryMockRevoke{mock: m} m.RevokeMock.callArgs = []*SessionRepositoryMockRevokeParams{} + m.RevokeByAccessTokenMock = mSessionRepositoryMockRevokeByAccessToken{mock: m} + m.RevokeByAccessTokenMock.callArgs = []*SessionRepositoryMockRevokeByAccessTokenParams{} + m.UpdateAccessTokenMock = mSessionRepositoryMockUpdateAccessToken{mock: m} m.UpdateAccessTokenMock.callArgs = []*SessionRepositoryMockUpdateAccessTokenParams{} @@ -1080,6 +1100,349 @@ func (m *SessionRepositoryMock) MinimockFindByRefreshTokenInspect() { } } +type mSessionRepositoryMockIsAccessTokenValid struct { + optional bool + mock *SessionRepositoryMock + defaultExpectation *SessionRepositoryMockIsAccessTokenValidExpectation + expectations []*SessionRepositoryMockIsAccessTokenValidExpectation + + callArgs []*SessionRepositoryMockIsAccessTokenValidParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// SessionRepositoryMockIsAccessTokenValidExpectation specifies expectation struct of the SessionRepository.IsAccessTokenValid +type SessionRepositoryMockIsAccessTokenValidExpectation struct { + mock *SessionRepositoryMock + params *SessionRepositoryMockIsAccessTokenValidParams + paramPtrs *SessionRepositoryMockIsAccessTokenValidParamPtrs + expectationOrigins SessionRepositoryMockIsAccessTokenValidExpectationOrigins + results *SessionRepositoryMockIsAccessTokenValidResults + returnOrigin string + Counter uint64 +} + +// SessionRepositoryMockIsAccessTokenValidParams contains parameters of the SessionRepository.IsAccessTokenValid +type SessionRepositoryMockIsAccessTokenValidParams struct { + ctx context.Context + accessToken string +} + +// SessionRepositoryMockIsAccessTokenValidParamPtrs contains pointers to parameters of the SessionRepository.IsAccessTokenValid +type SessionRepositoryMockIsAccessTokenValidParamPtrs struct { + ctx *context.Context + accessToken *string +} + +// SessionRepositoryMockIsAccessTokenValidResults contains results of the SessionRepository.IsAccessTokenValid +type SessionRepositoryMockIsAccessTokenValidResults struct { + b1 bool + err error +} + +// SessionRepositoryMockIsAccessTokenValidOrigins contains origins of expectations of the SessionRepository.IsAccessTokenValid +type SessionRepositoryMockIsAccessTokenValidExpectationOrigins struct { + origin string + originCtx string + originAccessToken string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Optional() *mSessionRepositoryMockIsAccessTokenValid { + mmIsAccessTokenValid.optional = true + return mmIsAccessTokenValid +} + +// Expect sets up expected params for SessionRepository.IsAccessTokenValid +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Expect(ctx context.Context, accessToken string) *mSessionRepositoryMockIsAccessTokenValid { + if mmIsAccessTokenValid.mock.funcIsAccessTokenValid != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Set") + } + + if mmIsAccessTokenValid.defaultExpectation == nil { + mmIsAccessTokenValid.defaultExpectation = &SessionRepositoryMockIsAccessTokenValidExpectation{} + } + + if mmIsAccessTokenValid.defaultExpectation.paramPtrs != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by ExpectParams functions") + } + + mmIsAccessTokenValid.defaultExpectation.params = &SessionRepositoryMockIsAccessTokenValidParams{ctx, accessToken} + mmIsAccessTokenValid.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmIsAccessTokenValid.expectations { + if minimock.Equal(e.params, mmIsAccessTokenValid.defaultExpectation.params) { + mmIsAccessTokenValid.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmIsAccessTokenValid.defaultExpectation.params) + } + } + + return mmIsAccessTokenValid +} + +// ExpectCtxParam1 sets up expected param ctx for SessionRepository.IsAccessTokenValid +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) ExpectCtxParam1(ctx context.Context) *mSessionRepositoryMockIsAccessTokenValid { + if mmIsAccessTokenValid.mock.funcIsAccessTokenValid != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Set") + } + + if mmIsAccessTokenValid.defaultExpectation == nil { + mmIsAccessTokenValid.defaultExpectation = &SessionRepositoryMockIsAccessTokenValidExpectation{} + } + + if mmIsAccessTokenValid.defaultExpectation.params != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Expect") + } + + if mmIsAccessTokenValid.defaultExpectation.paramPtrs == nil { + mmIsAccessTokenValid.defaultExpectation.paramPtrs = &SessionRepositoryMockIsAccessTokenValidParamPtrs{} + } + mmIsAccessTokenValid.defaultExpectation.paramPtrs.ctx = &ctx + mmIsAccessTokenValid.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmIsAccessTokenValid +} + +// ExpectAccessTokenParam2 sets up expected param accessToken for SessionRepository.IsAccessTokenValid +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) ExpectAccessTokenParam2(accessToken string) *mSessionRepositoryMockIsAccessTokenValid { + if mmIsAccessTokenValid.mock.funcIsAccessTokenValid != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Set") + } + + if mmIsAccessTokenValid.defaultExpectation == nil { + mmIsAccessTokenValid.defaultExpectation = &SessionRepositoryMockIsAccessTokenValidExpectation{} + } + + if mmIsAccessTokenValid.defaultExpectation.params != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Expect") + } + + if mmIsAccessTokenValid.defaultExpectation.paramPtrs == nil { + mmIsAccessTokenValid.defaultExpectation.paramPtrs = &SessionRepositoryMockIsAccessTokenValidParamPtrs{} + } + mmIsAccessTokenValid.defaultExpectation.paramPtrs.accessToken = &accessToken + mmIsAccessTokenValid.defaultExpectation.expectationOrigins.originAccessToken = minimock.CallerInfo(1) + + return mmIsAccessTokenValid +} + +// Inspect accepts an inspector function that has same arguments as the SessionRepository.IsAccessTokenValid +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Inspect(f func(ctx context.Context, accessToken string)) *mSessionRepositoryMockIsAccessTokenValid { + if mmIsAccessTokenValid.mock.inspectFuncIsAccessTokenValid != nil { + mmIsAccessTokenValid.mock.t.Fatalf("Inspect function is already set for SessionRepositoryMock.IsAccessTokenValid") + } + + mmIsAccessTokenValid.mock.inspectFuncIsAccessTokenValid = f + + return mmIsAccessTokenValid +} + +// Return sets up results that will be returned by SessionRepository.IsAccessTokenValid +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Return(b1 bool, err error) *SessionRepositoryMock { + if mmIsAccessTokenValid.mock.funcIsAccessTokenValid != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Set") + } + + if mmIsAccessTokenValid.defaultExpectation == nil { + mmIsAccessTokenValid.defaultExpectation = &SessionRepositoryMockIsAccessTokenValidExpectation{mock: mmIsAccessTokenValid.mock} + } + mmIsAccessTokenValid.defaultExpectation.results = &SessionRepositoryMockIsAccessTokenValidResults{b1, err} + mmIsAccessTokenValid.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmIsAccessTokenValid.mock +} + +// Set uses given function f to mock the SessionRepository.IsAccessTokenValid method +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Set(f func(ctx context.Context, accessToken string) (b1 bool, err error)) *SessionRepositoryMock { + if mmIsAccessTokenValid.defaultExpectation != nil { + mmIsAccessTokenValid.mock.t.Fatalf("Default expectation is already set for the SessionRepository.IsAccessTokenValid method") + } + + if len(mmIsAccessTokenValid.expectations) > 0 { + mmIsAccessTokenValid.mock.t.Fatalf("Some expectations are already set for the SessionRepository.IsAccessTokenValid method") + } + + mmIsAccessTokenValid.mock.funcIsAccessTokenValid = f + mmIsAccessTokenValid.mock.funcIsAccessTokenValidOrigin = minimock.CallerInfo(1) + return mmIsAccessTokenValid.mock +} + +// When sets expectation for the SessionRepository.IsAccessTokenValid which will trigger the result defined by the following +// Then helper +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) When(ctx context.Context, accessToken string) *SessionRepositoryMockIsAccessTokenValidExpectation { + if mmIsAccessTokenValid.mock.funcIsAccessTokenValid != nil { + mmIsAccessTokenValid.mock.t.Fatalf("SessionRepositoryMock.IsAccessTokenValid mock is already set by Set") + } + + expectation := &SessionRepositoryMockIsAccessTokenValidExpectation{ + mock: mmIsAccessTokenValid.mock, + params: &SessionRepositoryMockIsAccessTokenValidParams{ctx, accessToken}, + expectationOrigins: SessionRepositoryMockIsAccessTokenValidExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmIsAccessTokenValid.expectations = append(mmIsAccessTokenValid.expectations, expectation) + return expectation +} + +// Then sets up SessionRepository.IsAccessTokenValid return parameters for the expectation previously defined by the When method +func (e *SessionRepositoryMockIsAccessTokenValidExpectation) Then(b1 bool, err error) *SessionRepositoryMock { + e.results = &SessionRepositoryMockIsAccessTokenValidResults{b1, err} + return e.mock +} + +// Times sets number of times SessionRepository.IsAccessTokenValid should be invoked +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Times(n uint64) *mSessionRepositoryMockIsAccessTokenValid { + if n == 0 { + mmIsAccessTokenValid.mock.t.Fatalf("Times of SessionRepositoryMock.IsAccessTokenValid mock can not be zero") + } + mm_atomic.StoreUint64(&mmIsAccessTokenValid.expectedInvocations, n) + mmIsAccessTokenValid.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmIsAccessTokenValid +} + +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) invocationsDone() bool { + if len(mmIsAccessTokenValid.expectations) == 0 && mmIsAccessTokenValid.defaultExpectation == nil && mmIsAccessTokenValid.mock.funcIsAccessTokenValid == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmIsAccessTokenValid.mock.afterIsAccessTokenValidCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmIsAccessTokenValid.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// IsAccessTokenValid implements mm_repository.SessionRepository +func (mmIsAccessTokenValid *SessionRepositoryMock) IsAccessTokenValid(ctx context.Context, accessToken string) (b1 bool, err error) { + mm_atomic.AddUint64(&mmIsAccessTokenValid.beforeIsAccessTokenValidCounter, 1) + defer mm_atomic.AddUint64(&mmIsAccessTokenValid.afterIsAccessTokenValidCounter, 1) + + mmIsAccessTokenValid.t.Helper() + + if mmIsAccessTokenValid.inspectFuncIsAccessTokenValid != nil { + mmIsAccessTokenValid.inspectFuncIsAccessTokenValid(ctx, accessToken) + } + + mm_params := SessionRepositoryMockIsAccessTokenValidParams{ctx, accessToken} + + // Record call args + mmIsAccessTokenValid.IsAccessTokenValidMock.mutex.Lock() + mmIsAccessTokenValid.IsAccessTokenValidMock.callArgs = append(mmIsAccessTokenValid.IsAccessTokenValidMock.callArgs, &mm_params) + mmIsAccessTokenValid.IsAccessTokenValidMock.mutex.Unlock() + + for _, e := range mmIsAccessTokenValid.IsAccessTokenValidMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.b1, e.results.err + } + } + + if mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.Counter, 1) + mm_want := mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.params + mm_want_ptrs := mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.paramPtrs + + mm_got := SessionRepositoryMockIsAccessTokenValidParams{ctx, accessToken} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmIsAccessTokenValid.t.Errorf("SessionRepositoryMock.IsAccessTokenValid got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.accessToken != nil && !minimock.Equal(*mm_want_ptrs.accessToken, mm_got.accessToken) { + mmIsAccessTokenValid.t.Errorf("SessionRepositoryMock.IsAccessTokenValid got unexpected parameter accessToken, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.expectationOrigins.originAccessToken, *mm_want_ptrs.accessToken, mm_got.accessToken, minimock.Diff(*mm_want_ptrs.accessToken, mm_got.accessToken)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmIsAccessTokenValid.t.Errorf("SessionRepositoryMock.IsAccessTokenValid got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmIsAccessTokenValid.IsAccessTokenValidMock.defaultExpectation.results + if mm_results == nil { + mmIsAccessTokenValid.t.Fatal("No results are set for the SessionRepositoryMock.IsAccessTokenValid") + } + return (*mm_results).b1, (*mm_results).err + } + if mmIsAccessTokenValid.funcIsAccessTokenValid != nil { + return mmIsAccessTokenValid.funcIsAccessTokenValid(ctx, accessToken) + } + mmIsAccessTokenValid.t.Fatalf("Unexpected call to SessionRepositoryMock.IsAccessTokenValid. %v %v", ctx, accessToken) + return +} + +// IsAccessTokenValidAfterCounter returns a count of finished SessionRepositoryMock.IsAccessTokenValid invocations +func (mmIsAccessTokenValid *SessionRepositoryMock) IsAccessTokenValidAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmIsAccessTokenValid.afterIsAccessTokenValidCounter) +} + +// IsAccessTokenValidBeforeCounter returns a count of SessionRepositoryMock.IsAccessTokenValid invocations +func (mmIsAccessTokenValid *SessionRepositoryMock) IsAccessTokenValidBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmIsAccessTokenValid.beforeIsAccessTokenValidCounter) +} + +// Calls returns a list of arguments used in each call to SessionRepositoryMock.IsAccessTokenValid. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmIsAccessTokenValid *mSessionRepositoryMockIsAccessTokenValid) Calls() []*SessionRepositoryMockIsAccessTokenValidParams { + mmIsAccessTokenValid.mutex.RLock() + + argCopy := make([]*SessionRepositoryMockIsAccessTokenValidParams, len(mmIsAccessTokenValid.callArgs)) + copy(argCopy, mmIsAccessTokenValid.callArgs) + + mmIsAccessTokenValid.mutex.RUnlock() + + return argCopy +} + +// MinimockIsAccessTokenValidDone returns true if the count of the IsAccessTokenValid invocations corresponds +// the number of defined expectations +func (m *SessionRepositoryMock) MinimockIsAccessTokenValidDone() bool { + if m.IsAccessTokenValidMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.IsAccessTokenValidMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.IsAccessTokenValidMock.invocationsDone() +} + +// MinimockIsAccessTokenValidInspect logs each unmet expectation +func (m *SessionRepositoryMock) MinimockIsAccessTokenValidInspect() { + for _, e := range m.IsAccessTokenValidMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to SessionRepositoryMock.IsAccessTokenValid at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterIsAccessTokenValidCounter := mm_atomic.LoadUint64(&m.afterIsAccessTokenValidCounter) + // if default expectation was set then invocations count should be greater than zero + if m.IsAccessTokenValidMock.defaultExpectation != nil && afterIsAccessTokenValidCounter < 1 { + if m.IsAccessTokenValidMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to SessionRepositoryMock.IsAccessTokenValid at\n%s", m.IsAccessTokenValidMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to SessionRepositoryMock.IsAccessTokenValid at\n%s with params: %#v", m.IsAccessTokenValidMock.defaultExpectation.expectationOrigins.origin, *m.IsAccessTokenValidMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcIsAccessTokenValid != nil && afterIsAccessTokenValidCounter < 1 { + m.t.Errorf("Expected call to SessionRepositoryMock.IsAccessTokenValid at\n%s", m.funcIsAccessTokenValidOrigin) + } + + if !m.IsAccessTokenValidMock.invocationsDone() && afterIsAccessTokenValidCounter > 0 { + m.t.Errorf("Expected %d calls to SessionRepositoryMock.IsAccessTokenValid at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.IsAccessTokenValidMock.expectedInvocations), m.IsAccessTokenValidMock.expectedInvocationsOrigin, afterIsAccessTokenValidCounter) + } +} + type mSessionRepositoryMockRevoke struct { optional bool mock *SessionRepositoryMock @@ -1422,6 +1785,348 @@ func (m *SessionRepositoryMock) MinimockRevokeInspect() { } } +type mSessionRepositoryMockRevokeByAccessToken struct { + optional bool + mock *SessionRepositoryMock + defaultExpectation *SessionRepositoryMockRevokeByAccessTokenExpectation + expectations []*SessionRepositoryMockRevokeByAccessTokenExpectation + + callArgs []*SessionRepositoryMockRevokeByAccessTokenParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// SessionRepositoryMockRevokeByAccessTokenExpectation specifies expectation struct of the SessionRepository.RevokeByAccessToken +type SessionRepositoryMockRevokeByAccessTokenExpectation struct { + mock *SessionRepositoryMock + params *SessionRepositoryMockRevokeByAccessTokenParams + paramPtrs *SessionRepositoryMockRevokeByAccessTokenParamPtrs + expectationOrigins SessionRepositoryMockRevokeByAccessTokenExpectationOrigins + results *SessionRepositoryMockRevokeByAccessTokenResults + returnOrigin string + Counter uint64 +} + +// SessionRepositoryMockRevokeByAccessTokenParams contains parameters of the SessionRepository.RevokeByAccessToken +type SessionRepositoryMockRevokeByAccessTokenParams struct { + ctx context.Context + accessToken string +} + +// SessionRepositoryMockRevokeByAccessTokenParamPtrs contains pointers to parameters of the SessionRepository.RevokeByAccessToken +type SessionRepositoryMockRevokeByAccessTokenParamPtrs struct { + ctx *context.Context + accessToken *string +} + +// SessionRepositoryMockRevokeByAccessTokenResults contains results of the SessionRepository.RevokeByAccessToken +type SessionRepositoryMockRevokeByAccessTokenResults struct { + err error +} + +// SessionRepositoryMockRevokeByAccessTokenOrigins contains origins of expectations of the SessionRepository.RevokeByAccessToken +type SessionRepositoryMockRevokeByAccessTokenExpectationOrigins struct { + origin string + originCtx string + originAccessToken string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Optional() *mSessionRepositoryMockRevokeByAccessToken { + mmRevokeByAccessToken.optional = true + return mmRevokeByAccessToken +} + +// Expect sets up expected params for SessionRepository.RevokeByAccessToken +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Expect(ctx context.Context, accessToken string) *mSessionRepositoryMockRevokeByAccessToken { + if mmRevokeByAccessToken.mock.funcRevokeByAccessToken != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Set") + } + + if mmRevokeByAccessToken.defaultExpectation == nil { + mmRevokeByAccessToken.defaultExpectation = &SessionRepositoryMockRevokeByAccessTokenExpectation{} + } + + if mmRevokeByAccessToken.defaultExpectation.paramPtrs != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by ExpectParams functions") + } + + mmRevokeByAccessToken.defaultExpectation.params = &SessionRepositoryMockRevokeByAccessTokenParams{ctx, accessToken} + mmRevokeByAccessToken.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmRevokeByAccessToken.expectations { + if minimock.Equal(e.params, mmRevokeByAccessToken.defaultExpectation.params) { + mmRevokeByAccessToken.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmRevokeByAccessToken.defaultExpectation.params) + } + } + + return mmRevokeByAccessToken +} + +// ExpectCtxParam1 sets up expected param ctx for SessionRepository.RevokeByAccessToken +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) ExpectCtxParam1(ctx context.Context) *mSessionRepositoryMockRevokeByAccessToken { + if mmRevokeByAccessToken.mock.funcRevokeByAccessToken != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Set") + } + + if mmRevokeByAccessToken.defaultExpectation == nil { + mmRevokeByAccessToken.defaultExpectation = &SessionRepositoryMockRevokeByAccessTokenExpectation{} + } + + if mmRevokeByAccessToken.defaultExpectation.params != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Expect") + } + + if mmRevokeByAccessToken.defaultExpectation.paramPtrs == nil { + mmRevokeByAccessToken.defaultExpectation.paramPtrs = &SessionRepositoryMockRevokeByAccessTokenParamPtrs{} + } + mmRevokeByAccessToken.defaultExpectation.paramPtrs.ctx = &ctx + mmRevokeByAccessToken.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmRevokeByAccessToken +} + +// ExpectAccessTokenParam2 sets up expected param accessToken for SessionRepository.RevokeByAccessToken +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) ExpectAccessTokenParam2(accessToken string) *mSessionRepositoryMockRevokeByAccessToken { + if mmRevokeByAccessToken.mock.funcRevokeByAccessToken != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Set") + } + + if mmRevokeByAccessToken.defaultExpectation == nil { + mmRevokeByAccessToken.defaultExpectation = &SessionRepositoryMockRevokeByAccessTokenExpectation{} + } + + if mmRevokeByAccessToken.defaultExpectation.params != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Expect") + } + + if mmRevokeByAccessToken.defaultExpectation.paramPtrs == nil { + mmRevokeByAccessToken.defaultExpectation.paramPtrs = &SessionRepositoryMockRevokeByAccessTokenParamPtrs{} + } + mmRevokeByAccessToken.defaultExpectation.paramPtrs.accessToken = &accessToken + mmRevokeByAccessToken.defaultExpectation.expectationOrigins.originAccessToken = minimock.CallerInfo(1) + + return mmRevokeByAccessToken +} + +// Inspect accepts an inspector function that has same arguments as the SessionRepository.RevokeByAccessToken +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Inspect(f func(ctx context.Context, accessToken string)) *mSessionRepositoryMockRevokeByAccessToken { + if mmRevokeByAccessToken.mock.inspectFuncRevokeByAccessToken != nil { + mmRevokeByAccessToken.mock.t.Fatalf("Inspect function is already set for SessionRepositoryMock.RevokeByAccessToken") + } + + mmRevokeByAccessToken.mock.inspectFuncRevokeByAccessToken = f + + return mmRevokeByAccessToken +} + +// Return sets up results that will be returned by SessionRepository.RevokeByAccessToken +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Return(err error) *SessionRepositoryMock { + if mmRevokeByAccessToken.mock.funcRevokeByAccessToken != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Set") + } + + if mmRevokeByAccessToken.defaultExpectation == nil { + mmRevokeByAccessToken.defaultExpectation = &SessionRepositoryMockRevokeByAccessTokenExpectation{mock: mmRevokeByAccessToken.mock} + } + mmRevokeByAccessToken.defaultExpectation.results = &SessionRepositoryMockRevokeByAccessTokenResults{err} + mmRevokeByAccessToken.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmRevokeByAccessToken.mock +} + +// Set uses given function f to mock the SessionRepository.RevokeByAccessToken method +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Set(f func(ctx context.Context, accessToken string) (err error)) *SessionRepositoryMock { + if mmRevokeByAccessToken.defaultExpectation != nil { + mmRevokeByAccessToken.mock.t.Fatalf("Default expectation is already set for the SessionRepository.RevokeByAccessToken method") + } + + if len(mmRevokeByAccessToken.expectations) > 0 { + mmRevokeByAccessToken.mock.t.Fatalf("Some expectations are already set for the SessionRepository.RevokeByAccessToken method") + } + + mmRevokeByAccessToken.mock.funcRevokeByAccessToken = f + mmRevokeByAccessToken.mock.funcRevokeByAccessTokenOrigin = minimock.CallerInfo(1) + return mmRevokeByAccessToken.mock +} + +// When sets expectation for the SessionRepository.RevokeByAccessToken which will trigger the result defined by the following +// Then helper +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) When(ctx context.Context, accessToken string) *SessionRepositoryMockRevokeByAccessTokenExpectation { + if mmRevokeByAccessToken.mock.funcRevokeByAccessToken != nil { + mmRevokeByAccessToken.mock.t.Fatalf("SessionRepositoryMock.RevokeByAccessToken mock is already set by Set") + } + + expectation := &SessionRepositoryMockRevokeByAccessTokenExpectation{ + mock: mmRevokeByAccessToken.mock, + params: &SessionRepositoryMockRevokeByAccessTokenParams{ctx, accessToken}, + expectationOrigins: SessionRepositoryMockRevokeByAccessTokenExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmRevokeByAccessToken.expectations = append(mmRevokeByAccessToken.expectations, expectation) + return expectation +} + +// Then sets up SessionRepository.RevokeByAccessToken return parameters for the expectation previously defined by the When method +func (e *SessionRepositoryMockRevokeByAccessTokenExpectation) Then(err error) *SessionRepositoryMock { + e.results = &SessionRepositoryMockRevokeByAccessTokenResults{err} + return e.mock +} + +// Times sets number of times SessionRepository.RevokeByAccessToken should be invoked +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Times(n uint64) *mSessionRepositoryMockRevokeByAccessToken { + if n == 0 { + mmRevokeByAccessToken.mock.t.Fatalf("Times of SessionRepositoryMock.RevokeByAccessToken mock can not be zero") + } + mm_atomic.StoreUint64(&mmRevokeByAccessToken.expectedInvocations, n) + mmRevokeByAccessToken.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmRevokeByAccessToken +} + +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) invocationsDone() bool { + if len(mmRevokeByAccessToken.expectations) == 0 && mmRevokeByAccessToken.defaultExpectation == nil && mmRevokeByAccessToken.mock.funcRevokeByAccessToken == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmRevokeByAccessToken.mock.afterRevokeByAccessTokenCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmRevokeByAccessToken.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// RevokeByAccessToken implements mm_repository.SessionRepository +func (mmRevokeByAccessToken *SessionRepositoryMock) RevokeByAccessToken(ctx context.Context, accessToken string) (err error) { + mm_atomic.AddUint64(&mmRevokeByAccessToken.beforeRevokeByAccessTokenCounter, 1) + defer mm_atomic.AddUint64(&mmRevokeByAccessToken.afterRevokeByAccessTokenCounter, 1) + + mmRevokeByAccessToken.t.Helper() + + if mmRevokeByAccessToken.inspectFuncRevokeByAccessToken != nil { + mmRevokeByAccessToken.inspectFuncRevokeByAccessToken(ctx, accessToken) + } + + mm_params := SessionRepositoryMockRevokeByAccessTokenParams{ctx, accessToken} + + // Record call args + mmRevokeByAccessToken.RevokeByAccessTokenMock.mutex.Lock() + mmRevokeByAccessToken.RevokeByAccessTokenMock.callArgs = append(mmRevokeByAccessToken.RevokeByAccessTokenMock.callArgs, &mm_params) + mmRevokeByAccessToken.RevokeByAccessTokenMock.mutex.Unlock() + + for _, e := range mmRevokeByAccessToken.RevokeByAccessTokenMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.Counter, 1) + mm_want := mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.params + mm_want_ptrs := mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.paramPtrs + + mm_got := SessionRepositoryMockRevokeByAccessTokenParams{ctx, accessToken} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmRevokeByAccessToken.t.Errorf("SessionRepositoryMock.RevokeByAccessToken got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.accessToken != nil && !minimock.Equal(*mm_want_ptrs.accessToken, mm_got.accessToken) { + mmRevokeByAccessToken.t.Errorf("SessionRepositoryMock.RevokeByAccessToken got unexpected parameter accessToken, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.expectationOrigins.originAccessToken, *mm_want_ptrs.accessToken, mm_got.accessToken, minimock.Diff(*mm_want_ptrs.accessToken, mm_got.accessToken)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmRevokeByAccessToken.t.Errorf("SessionRepositoryMock.RevokeByAccessToken got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmRevokeByAccessToken.RevokeByAccessTokenMock.defaultExpectation.results + if mm_results == nil { + mmRevokeByAccessToken.t.Fatal("No results are set for the SessionRepositoryMock.RevokeByAccessToken") + } + return (*mm_results).err + } + if mmRevokeByAccessToken.funcRevokeByAccessToken != nil { + return mmRevokeByAccessToken.funcRevokeByAccessToken(ctx, accessToken) + } + mmRevokeByAccessToken.t.Fatalf("Unexpected call to SessionRepositoryMock.RevokeByAccessToken. %v %v", ctx, accessToken) + return +} + +// RevokeByAccessTokenAfterCounter returns a count of finished SessionRepositoryMock.RevokeByAccessToken invocations +func (mmRevokeByAccessToken *SessionRepositoryMock) RevokeByAccessTokenAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmRevokeByAccessToken.afterRevokeByAccessTokenCounter) +} + +// RevokeByAccessTokenBeforeCounter returns a count of SessionRepositoryMock.RevokeByAccessToken invocations +func (mmRevokeByAccessToken *SessionRepositoryMock) RevokeByAccessTokenBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmRevokeByAccessToken.beforeRevokeByAccessTokenCounter) +} + +// Calls returns a list of arguments used in each call to SessionRepositoryMock.RevokeByAccessToken. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmRevokeByAccessToken *mSessionRepositoryMockRevokeByAccessToken) Calls() []*SessionRepositoryMockRevokeByAccessTokenParams { + mmRevokeByAccessToken.mutex.RLock() + + argCopy := make([]*SessionRepositoryMockRevokeByAccessTokenParams, len(mmRevokeByAccessToken.callArgs)) + copy(argCopy, mmRevokeByAccessToken.callArgs) + + mmRevokeByAccessToken.mutex.RUnlock() + + return argCopy +} + +// MinimockRevokeByAccessTokenDone returns true if the count of the RevokeByAccessToken invocations corresponds +// the number of defined expectations +func (m *SessionRepositoryMock) MinimockRevokeByAccessTokenDone() bool { + if m.RevokeByAccessTokenMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.RevokeByAccessTokenMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.RevokeByAccessTokenMock.invocationsDone() +} + +// MinimockRevokeByAccessTokenInspect logs each unmet expectation +func (m *SessionRepositoryMock) MinimockRevokeByAccessTokenInspect() { + for _, e := range m.RevokeByAccessTokenMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to SessionRepositoryMock.RevokeByAccessToken at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterRevokeByAccessTokenCounter := mm_atomic.LoadUint64(&m.afterRevokeByAccessTokenCounter) + // if default expectation was set then invocations count should be greater than zero + if m.RevokeByAccessTokenMock.defaultExpectation != nil && afterRevokeByAccessTokenCounter < 1 { + if m.RevokeByAccessTokenMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to SessionRepositoryMock.RevokeByAccessToken at\n%s", m.RevokeByAccessTokenMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to SessionRepositoryMock.RevokeByAccessToken at\n%s with params: %#v", m.RevokeByAccessTokenMock.defaultExpectation.expectationOrigins.origin, *m.RevokeByAccessTokenMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcRevokeByAccessToken != nil && afterRevokeByAccessTokenCounter < 1 { + m.t.Errorf("Expected call to SessionRepositoryMock.RevokeByAccessToken at\n%s", m.funcRevokeByAccessTokenOrigin) + } + + if !m.RevokeByAccessTokenMock.invocationsDone() && afterRevokeByAccessTokenCounter > 0 { + m.t.Errorf("Expected %d calls to SessionRepositoryMock.RevokeByAccessToken at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.RevokeByAccessTokenMock.expectedInvocations), m.RevokeByAccessTokenMock.expectedInvocationsOrigin, afterRevokeByAccessTokenCounter) + } +} + type mSessionRepositoryMockUpdateAccessToken struct { optional bool mock *SessionRepositoryMock @@ -1805,8 +2510,12 @@ func (m *SessionRepositoryMock) MinimockFinish() { m.MinimockFindByRefreshTokenInspect() + m.MinimockIsAccessTokenValidInspect() + m.MinimockRevokeInspect() + m.MinimockRevokeByAccessTokenInspect() + m.MinimockUpdateAccessTokenInspect() } }) @@ -1834,6 +2543,8 @@ func (m *SessionRepositoryMock) minimockDone() bool { m.MinimockCreateDone() && m.MinimockDeleteExpiredDone() && m.MinimockFindByRefreshTokenDone() && + m.MinimockIsAccessTokenValidDone() && m.MinimockRevokeDone() && + m.MinimockRevokeByAccessTokenDone() && m.MinimockUpdateAccessTokenDone() } diff --git a/internal/mocks/supplier_repository_mock.go b/internal/mocks/supplier_repository_mock.go index fde4942..72a773c 100644 --- a/internal/mocks/supplier_repository_mock.go +++ b/internal/mocks/supplier_repository_mock.go @@ -2,17 +2,18 @@ package mocks -//go:generate minimock -i smart-search-back/internal/repository.SupplierRepository -o supplier_repository_mock.go -n SupplierRepositoryMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/repository.SupplierRepository -o supplier_repository_mock.go -n SupplierRepositoryMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" "github.com/google/uuid" + "github.com/jackc/pgx/v5" ) // SupplierRepositoryMock implements mm_repository.SupplierRepository @@ -27,6 +28,13 @@ type SupplierRepositoryMock struct { beforeBulkInsertCounter uint64 BulkInsertMock mSupplierRepositoryMockBulkInsert + funcBulkInsertTx func(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) (err error) + funcBulkInsertTxOrigin string + inspectFuncBulkInsertTx func(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) + afterBulkInsertTxCounter uint64 + beforeBulkInsertTxCounter uint64 + BulkInsertTxMock mSupplierRepositoryMockBulkInsertTx + funcDeleteByRequestID func(ctx context.Context, requestID uuid.UUID) (err error) funcDeleteByRequestIDOrigin string inspectFuncDeleteByRequestID func(ctx context.Context, requestID uuid.UUID) @@ -53,6 +61,9 @@ func NewSupplierRepositoryMock(t minimock.Tester) *SupplierRepositoryMock { m.BulkInsertMock = mSupplierRepositoryMockBulkInsert{mock: m} m.BulkInsertMock.callArgs = []*SupplierRepositoryMockBulkInsertParams{} + m.BulkInsertTxMock = mSupplierRepositoryMockBulkInsertTx{mock: m} + m.BulkInsertTxMock.callArgs = []*SupplierRepositoryMockBulkInsertTxParams{} + m.DeleteByRequestIDMock = mSupplierRepositoryMockDeleteByRequestID{mock: m} m.DeleteByRequestIDMock.callArgs = []*SupplierRepositoryMockDeleteByRequestIDParams{} @@ -437,6 +448,410 @@ func (m *SupplierRepositoryMock) MinimockBulkInsertInspect() { } } +type mSupplierRepositoryMockBulkInsertTx struct { + optional bool + mock *SupplierRepositoryMock + defaultExpectation *SupplierRepositoryMockBulkInsertTxExpectation + expectations []*SupplierRepositoryMockBulkInsertTxExpectation + + callArgs []*SupplierRepositoryMockBulkInsertTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// SupplierRepositoryMockBulkInsertTxExpectation specifies expectation struct of the SupplierRepository.BulkInsertTx +type SupplierRepositoryMockBulkInsertTxExpectation struct { + mock *SupplierRepositoryMock + params *SupplierRepositoryMockBulkInsertTxParams + paramPtrs *SupplierRepositoryMockBulkInsertTxParamPtrs + expectationOrigins SupplierRepositoryMockBulkInsertTxExpectationOrigins + results *SupplierRepositoryMockBulkInsertTxResults + returnOrigin string + Counter uint64 +} + +// SupplierRepositoryMockBulkInsertTxParams contains parameters of the SupplierRepository.BulkInsertTx +type SupplierRepositoryMockBulkInsertTxParams struct { + ctx context.Context + tx pgx.Tx + requestID uuid.UUID + suppliers []*model.Supplier +} + +// SupplierRepositoryMockBulkInsertTxParamPtrs contains pointers to parameters of the SupplierRepository.BulkInsertTx +type SupplierRepositoryMockBulkInsertTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + requestID *uuid.UUID + suppliers *[]*model.Supplier +} + +// SupplierRepositoryMockBulkInsertTxResults contains results of the SupplierRepository.BulkInsertTx +type SupplierRepositoryMockBulkInsertTxResults struct { + err error +} + +// SupplierRepositoryMockBulkInsertTxOrigins contains origins of expectations of the SupplierRepository.BulkInsertTx +type SupplierRepositoryMockBulkInsertTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originRequestID string + originSuppliers string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Optional() *mSupplierRepositoryMockBulkInsertTx { + mmBulkInsertTx.optional = true + return mmBulkInsertTx +} + +// Expect sets up expected params for SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Expect(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) *mSupplierRepositoryMockBulkInsertTx { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + if mmBulkInsertTx.defaultExpectation == nil { + mmBulkInsertTx.defaultExpectation = &SupplierRepositoryMockBulkInsertTxExpectation{} + } + + if mmBulkInsertTx.defaultExpectation.paramPtrs != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by ExpectParams functions") + } + + mmBulkInsertTx.defaultExpectation.params = &SupplierRepositoryMockBulkInsertTxParams{ctx, tx, requestID, suppliers} + mmBulkInsertTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmBulkInsertTx.expectations { + if minimock.Equal(e.params, mmBulkInsertTx.defaultExpectation.params) { + mmBulkInsertTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmBulkInsertTx.defaultExpectation.params) + } + } + + return mmBulkInsertTx +} + +// ExpectCtxParam1 sets up expected param ctx for SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) ExpectCtxParam1(ctx context.Context) *mSupplierRepositoryMockBulkInsertTx { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + if mmBulkInsertTx.defaultExpectation == nil { + mmBulkInsertTx.defaultExpectation = &SupplierRepositoryMockBulkInsertTxExpectation{} + } + + if mmBulkInsertTx.defaultExpectation.params != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Expect") + } + + if mmBulkInsertTx.defaultExpectation.paramPtrs == nil { + mmBulkInsertTx.defaultExpectation.paramPtrs = &SupplierRepositoryMockBulkInsertTxParamPtrs{} + } + mmBulkInsertTx.defaultExpectation.paramPtrs.ctx = &ctx + mmBulkInsertTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmBulkInsertTx +} + +// ExpectTxParam2 sets up expected param tx for SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) ExpectTxParam2(tx pgx.Tx) *mSupplierRepositoryMockBulkInsertTx { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + if mmBulkInsertTx.defaultExpectation == nil { + mmBulkInsertTx.defaultExpectation = &SupplierRepositoryMockBulkInsertTxExpectation{} + } + + if mmBulkInsertTx.defaultExpectation.params != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Expect") + } + + if mmBulkInsertTx.defaultExpectation.paramPtrs == nil { + mmBulkInsertTx.defaultExpectation.paramPtrs = &SupplierRepositoryMockBulkInsertTxParamPtrs{} + } + mmBulkInsertTx.defaultExpectation.paramPtrs.tx = &tx + mmBulkInsertTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmBulkInsertTx +} + +// ExpectRequestIDParam3 sets up expected param requestID for SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) ExpectRequestIDParam3(requestID uuid.UUID) *mSupplierRepositoryMockBulkInsertTx { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + if mmBulkInsertTx.defaultExpectation == nil { + mmBulkInsertTx.defaultExpectation = &SupplierRepositoryMockBulkInsertTxExpectation{} + } + + if mmBulkInsertTx.defaultExpectation.params != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Expect") + } + + if mmBulkInsertTx.defaultExpectation.paramPtrs == nil { + mmBulkInsertTx.defaultExpectation.paramPtrs = &SupplierRepositoryMockBulkInsertTxParamPtrs{} + } + mmBulkInsertTx.defaultExpectation.paramPtrs.requestID = &requestID + mmBulkInsertTx.defaultExpectation.expectationOrigins.originRequestID = minimock.CallerInfo(1) + + return mmBulkInsertTx +} + +// ExpectSuppliersParam4 sets up expected param suppliers for SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) ExpectSuppliersParam4(suppliers []*model.Supplier) *mSupplierRepositoryMockBulkInsertTx { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + if mmBulkInsertTx.defaultExpectation == nil { + mmBulkInsertTx.defaultExpectation = &SupplierRepositoryMockBulkInsertTxExpectation{} + } + + if mmBulkInsertTx.defaultExpectation.params != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Expect") + } + + if mmBulkInsertTx.defaultExpectation.paramPtrs == nil { + mmBulkInsertTx.defaultExpectation.paramPtrs = &SupplierRepositoryMockBulkInsertTxParamPtrs{} + } + mmBulkInsertTx.defaultExpectation.paramPtrs.suppliers = &suppliers + mmBulkInsertTx.defaultExpectation.expectationOrigins.originSuppliers = minimock.CallerInfo(1) + + return mmBulkInsertTx +} + +// Inspect accepts an inspector function that has same arguments as the SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Inspect(f func(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier)) *mSupplierRepositoryMockBulkInsertTx { + if mmBulkInsertTx.mock.inspectFuncBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("Inspect function is already set for SupplierRepositoryMock.BulkInsertTx") + } + + mmBulkInsertTx.mock.inspectFuncBulkInsertTx = f + + return mmBulkInsertTx +} + +// Return sets up results that will be returned by SupplierRepository.BulkInsertTx +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Return(err error) *SupplierRepositoryMock { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + if mmBulkInsertTx.defaultExpectation == nil { + mmBulkInsertTx.defaultExpectation = &SupplierRepositoryMockBulkInsertTxExpectation{mock: mmBulkInsertTx.mock} + } + mmBulkInsertTx.defaultExpectation.results = &SupplierRepositoryMockBulkInsertTxResults{err} + mmBulkInsertTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmBulkInsertTx.mock +} + +// Set uses given function f to mock the SupplierRepository.BulkInsertTx method +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Set(f func(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) (err error)) *SupplierRepositoryMock { + if mmBulkInsertTx.defaultExpectation != nil { + mmBulkInsertTx.mock.t.Fatalf("Default expectation is already set for the SupplierRepository.BulkInsertTx method") + } + + if len(mmBulkInsertTx.expectations) > 0 { + mmBulkInsertTx.mock.t.Fatalf("Some expectations are already set for the SupplierRepository.BulkInsertTx method") + } + + mmBulkInsertTx.mock.funcBulkInsertTx = f + mmBulkInsertTx.mock.funcBulkInsertTxOrigin = minimock.CallerInfo(1) + return mmBulkInsertTx.mock +} + +// When sets expectation for the SupplierRepository.BulkInsertTx which will trigger the result defined by the following +// Then helper +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) When(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) *SupplierRepositoryMockBulkInsertTxExpectation { + if mmBulkInsertTx.mock.funcBulkInsertTx != nil { + mmBulkInsertTx.mock.t.Fatalf("SupplierRepositoryMock.BulkInsertTx mock is already set by Set") + } + + expectation := &SupplierRepositoryMockBulkInsertTxExpectation{ + mock: mmBulkInsertTx.mock, + params: &SupplierRepositoryMockBulkInsertTxParams{ctx, tx, requestID, suppliers}, + expectationOrigins: SupplierRepositoryMockBulkInsertTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmBulkInsertTx.expectations = append(mmBulkInsertTx.expectations, expectation) + return expectation +} + +// Then sets up SupplierRepository.BulkInsertTx return parameters for the expectation previously defined by the When method +func (e *SupplierRepositoryMockBulkInsertTxExpectation) Then(err error) *SupplierRepositoryMock { + e.results = &SupplierRepositoryMockBulkInsertTxResults{err} + return e.mock +} + +// Times sets number of times SupplierRepository.BulkInsertTx should be invoked +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Times(n uint64) *mSupplierRepositoryMockBulkInsertTx { + if n == 0 { + mmBulkInsertTx.mock.t.Fatalf("Times of SupplierRepositoryMock.BulkInsertTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmBulkInsertTx.expectedInvocations, n) + mmBulkInsertTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmBulkInsertTx +} + +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) invocationsDone() bool { + if len(mmBulkInsertTx.expectations) == 0 && mmBulkInsertTx.defaultExpectation == nil && mmBulkInsertTx.mock.funcBulkInsertTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmBulkInsertTx.mock.afterBulkInsertTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmBulkInsertTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// BulkInsertTx implements mm_repository.SupplierRepository +func (mmBulkInsertTx *SupplierRepositoryMock) BulkInsertTx(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) (err error) { + mm_atomic.AddUint64(&mmBulkInsertTx.beforeBulkInsertTxCounter, 1) + defer mm_atomic.AddUint64(&mmBulkInsertTx.afterBulkInsertTxCounter, 1) + + mmBulkInsertTx.t.Helper() + + if mmBulkInsertTx.inspectFuncBulkInsertTx != nil { + mmBulkInsertTx.inspectFuncBulkInsertTx(ctx, tx, requestID, suppliers) + } + + mm_params := SupplierRepositoryMockBulkInsertTxParams{ctx, tx, requestID, suppliers} + + // Record call args + mmBulkInsertTx.BulkInsertTxMock.mutex.Lock() + mmBulkInsertTx.BulkInsertTxMock.callArgs = append(mmBulkInsertTx.BulkInsertTxMock.callArgs, &mm_params) + mmBulkInsertTx.BulkInsertTxMock.mutex.Unlock() + + for _, e := range mmBulkInsertTx.BulkInsertTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmBulkInsertTx.BulkInsertTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.Counter, 1) + mm_want := mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.params + mm_want_ptrs := mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.paramPtrs + + mm_got := SupplierRepositoryMockBulkInsertTxParams{ctx, tx, requestID, suppliers} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmBulkInsertTx.t.Errorf("SupplierRepositoryMock.BulkInsertTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmBulkInsertTx.t.Errorf("SupplierRepositoryMock.BulkInsertTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.requestID != nil && !minimock.Equal(*mm_want_ptrs.requestID, mm_got.requestID) { + mmBulkInsertTx.t.Errorf("SupplierRepositoryMock.BulkInsertTx got unexpected parameter requestID, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.expectationOrigins.originRequestID, *mm_want_ptrs.requestID, mm_got.requestID, minimock.Diff(*mm_want_ptrs.requestID, mm_got.requestID)) + } + + if mm_want_ptrs.suppliers != nil && !minimock.Equal(*mm_want_ptrs.suppliers, mm_got.suppliers) { + mmBulkInsertTx.t.Errorf("SupplierRepositoryMock.BulkInsertTx got unexpected parameter suppliers, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.expectationOrigins.originSuppliers, *mm_want_ptrs.suppliers, mm_got.suppliers, minimock.Diff(*mm_want_ptrs.suppliers, mm_got.suppliers)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmBulkInsertTx.t.Errorf("SupplierRepositoryMock.BulkInsertTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmBulkInsertTx.BulkInsertTxMock.defaultExpectation.results + if mm_results == nil { + mmBulkInsertTx.t.Fatal("No results are set for the SupplierRepositoryMock.BulkInsertTx") + } + return (*mm_results).err + } + if mmBulkInsertTx.funcBulkInsertTx != nil { + return mmBulkInsertTx.funcBulkInsertTx(ctx, tx, requestID, suppliers) + } + mmBulkInsertTx.t.Fatalf("Unexpected call to SupplierRepositoryMock.BulkInsertTx. %v %v %v %v", ctx, tx, requestID, suppliers) + return +} + +// BulkInsertTxAfterCounter returns a count of finished SupplierRepositoryMock.BulkInsertTx invocations +func (mmBulkInsertTx *SupplierRepositoryMock) BulkInsertTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmBulkInsertTx.afterBulkInsertTxCounter) +} + +// BulkInsertTxBeforeCounter returns a count of SupplierRepositoryMock.BulkInsertTx invocations +func (mmBulkInsertTx *SupplierRepositoryMock) BulkInsertTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmBulkInsertTx.beforeBulkInsertTxCounter) +} + +// Calls returns a list of arguments used in each call to SupplierRepositoryMock.BulkInsertTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmBulkInsertTx *mSupplierRepositoryMockBulkInsertTx) Calls() []*SupplierRepositoryMockBulkInsertTxParams { + mmBulkInsertTx.mutex.RLock() + + argCopy := make([]*SupplierRepositoryMockBulkInsertTxParams, len(mmBulkInsertTx.callArgs)) + copy(argCopy, mmBulkInsertTx.callArgs) + + mmBulkInsertTx.mutex.RUnlock() + + return argCopy +} + +// MinimockBulkInsertTxDone returns true if the count of the BulkInsertTx invocations corresponds +// the number of defined expectations +func (m *SupplierRepositoryMock) MinimockBulkInsertTxDone() bool { + if m.BulkInsertTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.BulkInsertTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.BulkInsertTxMock.invocationsDone() +} + +// MinimockBulkInsertTxInspect logs each unmet expectation +func (m *SupplierRepositoryMock) MinimockBulkInsertTxInspect() { + for _, e := range m.BulkInsertTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to SupplierRepositoryMock.BulkInsertTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterBulkInsertTxCounter := mm_atomic.LoadUint64(&m.afterBulkInsertTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.BulkInsertTxMock.defaultExpectation != nil && afterBulkInsertTxCounter < 1 { + if m.BulkInsertTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to SupplierRepositoryMock.BulkInsertTx at\n%s", m.BulkInsertTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to SupplierRepositoryMock.BulkInsertTx at\n%s with params: %#v", m.BulkInsertTxMock.defaultExpectation.expectationOrigins.origin, *m.BulkInsertTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcBulkInsertTx != nil && afterBulkInsertTxCounter < 1 { + m.t.Errorf("Expected call to SupplierRepositoryMock.BulkInsertTx at\n%s", m.funcBulkInsertTxOrigin) + } + + if !m.BulkInsertTxMock.invocationsDone() && afterBulkInsertTxCounter > 0 { + m.t.Errorf("Expected %d calls to SupplierRepositoryMock.BulkInsertTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.BulkInsertTxMock.expectedInvocations), m.BulkInsertTxMock.expectedInvocationsOrigin, afterBulkInsertTxCounter) + } +} + type mSupplierRepositoryMockDeleteByRequestID struct { optional bool mock *SupplierRepositoryMock @@ -1128,6 +1543,8 @@ func (m *SupplierRepositoryMock) MinimockFinish() { if !m.minimockDone() { m.MinimockBulkInsertInspect() + m.MinimockBulkInsertTxInspect() + m.MinimockDeleteByRequestIDInspect() m.MinimockGetByRequestIDInspect() @@ -1155,6 +1572,7 @@ func (m *SupplierRepositoryMock) minimockDone() bool { done := true return done && m.MinimockBulkInsertDone() && + m.MinimockBulkInsertTxDone() && m.MinimockDeleteByRequestIDDone() && m.MinimockGetByRequestIDDone() } diff --git a/internal/mocks/supplier_service_mock.go b/internal/mocks/supplier_service_mock.go index aa48e56..3b165f1 100644 --- a/internal/mocks/supplier_service_mock.go +++ b/internal/mocks/supplier_service_mock.go @@ -2,7 +2,7 @@ package mocks -//go:generate minimock -i smart-search-back/internal/service.SupplierService -o supplier_service_mock.go -n SupplierServiceMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/service.SupplierService -o supplier_service_mock.go -n SupplierServiceMock -p mocks import ( "context" diff --git a/internal/mocks/token_usage_repository_mock.go b/internal/mocks/token_usage_repository_mock.go index d610e6d..779b8f3 100644 --- a/internal/mocks/token_usage_repository_mock.go +++ b/internal/mocks/token_usage_repository_mock.go @@ -2,16 +2,17 @@ package mocks -//go:generate minimock -i smart-search-back/internal/repository.TokenUsageRepository -o token_usage_repository_mock.go -n TokenUsageRepositoryMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/repository.TokenUsageRepository -o token_usage_repository_mock.go -n TokenUsageRepositoryMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" + "github.com/jackc/pgx/v5" ) // TokenUsageRepositoryMock implements mm_repository.TokenUsageRepository @@ -25,6 +26,13 @@ type TokenUsageRepositoryMock struct { afterCreateCounter uint64 beforeCreateCounter uint64 CreateMock mTokenUsageRepositoryMockCreate + + funcCreateTx func(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) (err error) + funcCreateTxOrigin string + inspectFuncCreateTx func(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) + afterCreateTxCounter uint64 + beforeCreateTxCounter uint64 + CreateTxMock mTokenUsageRepositoryMockCreateTx } // NewTokenUsageRepositoryMock returns a mock for mm_repository.TokenUsageRepository @@ -38,6 +46,9 @@ func NewTokenUsageRepositoryMock(t minimock.Tester) *TokenUsageRepositoryMock { m.CreateMock = mTokenUsageRepositoryMockCreate{mock: m} m.CreateMock.callArgs = []*TokenUsageRepositoryMockCreateParams{} + m.CreateTxMock = mTokenUsageRepositoryMockCreateTx{mock: m} + m.CreateTxMock.callArgs = []*TokenUsageRepositoryMockCreateTxParams{} + t.Cleanup(m.MinimockFinish) return m @@ -385,11 +396,386 @@ func (m *TokenUsageRepositoryMock) MinimockCreateInspect() { } } +type mTokenUsageRepositoryMockCreateTx struct { + optional bool + mock *TokenUsageRepositoryMock + defaultExpectation *TokenUsageRepositoryMockCreateTxExpectation + expectations []*TokenUsageRepositoryMockCreateTxExpectation + + callArgs []*TokenUsageRepositoryMockCreateTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// TokenUsageRepositoryMockCreateTxExpectation specifies expectation struct of the TokenUsageRepository.CreateTx +type TokenUsageRepositoryMockCreateTxExpectation struct { + mock *TokenUsageRepositoryMock + params *TokenUsageRepositoryMockCreateTxParams + paramPtrs *TokenUsageRepositoryMockCreateTxParamPtrs + expectationOrigins TokenUsageRepositoryMockCreateTxExpectationOrigins + results *TokenUsageRepositoryMockCreateTxResults + returnOrigin string + Counter uint64 +} + +// TokenUsageRepositoryMockCreateTxParams contains parameters of the TokenUsageRepository.CreateTx +type TokenUsageRepositoryMockCreateTxParams struct { + ctx context.Context + tx pgx.Tx + usage *model.TokenUsage +} + +// TokenUsageRepositoryMockCreateTxParamPtrs contains pointers to parameters of the TokenUsageRepository.CreateTx +type TokenUsageRepositoryMockCreateTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + usage **model.TokenUsage +} + +// TokenUsageRepositoryMockCreateTxResults contains results of the TokenUsageRepository.CreateTx +type TokenUsageRepositoryMockCreateTxResults struct { + err error +} + +// TokenUsageRepositoryMockCreateTxOrigins contains origins of expectations of the TokenUsageRepository.CreateTx +type TokenUsageRepositoryMockCreateTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originUsage string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Optional() *mTokenUsageRepositoryMockCreateTx { + mmCreateTx.optional = true + return mmCreateTx +} + +// Expect sets up expected params for TokenUsageRepository.CreateTx +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Expect(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) *mTokenUsageRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &TokenUsageRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.paramPtrs != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by ExpectParams functions") + } + + mmCreateTx.defaultExpectation.params = &TokenUsageRepositoryMockCreateTxParams{ctx, tx, usage} + mmCreateTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmCreateTx.expectations { + if minimock.Equal(e.params, mmCreateTx.defaultExpectation.params) { + mmCreateTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmCreateTx.defaultExpectation.params) + } + } + + return mmCreateTx +} + +// ExpectCtxParam1 sets up expected param ctx for TokenUsageRepository.CreateTx +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) ExpectCtxParam1(ctx context.Context) *mTokenUsageRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &TokenUsageRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.params != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Expect") + } + + if mmCreateTx.defaultExpectation.paramPtrs == nil { + mmCreateTx.defaultExpectation.paramPtrs = &TokenUsageRepositoryMockCreateTxParamPtrs{} + } + mmCreateTx.defaultExpectation.paramPtrs.ctx = &ctx + mmCreateTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmCreateTx +} + +// ExpectTxParam2 sets up expected param tx for TokenUsageRepository.CreateTx +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) ExpectTxParam2(tx pgx.Tx) *mTokenUsageRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &TokenUsageRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.params != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Expect") + } + + if mmCreateTx.defaultExpectation.paramPtrs == nil { + mmCreateTx.defaultExpectation.paramPtrs = &TokenUsageRepositoryMockCreateTxParamPtrs{} + } + mmCreateTx.defaultExpectation.paramPtrs.tx = &tx + mmCreateTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmCreateTx +} + +// ExpectUsageParam3 sets up expected param usage for TokenUsageRepository.CreateTx +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) ExpectUsageParam3(usage *model.TokenUsage) *mTokenUsageRepositoryMockCreateTx { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &TokenUsageRepositoryMockCreateTxExpectation{} + } + + if mmCreateTx.defaultExpectation.params != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Expect") + } + + if mmCreateTx.defaultExpectation.paramPtrs == nil { + mmCreateTx.defaultExpectation.paramPtrs = &TokenUsageRepositoryMockCreateTxParamPtrs{} + } + mmCreateTx.defaultExpectation.paramPtrs.usage = &usage + mmCreateTx.defaultExpectation.expectationOrigins.originUsage = minimock.CallerInfo(1) + + return mmCreateTx +} + +// Inspect accepts an inspector function that has same arguments as the TokenUsageRepository.CreateTx +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Inspect(f func(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage)) *mTokenUsageRepositoryMockCreateTx { + if mmCreateTx.mock.inspectFuncCreateTx != nil { + mmCreateTx.mock.t.Fatalf("Inspect function is already set for TokenUsageRepositoryMock.CreateTx") + } + + mmCreateTx.mock.inspectFuncCreateTx = f + + return mmCreateTx +} + +// Return sets up results that will be returned by TokenUsageRepository.CreateTx +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Return(err error) *TokenUsageRepositoryMock { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Set") + } + + if mmCreateTx.defaultExpectation == nil { + mmCreateTx.defaultExpectation = &TokenUsageRepositoryMockCreateTxExpectation{mock: mmCreateTx.mock} + } + mmCreateTx.defaultExpectation.results = &TokenUsageRepositoryMockCreateTxResults{err} + mmCreateTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmCreateTx.mock +} + +// Set uses given function f to mock the TokenUsageRepository.CreateTx method +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Set(f func(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) (err error)) *TokenUsageRepositoryMock { + if mmCreateTx.defaultExpectation != nil { + mmCreateTx.mock.t.Fatalf("Default expectation is already set for the TokenUsageRepository.CreateTx method") + } + + if len(mmCreateTx.expectations) > 0 { + mmCreateTx.mock.t.Fatalf("Some expectations are already set for the TokenUsageRepository.CreateTx method") + } + + mmCreateTx.mock.funcCreateTx = f + mmCreateTx.mock.funcCreateTxOrigin = minimock.CallerInfo(1) + return mmCreateTx.mock +} + +// When sets expectation for the TokenUsageRepository.CreateTx which will trigger the result defined by the following +// Then helper +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) When(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) *TokenUsageRepositoryMockCreateTxExpectation { + if mmCreateTx.mock.funcCreateTx != nil { + mmCreateTx.mock.t.Fatalf("TokenUsageRepositoryMock.CreateTx mock is already set by Set") + } + + expectation := &TokenUsageRepositoryMockCreateTxExpectation{ + mock: mmCreateTx.mock, + params: &TokenUsageRepositoryMockCreateTxParams{ctx, tx, usage}, + expectationOrigins: TokenUsageRepositoryMockCreateTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmCreateTx.expectations = append(mmCreateTx.expectations, expectation) + return expectation +} + +// Then sets up TokenUsageRepository.CreateTx return parameters for the expectation previously defined by the When method +func (e *TokenUsageRepositoryMockCreateTxExpectation) Then(err error) *TokenUsageRepositoryMock { + e.results = &TokenUsageRepositoryMockCreateTxResults{err} + return e.mock +} + +// Times sets number of times TokenUsageRepository.CreateTx should be invoked +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Times(n uint64) *mTokenUsageRepositoryMockCreateTx { + if n == 0 { + mmCreateTx.mock.t.Fatalf("Times of TokenUsageRepositoryMock.CreateTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmCreateTx.expectedInvocations, n) + mmCreateTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmCreateTx +} + +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) invocationsDone() bool { + if len(mmCreateTx.expectations) == 0 && mmCreateTx.defaultExpectation == nil && mmCreateTx.mock.funcCreateTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmCreateTx.mock.afterCreateTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmCreateTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// CreateTx implements mm_repository.TokenUsageRepository +func (mmCreateTx *TokenUsageRepositoryMock) CreateTx(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) (err error) { + mm_atomic.AddUint64(&mmCreateTx.beforeCreateTxCounter, 1) + defer mm_atomic.AddUint64(&mmCreateTx.afterCreateTxCounter, 1) + + mmCreateTx.t.Helper() + + if mmCreateTx.inspectFuncCreateTx != nil { + mmCreateTx.inspectFuncCreateTx(ctx, tx, usage) + } + + mm_params := TokenUsageRepositoryMockCreateTxParams{ctx, tx, usage} + + // Record call args + mmCreateTx.CreateTxMock.mutex.Lock() + mmCreateTx.CreateTxMock.callArgs = append(mmCreateTx.CreateTxMock.callArgs, &mm_params) + mmCreateTx.CreateTxMock.mutex.Unlock() + + for _, e := range mmCreateTx.CreateTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmCreateTx.CreateTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmCreateTx.CreateTxMock.defaultExpectation.Counter, 1) + mm_want := mmCreateTx.CreateTxMock.defaultExpectation.params + mm_want_ptrs := mmCreateTx.CreateTxMock.defaultExpectation.paramPtrs + + mm_got := TokenUsageRepositoryMockCreateTxParams{ctx, tx, usage} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmCreateTx.t.Errorf("TokenUsageRepositoryMock.CreateTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmCreateTx.t.Errorf("TokenUsageRepositoryMock.CreateTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.usage != nil && !minimock.Equal(*mm_want_ptrs.usage, mm_got.usage) { + mmCreateTx.t.Errorf("TokenUsageRepositoryMock.CreateTx got unexpected parameter usage, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.originUsage, *mm_want_ptrs.usage, mm_got.usage, minimock.Diff(*mm_want_ptrs.usage, mm_got.usage)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmCreateTx.t.Errorf("TokenUsageRepositoryMock.CreateTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCreateTx.CreateTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmCreateTx.CreateTxMock.defaultExpectation.results + if mm_results == nil { + mmCreateTx.t.Fatal("No results are set for the TokenUsageRepositoryMock.CreateTx") + } + return (*mm_results).err + } + if mmCreateTx.funcCreateTx != nil { + return mmCreateTx.funcCreateTx(ctx, tx, usage) + } + mmCreateTx.t.Fatalf("Unexpected call to TokenUsageRepositoryMock.CreateTx. %v %v %v", ctx, tx, usage) + return +} + +// CreateTxAfterCounter returns a count of finished TokenUsageRepositoryMock.CreateTx invocations +func (mmCreateTx *TokenUsageRepositoryMock) CreateTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmCreateTx.afterCreateTxCounter) +} + +// CreateTxBeforeCounter returns a count of TokenUsageRepositoryMock.CreateTx invocations +func (mmCreateTx *TokenUsageRepositoryMock) CreateTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmCreateTx.beforeCreateTxCounter) +} + +// Calls returns a list of arguments used in each call to TokenUsageRepositoryMock.CreateTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmCreateTx *mTokenUsageRepositoryMockCreateTx) Calls() []*TokenUsageRepositoryMockCreateTxParams { + mmCreateTx.mutex.RLock() + + argCopy := make([]*TokenUsageRepositoryMockCreateTxParams, len(mmCreateTx.callArgs)) + copy(argCopy, mmCreateTx.callArgs) + + mmCreateTx.mutex.RUnlock() + + return argCopy +} + +// MinimockCreateTxDone returns true if the count of the CreateTx invocations corresponds +// the number of defined expectations +func (m *TokenUsageRepositoryMock) MinimockCreateTxDone() bool { + if m.CreateTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.CreateTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.CreateTxMock.invocationsDone() +} + +// MinimockCreateTxInspect logs each unmet expectation +func (m *TokenUsageRepositoryMock) MinimockCreateTxInspect() { + for _, e := range m.CreateTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to TokenUsageRepositoryMock.CreateTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterCreateTxCounter := mm_atomic.LoadUint64(&m.afterCreateTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.CreateTxMock.defaultExpectation != nil && afterCreateTxCounter < 1 { + if m.CreateTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to TokenUsageRepositoryMock.CreateTx at\n%s", m.CreateTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to TokenUsageRepositoryMock.CreateTx at\n%s with params: %#v", m.CreateTxMock.defaultExpectation.expectationOrigins.origin, *m.CreateTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcCreateTx != nil && afterCreateTxCounter < 1 { + m.t.Errorf("Expected call to TokenUsageRepositoryMock.CreateTx at\n%s", m.funcCreateTxOrigin) + } + + if !m.CreateTxMock.invocationsDone() && afterCreateTxCounter > 0 { + m.t.Errorf("Expected %d calls to TokenUsageRepositoryMock.CreateTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.CreateTxMock.expectedInvocations), m.CreateTxMock.expectedInvocationsOrigin, afterCreateTxCounter) + } +} + // MinimockFinish checks that all mocked methods have been called the expected number of times func (m *TokenUsageRepositoryMock) MinimockFinish() { m.finishOnce.Do(func() { if !m.minimockDone() { m.MinimockCreateInspect() + + m.MinimockCreateTxInspect() } }) } @@ -413,5 +799,6 @@ func (m *TokenUsageRepositoryMock) MinimockWait(timeout mm_time.Duration) { func (m *TokenUsageRepositoryMock) minimockDone() bool { done := true return done && - m.MinimockCreateDone() + m.MinimockCreateDone() && + m.MinimockCreateTxDone() } diff --git a/internal/mocks/user_repository_mock.go b/internal/mocks/user_repository_mock.go index 9497aff..0fa4f8f 100644 --- a/internal/mocks/user_repository_mock.go +++ b/internal/mocks/user_repository_mock.go @@ -2,16 +2,17 @@ package mocks -//go:generate minimock -i smart-search-back/internal/repository.UserRepository -o user_repository_mock.go -n UserRepositoryMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/repository.UserRepository -o user_repository_mock.go -n UserRepositoryMock -p mocks import ( "context" - "smart-search-back/internal/model" "sync" mm_atomic "sync/atomic" mm_time "time" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/gojuno/minimock/v3" + "github.com/jackc/pgx/v5" ) // UserRepositoryMock implements mm_repository.UserRepository @@ -26,6 +27,13 @@ type UserRepositoryMock struct { beforeCheckInviteLimitCounter uint64 CheckInviteLimitMock mUserRepositoryMockCheckInviteLimit + funcCheckInviteLimitTx func(ctx context.Context, tx pgx.Tx, userID int) (b1 bool, err error) + funcCheckInviteLimitTxOrigin string + inspectFuncCheckInviteLimitTx func(ctx context.Context, tx pgx.Tx, userID int) + afterCheckInviteLimitTxCounter uint64 + beforeCheckInviteLimitTxCounter uint64 + CheckInviteLimitTxMock mUserRepositoryMockCheckInviteLimitTx + funcCreate func(ctx context.Context, user *model.User) (err error) funcCreateOrigin string inspectFuncCreate func(ctx context.Context, user *model.User) @@ -61,12 +69,26 @@ type UserRepositoryMock struct { beforeIncrementInvitesIssuedCounter uint64 IncrementInvitesIssuedMock mUserRepositoryMockIncrementInvitesIssued + funcIncrementInvitesIssuedTx func(ctx context.Context, tx pgx.Tx, userID int) (err error) + funcIncrementInvitesIssuedTxOrigin string + inspectFuncIncrementInvitesIssuedTx func(ctx context.Context, tx pgx.Tx, userID int) + afterIncrementInvitesIssuedTxCounter uint64 + beforeIncrementInvitesIssuedTxCounter uint64 + IncrementInvitesIssuedTxMock mUserRepositoryMockIncrementInvitesIssuedTx + funcUpdateBalance func(ctx context.Context, userID int, delta float64) (err error) funcUpdateBalanceOrigin string inspectFuncUpdateBalance func(ctx context.Context, userID int, delta float64) afterUpdateBalanceCounter uint64 beforeUpdateBalanceCounter uint64 UpdateBalanceMock mUserRepositoryMockUpdateBalance + + funcUpdateBalanceTx func(ctx context.Context, tx pgx.Tx, userID int, delta float64) (err error) + funcUpdateBalanceTxOrigin string + inspectFuncUpdateBalanceTx func(ctx context.Context, tx pgx.Tx, userID int, delta float64) + afterUpdateBalanceTxCounter uint64 + beforeUpdateBalanceTxCounter uint64 + UpdateBalanceTxMock mUserRepositoryMockUpdateBalanceTx } // NewUserRepositoryMock returns a mock for mm_repository.UserRepository @@ -80,6 +102,9 @@ func NewUserRepositoryMock(t minimock.Tester) *UserRepositoryMock { m.CheckInviteLimitMock = mUserRepositoryMockCheckInviteLimit{mock: m} m.CheckInviteLimitMock.callArgs = []*UserRepositoryMockCheckInviteLimitParams{} + m.CheckInviteLimitTxMock = mUserRepositoryMockCheckInviteLimitTx{mock: m} + m.CheckInviteLimitTxMock.callArgs = []*UserRepositoryMockCheckInviteLimitTxParams{} + m.CreateMock = mUserRepositoryMockCreate{mock: m} m.CreateMock.callArgs = []*UserRepositoryMockCreateParams{} @@ -95,9 +120,15 @@ func NewUserRepositoryMock(t minimock.Tester) *UserRepositoryMock { m.IncrementInvitesIssuedMock = mUserRepositoryMockIncrementInvitesIssued{mock: m} m.IncrementInvitesIssuedMock.callArgs = []*UserRepositoryMockIncrementInvitesIssuedParams{} + m.IncrementInvitesIssuedTxMock = mUserRepositoryMockIncrementInvitesIssuedTx{mock: m} + m.IncrementInvitesIssuedTxMock.callArgs = []*UserRepositoryMockIncrementInvitesIssuedTxParams{} + m.UpdateBalanceMock = mUserRepositoryMockUpdateBalance{mock: m} m.UpdateBalanceMock.callArgs = []*UserRepositoryMockUpdateBalanceParams{} + m.UpdateBalanceTxMock = mUserRepositoryMockUpdateBalanceTx{mock: m} + m.UpdateBalanceTxMock.callArgs = []*UserRepositoryMockUpdateBalanceTxParams{} + t.Cleanup(m.MinimockFinish) return m @@ -446,6 +477,380 @@ func (m *UserRepositoryMock) MinimockCheckInviteLimitInspect() { } } +type mUserRepositoryMockCheckInviteLimitTx struct { + optional bool + mock *UserRepositoryMock + defaultExpectation *UserRepositoryMockCheckInviteLimitTxExpectation + expectations []*UserRepositoryMockCheckInviteLimitTxExpectation + + callArgs []*UserRepositoryMockCheckInviteLimitTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// UserRepositoryMockCheckInviteLimitTxExpectation specifies expectation struct of the UserRepository.CheckInviteLimitTx +type UserRepositoryMockCheckInviteLimitTxExpectation struct { + mock *UserRepositoryMock + params *UserRepositoryMockCheckInviteLimitTxParams + paramPtrs *UserRepositoryMockCheckInviteLimitTxParamPtrs + expectationOrigins UserRepositoryMockCheckInviteLimitTxExpectationOrigins + results *UserRepositoryMockCheckInviteLimitTxResults + returnOrigin string + Counter uint64 +} + +// UserRepositoryMockCheckInviteLimitTxParams contains parameters of the UserRepository.CheckInviteLimitTx +type UserRepositoryMockCheckInviteLimitTxParams struct { + ctx context.Context + tx pgx.Tx + userID int +} + +// UserRepositoryMockCheckInviteLimitTxParamPtrs contains pointers to parameters of the UserRepository.CheckInviteLimitTx +type UserRepositoryMockCheckInviteLimitTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + userID *int +} + +// UserRepositoryMockCheckInviteLimitTxResults contains results of the UserRepository.CheckInviteLimitTx +type UserRepositoryMockCheckInviteLimitTxResults struct { + b1 bool + err error +} + +// UserRepositoryMockCheckInviteLimitTxOrigins contains origins of expectations of the UserRepository.CheckInviteLimitTx +type UserRepositoryMockCheckInviteLimitTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originUserID string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Optional() *mUserRepositoryMockCheckInviteLimitTx { + mmCheckInviteLimitTx.optional = true + return mmCheckInviteLimitTx +} + +// Expect sets up expected params for UserRepository.CheckInviteLimitTx +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Expect(ctx context.Context, tx pgx.Tx, userID int) *mUserRepositoryMockCheckInviteLimitTx { + if mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Set") + } + + if mmCheckInviteLimitTx.defaultExpectation == nil { + mmCheckInviteLimitTx.defaultExpectation = &UserRepositoryMockCheckInviteLimitTxExpectation{} + } + + if mmCheckInviteLimitTx.defaultExpectation.paramPtrs != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by ExpectParams functions") + } + + mmCheckInviteLimitTx.defaultExpectation.params = &UserRepositoryMockCheckInviteLimitTxParams{ctx, tx, userID} + mmCheckInviteLimitTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmCheckInviteLimitTx.expectations { + if minimock.Equal(e.params, mmCheckInviteLimitTx.defaultExpectation.params) { + mmCheckInviteLimitTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmCheckInviteLimitTx.defaultExpectation.params) + } + } + + return mmCheckInviteLimitTx +} + +// ExpectCtxParam1 sets up expected param ctx for UserRepository.CheckInviteLimitTx +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) ExpectCtxParam1(ctx context.Context) *mUserRepositoryMockCheckInviteLimitTx { + if mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Set") + } + + if mmCheckInviteLimitTx.defaultExpectation == nil { + mmCheckInviteLimitTx.defaultExpectation = &UserRepositoryMockCheckInviteLimitTxExpectation{} + } + + if mmCheckInviteLimitTx.defaultExpectation.params != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Expect") + } + + if mmCheckInviteLimitTx.defaultExpectation.paramPtrs == nil { + mmCheckInviteLimitTx.defaultExpectation.paramPtrs = &UserRepositoryMockCheckInviteLimitTxParamPtrs{} + } + mmCheckInviteLimitTx.defaultExpectation.paramPtrs.ctx = &ctx + mmCheckInviteLimitTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmCheckInviteLimitTx +} + +// ExpectTxParam2 sets up expected param tx for UserRepository.CheckInviteLimitTx +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) ExpectTxParam2(tx pgx.Tx) *mUserRepositoryMockCheckInviteLimitTx { + if mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Set") + } + + if mmCheckInviteLimitTx.defaultExpectation == nil { + mmCheckInviteLimitTx.defaultExpectation = &UserRepositoryMockCheckInviteLimitTxExpectation{} + } + + if mmCheckInviteLimitTx.defaultExpectation.params != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Expect") + } + + if mmCheckInviteLimitTx.defaultExpectation.paramPtrs == nil { + mmCheckInviteLimitTx.defaultExpectation.paramPtrs = &UserRepositoryMockCheckInviteLimitTxParamPtrs{} + } + mmCheckInviteLimitTx.defaultExpectation.paramPtrs.tx = &tx + mmCheckInviteLimitTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmCheckInviteLimitTx +} + +// ExpectUserIDParam3 sets up expected param userID for UserRepository.CheckInviteLimitTx +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) ExpectUserIDParam3(userID int) *mUserRepositoryMockCheckInviteLimitTx { + if mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Set") + } + + if mmCheckInviteLimitTx.defaultExpectation == nil { + mmCheckInviteLimitTx.defaultExpectation = &UserRepositoryMockCheckInviteLimitTxExpectation{} + } + + if mmCheckInviteLimitTx.defaultExpectation.params != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Expect") + } + + if mmCheckInviteLimitTx.defaultExpectation.paramPtrs == nil { + mmCheckInviteLimitTx.defaultExpectation.paramPtrs = &UserRepositoryMockCheckInviteLimitTxParamPtrs{} + } + mmCheckInviteLimitTx.defaultExpectation.paramPtrs.userID = &userID + mmCheckInviteLimitTx.defaultExpectation.expectationOrigins.originUserID = minimock.CallerInfo(1) + + return mmCheckInviteLimitTx +} + +// Inspect accepts an inspector function that has same arguments as the UserRepository.CheckInviteLimitTx +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Inspect(f func(ctx context.Context, tx pgx.Tx, userID int)) *mUserRepositoryMockCheckInviteLimitTx { + if mmCheckInviteLimitTx.mock.inspectFuncCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("Inspect function is already set for UserRepositoryMock.CheckInviteLimitTx") + } + + mmCheckInviteLimitTx.mock.inspectFuncCheckInviteLimitTx = f + + return mmCheckInviteLimitTx +} + +// Return sets up results that will be returned by UserRepository.CheckInviteLimitTx +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Return(b1 bool, err error) *UserRepositoryMock { + if mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Set") + } + + if mmCheckInviteLimitTx.defaultExpectation == nil { + mmCheckInviteLimitTx.defaultExpectation = &UserRepositoryMockCheckInviteLimitTxExpectation{mock: mmCheckInviteLimitTx.mock} + } + mmCheckInviteLimitTx.defaultExpectation.results = &UserRepositoryMockCheckInviteLimitTxResults{b1, err} + mmCheckInviteLimitTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmCheckInviteLimitTx.mock +} + +// Set uses given function f to mock the UserRepository.CheckInviteLimitTx method +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Set(f func(ctx context.Context, tx pgx.Tx, userID int) (b1 bool, err error)) *UserRepositoryMock { + if mmCheckInviteLimitTx.defaultExpectation != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("Default expectation is already set for the UserRepository.CheckInviteLimitTx method") + } + + if len(mmCheckInviteLimitTx.expectations) > 0 { + mmCheckInviteLimitTx.mock.t.Fatalf("Some expectations are already set for the UserRepository.CheckInviteLimitTx method") + } + + mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx = f + mmCheckInviteLimitTx.mock.funcCheckInviteLimitTxOrigin = minimock.CallerInfo(1) + return mmCheckInviteLimitTx.mock +} + +// When sets expectation for the UserRepository.CheckInviteLimitTx which will trigger the result defined by the following +// Then helper +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) When(ctx context.Context, tx pgx.Tx, userID int) *UserRepositoryMockCheckInviteLimitTxExpectation { + if mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.mock.t.Fatalf("UserRepositoryMock.CheckInviteLimitTx mock is already set by Set") + } + + expectation := &UserRepositoryMockCheckInviteLimitTxExpectation{ + mock: mmCheckInviteLimitTx.mock, + params: &UserRepositoryMockCheckInviteLimitTxParams{ctx, tx, userID}, + expectationOrigins: UserRepositoryMockCheckInviteLimitTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmCheckInviteLimitTx.expectations = append(mmCheckInviteLimitTx.expectations, expectation) + return expectation +} + +// Then sets up UserRepository.CheckInviteLimitTx return parameters for the expectation previously defined by the When method +func (e *UserRepositoryMockCheckInviteLimitTxExpectation) Then(b1 bool, err error) *UserRepositoryMock { + e.results = &UserRepositoryMockCheckInviteLimitTxResults{b1, err} + return e.mock +} + +// Times sets number of times UserRepository.CheckInviteLimitTx should be invoked +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Times(n uint64) *mUserRepositoryMockCheckInviteLimitTx { + if n == 0 { + mmCheckInviteLimitTx.mock.t.Fatalf("Times of UserRepositoryMock.CheckInviteLimitTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmCheckInviteLimitTx.expectedInvocations, n) + mmCheckInviteLimitTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmCheckInviteLimitTx +} + +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) invocationsDone() bool { + if len(mmCheckInviteLimitTx.expectations) == 0 && mmCheckInviteLimitTx.defaultExpectation == nil && mmCheckInviteLimitTx.mock.funcCheckInviteLimitTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmCheckInviteLimitTx.mock.afterCheckInviteLimitTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmCheckInviteLimitTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// CheckInviteLimitTx implements mm_repository.UserRepository +func (mmCheckInviteLimitTx *UserRepositoryMock) CheckInviteLimitTx(ctx context.Context, tx pgx.Tx, userID int) (b1 bool, err error) { + mm_atomic.AddUint64(&mmCheckInviteLimitTx.beforeCheckInviteLimitTxCounter, 1) + defer mm_atomic.AddUint64(&mmCheckInviteLimitTx.afterCheckInviteLimitTxCounter, 1) + + mmCheckInviteLimitTx.t.Helper() + + if mmCheckInviteLimitTx.inspectFuncCheckInviteLimitTx != nil { + mmCheckInviteLimitTx.inspectFuncCheckInviteLimitTx(ctx, tx, userID) + } + + mm_params := UserRepositoryMockCheckInviteLimitTxParams{ctx, tx, userID} + + // Record call args + mmCheckInviteLimitTx.CheckInviteLimitTxMock.mutex.Lock() + mmCheckInviteLimitTx.CheckInviteLimitTxMock.callArgs = append(mmCheckInviteLimitTx.CheckInviteLimitTxMock.callArgs, &mm_params) + mmCheckInviteLimitTx.CheckInviteLimitTxMock.mutex.Unlock() + + for _, e := range mmCheckInviteLimitTx.CheckInviteLimitTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.b1, e.results.err + } + } + + if mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.Counter, 1) + mm_want := mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.params + mm_want_ptrs := mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.paramPtrs + + mm_got := UserRepositoryMockCheckInviteLimitTxParams{ctx, tx, userID} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmCheckInviteLimitTx.t.Errorf("UserRepositoryMock.CheckInviteLimitTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmCheckInviteLimitTx.t.Errorf("UserRepositoryMock.CheckInviteLimitTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.userID != nil && !minimock.Equal(*mm_want_ptrs.userID, mm_got.userID) { + mmCheckInviteLimitTx.t.Errorf("UserRepositoryMock.CheckInviteLimitTx got unexpected parameter userID, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.expectationOrigins.originUserID, *mm_want_ptrs.userID, mm_got.userID, minimock.Diff(*mm_want_ptrs.userID, mm_got.userID)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmCheckInviteLimitTx.t.Errorf("UserRepositoryMock.CheckInviteLimitTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmCheckInviteLimitTx.CheckInviteLimitTxMock.defaultExpectation.results + if mm_results == nil { + mmCheckInviteLimitTx.t.Fatal("No results are set for the UserRepositoryMock.CheckInviteLimitTx") + } + return (*mm_results).b1, (*mm_results).err + } + if mmCheckInviteLimitTx.funcCheckInviteLimitTx != nil { + return mmCheckInviteLimitTx.funcCheckInviteLimitTx(ctx, tx, userID) + } + mmCheckInviteLimitTx.t.Fatalf("Unexpected call to UserRepositoryMock.CheckInviteLimitTx. %v %v %v", ctx, tx, userID) + return +} + +// CheckInviteLimitTxAfterCounter returns a count of finished UserRepositoryMock.CheckInviteLimitTx invocations +func (mmCheckInviteLimitTx *UserRepositoryMock) CheckInviteLimitTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmCheckInviteLimitTx.afterCheckInviteLimitTxCounter) +} + +// CheckInviteLimitTxBeforeCounter returns a count of UserRepositoryMock.CheckInviteLimitTx invocations +func (mmCheckInviteLimitTx *UserRepositoryMock) CheckInviteLimitTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmCheckInviteLimitTx.beforeCheckInviteLimitTxCounter) +} + +// Calls returns a list of arguments used in each call to UserRepositoryMock.CheckInviteLimitTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmCheckInviteLimitTx *mUserRepositoryMockCheckInviteLimitTx) Calls() []*UserRepositoryMockCheckInviteLimitTxParams { + mmCheckInviteLimitTx.mutex.RLock() + + argCopy := make([]*UserRepositoryMockCheckInviteLimitTxParams, len(mmCheckInviteLimitTx.callArgs)) + copy(argCopy, mmCheckInviteLimitTx.callArgs) + + mmCheckInviteLimitTx.mutex.RUnlock() + + return argCopy +} + +// MinimockCheckInviteLimitTxDone returns true if the count of the CheckInviteLimitTx invocations corresponds +// the number of defined expectations +func (m *UserRepositoryMock) MinimockCheckInviteLimitTxDone() bool { + if m.CheckInviteLimitTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.CheckInviteLimitTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.CheckInviteLimitTxMock.invocationsDone() +} + +// MinimockCheckInviteLimitTxInspect logs each unmet expectation +func (m *UserRepositoryMock) MinimockCheckInviteLimitTxInspect() { + for _, e := range m.CheckInviteLimitTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to UserRepositoryMock.CheckInviteLimitTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterCheckInviteLimitTxCounter := mm_atomic.LoadUint64(&m.afterCheckInviteLimitTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.CheckInviteLimitTxMock.defaultExpectation != nil && afterCheckInviteLimitTxCounter < 1 { + if m.CheckInviteLimitTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to UserRepositoryMock.CheckInviteLimitTx at\n%s", m.CheckInviteLimitTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to UserRepositoryMock.CheckInviteLimitTx at\n%s with params: %#v", m.CheckInviteLimitTxMock.defaultExpectation.expectationOrigins.origin, *m.CheckInviteLimitTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcCheckInviteLimitTx != nil && afterCheckInviteLimitTxCounter < 1 { + m.t.Errorf("Expected call to UserRepositoryMock.CheckInviteLimitTx at\n%s", m.funcCheckInviteLimitTxOrigin) + } + + if !m.CheckInviteLimitTxMock.invocationsDone() && afterCheckInviteLimitTxCounter > 0 { + m.t.Errorf("Expected %d calls to UserRepositoryMock.CheckInviteLimitTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.CheckInviteLimitTxMock.expectedInvocations), m.CheckInviteLimitTxMock.expectedInvocationsOrigin, afterCheckInviteLimitTxCounter) + } +} + type mUserRepositoryMockCreate struct { optional bool mock *UserRepositoryMock @@ -2159,6 +2564,379 @@ func (m *UserRepositoryMock) MinimockIncrementInvitesIssuedInspect() { } } +type mUserRepositoryMockIncrementInvitesIssuedTx struct { + optional bool + mock *UserRepositoryMock + defaultExpectation *UserRepositoryMockIncrementInvitesIssuedTxExpectation + expectations []*UserRepositoryMockIncrementInvitesIssuedTxExpectation + + callArgs []*UserRepositoryMockIncrementInvitesIssuedTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// UserRepositoryMockIncrementInvitesIssuedTxExpectation specifies expectation struct of the UserRepository.IncrementInvitesIssuedTx +type UserRepositoryMockIncrementInvitesIssuedTxExpectation struct { + mock *UserRepositoryMock + params *UserRepositoryMockIncrementInvitesIssuedTxParams + paramPtrs *UserRepositoryMockIncrementInvitesIssuedTxParamPtrs + expectationOrigins UserRepositoryMockIncrementInvitesIssuedTxExpectationOrigins + results *UserRepositoryMockIncrementInvitesIssuedTxResults + returnOrigin string + Counter uint64 +} + +// UserRepositoryMockIncrementInvitesIssuedTxParams contains parameters of the UserRepository.IncrementInvitesIssuedTx +type UserRepositoryMockIncrementInvitesIssuedTxParams struct { + ctx context.Context + tx pgx.Tx + userID int +} + +// UserRepositoryMockIncrementInvitesIssuedTxParamPtrs contains pointers to parameters of the UserRepository.IncrementInvitesIssuedTx +type UserRepositoryMockIncrementInvitesIssuedTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + userID *int +} + +// UserRepositoryMockIncrementInvitesIssuedTxResults contains results of the UserRepository.IncrementInvitesIssuedTx +type UserRepositoryMockIncrementInvitesIssuedTxResults struct { + err error +} + +// UserRepositoryMockIncrementInvitesIssuedTxOrigins contains origins of expectations of the UserRepository.IncrementInvitesIssuedTx +type UserRepositoryMockIncrementInvitesIssuedTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originUserID string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Optional() *mUserRepositoryMockIncrementInvitesIssuedTx { + mmIncrementInvitesIssuedTx.optional = true + return mmIncrementInvitesIssuedTx +} + +// Expect sets up expected params for UserRepository.IncrementInvitesIssuedTx +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Expect(ctx context.Context, tx pgx.Tx, userID int) *mUserRepositoryMockIncrementInvitesIssuedTx { + if mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Set") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation == nil { + mmIncrementInvitesIssuedTx.defaultExpectation = &UserRepositoryMockIncrementInvitesIssuedTxExpectation{} + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by ExpectParams functions") + } + + mmIncrementInvitesIssuedTx.defaultExpectation.params = &UserRepositoryMockIncrementInvitesIssuedTxParams{ctx, tx, userID} + mmIncrementInvitesIssuedTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmIncrementInvitesIssuedTx.expectations { + if minimock.Equal(e.params, mmIncrementInvitesIssuedTx.defaultExpectation.params) { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmIncrementInvitesIssuedTx.defaultExpectation.params) + } + } + + return mmIncrementInvitesIssuedTx +} + +// ExpectCtxParam1 sets up expected param ctx for UserRepository.IncrementInvitesIssuedTx +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) ExpectCtxParam1(ctx context.Context) *mUserRepositoryMockIncrementInvitesIssuedTx { + if mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Set") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation == nil { + mmIncrementInvitesIssuedTx.defaultExpectation = &UserRepositoryMockIncrementInvitesIssuedTxExpectation{} + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.params != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Expect") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs == nil { + mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs = &UserRepositoryMockIncrementInvitesIssuedTxParamPtrs{} + } + mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs.ctx = &ctx + mmIncrementInvitesIssuedTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmIncrementInvitesIssuedTx +} + +// ExpectTxParam2 sets up expected param tx for UserRepository.IncrementInvitesIssuedTx +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) ExpectTxParam2(tx pgx.Tx) *mUserRepositoryMockIncrementInvitesIssuedTx { + if mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Set") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation == nil { + mmIncrementInvitesIssuedTx.defaultExpectation = &UserRepositoryMockIncrementInvitesIssuedTxExpectation{} + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.params != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Expect") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs == nil { + mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs = &UserRepositoryMockIncrementInvitesIssuedTxParamPtrs{} + } + mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs.tx = &tx + mmIncrementInvitesIssuedTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmIncrementInvitesIssuedTx +} + +// ExpectUserIDParam3 sets up expected param userID for UserRepository.IncrementInvitesIssuedTx +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) ExpectUserIDParam3(userID int) *mUserRepositoryMockIncrementInvitesIssuedTx { + if mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Set") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation == nil { + mmIncrementInvitesIssuedTx.defaultExpectation = &UserRepositoryMockIncrementInvitesIssuedTxExpectation{} + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.params != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Expect") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs == nil { + mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs = &UserRepositoryMockIncrementInvitesIssuedTxParamPtrs{} + } + mmIncrementInvitesIssuedTx.defaultExpectation.paramPtrs.userID = &userID + mmIncrementInvitesIssuedTx.defaultExpectation.expectationOrigins.originUserID = minimock.CallerInfo(1) + + return mmIncrementInvitesIssuedTx +} + +// Inspect accepts an inspector function that has same arguments as the UserRepository.IncrementInvitesIssuedTx +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Inspect(f func(ctx context.Context, tx pgx.Tx, userID int)) *mUserRepositoryMockIncrementInvitesIssuedTx { + if mmIncrementInvitesIssuedTx.mock.inspectFuncIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("Inspect function is already set for UserRepositoryMock.IncrementInvitesIssuedTx") + } + + mmIncrementInvitesIssuedTx.mock.inspectFuncIncrementInvitesIssuedTx = f + + return mmIncrementInvitesIssuedTx +} + +// Return sets up results that will be returned by UserRepository.IncrementInvitesIssuedTx +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Return(err error) *UserRepositoryMock { + if mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Set") + } + + if mmIncrementInvitesIssuedTx.defaultExpectation == nil { + mmIncrementInvitesIssuedTx.defaultExpectation = &UserRepositoryMockIncrementInvitesIssuedTxExpectation{mock: mmIncrementInvitesIssuedTx.mock} + } + mmIncrementInvitesIssuedTx.defaultExpectation.results = &UserRepositoryMockIncrementInvitesIssuedTxResults{err} + mmIncrementInvitesIssuedTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmIncrementInvitesIssuedTx.mock +} + +// Set uses given function f to mock the UserRepository.IncrementInvitesIssuedTx method +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Set(f func(ctx context.Context, tx pgx.Tx, userID int) (err error)) *UserRepositoryMock { + if mmIncrementInvitesIssuedTx.defaultExpectation != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("Default expectation is already set for the UserRepository.IncrementInvitesIssuedTx method") + } + + if len(mmIncrementInvitesIssuedTx.expectations) > 0 { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("Some expectations are already set for the UserRepository.IncrementInvitesIssuedTx method") + } + + mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx = f + mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTxOrigin = minimock.CallerInfo(1) + return mmIncrementInvitesIssuedTx.mock +} + +// When sets expectation for the UserRepository.IncrementInvitesIssuedTx which will trigger the result defined by the following +// Then helper +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) When(ctx context.Context, tx pgx.Tx, userID int) *UserRepositoryMockIncrementInvitesIssuedTxExpectation { + if mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("UserRepositoryMock.IncrementInvitesIssuedTx mock is already set by Set") + } + + expectation := &UserRepositoryMockIncrementInvitesIssuedTxExpectation{ + mock: mmIncrementInvitesIssuedTx.mock, + params: &UserRepositoryMockIncrementInvitesIssuedTxParams{ctx, tx, userID}, + expectationOrigins: UserRepositoryMockIncrementInvitesIssuedTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmIncrementInvitesIssuedTx.expectations = append(mmIncrementInvitesIssuedTx.expectations, expectation) + return expectation +} + +// Then sets up UserRepository.IncrementInvitesIssuedTx return parameters for the expectation previously defined by the When method +func (e *UserRepositoryMockIncrementInvitesIssuedTxExpectation) Then(err error) *UserRepositoryMock { + e.results = &UserRepositoryMockIncrementInvitesIssuedTxResults{err} + return e.mock +} + +// Times sets number of times UserRepository.IncrementInvitesIssuedTx should be invoked +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Times(n uint64) *mUserRepositoryMockIncrementInvitesIssuedTx { + if n == 0 { + mmIncrementInvitesIssuedTx.mock.t.Fatalf("Times of UserRepositoryMock.IncrementInvitesIssuedTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmIncrementInvitesIssuedTx.expectedInvocations, n) + mmIncrementInvitesIssuedTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmIncrementInvitesIssuedTx +} + +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) invocationsDone() bool { + if len(mmIncrementInvitesIssuedTx.expectations) == 0 && mmIncrementInvitesIssuedTx.defaultExpectation == nil && mmIncrementInvitesIssuedTx.mock.funcIncrementInvitesIssuedTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmIncrementInvitesIssuedTx.mock.afterIncrementInvitesIssuedTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmIncrementInvitesIssuedTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// IncrementInvitesIssuedTx implements mm_repository.UserRepository +func (mmIncrementInvitesIssuedTx *UserRepositoryMock) IncrementInvitesIssuedTx(ctx context.Context, tx pgx.Tx, userID int) (err error) { + mm_atomic.AddUint64(&mmIncrementInvitesIssuedTx.beforeIncrementInvitesIssuedTxCounter, 1) + defer mm_atomic.AddUint64(&mmIncrementInvitesIssuedTx.afterIncrementInvitesIssuedTxCounter, 1) + + mmIncrementInvitesIssuedTx.t.Helper() + + if mmIncrementInvitesIssuedTx.inspectFuncIncrementInvitesIssuedTx != nil { + mmIncrementInvitesIssuedTx.inspectFuncIncrementInvitesIssuedTx(ctx, tx, userID) + } + + mm_params := UserRepositoryMockIncrementInvitesIssuedTxParams{ctx, tx, userID} + + // Record call args + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.mutex.Lock() + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.callArgs = append(mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.callArgs, &mm_params) + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.mutex.Unlock() + + for _, e := range mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.Counter, 1) + mm_want := mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.params + mm_want_ptrs := mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.paramPtrs + + mm_got := UserRepositoryMockIncrementInvitesIssuedTxParams{ctx, tx, userID} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmIncrementInvitesIssuedTx.t.Errorf("UserRepositoryMock.IncrementInvitesIssuedTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmIncrementInvitesIssuedTx.t.Errorf("UserRepositoryMock.IncrementInvitesIssuedTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.userID != nil && !minimock.Equal(*mm_want_ptrs.userID, mm_got.userID) { + mmIncrementInvitesIssuedTx.t.Errorf("UserRepositoryMock.IncrementInvitesIssuedTx got unexpected parameter userID, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.expectationOrigins.originUserID, *mm_want_ptrs.userID, mm_got.userID, minimock.Diff(*mm_want_ptrs.userID, mm_got.userID)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmIncrementInvitesIssuedTx.t.Errorf("UserRepositoryMock.IncrementInvitesIssuedTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmIncrementInvitesIssuedTx.IncrementInvitesIssuedTxMock.defaultExpectation.results + if mm_results == nil { + mmIncrementInvitesIssuedTx.t.Fatal("No results are set for the UserRepositoryMock.IncrementInvitesIssuedTx") + } + return (*mm_results).err + } + if mmIncrementInvitesIssuedTx.funcIncrementInvitesIssuedTx != nil { + return mmIncrementInvitesIssuedTx.funcIncrementInvitesIssuedTx(ctx, tx, userID) + } + mmIncrementInvitesIssuedTx.t.Fatalf("Unexpected call to UserRepositoryMock.IncrementInvitesIssuedTx. %v %v %v", ctx, tx, userID) + return +} + +// IncrementInvitesIssuedTxAfterCounter returns a count of finished UserRepositoryMock.IncrementInvitesIssuedTx invocations +func (mmIncrementInvitesIssuedTx *UserRepositoryMock) IncrementInvitesIssuedTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmIncrementInvitesIssuedTx.afterIncrementInvitesIssuedTxCounter) +} + +// IncrementInvitesIssuedTxBeforeCounter returns a count of UserRepositoryMock.IncrementInvitesIssuedTx invocations +func (mmIncrementInvitesIssuedTx *UserRepositoryMock) IncrementInvitesIssuedTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmIncrementInvitesIssuedTx.beforeIncrementInvitesIssuedTxCounter) +} + +// Calls returns a list of arguments used in each call to UserRepositoryMock.IncrementInvitesIssuedTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmIncrementInvitesIssuedTx *mUserRepositoryMockIncrementInvitesIssuedTx) Calls() []*UserRepositoryMockIncrementInvitesIssuedTxParams { + mmIncrementInvitesIssuedTx.mutex.RLock() + + argCopy := make([]*UserRepositoryMockIncrementInvitesIssuedTxParams, len(mmIncrementInvitesIssuedTx.callArgs)) + copy(argCopy, mmIncrementInvitesIssuedTx.callArgs) + + mmIncrementInvitesIssuedTx.mutex.RUnlock() + + return argCopy +} + +// MinimockIncrementInvitesIssuedTxDone returns true if the count of the IncrementInvitesIssuedTx invocations corresponds +// the number of defined expectations +func (m *UserRepositoryMock) MinimockIncrementInvitesIssuedTxDone() bool { + if m.IncrementInvitesIssuedTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.IncrementInvitesIssuedTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.IncrementInvitesIssuedTxMock.invocationsDone() +} + +// MinimockIncrementInvitesIssuedTxInspect logs each unmet expectation +func (m *UserRepositoryMock) MinimockIncrementInvitesIssuedTxInspect() { + for _, e := range m.IncrementInvitesIssuedTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to UserRepositoryMock.IncrementInvitesIssuedTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterIncrementInvitesIssuedTxCounter := mm_atomic.LoadUint64(&m.afterIncrementInvitesIssuedTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.IncrementInvitesIssuedTxMock.defaultExpectation != nil && afterIncrementInvitesIssuedTxCounter < 1 { + if m.IncrementInvitesIssuedTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to UserRepositoryMock.IncrementInvitesIssuedTx at\n%s", m.IncrementInvitesIssuedTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to UserRepositoryMock.IncrementInvitesIssuedTx at\n%s with params: %#v", m.IncrementInvitesIssuedTxMock.defaultExpectation.expectationOrigins.origin, *m.IncrementInvitesIssuedTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcIncrementInvitesIssuedTx != nil && afterIncrementInvitesIssuedTxCounter < 1 { + m.t.Errorf("Expected call to UserRepositoryMock.IncrementInvitesIssuedTx at\n%s", m.funcIncrementInvitesIssuedTxOrigin) + } + + if !m.IncrementInvitesIssuedTxMock.invocationsDone() && afterIncrementInvitesIssuedTxCounter > 0 { + m.t.Errorf("Expected %d calls to UserRepositoryMock.IncrementInvitesIssuedTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.IncrementInvitesIssuedTxMock.expectedInvocations), m.IncrementInvitesIssuedTxMock.expectedInvocationsOrigin, afterIncrementInvitesIssuedTxCounter) + } +} + type mUserRepositoryMockUpdateBalance struct { optional bool mock *UserRepositoryMock @@ -2532,12 +3310,418 @@ func (m *UserRepositoryMock) MinimockUpdateBalanceInspect() { } } +type mUserRepositoryMockUpdateBalanceTx struct { + optional bool + mock *UserRepositoryMock + defaultExpectation *UserRepositoryMockUpdateBalanceTxExpectation + expectations []*UserRepositoryMockUpdateBalanceTxExpectation + + callArgs []*UserRepositoryMockUpdateBalanceTxParams + mutex sync.RWMutex + + expectedInvocations uint64 + expectedInvocationsOrigin string +} + +// UserRepositoryMockUpdateBalanceTxExpectation specifies expectation struct of the UserRepository.UpdateBalanceTx +type UserRepositoryMockUpdateBalanceTxExpectation struct { + mock *UserRepositoryMock + params *UserRepositoryMockUpdateBalanceTxParams + paramPtrs *UserRepositoryMockUpdateBalanceTxParamPtrs + expectationOrigins UserRepositoryMockUpdateBalanceTxExpectationOrigins + results *UserRepositoryMockUpdateBalanceTxResults + returnOrigin string + Counter uint64 +} + +// UserRepositoryMockUpdateBalanceTxParams contains parameters of the UserRepository.UpdateBalanceTx +type UserRepositoryMockUpdateBalanceTxParams struct { + ctx context.Context + tx pgx.Tx + userID int + delta float64 +} + +// UserRepositoryMockUpdateBalanceTxParamPtrs contains pointers to parameters of the UserRepository.UpdateBalanceTx +type UserRepositoryMockUpdateBalanceTxParamPtrs struct { + ctx *context.Context + tx *pgx.Tx + userID *int + delta *float64 +} + +// UserRepositoryMockUpdateBalanceTxResults contains results of the UserRepository.UpdateBalanceTx +type UserRepositoryMockUpdateBalanceTxResults struct { + err error +} + +// UserRepositoryMockUpdateBalanceTxOrigins contains origins of expectations of the UserRepository.UpdateBalanceTx +type UserRepositoryMockUpdateBalanceTxExpectationOrigins struct { + origin string + originCtx string + originTx string + originUserID string + originDelta string +} + +// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning +// the test will fail minimock's automatic final call check if the mocked method was not called at least once. +// Optional() makes method check to work in '0 or more' mode. +// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to +// catch the problems when the expected method call is totally skipped during test run. +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Optional() *mUserRepositoryMockUpdateBalanceTx { + mmUpdateBalanceTx.optional = true + return mmUpdateBalanceTx +} + +// Expect sets up expected params for UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Expect(ctx context.Context, tx pgx.Tx, userID int, delta float64) *mUserRepositoryMockUpdateBalanceTx { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + if mmUpdateBalanceTx.defaultExpectation == nil { + mmUpdateBalanceTx.defaultExpectation = &UserRepositoryMockUpdateBalanceTxExpectation{} + } + + if mmUpdateBalanceTx.defaultExpectation.paramPtrs != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by ExpectParams functions") + } + + mmUpdateBalanceTx.defaultExpectation.params = &UserRepositoryMockUpdateBalanceTxParams{ctx, tx, userID, delta} + mmUpdateBalanceTx.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) + for _, e := range mmUpdateBalanceTx.expectations { + if minimock.Equal(e.params, mmUpdateBalanceTx.defaultExpectation.params) { + mmUpdateBalanceTx.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmUpdateBalanceTx.defaultExpectation.params) + } + } + + return mmUpdateBalanceTx +} + +// ExpectCtxParam1 sets up expected param ctx for UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) ExpectCtxParam1(ctx context.Context) *mUserRepositoryMockUpdateBalanceTx { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + if mmUpdateBalanceTx.defaultExpectation == nil { + mmUpdateBalanceTx.defaultExpectation = &UserRepositoryMockUpdateBalanceTxExpectation{} + } + + if mmUpdateBalanceTx.defaultExpectation.params != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Expect") + } + + if mmUpdateBalanceTx.defaultExpectation.paramPtrs == nil { + mmUpdateBalanceTx.defaultExpectation.paramPtrs = &UserRepositoryMockUpdateBalanceTxParamPtrs{} + } + mmUpdateBalanceTx.defaultExpectation.paramPtrs.ctx = &ctx + mmUpdateBalanceTx.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) + + return mmUpdateBalanceTx +} + +// ExpectTxParam2 sets up expected param tx for UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) ExpectTxParam2(tx pgx.Tx) *mUserRepositoryMockUpdateBalanceTx { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + if mmUpdateBalanceTx.defaultExpectation == nil { + mmUpdateBalanceTx.defaultExpectation = &UserRepositoryMockUpdateBalanceTxExpectation{} + } + + if mmUpdateBalanceTx.defaultExpectation.params != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Expect") + } + + if mmUpdateBalanceTx.defaultExpectation.paramPtrs == nil { + mmUpdateBalanceTx.defaultExpectation.paramPtrs = &UserRepositoryMockUpdateBalanceTxParamPtrs{} + } + mmUpdateBalanceTx.defaultExpectation.paramPtrs.tx = &tx + mmUpdateBalanceTx.defaultExpectation.expectationOrigins.originTx = minimock.CallerInfo(1) + + return mmUpdateBalanceTx +} + +// ExpectUserIDParam3 sets up expected param userID for UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) ExpectUserIDParam3(userID int) *mUserRepositoryMockUpdateBalanceTx { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + if mmUpdateBalanceTx.defaultExpectation == nil { + mmUpdateBalanceTx.defaultExpectation = &UserRepositoryMockUpdateBalanceTxExpectation{} + } + + if mmUpdateBalanceTx.defaultExpectation.params != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Expect") + } + + if mmUpdateBalanceTx.defaultExpectation.paramPtrs == nil { + mmUpdateBalanceTx.defaultExpectation.paramPtrs = &UserRepositoryMockUpdateBalanceTxParamPtrs{} + } + mmUpdateBalanceTx.defaultExpectation.paramPtrs.userID = &userID + mmUpdateBalanceTx.defaultExpectation.expectationOrigins.originUserID = minimock.CallerInfo(1) + + return mmUpdateBalanceTx +} + +// ExpectDeltaParam4 sets up expected param delta for UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) ExpectDeltaParam4(delta float64) *mUserRepositoryMockUpdateBalanceTx { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + if mmUpdateBalanceTx.defaultExpectation == nil { + mmUpdateBalanceTx.defaultExpectation = &UserRepositoryMockUpdateBalanceTxExpectation{} + } + + if mmUpdateBalanceTx.defaultExpectation.params != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Expect") + } + + if mmUpdateBalanceTx.defaultExpectation.paramPtrs == nil { + mmUpdateBalanceTx.defaultExpectation.paramPtrs = &UserRepositoryMockUpdateBalanceTxParamPtrs{} + } + mmUpdateBalanceTx.defaultExpectation.paramPtrs.delta = &delta + mmUpdateBalanceTx.defaultExpectation.expectationOrigins.originDelta = minimock.CallerInfo(1) + + return mmUpdateBalanceTx +} + +// Inspect accepts an inspector function that has same arguments as the UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Inspect(f func(ctx context.Context, tx pgx.Tx, userID int, delta float64)) *mUserRepositoryMockUpdateBalanceTx { + if mmUpdateBalanceTx.mock.inspectFuncUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("Inspect function is already set for UserRepositoryMock.UpdateBalanceTx") + } + + mmUpdateBalanceTx.mock.inspectFuncUpdateBalanceTx = f + + return mmUpdateBalanceTx +} + +// Return sets up results that will be returned by UserRepository.UpdateBalanceTx +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Return(err error) *UserRepositoryMock { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + if mmUpdateBalanceTx.defaultExpectation == nil { + mmUpdateBalanceTx.defaultExpectation = &UserRepositoryMockUpdateBalanceTxExpectation{mock: mmUpdateBalanceTx.mock} + } + mmUpdateBalanceTx.defaultExpectation.results = &UserRepositoryMockUpdateBalanceTxResults{err} + mmUpdateBalanceTx.defaultExpectation.returnOrigin = minimock.CallerInfo(1) + return mmUpdateBalanceTx.mock +} + +// Set uses given function f to mock the UserRepository.UpdateBalanceTx method +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Set(f func(ctx context.Context, tx pgx.Tx, userID int, delta float64) (err error)) *UserRepositoryMock { + if mmUpdateBalanceTx.defaultExpectation != nil { + mmUpdateBalanceTx.mock.t.Fatalf("Default expectation is already set for the UserRepository.UpdateBalanceTx method") + } + + if len(mmUpdateBalanceTx.expectations) > 0 { + mmUpdateBalanceTx.mock.t.Fatalf("Some expectations are already set for the UserRepository.UpdateBalanceTx method") + } + + mmUpdateBalanceTx.mock.funcUpdateBalanceTx = f + mmUpdateBalanceTx.mock.funcUpdateBalanceTxOrigin = minimock.CallerInfo(1) + return mmUpdateBalanceTx.mock +} + +// When sets expectation for the UserRepository.UpdateBalanceTx which will trigger the result defined by the following +// Then helper +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) When(ctx context.Context, tx pgx.Tx, userID int, delta float64) *UserRepositoryMockUpdateBalanceTxExpectation { + if mmUpdateBalanceTx.mock.funcUpdateBalanceTx != nil { + mmUpdateBalanceTx.mock.t.Fatalf("UserRepositoryMock.UpdateBalanceTx mock is already set by Set") + } + + expectation := &UserRepositoryMockUpdateBalanceTxExpectation{ + mock: mmUpdateBalanceTx.mock, + params: &UserRepositoryMockUpdateBalanceTxParams{ctx, tx, userID, delta}, + expectationOrigins: UserRepositoryMockUpdateBalanceTxExpectationOrigins{origin: minimock.CallerInfo(1)}, + } + mmUpdateBalanceTx.expectations = append(mmUpdateBalanceTx.expectations, expectation) + return expectation +} + +// Then sets up UserRepository.UpdateBalanceTx return parameters for the expectation previously defined by the When method +func (e *UserRepositoryMockUpdateBalanceTxExpectation) Then(err error) *UserRepositoryMock { + e.results = &UserRepositoryMockUpdateBalanceTxResults{err} + return e.mock +} + +// Times sets number of times UserRepository.UpdateBalanceTx should be invoked +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Times(n uint64) *mUserRepositoryMockUpdateBalanceTx { + if n == 0 { + mmUpdateBalanceTx.mock.t.Fatalf("Times of UserRepositoryMock.UpdateBalanceTx mock can not be zero") + } + mm_atomic.StoreUint64(&mmUpdateBalanceTx.expectedInvocations, n) + mmUpdateBalanceTx.expectedInvocationsOrigin = minimock.CallerInfo(1) + return mmUpdateBalanceTx +} + +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) invocationsDone() bool { + if len(mmUpdateBalanceTx.expectations) == 0 && mmUpdateBalanceTx.defaultExpectation == nil && mmUpdateBalanceTx.mock.funcUpdateBalanceTx == nil { + return true + } + + totalInvocations := mm_atomic.LoadUint64(&mmUpdateBalanceTx.mock.afterUpdateBalanceTxCounter) + expectedInvocations := mm_atomic.LoadUint64(&mmUpdateBalanceTx.expectedInvocations) + + return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) +} + +// UpdateBalanceTx implements mm_repository.UserRepository +func (mmUpdateBalanceTx *UserRepositoryMock) UpdateBalanceTx(ctx context.Context, tx pgx.Tx, userID int, delta float64) (err error) { + mm_atomic.AddUint64(&mmUpdateBalanceTx.beforeUpdateBalanceTxCounter, 1) + defer mm_atomic.AddUint64(&mmUpdateBalanceTx.afterUpdateBalanceTxCounter, 1) + + mmUpdateBalanceTx.t.Helper() + + if mmUpdateBalanceTx.inspectFuncUpdateBalanceTx != nil { + mmUpdateBalanceTx.inspectFuncUpdateBalanceTx(ctx, tx, userID, delta) + } + + mm_params := UserRepositoryMockUpdateBalanceTxParams{ctx, tx, userID, delta} + + // Record call args + mmUpdateBalanceTx.UpdateBalanceTxMock.mutex.Lock() + mmUpdateBalanceTx.UpdateBalanceTxMock.callArgs = append(mmUpdateBalanceTx.UpdateBalanceTxMock.callArgs, &mm_params) + mmUpdateBalanceTx.UpdateBalanceTxMock.mutex.Unlock() + + for _, e := range mmUpdateBalanceTx.UpdateBalanceTxMock.expectations { + if minimock.Equal(*e.params, mm_params) { + mm_atomic.AddUint64(&e.Counter, 1) + return e.results.err + } + } + + if mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation != nil { + mm_atomic.AddUint64(&mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.Counter, 1) + mm_want := mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.params + mm_want_ptrs := mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.paramPtrs + + mm_got := UserRepositoryMockUpdateBalanceTxParams{ctx, tx, userID, delta} + + if mm_want_ptrs != nil { + + if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { + mmUpdateBalanceTx.t.Errorf("UserRepositoryMock.UpdateBalanceTx got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) + } + + if mm_want_ptrs.tx != nil && !minimock.Equal(*mm_want_ptrs.tx, mm_got.tx) { + mmUpdateBalanceTx.t.Errorf("UserRepositoryMock.UpdateBalanceTx got unexpected parameter tx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.expectationOrigins.originTx, *mm_want_ptrs.tx, mm_got.tx, minimock.Diff(*mm_want_ptrs.tx, mm_got.tx)) + } + + if mm_want_ptrs.userID != nil && !minimock.Equal(*mm_want_ptrs.userID, mm_got.userID) { + mmUpdateBalanceTx.t.Errorf("UserRepositoryMock.UpdateBalanceTx got unexpected parameter userID, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.expectationOrigins.originUserID, *mm_want_ptrs.userID, mm_got.userID, minimock.Diff(*mm_want_ptrs.userID, mm_got.userID)) + } + + if mm_want_ptrs.delta != nil && !minimock.Equal(*mm_want_ptrs.delta, mm_got.delta) { + mmUpdateBalanceTx.t.Errorf("UserRepositoryMock.UpdateBalanceTx got unexpected parameter delta, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.expectationOrigins.originDelta, *mm_want_ptrs.delta, mm_got.delta, minimock.Diff(*mm_want_ptrs.delta, mm_got.delta)) + } + + } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { + mmUpdateBalanceTx.t.Errorf("UserRepositoryMock.UpdateBalanceTx got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", + mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) + } + + mm_results := mmUpdateBalanceTx.UpdateBalanceTxMock.defaultExpectation.results + if mm_results == nil { + mmUpdateBalanceTx.t.Fatal("No results are set for the UserRepositoryMock.UpdateBalanceTx") + } + return (*mm_results).err + } + if mmUpdateBalanceTx.funcUpdateBalanceTx != nil { + return mmUpdateBalanceTx.funcUpdateBalanceTx(ctx, tx, userID, delta) + } + mmUpdateBalanceTx.t.Fatalf("Unexpected call to UserRepositoryMock.UpdateBalanceTx. %v %v %v %v", ctx, tx, userID, delta) + return +} + +// UpdateBalanceTxAfterCounter returns a count of finished UserRepositoryMock.UpdateBalanceTx invocations +func (mmUpdateBalanceTx *UserRepositoryMock) UpdateBalanceTxAfterCounter() uint64 { + return mm_atomic.LoadUint64(&mmUpdateBalanceTx.afterUpdateBalanceTxCounter) +} + +// UpdateBalanceTxBeforeCounter returns a count of UserRepositoryMock.UpdateBalanceTx invocations +func (mmUpdateBalanceTx *UserRepositoryMock) UpdateBalanceTxBeforeCounter() uint64 { + return mm_atomic.LoadUint64(&mmUpdateBalanceTx.beforeUpdateBalanceTxCounter) +} + +// Calls returns a list of arguments used in each call to UserRepositoryMock.UpdateBalanceTx. +// The list is in the same order as the calls were made (i.e. recent calls have a higher index) +func (mmUpdateBalanceTx *mUserRepositoryMockUpdateBalanceTx) Calls() []*UserRepositoryMockUpdateBalanceTxParams { + mmUpdateBalanceTx.mutex.RLock() + + argCopy := make([]*UserRepositoryMockUpdateBalanceTxParams, len(mmUpdateBalanceTx.callArgs)) + copy(argCopy, mmUpdateBalanceTx.callArgs) + + mmUpdateBalanceTx.mutex.RUnlock() + + return argCopy +} + +// MinimockUpdateBalanceTxDone returns true if the count of the UpdateBalanceTx invocations corresponds +// the number of defined expectations +func (m *UserRepositoryMock) MinimockUpdateBalanceTxDone() bool { + if m.UpdateBalanceTxMock.optional { + // Optional methods provide '0 or more' call count restriction. + return true + } + + for _, e := range m.UpdateBalanceTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + return false + } + } + + return m.UpdateBalanceTxMock.invocationsDone() +} + +// MinimockUpdateBalanceTxInspect logs each unmet expectation +func (m *UserRepositoryMock) MinimockUpdateBalanceTxInspect() { + for _, e := range m.UpdateBalanceTxMock.expectations { + if mm_atomic.LoadUint64(&e.Counter) < 1 { + m.t.Errorf("Expected call to UserRepositoryMock.UpdateBalanceTx at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) + } + } + + afterUpdateBalanceTxCounter := mm_atomic.LoadUint64(&m.afterUpdateBalanceTxCounter) + // if default expectation was set then invocations count should be greater than zero + if m.UpdateBalanceTxMock.defaultExpectation != nil && afterUpdateBalanceTxCounter < 1 { + if m.UpdateBalanceTxMock.defaultExpectation.params == nil { + m.t.Errorf("Expected call to UserRepositoryMock.UpdateBalanceTx at\n%s", m.UpdateBalanceTxMock.defaultExpectation.returnOrigin) + } else { + m.t.Errorf("Expected call to UserRepositoryMock.UpdateBalanceTx at\n%s with params: %#v", m.UpdateBalanceTxMock.defaultExpectation.expectationOrigins.origin, *m.UpdateBalanceTxMock.defaultExpectation.params) + } + } + // if func was set then invocations count should be greater than zero + if m.funcUpdateBalanceTx != nil && afterUpdateBalanceTxCounter < 1 { + m.t.Errorf("Expected call to UserRepositoryMock.UpdateBalanceTx at\n%s", m.funcUpdateBalanceTxOrigin) + } + + if !m.UpdateBalanceTxMock.invocationsDone() && afterUpdateBalanceTxCounter > 0 { + m.t.Errorf("Expected %d calls to UserRepositoryMock.UpdateBalanceTx at\n%s but found %d calls", + mm_atomic.LoadUint64(&m.UpdateBalanceTxMock.expectedInvocations), m.UpdateBalanceTxMock.expectedInvocationsOrigin, afterUpdateBalanceTxCounter) + } +} + // MinimockFinish checks that all mocked methods have been called the expected number of times func (m *UserRepositoryMock) MinimockFinish() { m.finishOnce.Do(func() { if !m.minimockDone() { m.MinimockCheckInviteLimitInspect() + m.MinimockCheckInviteLimitTxInspect() + m.MinimockCreateInspect() m.MinimockFindByEmailHashInspect() @@ -2548,7 +3732,11 @@ func (m *UserRepositoryMock) MinimockFinish() { m.MinimockIncrementInvitesIssuedInspect() + m.MinimockIncrementInvitesIssuedTxInspect() + m.MinimockUpdateBalanceInspect() + + m.MinimockUpdateBalanceTxInspect() } }) } @@ -2573,10 +3761,13 @@ func (m *UserRepositoryMock) minimockDone() bool { done := true return done && m.MinimockCheckInviteLimitDone() && + m.MinimockCheckInviteLimitTxDone() && m.MinimockCreateDone() && m.MinimockFindByEmailHashDone() && m.MinimockFindByIDDone() && m.MinimockGetBalanceDone() && m.MinimockIncrementInvitesIssuedDone() && - m.MinimockUpdateBalanceDone() + m.MinimockIncrementInvitesIssuedTxDone() && + m.MinimockUpdateBalanceDone() && + m.MinimockUpdateBalanceTxDone() } diff --git a/internal/mocks/user_service_mock.go b/internal/mocks/user_service_mock.go index ed99151..1b1a868 100644 --- a/internal/mocks/user_service_mock.go +++ b/internal/mocks/user_service_mock.go @@ -2,15 +2,15 @@ package mocks -//go:generate minimock -i smart-search-back/internal/service.UserService -o user_service_mock.go -n UserServiceMock -p mocks +//go:generate minimock -i git.techease.ru/Smart-search/smart-search-back/internal/service.UserService -o user_service_mock.go -n UserServiceMock -p mocks import ( "context" - mm_service "smart-search-back/internal/service" "sync" mm_atomic "sync/atomic" mm_time "time" + mm_service "git.techease.ru/Smart-search/smart-search-back/internal/service" "github.com/gojuno/minimock/v3" ) diff --git a/internal/repository/interfaces.go b/internal/repository/interfaces.go index d69b2d1..a9e19fc 100644 --- a/internal/repository/interfaces.go +++ b/internal/repository/interfaces.go @@ -3,8 +3,9 @@ package repository import ( "context" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/google/uuid" - "smart-search-back/internal/model" + "github.com/jackc/pgx/v5" ) type UserRepository interface { @@ -12,9 +13,12 @@ type UserRepository interface { FindByID(ctx context.Context, userID int) (*model.User, error) Create(ctx context.Context, user *model.User) error UpdateBalance(ctx context.Context, userID int, delta float64) error + UpdateBalanceTx(ctx context.Context, tx pgx.Tx, userID int, delta float64) error GetBalance(ctx context.Context, userID int) (float64, error) IncrementInvitesIssued(ctx context.Context, userID int) error + IncrementInvitesIssuedTx(ctx context.Context, tx pgx.Tx, userID int) error CheckInviteLimit(ctx context.Context, userID int) (bool, error) + CheckInviteLimitTx(ctx context.Context, tx pgx.Tx, userID int) (bool, error) } type SessionRepository interface { @@ -22,11 +26,14 @@ type SessionRepository interface { FindByRefreshToken(ctx context.Context, token string) (*model.Session, error) UpdateAccessToken(ctx context.Context, refreshToken, newAccessToken string) error Revoke(ctx context.Context, refreshToken string) error + RevokeByAccessToken(ctx context.Context, accessToken string) error + IsAccessTokenValid(ctx context.Context, accessToken string) (bool, error) DeleteExpired(ctx context.Context) (int, error) } type InviteRepository interface { Create(ctx context.Context, invite *model.InviteCode) error + CreateTx(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) error FindByCode(ctx context.Context, code int64) (*model.InviteCode, error) IncrementUsedCount(ctx context.Context, code int64) error DeactivateExpired(ctx context.Context) (int, error) @@ -36,6 +43,7 @@ type InviteRepository interface { type RequestRepository interface { Create(ctx context.Context, req *model.Request) error UpdateWithTZ(ctx context.Context, id uuid.UUID, tz string, generated bool) error + UpdateWithTZTx(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) error UpdateFinalTZ(ctx context.Context, id uuid.UUID, finalTZ string) error GetByUserID(ctx context.Context, userID int) ([]*model.Request, error) GetByID(ctx context.Context, id uuid.UUID) (*model.Request, error) @@ -45,10 +53,12 @@ type RequestRepository interface { type SupplierRepository interface { BulkInsert(ctx context.Context, requestID uuid.UUID, suppliers []*model.Supplier) error + BulkInsertTx(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) error GetByRequestID(ctx context.Context, requestID uuid.UUID) ([]*model.Supplier, error) DeleteByRequestID(ctx context.Context, requestID uuid.UUID) error } type TokenUsageRepository interface { Create(ctx context.Context, usage *model.TokenUsage) error + CreateTx(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) error } diff --git a/internal/repository/invite.go b/internal/repository/invite.go index 3a96a80..b796876 100644 --- a/internal/repository/invite.go +++ b/internal/repository/invite.go @@ -4,9 +4,8 @@ import ( "context" "errors" - "smart-search-back/internal/model" - errs "smart-search-back/pkg/errors" - + "git.techease.ru/Smart-search/smart-search-back/internal/model" + errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors" sq "github.com/Masterminds/squirrel" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" @@ -25,6 +24,14 @@ func NewInviteRepository(pool *pgxpool.Pool) InviteRepository { } func (r *inviteRepository) Create(ctx context.Context, invite *model.InviteCode) error { + return r.createWithExecutor(ctx, r.pool, invite) +} + +func (r *inviteRepository) CreateTx(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) error { + return r.createWithExecutor(ctx, tx, invite) +} + +func (r *inviteRepository) createWithExecutor(ctx context.Context, exec DBTX, invite *model.InviteCode) error { query := r.qb.Insert("invite_codes").Columns( "user_id", "code", "can_be_used_count", "expires_at", ).Values( @@ -36,7 +43,7 @@ func (r *inviteRepository) Create(ctx context.Context, invite *model.InviteCode) return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) } - err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(&invite.ID, &invite.CreatedAt) + err = exec.QueryRow(ctx, sqlQuery, args...).Scan(&invite.ID, &invite.CreatedAt) if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to create invite code", err) } diff --git a/internal/repository/request.go b/internal/repository/request.go index 299b67d..0584922 100644 --- a/internal/repository/request.go +++ b/internal/repository/request.go @@ -5,9 +5,8 @@ import ( "encoding/json" "errors" - "smart-search-back/internal/model" - errs "smart-search-back/pkg/errors" - + "git.techease.ru/Smart-search/smart-search-back/internal/model" + errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors" sq "github.com/Masterminds/squirrel" "github.com/google/uuid" "github.com/jackc/pgx/v5" @@ -47,6 +46,14 @@ func (r *requestRepository) Create(ctx context.Context, req *model.Request) erro } func (r *requestRepository) UpdateWithTZ(ctx context.Context, id uuid.UUID, tz string, generated bool) error { + return r.updateWithTZExecutor(ctx, r.pool, id, tz, generated) +} + +func (r *requestRepository) UpdateWithTZTx(ctx context.Context, tx pgx.Tx, id uuid.UUID, tz string, generated bool) error { + return r.updateWithTZExecutor(ctx, tx, id, tz, generated) +} + +func (r *requestRepository) updateWithTZExecutor(ctx context.Context, exec DBTX, id uuid.UUID, tz string, generated bool) error { query := r.qb.Update("requests_for_suppliers"). Set("final_tz", tz). Set("generated_tz", generated). @@ -58,7 +65,7 @@ func (r *requestRepository) UpdateWithTZ(ctx context.Context, id uuid.UUID, tz s return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) } - _, err = r.pool.Exec(ctx, sqlQuery, args...) + _, err = exec.Exec(ctx, sqlQuery, args...) if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to update request", err) } diff --git a/internal/repository/session.go b/internal/repository/session.go index e3241b6..b63ca2d 100644 --- a/internal/repository/session.go +++ b/internal/repository/session.go @@ -5,8 +5,8 @@ import ( "errors" "time" - "smart-search-back/internal/model" - errs "smart-search-back/pkg/errors" + "git.techease.ru/Smart-search/smart-search-back/internal/model" + errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors" sq "github.com/Masterminds/squirrel" "github.com/jackc/pgx/v5" @@ -114,6 +114,47 @@ func (r *sessionRepository) Revoke(ctx context.Context, refreshToken string) err return nil } +func (r *sessionRepository) RevokeByAccessToken(ctx context.Context, accessToken string) error { + query := r.qb.Update("sessions"). + Set("revoked_at", time.Now()). + Where(sq.Eq{"access_token": accessToken}) + + sqlQuery, args, err := query.ToSql() + if err != nil { + return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) + } + + _, err = r.pool.Exec(ctx, sqlQuery, args...) + if err != nil { + return errs.NewInternalError(errs.DatabaseError, "failed to revoke session", err) + } + + return nil +} + +func (r *sessionRepository) IsAccessTokenValid(ctx context.Context, accessToken string) (bool, error) { + query := r.qb.Select("COUNT(*)"). + From("sessions"). + Where(sq.And{ + sq.Eq{"access_token": accessToken}, + sq.Expr("revoked_at IS NULL"), + sq.Expr("expires_at > now()"), + }) + + sqlQuery, args, err := query.ToSql() + if err != nil { + return false, errs.NewInternalError(errs.DatabaseError, "failed to build query", err) + } + + var count int + err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(&count) + if err != nil { + return false, errs.NewInternalError(errs.DatabaseError, "failed to check token validity", err) + } + + return count > 0, nil +} + func (r *sessionRepository) DeleteExpired(ctx context.Context) (int, error) { query := r.qb.Delete("sessions").Where(sq.Or{ sq.Expr("expires_at < now()"), diff --git a/internal/repository/supplier.go b/internal/repository/supplier.go index 9a32a45..18b693c 100644 --- a/internal/repository/supplier.go +++ b/internal/repository/supplier.go @@ -3,11 +3,11 @@ package repository import ( "context" - "smart-search-back/internal/model" - errs "smart-search-back/pkg/errors" - + "git.techease.ru/Smart-search/smart-search-back/internal/model" + errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors" sq "github.com/Masterminds/squirrel" "github.com/google/uuid" + "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) @@ -24,6 +24,14 @@ func NewSupplierRepository(pool *pgxpool.Pool) SupplierRepository { } func (r *supplierRepository) BulkInsert(ctx context.Context, requestID uuid.UUID, suppliers []*model.Supplier) error { + return r.bulkInsertWithExecutor(ctx, r.pool, requestID, suppliers) +} + +func (r *supplierRepository) BulkInsertTx(ctx context.Context, tx pgx.Tx, requestID uuid.UUID, suppliers []*model.Supplier) error { + return r.bulkInsertWithExecutor(ctx, tx, requestID, suppliers) +} + +func (r *supplierRepository) bulkInsertWithExecutor(ctx context.Context, exec DBTX, requestID uuid.UUID, suppliers []*model.Supplier) error { if len(suppliers) == 0 { return nil } @@ -41,7 +49,7 @@ func (r *supplierRepository) BulkInsert(ctx context.Context, requestID uuid.UUID return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) } - _, err = r.pool.Exec(ctx, sqlQuery, args...) + _, err = exec.Exec(ctx, sqlQuery, args...) if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to bulk insert suppliers", err) } diff --git a/internal/repository/token_usage.go b/internal/repository/token_usage.go index edb0619..30ec8e5 100644 --- a/internal/repository/token_usage.go +++ b/internal/repository/token_usage.go @@ -3,10 +3,10 @@ package repository import ( "context" - "smart-search-back/internal/model" - errs "smart-search-back/pkg/errors" - + "git.techease.ru/Smart-search/smart-search-back/internal/model" + errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors" sq "github.com/Masterminds/squirrel" + "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) @@ -23,6 +23,14 @@ func NewTokenUsageRepository(pool *pgxpool.Pool) TokenUsageRepository { } func (r *tokenUsageRepository) Create(ctx context.Context, usage *model.TokenUsage) error { + return r.createWithExecutor(ctx, r.pool, usage) +} + +func (r *tokenUsageRepository) CreateTx(ctx context.Context, tx pgx.Tx, usage *model.TokenUsage) error { + return r.createWithExecutor(ctx, tx, usage) +} + +func (r *tokenUsageRepository) createWithExecutor(ctx context.Context, exec DBTX, usage *model.TokenUsage) error { query := r.qb.Insert("request_token_usage").Columns( "request_id", "request_token_count", "response_token_count", "token_cost", "type", ).Values( @@ -34,7 +42,7 @@ func (r *tokenUsageRepository) Create(ctx context.Context, usage *model.TokenUsa return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) } - err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(&usage.ID, &usage.CreatedAt) + err = exec.QueryRow(ctx, sqlQuery, args...).Scan(&usage.ID, &usage.CreatedAt) if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to create token usage", err) } diff --git a/internal/repository/tx.go b/internal/repository/tx.go new file mode 100644 index 0000000..79f4f00 --- /dev/null +++ b/internal/repository/tx.go @@ -0,0 +1,48 @@ +package repository + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgxpool" +) + +type DBTX interface { + Exec(ctx context.Context, sql string, arguments ...any) (pgconn.CommandTag, error) + Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) + QueryRow(ctx context.Context, sql string, args ...any) pgx.Row +} + +type TxManager struct { + pool *pgxpool.Pool +} + +func NewTxManager(pool *pgxpool.Pool) *TxManager { + return &TxManager{pool: pool} +} + +func (tm *TxManager) WithTx(ctx context.Context, fn func(tx pgx.Tx) error) error { + tx, err := tm.pool.Begin(ctx) + if err != nil { + return err + } + + defer func() { + if p := recover(); p != nil { + _ = tx.Rollback(ctx) + panic(p) + } + }() + + if err := fn(tx); err != nil { + _ = tx.Rollback(ctx) + return err + } + + return tx.Commit(ctx) +} + +func (tm *TxManager) Pool() *pgxpool.Pool { + return tm.pool +} diff --git a/internal/repository/user.go b/internal/repository/user.go index 45e4e6a..5533417 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -4,9 +4,9 @@ import ( "context" "errors" - "smart-search-back/internal/model" - "smart-search-back/pkg/crypto" - errs "smart-search-back/pkg/errors" + "git.techease.ru/Smart-search/smart-search-back/internal/model" + "git.techease.ru/Smart-search/smart-search-back/pkg/crypto" + errs "git.techease.ru/Smart-search/smart-search-back/pkg/errors" sq "github.com/Masterminds/squirrel" "github.com/jackc/pgx/v5" @@ -123,20 +123,35 @@ func (r *userRepository) Create(ctx context.Context, user *model.User) error { } func (r *userRepository) UpdateBalance(ctx context.Context, userID int, delta float64) error { + return r.updateBalanceWithExecutor(ctx, r.pool, userID, delta) +} + +func (r *userRepository) UpdateBalanceTx(ctx context.Context, tx pgx.Tx, userID int, delta float64) error { + return r.updateBalanceWithExecutor(ctx, tx, userID, delta) +} + +func (r *userRepository) updateBalanceWithExecutor(ctx context.Context, exec DBTX, userID int, delta float64) error { query := r.qb.Update("users"). Set("balance", sq.Expr("balance + ?", delta)). - Where(sq.Eq{"id": userID}) + Where(sq.And{ + sq.Eq{"id": userID}, + sq.Expr("balance + ? >= 0", delta), + }) sqlQuery, args, err := query.ToSql() if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) } - _, err = r.pool.Exec(ctx, sqlQuery, args...) + result, err := exec.Exec(ctx, sqlQuery, args...) if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to update balance", err) } + if result.RowsAffected() == 0 { + return errs.NewBusinessError(errs.InsufficientBalance, "insufficient balance") + } + return nil } @@ -161,24 +176,47 @@ func (r *userRepository) GetBalance(ctx context.Context, userID int) (float64, e } func (r *userRepository) IncrementInvitesIssued(ctx context.Context, userID int) error { + return r.incrementInvitesIssuedWithExecutor(ctx, r.pool, userID) +} + +func (r *userRepository) IncrementInvitesIssuedTx(ctx context.Context, tx pgx.Tx, userID int) error { + return r.incrementInvitesIssuedWithExecutor(ctx, tx, userID) +} + +func (r *userRepository) incrementInvitesIssuedWithExecutor(ctx context.Context, exec DBTX, userID int) error { query := r.qb.Update("users"). Set("invites_issued", sq.Expr("invites_issued + 1")). - Where(sq.Eq{"id": userID}) + Where(sq.And{ + sq.Eq{"id": userID}, + sq.Expr("invites_issued < invites_limit"), + }) sqlQuery, args, err := query.ToSql() if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) } - _, err = r.pool.Exec(ctx, sqlQuery, args...) + result, err := exec.Exec(ctx, sqlQuery, args...) if err != nil { return errs.NewInternalError(errs.DatabaseError, "failed to increment invites issued", err) } + if result.RowsAffected() == 0 { + return errs.NewBusinessError(errs.InviteLimitReached, "invite limit reached") + } + return nil } func (r *userRepository) CheckInviteLimit(ctx context.Context, userID int) (bool, error) { + return r.checkInviteLimitWithExecutor(ctx, r.pool, userID) +} + +func (r *userRepository) CheckInviteLimitTx(ctx context.Context, tx pgx.Tx, userID int) (bool, error) { + return r.checkInviteLimitWithExecutor(ctx, tx, userID) +} + +func (r *userRepository) checkInviteLimitWithExecutor(ctx context.Context, exec DBTX, userID int) (bool, error) { query := r.qb.Select("invites_issued", "invites_limit"). From("users"). Where(sq.Eq{"id": userID}). @@ -190,7 +228,7 @@ func (r *userRepository) CheckInviteLimit(ctx context.Context, userID int) (bool } var issued, limit int - err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(&issued, &limit) + err = exec.QueryRow(ctx, sqlQuery, args...).Scan(&issued, &limit) if err != nil { return false, errs.NewInternalError(errs.DatabaseError, "failed to check invite limit", err) } diff --git a/internal/service/auth.go b/internal/service/auth.go index 832b6cb..e5063f3 100644 --- a/internal/service/auth.go +++ b/internal/service/auth.go @@ -4,11 +4,11 @@ import ( "context" "time" - "smart-search-back/internal/model" - "smart-search-back/internal/repository" - "smart-search-back/pkg/crypto" - "smart-search-back/pkg/errors" - "smart-search-back/pkg/jwt" + "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" + "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + "git.techease.ru/Smart-search/smart-search-back/pkg/jwt" ) type authService struct { @@ -99,9 +99,18 @@ func (s *authService) Validate(ctx context.Context, accessToken string) (int, er return 0, errors.NewBusinessError(errors.AuthInvalidToken, "Invalid user ID in token") } + isValid, err := s.sessionRepo.IsAccessTokenValid(ctx, accessToken) + if err != nil { + return 0, err + } + + if !isValid { + return 0, errors.NewBusinessError(errors.AuthInvalidToken, "Token has been revoked or expired") + } + return userID, nil } -func (s *authService) Logout(ctx context.Context, refreshToken string) error { - return s.sessionRepo.Revoke(ctx, refreshToken) +func (s *authService) Logout(ctx context.Context, accessToken string) error { + return s.sessionRepo.RevokeByAccessToken(ctx, accessToken) } diff --git a/internal/service/interfaces.go b/internal/service/interfaces.go index 401adc7..c8e2ec9 100644 --- a/internal/service/interfaces.go +++ b/internal/service/interfaces.go @@ -3,7 +3,7 @@ package service import ( "context" - "smart-search-back/internal/model" + "git.techease.ru/Smart-search/smart-search-back/internal/model" "github.com/google/uuid" ) @@ -12,7 +12,7 @@ type AuthService interface { Login(ctx context.Context, email, password, ip, userAgent string) (accessToken, refreshToken string, err error) Refresh(ctx context.Context, refreshToken string) (string, error) Validate(ctx context.Context, accessToken string) (int, error) - Logout(ctx context.Context, refreshToken string) error + Logout(ctx context.Context, accessToken string) error } type UserService interface { diff --git a/internal/service/invite.go b/internal/service/invite.go index e578f4f..e2b0f5b 100644 --- a/internal/service/invite.go +++ b/internal/service/invite.go @@ -5,33 +5,27 @@ import ( "math/rand" "time" - "smart-search-back/internal/model" - "smart-search-back/internal/repository" - "smart-search-back/pkg/errors" + "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/errors" + "github.com/jackc/pgx/v5" ) type inviteService struct { inviteRepo repository.InviteRepository userRepo repository.UserRepository + txManager *repository.TxManager } -func NewInviteService(inviteRepo repository.InviteRepository, userRepo repository.UserRepository) InviteService { +func NewInviteService(inviteRepo repository.InviteRepository, userRepo repository.UserRepository, txManager *repository.TxManager) InviteService { return &inviteService{ inviteRepo: inviteRepo, userRepo: userRepo, + txManager: txManager, } } func (s *inviteService) Generate(ctx context.Context, userID, maxUses, ttlDays int) (*model.InviteCode, error) { - canIssue, err := s.userRepo.CheckInviteLimit(ctx, userID) - if err != nil { - return nil, err - } - - if !canIssue { - return nil, errors.NewBusinessError(errors.InviteLimitReached, "User reached maximum invite codes limit") - } - code := rand.Int63n(90000000) + 10000000 invite := &model.InviteCode{ @@ -41,11 +35,28 @@ func (s *inviteService) Generate(ctx context.Context, userID, maxUses, ttlDays i ExpiresAt: time.Now().Add(time.Duration(ttlDays) * 24 * time.Hour), } - if err := s.inviteRepo.Create(ctx, invite); err != nil { - return nil, err - } + err := s.txManager.WithTx(ctx, func(tx pgx.Tx) error { + canIssue, err := s.userRepo.CheckInviteLimitTx(ctx, tx, userID) + if err != nil { + return err + } - if err := s.userRepo.IncrementInvitesIssued(ctx, userID); err != nil { + if !canIssue { + return errors.NewBusinessError(errors.InviteLimitReached, "User reached maximum invite codes limit") + } + + if err := s.inviteRepo.CreateTx(ctx, tx, invite); err != nil { + return err + } + + if err := s.userRepo.IncrementInvitesIssuedTx(ctx, tx, userID); err != nil { + return err + } + + return nil + }) + + if err != nil { return nil, err } diff --git a/internal/service/request.go b/internal/service/request.go index 26e1a75..41483e8 100644 --- a/internal/service/request.go +++ b/internal/service/request.go @@ -4,11 +4,12 @@ import ( "context" "math" + "git.techease.ru/Smart-search/smart-search-back/internal/ai" + "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/errors" "github.com/google/uuid" - "smart-search-back/internal/ai" - "smart-search-back/internal/model" - "smart-search-back/internal/repository" - "smart-search-back/pkg/errors" + "github.com/jackc/pgx/v5" ) type requestService struct { @@ -18,6 +19,7 @@ type requestService struct { userRepo repository.UserRepository openAI *ai.OpenAIClient perplexity *ai.PerplexityClient + txManager *repository.TxManager } func NewRequestService( @@ -27,6 +29,7 @@ func NewRequestService( userRepo repository.UserRepository, openAI *ai.OpenAIClient, perplexity *ai.PerplexityClient, + txManager *repository.TxManager, ) RequestService { return &requestService{ requestRepo: requestRepo, @@ -35,6 +38,7 @@ func NewRequestService( userRepo: userRepo, openAI: openAI, perplexity: perplexity, + txManager: txManager, } } @@ -79,15 +83,23 @@ func (s *requestService) CreateTZ(ctx context.Context, userID int, requestTxt st Type: "tz", } - if err := s.tokenUsageRepo.Create(ctx, tokenUsage); err != nil { - return req.ID, "", err - } + err = s.txManager.WithTx(ctx, func(tx pgx.Tx) error { + if err := s.tokenUsageRepo.CreateTx(ctx, tx, tokenUsage); err != nil { + return err + } - if err := s.userRepo.UpdateBalance(ctx, userID, -cost); err != nil { - return req.ID, "", err - } + if err := s.userRepo.UpdateBalanceTx(ctx, tx, userID, -cost); err != nil { + return err + } - if err := s.requestRepo.UpdateWithTZ(ctx, req.ID, tzText, true); err != nil { + if err := s.requestRepo.UpdateWithTZTx(ctx, tx, req.ID, tzText, true); err != nil { + return err + } + + return nil + }) + + if err != nil { return req.ID, "", err } @@ -118,10 +130,6 @@ func (s *requestService) ApproveTZ(ctx context.Context, requestID uuid.UUID, tzT return nil, errors.NewInternalError(errors.AIAPIError, "no suppliers found", nil) } - if err := s.supplierRepo.BulkInsert(ctx, requestID, suppliers); err != nil { - return nil, err - } - tokenPrice := 25000.0 / 1000000.0 totalTokens := promptTokens + responseTokens cost := float64(totalTokens) * tokenPrice @@ -134,11 +142,23 @@ func (s *requestService) ApproveTZ(ctx context.Context, requestID uuid.UUID, tzT Type: "suppliers", } - if err := s.tokenUsageRepo.Create(ctx, tokenUsage); err != nil { - return nil, err - } + err = s.txManager.WithTx(ctx, func(tx pgx.Tx) error { + if err := s.supplierRepo.BulkInsertTx(ctx, tx, requestID, suppliers); err != nil { + return err + } - if err := s.userRepo.UpdateBalance(ctx, userID, -cost); err != nil { + if err := s.tokenUsageRepo.CreateTx(ctx, tx, tokenUsage); err != nil { + return err + } + + if err := s.userRepo.UpdateBalanceTx(ctx, tx, userID, -cost); err != nil { + return err + } + + return nil + }) + + if err != nil { return nil, err } diff --git a/internal/service/supplier.go b/internal/service/supplier.go index e420067..dbdf441 100644 --- a/internal/service/supplier.go +++ b/internal/service/supplier.go @@ -4,9 +4,9 @@ import ( "context" "fmt" + "git.techease.ru/Smart-search/smart-search-back/internal/repository" "github.com/google/uuid" "github.com/xuri/excelize/v2" - "smart-search-back/internal/repository" ) type supplierService struct { @@ -26,7 +26,7 @@ func (s *supplierService) ExportExcel(ctx context.Context, requestID uuid.UUID) } f := excelize.NewFile() - defer f.Close() + defer func() { _ = f.Close() }() sheetName := "Suppliers" index, err := f.NewSheet(sheetName) @@ -37,7 +37,7 @@ func (s *supplierService) ExportExcel(ctx context.Context, requestID uuid.UUID) headers := []string{"Company ID", "Email", "Phone", "Company Name", "URL"} for i, header := range headers { cell := fmt.Sprintf("%c1", 'A'+i) - f.SetCellValue(sheetName, cell, header) + _ = f.SetCellValue(sheetName, cell, header) } style, err := f.NewStyle(&excelize.Style{ @@ -45,26 +45,26 @@ func (s *supplierService) ExportExcel(ctx context.Context, requestID uuid.UUID) Fill: excelize.Fill{Type: "pattern", Color: []string{"#E0E0E0"}, Pattern: 1}, }) if err == nil { - f.SetCellStyle(sheetName, "A1", fmt.Sprintf("%c1", 'A'+len(headers)-1), style) + _ = f.SetCellStyle(sheetName, "A1", fmt.Sprintf("%c1", 'A'+len(headers)-1), style) } for i, supplier := range suppliers { row := i + 2 - f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), supplier.ID) - f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), supplier.Email) - f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), supplier.Phone) - f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), supplier.Name) - f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), supplier.URL) + _ = f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), supplier.ID) + _ = f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), supplier.Email) + _ = f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), supplier.Phone) + _ = f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), supplier.Name) + _ = f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), supplier.URL) } - f.SetColWidth(sheetName, "A", "A", 12) - f.SetColWidth(sheetName, "B", "B", 30) - f.SetColWidth(sheetName, "C", "C", 20) - f.SetColWidth(sheetName, "D", "D", 40) - f.SetColWidth(sheetName, "E", "E", 40) + _ = f.SetColWidth(sheetName, "A", "A", 12) + _ = f.SetColWidth(sheetName, "B", "B", 30) + _ = f.SetColWidth(sheetName, "C", "C", 20) + _ = f.SetColWidth(sheetName, "D", "D", 40) + _ = f.SetColWidth(sheetName, "E", "E", 40) f.SetActiveSheet(index) - f.DeleteSheet("Sheet1") + _ = f.DeleteSheet("Sheet1") buffer, err := f.WriteToBuffer() if err != nil { diff --git a/internal/service/tests/auth_suite_test.go b/internal/service/tests/auth_suite_test.go index b5b8577..432b4fb 100644 --- a/internal/service/tests/auth_suite_test.go +++ b/internal/service/tests/auth_suite_test.go @@ -9,12 +9,17 @@ import ( "github.com/gojuno/minimock/v3" "github.com/stretchr/testify/suite" - "smart-search-back/internal/mocks" - "smart-search-back/internal/model" - "smart-search-back/internal/service" - "smart-search-back/pkg/crypto" - apperrors "smart-search-back/pkg/errors" - "smart-search-back/pkg/jwt" + "git.techease.ru/Smart-search/smart-search-back/internal/mocks" + "git.techease.ru/Smart-search/smart-search-back/internal/model" + "git.techease.ru/Smart-search/smart-search-back/internal/service" + "git.techease.ru/Smart-search/smart-search-back/pkg/crypto" + apperrors "git.techease.ru/Smart-search/smart-search-back/pkg/errors" + "git.techease.ru/Smart-search/smart-search-back/pkg/jwt" +) + +const ( + testJWTSecret = "test-jwt-secret-key" + testCryptoSecret = "test-crypto-secret-key" ) type Suite struct { @@ -24,6 +29,7 @@ type Suite struct { authService service.AuthService userRepo *mocks.UserRepositoryMock sessionRepo *mocks.SessionRepositoryMock + crypto *crypto.Crypto } func newSuite(ctx context.Context) *Suite { @@ -46,15 +52,17 @@ func (s *Suite) SetupTest() { s.userRepo = mocks.NewUserRepositoryMock(ctrl) s.sessionRepo = mocks.NewSessionRepositoryMock(ctrl) + s.crypto = crypto.NewCrypto(testCryptoSecret) - s.authService = service.NewAuthService(s.userRepo, s.sessionRepo) + s.authService = service.NewAuthService(s.userRepo, s.sessionRepo, testJWTSecret, testCryptoSecret) } func createTestUser(password string) *model.User { + c := crypto.NewCrypto(testCryptoSecret) return &model.User{ ID: 1, Email: "test@example.com", - EmailHash: crypto.EmailHash("test@example.com"), + EmailHash: c.EmailHash("test@example.com"), PasswordHash: crypto.PasswordHash(password), CreatedAt: time.Now(), } @@ -180,7 +188,7 @@ func (s *Suite) TestAuthService_Login_EmailWithSpacesAndCase() { password := "testpassword" normalizedEmail := "test@example.com" user := createTestUser(password) - user.EmailHash = crypto.EmailHash(normalizedEmail) + user.EmailHash = s.crypto.EmailHash(normalizedEmail) s.userRepo.FindByEmailHashMock.Return(user, nil) s.sessionRepo.CreateMock.Return(nil) @@ -328,12 +336,12 @@ func (s *Suite) TestAuthService_Refresh_UserIDZero() { } func (s *Suite) TestAuthService_Validate_Success() { - s.T().Parallel() - userID := 1 - accessToken, err := jwt.GenerateAccessToken(userID) + accessToken, err := jwt.GenerateAccessToken(userID, testJWTSecret) s.NoError(err) + s.sessionRepo.IsAccessTokenValidMock.Return(true, nil) + validatedUserID, validateErr := s.authService.Validate(s.ctx, accessToken) s.NoError(validateErr) @@ -370,7 +378,7 @@ func (s *Suite) TestAuthService_Validate_RefreshTokenInsteadOfAccess() { s.T().Parallel() userID := 1 - refreshToken, err := jwt.GenerateRefreshToken(userID) + refreshToken, err := jwt.GenerateRefreshToken(userID, testJWTSecret) s.NoError(err) validatedUserID, validateErr := s.authService.Validate(s.ctx, refreshToken) @@ -385,11 +393,11 @@ func (s *Suite) TestAuthService_Validate_RefreshTokenInsteadOfAccess() { } func (s *Suite) TestAuthService_Validate_UserIDZero() { - s.T().Parallel() - - accessToken, err := jwt.GenerateAccessToken(0) + accessToken, err := jwt.GenerateAccessToken(0, testJWTSecret) s.NoError(err) + s.sessionRepo.IsAccessTokenValidMock.Return(true, nil) + validatedUserID, validateErr := s.authService.Validate(s.ctx, accessToken) s.NoError(validateErr) @@ -412,18 +420,18 @@ func (s *Suite) TestAuthService_Validate_InvalidSignature() { } func (s *Suite) TestAuthService_Logout_Success() { - s.sessionRepo.RevokeMock.Return(nil) + s.sessionRepo.RevokeByAccessTokenMock.Return(nil) - err := s.authService.Logout(s.ctx, "test-refresh-token") + err := s.authService.Logout(s.ctx, "test-access-token") s.NoError(err) } func (s *Suite) TestAuthService_Logout_DatabaseError() { dbErr := apperrors.NewInternalError(apperrors.DatabaseError, "failed to revoke session", nil) - s.sessionRepo.RevokeMock.Return(dbErr) + s.sessionRepo.RevokeByAccessTokenMock.Return(dbErr) - err := s.authService.Logout(s.ctx, "test-refresh-token") + err := s.authService.Logout(s.ctx, "test-access-token") s.Error(err) @@ -433,7 +441,7 @@ func (s *Suite) TestAuthService_Logout_DatabaseError() { } func (s *Suite) TestAuthService_Logout_EmptyToken() { - s.sessionRepo.RevokeMock.Return(nil) + s.sessionRepo.RevokeByAccessTokenMock.Return(nil) err := s.authService.Logout(s.ctx, "") @@ -441,7 +449,7 @@ func (s *Suite) TestAuthService_Logout_EmptyToken() { } func (s *Suite) TestAuthService_Logout_NonExistentToken() { - s.sessionRepo.RevokeMock.Return(nil) + s.sessionRepo.RevokeByAccessTokenMock.Return(nil) err := s.authService.Logout(s.ctx, "non-existent-token") diff --git a/internal/service/user.go b/internal/service/user.go index 939a98c..fcb19f0 100644 --- a/internal/service/user.go +++ b/internal/service/user.go @@ -3,8 +3,8 @@ package service import ( "context" - "smart-search-back/internal/repository" - "smart-search-back/pkg/crypto" + "git.techease.ru/Smart-search/smart-search-back/internal/repository" + "git.techease.ru/Smart-search/smart-search-back/pkg/crypto" ) type userService struct { diff --git a/internal/worker/invite_cleaner.go b/internal/worker/invite_cleaner.go index 228c365..7cb3680 100644 --- a/internal/worker/invite_cleaner.go +++ b/internal/worker/invite_cleaner.go @@ -5,7 +5,7 @@ import ( "log" "time" - "smart-search-back/internal/repository" + "git.techease.ru/Smart-search/smart-search-back/internal/repository" ) type InviteCleaner struct { diff --git a/internal/worker/session_cleaner.go b/internal/worker/session_cleaner.go index 9459954..97b6ddf 100644 --- a/internal/worker/session_cleaner.go +++ b/internal/worker/session_cleaner.go @@ -5,7 +5,7 @@ import ( "log" "time" - "smart-search-back/internal/repository" + "git.techease.ru/Smart-search/smart-search-back/internal/repository" ) type SessionCleaner struct { diff --git a/internal/worker/worker_test.go b/internal/worker/worker_test.go new file mode 100644 index 0000000..c6b864e --- /dev/null +++ b/internal/worker/worker_test.go @@ -0,0 +1,213 @@ +package worker + +import ( + "context" + "sync/atomic" + "testing" + "time" + + "github.com/gojuno/minimock/v3" + "github.com/stretchr/testify/suite" + + "git.techease.ru/Smart-search/smart-search-back/internal/mocks" +) + +type WorkerSuite struct { + suite.Suite + ctx context.Context + cancel context.CancelFunc + ctrl *minimock.Controller +} + +func TestWorkerSuite(t *testing.T) { + suite.Run(t, new(WorkerSuite)) +} + +func (s *WorkerSuite) SetupTest() { + s.ctx, s.cancel = context.WithCancel(context.Background()) + s.ctrl = minimock.NewController(s.T()) +} + +func (s *WorkerSuite) TearDownTest() { + if s.cancel != nil { + s.cancel() + } +} + +func (s *WorkerSuite) TestSessionCleaner_StartStop() { + var callCount int32 + sessionRepo := mocks.NewSessionRepositoryMock(s.ctrl) + sessionRepo.DeleteExpiredMock.Set(func(_ context.Context) (int, error) { + atomic.AddInt32(&callCount, 1) + return 5, nil + }) + + cleaner := NewSessionCleaner(s.ctx, sessionRepo) + + cleaner.Start() + + time.Sleep(50 * time.Millisecond) + + cleaner.Stop() + + s.GreaterOrEqual(int(atomic.LoadInt32(&callCount)), 1, + "DeleteExpired должен быть вызван хотя бы раз при старте") +} + +func (s *WorkerSuite) TestSessionCleaner_ContextCancellation() { + var callCount int32 + sessionRepo := mocks.NewSessionRepositoryMock(s.ctrl) + sessionRepo.DeleteExpiredMock.Set(func(_ context.Context) (int, error) { + atomic.AddInt32(&callCount, 1) + return 0, nil + }) + + cleaner := NewSessionCleaner(s.ctx, sessionRepo) + + cleaner.Start() + + time.Sleep(50 * time.Millisecond) + + s.cancel() + + time.Sleep(50 * time.Millisecond) + + s.GreaterOrEqual(int(atomic.LoadInt32(&callCount)), 1, + "DeleteExpired должен быть вызван хотя бы раз") +} + +func (s *WorkerSuite) TestInviteCleaner_StartStop() { + var callCount int32 + inviteRepo := mocks.NewInviteRepositoryMock(s.ctrl) + inviteRepo.DeactivateExpiredMock.Set(func(_ context.Context) (int, error) { + atomic.AddInt32(&callCount, 1) + return 3, nil + }) + + cleaner := NewInviteCleaner(s.ctx, inviteRepo) + + cleaner.Start() + + time.Sleep(50 * time.Millisecond) + + cleaner.Stop() + + s.GreaterOrEqual(int(atomic.LoadInt32(&callCount)), 1, + "DeactivateExpired должен быть вызван хотя бы раз при старте") +} + +func (s *WorkerSuite) TestInviteCleaner_ContextCancellation() { + var callCount int32 + inviteRepo := mocks.NewInviteRepositoryMock(s.ctrl) + inviteRepo.DeactivateExpiredMock.Set(func(_ context.Context) (int, error) { + atomic.AddInt32(&callCount, 1) + return 0, nil + }) + + cleaner := NewInviteCleaner(s.ctx, inviteRepo) + + cleaner.Start() + + time.Sleep(50 * time.Millisecond) + + s.cancel() + + time.Sleep(50 * time.Millisecond) + + s.GreaterOrEqual(int(atomic.LoadInt32(&callCount)), 1, + "DeactivateExpired должен быть вызван хотя бы раз") +} + +func (s *WorkerSuite) TestSessionCleaner_ConcurrentStops() { + sessionRepo := mocks.NewSessionRepositoryMock(s.ctrl) + sessionRepo.DeleteExpiredMock.Set(func(_ context.Context) (int, error) { + return 0, nil + }) + + cleaner := NewSessionCleaner(s.ctx, sessionRepo) + + cleaner.Start() + + time.Sleep(50 * time.Millisecond) + + done := make(chan struct{}) + for i := 0; i < 5; i++ { + go func() { + cleaner.Stop() + }() + } + + go func() { + time.Sleep(100 * time.Millisecond) + close(done) + }() + + <-done +} + +func (s *WorkerSuite) TestInviteCleaner_ConcurrentStops() { + inviteRepo := mocks.NewInviteRepositoryMock(s.ctrl) + inviteRepo.DeactivateExpiredMock.Set(func(_ context.Context) (int, error) { + return 0, nil + }) + + cleaner := NewInviteCleaner(s.ctx, inviteRepo) + + cleaner.Start() + + time.Sleep(50 * time.Millisecond) + + done := make(chan struct{}) + for i := 0; i < 5; i++ { + go func() { + cleaner.Stop() + }() + } + + go func() { + time.Sleep(100 * time.Millisecond) + close(done) + }() + + <-done +} + +func (s *WorkerSuite) TestSessionCleaner_MultipleStartStop() { + var callCount int32 + sessionRepo := mocks.NewSessionRepositoryMock(s.ctrl) + sessionRepo.DeleteExpiredMock.Set(func(_ context.Context) (int, error) { + atomic.AddInt32(&callCount, 1) + return 2, nil + }) + + cleaner := NewSessionCleaner(s.ctx, sessionRepo) + + for i := 0; i < 3; i++ { + cleaner.Start() + time.Sleep(20 * time.Millisecond) + cleaner.Stop() + } + + s.GreaterOrEqual(int(atomic.LoadInt32(&callCount)), 3, + "DeleteExpired должен быть вызван минимум 3 раза") +} + +func (s *WorkerSuite) TestInviteCleaner_MultipleStartStop() { + var callCount int32 + inviteRepo := mocks.NewInviteRepositoryMock(s.ctrl) + inviteRepo.DeactivateExpiredMock.Set(func(_ context.Context) (int, error) { + atomic.AddInt32(&callCount, 1) + return 1, nil + }) + + cleaner := NewInviteCleaner(s.ctx, inviteRepo) + + for i := 0; i < 3; i++ { + cleaner.Start() + time.Sleep(20 * time.Millisecond) + cleaner.Stop() + } + + s.GreaterOrEqual(int(atomic.LoadInt32(&callCount)), 3, + "DeactivateExpired должен быть вызван минимум 3 раза") +} diff --git a/migrations/00008_add_balance_check_constraint.sql b/migrations/00008_add_balance_check_constraint.sql new file mode 100644 index 0000000..8856557 --- /dev/null +++ b/migrations/00008_add_balance_check_constraint.sql @@ -0,0 +1,10 @@ +-- +goose Up +ALTER TABLE users ADD CONSTRAINT balance_non_negative CHECK (balance >= 0); + +ALTER TABLE invite_codes ADD CONSTRAINT used_count_non_negative CHECK (used_count >= 0); +ALTER TABLE invite_codes ADD CONSTRAINT used_count_within_limit CHECK (used_count <= can_be_used_count); + +-- +goose Down +ALTER TABLE users DROP CONSTRAINT IF EXISTS balance_non_negative; +ALTER TABLE invite_codes DROP CONSTRAINT IF EXISTS used_count_non_negative; +ALTER TABLE invite_codes DROP CONSTRAINT IF EXISTS used_count_within_limit; diff --git a/pkg/jwt/jwt.go b/pkg/jwt/jwt.go index 8887462..d786523 100644 --- a/pkg/jwt/jwt.go +++ b/pkg/jwt/jwt.go @@ -7,6 +7,7 @@ import ( "time" "github.com/golang-jwt/jwt/v5" + "github.com/google/uuid" ) type Claims struct { @@ -21,6 +22,7 @@ func GenerateAccessToken(userID int, secret string) (string, error) { Sub: strconv.Itoa(userID), Type: "access", RegisteredClaims: jwt.RegisteredClaims{ + ID: uuid.New().String(), IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(15 * time.Minute)), }, @@ -36,6 +38,7 @@ func GenerateRefreshToken(userID int, secret string) (string, error) { Sub: strconv.Itoa(userID), Type: "refresh", RegisteredClaims: jwt.RegisteredClaims{ + ID: uuid.New().String(), IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(30 * 24 * time.Hour)), }, diff --git a/pkg/pb/api/proto/auth/auth.pb.go b/pkg/pb/auth/auth.pb.go similarity index 82% rename from pkg/pb/api/proto/auth/auth.pb.go rename to pkg/pb/auth/auth.pb.go index 49d73d8..5d83932 100644 --- a/pkg/pb/api/proto/auth/auth.pb.go +++ b/pkg/pb/auth/auth.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.6 // protoc v5.29.3 -// source: api/proto/auth/auth.proto +// source: auth/auth.proto package auth @@ -33,7 +33,7 @@ type LoginRequest struct { func (x *LoginRequest) Reset() { *x = LoginRequest{} - mi := &file_api_proto_auth_auth_proto_msgTypes[0] + mi := &file_auth_auth_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -45,7 +45,7 @@ func (x *LoginRequest) String() string { func (*LoginRequest) ProtoMessage() {} func (x *LoginRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[0] + mi := &file_auth_auth_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -58,7 +58,7 @@ func (x *LoginRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. func (*LoginRequest) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{0} + return file_auth_auth_proto_rawDescGZIP(), []int{0} } func (x *LoginRequest) GetEmail() string { @@ -99,7 +99,7 @@ type LoginResponse struct { func (x *LoginResponse) Reset() { *x = LoginResponse{} - mi := &file_api_proto_auth_auth_proto_msgTypes[1] + mi := &file_auth_auth_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -111,7 +111,7 @@ func (x *LoginResponse) String() string { func (*LoginResponse) ProtoMessage() {} func (x *LoginResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[1] + mi := &file_auth_auth_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -124,7 +124,7 @@ func (x *LoginResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead. func (*LoginResponse) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{1} + return file_auth_auth_proto_rawDescGZIP(), []int{1} } func (x *LoginResponse) GetAccessToken() string { @@ -152,7 +152,7 @@ type RefreshRequest struct { func (x *RefreshRequest) Reset() { *x = RefreshRequest{} - mi := &file_api_proto_auth_auth_proto_msgTypes[2] + mi := &file_auth_auth_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -164,7 +164,7 @@ func (x *RefreshRequest) String() string { func (*RefreshRequest) ProtoMessage() {} func (x *RefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[2] + mi := &file_auth_auth_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -177,7 +177,7 @@ func (x *RefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshRequest.ProtoReflect.Descriptor instead. func (*RefreshRequest) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{2} + return file_auth_auth_proto_rawDescGZIP(), []int{2} } func (x *RefreshRequest) GetRefreshToken() string { @@ -211,7 +211,7 @@ type RefreshResponse struct { func (x *RefreshResponse) Reset() { *x = RefreshResponse{} - mi := &file_api_proto_auth_auth_proto_msgTypes[3] + mi := &file_auth_auth_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -223,7 +223,7 @@ func (x *RefreshResponse) String() string { func (*RefreshResponse) ProtoMessage() {} func (x *RefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[3] + mi := &file_auth_auth_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -236,7 +236,7 @@ func (x *RefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RefreshResponse.ProtoReflect.Descriptor instead. func (*RefreshResponse) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{3} + return file_auth_auth_proto_rawDescGZIP(), []int{3} } func (x *RefreshResponse) GetAccessToken() string { @@ -262,7 +262,7 @@ type ValidateRequest struct { func (x *ValidateRequest) Reset() { *x = ValidateRequest{} - mi := &file_api_proto_auth_auth_proto_msgTypes[4] + mi := &file_auth_auth_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -274,7 +274,7 @@ func (x *ValidateRequest) String() string { func (*ValidateRequest) ProtoMessage() {} func (x *ValidateRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[4] + mi := &file_auth_auth_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -287,7 +287,7 @@ func (x *ValidateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ValidateRequest.ProtoReflect.Descriptor instead. func (*ValidateRequest) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{4} + return file_auth_auth_proto_rawDescGZIP(), []int{4} } func (x *ValidateRequest) GetAccessToken() string { @@ -307,7 +307,7 @@ type ValidateResponse struct { func (x *ValidateResponse) Reset() { *x = ValidateResponse{} - mi := &file_api_proto_auth_auth_proto_msgTypes[5] + mi := &file_auth_auth_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -319,7 +319,7 @@ func (x *ValidateResponse) String() string { func (*ValidateResponse) ProtoMessage() {} func (x *ValidateResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[5] + mi := &file_auth_auth_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -332,7 +332,7 @@ func (x *ValidateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ValidateResponse.ProtoReflect.Descriptor instead. func (*ValidateResponse) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{5} + return file_auth_auth_proto_rawDescGZIP(), []int{5} } func (x *ValidateResponse) GetValid() bool { @@ -358,7 +358,7 @@ type LogoutRequest struct { func (x *LogoutRequest) Reset() { *x = LogoutRequest{} - mi := &file_api_proto_auth_auth_proto_msgTypes[6] + mi := &file_auth_auth_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -370,7 +370,7 @@ func (x *LogoutRequest) String() string { func (*LogoutRequest) ProtoMessage() {} func (x *LogoutRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[6] + mi := &file_auth_auth_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -383,7 +383,7 @@ func (x *LogoutRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead. func (*LogoutRequest) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{6} + return file_auth_auth_proto_rawDescGZIP(), []int{6} } func (x *LogoutRequest) GetAccessToken() string { @@ -402,7 +402,7 @@ type LogoutResponse struct { func (x *LogoutResponse) Reset() { *x = LogoutResponse{} - mi := &file_api_proto_auth_auth_proto_msgTypes[7] + mi := &file_auth_auth_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -414,7 +414,7 @@ func (x *LogoutResponse) String() string { func (*LogoutResponse) ProtoMessage() {} func (x *LogoutResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_auth_auth_proto_msgTypes[7] + mi := &file_auth_auth_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -427,7 +427,7 @@ func (x *LogoutResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead. func (*LogoutResponse) Descriptor() ([]byte, []int) { - return file_api_proto_auth_auth_proto_rawDescGZIP(), []int{7} + return file_auth_auth_proto_rawDescGZIP(), []int{7} } func (x *LogoutResponse) GetSuccess() bool { @@ -437,11 +437,11 @@ func (x *LogoutResponse) GetSuccess() bool { return false } -var File_api_proto_auth_auth_proto protoreflect.FileDescriptor +var File_auth_auth_proto protoreflect.FileDescriptor -const file_api_proto_auth_auth_proto_rawDesc = "" + +const file_auth_auth_proto_rawDesc = "" + "\n" + - "\x19api/proto/auth/auth.proto\x12\x04auth\"o\n" + + "\x0fauth/auth.proto\x12\x04auth\"o\n" + "\fLoginRequest\x12\x14\n" + "\x05email\x18\x01 \x01(\tR\x05email\x12\x1a\n" + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x0e\n" + @@ -472,22 +472,22 @@ const file_api_proto_auth_auth_proto_rawDesc = "" + "\x05Login\x12\x12.auth.LoginRequest\x1a\x13.auth.LoginResponse\x126\n" + "\aRefresh\x12\x14.auth.RefreshRequest\x1a\x15.auth.RefreshResponse\x129\n" + "\bValidate\x12\x15.auth.ValidateRequest\x1a\x16.auth.ValidateResponse\x123\n" + - "\x06Logout\x12\x13.auth.LogoutRequest\x1a\x14.auth.LogoutResponseB5Z3github.com/smart-search-gateway/api/proto/auth/authb\x06proto3" + "\x06Logout\x12\x13.auth.LogoutRequest\x1a\x14.auth.LogoutResponseB auth.LoginRequest 2, // 1: auth.AuthService.Refresh:input_type -> auth.RefreshRequest 4, // 2: auth.AuthService.Validate:input_type -> auth.ValidateRequest @@ -513,26 +513,26 @@ var file_api_proto_auth_auth_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_api_proto_auth_auth_proto_init() } -func file_api_proto_auth_auth_proto_init() { - if File_api_proto_auth_auth_proto != nil { +func init() { file_auth_auth_proto_init() } +func file_auth_auth_proto_init() { + if File_auth_auth_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_auth_auth_proto_rawDesc), len(file_api_proto_auth_auth_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_auth_auth_proto_rawDesc), len(file_auth_auth_proto_rawDesc)), NumEnums: 0, NumMessages: 8, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_api_proto_auth_auth_proto_goTypes, - DependencyIndexes: file_api_proto_auth_auth_proto_depIdxs, - MessageInfos: file_api_proto_auth_auth_proto_msgTypes, + GoTypes: file_auth_auth_proto_goTypes, + DependencyIndexes: file_auth_auth_proto_depIdxs, + MessageInfos: file_auth_auth_proto_msgTypes, }.Build() - File_api_proto_auth_auth_proto = out.File - file_api_proto_auth_auth_proto_goTypes = nil - file_api_proto_auth_auth_proto_depIdxs = nil + File_auth_auth_proto = out.File + file_auth_auth_proto_goTypes = nil + file_auth_auth_proto_depIdxs = nil } diff --git a/pkg/pb/api/proto/auth/auth_grpc.pb.go b/pkg/pb/auth/auth_grpc.pb.go similarity index 99% rename from pkg/pb/api/proto/auth/auth_grpc.pb.go rename to pkg/pb/auth/auth_grpc.pb.go index ecb5e03..1b9c5a5 100644 --- a/pkg/pb/api/proto/auth/auth_grpc.pb.go +++ b/pkg/pb/auth/auth_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: api/proto/auth/auth.proto +// source: auth/auth.proto package auth @@ -231,5 +231,5 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "api/proto/auth/auth.proto", + Metadata: "auth/auth.proto", } diff --git a/pkg/pb/api/proto/invite/invite.pb.go b/pkg/pb/invite/invite.pb.go similarity index 80% rename from pkg/pb/api/proto/invite/invite.pb.go rename to pkg/pb/invite/invite.pb.go index 7aa914e..6328374 100644 --- a/pkg/pb/api/proto/invite/invite.pb.go +++ b/pkg/pb/invite/invite.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.6 // protoc v5.29.3 -// source: api/proto/invite/invite.proto +// source: invite/invite.proto package invite @@ -33,7 +33,7 @@ type GenerateRequest struct { func (x *GenerateRequest) Reset() { *x = GenerateRequest{} - mi := &file_api_proto_invite_invite_proto_msgTypes[0] + mi := &file_invite_invite_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -45,7 +45,7 @@ func (x *GenerateRequest) String() string { func (*GenerateRequest) ProtoMessage() {} func (x *GenerateRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_invite_invite_proto_msgTypes[0] + mi := &file_invite_invite_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -58,7 +58,7 @@ func (x *GenerateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateRequest.ProtoReflect.Descriptor instead. func (*GenerateRequest) Descriptor() ([]byte, []int) { - return file_api_proto_invite_invite_proto_rawDescGZIP(), []int{0} + return file_invite_invite_proto_rawDescGZIP(), []int{0} } func (x *GenerateRequest) GetUserId() int64 { @@ -93,7 +93,7 @@ type GenerateResponse struct { func (x *GenerateResponse) Reset() { *x = GenerateResponse{} - mi := &file_api_proto_invite_invite_proto_msgTypes[1] + mi := &file_invite_invite_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -105,7 +105,7 @@ func (x *GenerateResponse) String() string { func (*GenerateResponse) ProtoMessage() {} func (x *GenerateResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_invite_invite_proto_msgTypes[1] + mi := &file_invite_invite_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -118,7 +118,7 @@ func (x *GenerateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateResponse.ProtoReflect.Descriptor instead. func (*GenerateResponse) Descriptor() ([]byte, []int) { - return file_api_proto_invite_invite_proto_rawDescGZIP(), []int{1} + return file_invite_invite_proto_rawDescGZIP(), []int{1} } func (x *GenerateResponse) GetCode() string { @@ -151,7 +151,7 @@ type GetInfoRequest struct { func (x *GetInfoRequest) Reset() { *x = GetInfoRequest{} - mi := &file_api_proto_invite_invite_proto_msgTypes[2] + mi := &file_invite_invite_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -163,7 +163,7 @@ func (x *GetInfoRequest) String() string { func (*GetInfoRequest) ProtoMessage() {} func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_invite_invite_proto_msgTypes[2] + mi := &file_invite_invite_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -176,7 +176,7 @@ func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoRequest.ProtoReflect.Descriptor instead. func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return file_api_proto_invite_invite_proto_rawDescGZIP(), []int{2} + return file_invite_invite_proto_rawDescGZIP(), []int{2} } func (x *GetInfoRequest) GetCode() string { @@ -201,7 +201,7 @@ type GetInfoResponse struct { func (x *GetInfoResponse) Reset() { *x = GetInfoResponse{} - mi := &file_api_proto_invite_invite_proto_msgTypes[3] + mi := &file_invite_invite_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -213,7 +213,7 @@ func (x *GetInfoResponse) String() string { func (*GetInfoResponse) ProtoMessage() {} func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_invite_invite_proto_msgTypes[3] + mi := &file_invite_invite_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -226,7 +226,7 @@ func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoResponse.ProtoReflect.Descriptor instead. func (*GetInfoResponse) Descriptor() ([]byte, []int) { - return file_api_proto_invite_invite_proto_rawDescGZIP(), []int{3} + return file_invite_invite_proto_rawDescGZIP(), []int{3} } func (x *GetInfoResponse) GetCode() string { @@ -278,11 +278,11 @@ func (x *GetInfoResponse) GetCreatedAt() *timestamppb.Timestamp { return nil } -var File_api_proto_invite_invite_proto protoreflect.FileDescriptor +var File_invite_invite_proto protoreflect.FileDescriptor -const file_api_proto_invite_invite_proto_rawDesc = "" + +const file_invite_invite_proto_rawDesc = "" + "\n" + - "\x1dapi/proto/invite/invite.proto\x12\x06invite\x1a\x1fgoogle/protobuf/timestamp.proto\"`\n" + + "\x13invite/invite.proto\x12\x06invite\x1a\x1fgoogle/protobuf/timestamp.proto\"`\n" + "\x0fGenerateRequest\x12\x17\n" + "\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x19\n" + "\bttl_days\x18\x02 \x01(\x05R\attlDays\x12\x19\n" + @@ -307,29 +307,29 @@ const file_api_proto_invite_invite_proto_rawDesc = "" + "created_at\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt2\x8a\x01\n" + "\rInviteService\x12=\n" + "\bGenerate\x12\x17.invite.GenerateRequest\x1a\x18.invite.GenerateResponse\x12:\n" + - "\aGetInfo\x12\x16.invite.GetInfoRequest\x1a\x17.invite.GetInfoResponseB9Z7github.com/smart-search-gateway/api/proto/invite/inviteb\x06proto3" + "\aGetInfo\x12\x16.invite.GetInfoRequest\x1a\x17.invite.GetInfoResponseB>Z google.protobuf.Timestamp 4, // 1: invite.GetInfoResponse.expires_at:type_name -> google.protobuf.Timestamp 4, // 2: invite.GetInfoResponse.created_at:type_name -> google.protobuf.Timestamp @@ -344,26 +344,26 @@ var file_api_proto_invite_invite_proto_depIdxs = []int32{ 0, // [0:3] is the sub-list for field type_name } -func init() { file_api_proto_invite_invite_proto_init() } -func file_api_proto_invite_invite_proto_init() { - if File_api_proto_invite_invite_proto != nil { +func init() { file_invite_invite_proto_init() } +func file_invite_invite_proto_init() { + if File_invite_invite_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_invite_invite_proto_rawDesc), len(file_api_proto_invite_invite_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_invite_invite_proto_rawDesc), len(file_invite_invite_proto_rawDesc)), NumEnums: 0, NumMessages: 4, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_api_proto_invite_invite_proto_goTypes, - DependencyIndexes: file_api_proto_invite_invite_proto_depIdxs, - MessageInfos: file_api_proto_invite_invite_proto_msgTypes, + GoTypes: file_invite_invite_proto_goTypes, + DependencyIndexes: file_invite_invite_proto_depIdxs, + MessageInfos: file_invite_invite_proto_msgTypes, }.Build() - File_api_proto_invite_invite_proto = out.File - file_api_proto_invite_invite_proto_goTypes = nil - file_api_proto_invite_invite_proto_depIdxs = nil + File_invite_invite_proto = out.File + file_invite_invite_proto_goTypes = nil + file_invite_invite_proto_depIdxs = nil } diff --git a/pkg/pb/api/proto/invite/invite_grpc.pb.go b/pkg/pb/invite/invite_grpc.pb.go similarity index 98% rename from pkg/pb/api/proto/invite/invite_grpc.pb.go rename to pkg/pb/invite/invite_grpc.pb.go index 3367574..0949b3a 100644 --- a/pkg/pb/api/proto/invite/invite_grpc.pb.go +++ b/pkg/pb/invite/invite_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: api/proto/invite/invite.proto +// source: invite/invite.proto package invite @@ -155,5 +155,5 @@ var InviteService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "api/proto/invite/invite.proto", + Metadata: "invite/invite.proto", } diff --git a/pkg/pb/api/proto/request/request.pb.go b/pkg/pb/request/request.pb.go similarity index 83% rename from pkg/pb/api/proto/request/request.pb.go rename to pkg/pb/request/request.pb.go index fe3e1b8..f818147 100644 --- a/pkg/pb/api/proto/request/request.pb.go +++ b/pkg/pb/request/request.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.6 // protoc v5.29.3 -// source: api/proto/request/request.proto +// source: request/request.proto package request @@ -34,7 +34,7 @@ type CreateTZRequest struct { func (x *CreateTZRequest) Reset() { *x = CreateTZRequest{} - mi := &file_api_proto_request_request_proto_msgTypes[0] + mi := &file_request_request_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -46,7 +46,7 @@ func (x *CreateTZRequest) String() string { func (*CreateTZRequest) ProtoMessage() {} func (x *CreateTZRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[0] + mi := &file_request_request_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -59,7 +59,7 @@ func (x *CreateTZRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTZRequest.ProtoReflect.Descriptor instead. func (*CreateTZRequest) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{0} + return file_request_request_proto_rawDescGZIP(), []int{0} } func (x *CreateTZRequest) GetUserId() int64 { @@ -100,7 +100,7 @@ type CreateTZResponse struct { func (x *CreateTZResponse) Reset() { *x = CreateTZResponse{} - mi := &file_api_proto_request_request_proto_msgTypes[1] + mi := &file_request_request_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -112,7 +112,7 @@ func (x *CreateTZResponse) String() string { func (*CreateTZResponse) ProtoMessage() {} func (x *CreateTZResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[1] + mi := &file_request_request_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -125,7 +125,7 @@ func (x *CreateTZResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTZResponse.ProtoReflect.Descriptor instead. func (*CreateTZResponse) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{1} + return file_request_request_proto_rawDescGZIP(), []int{1} } func (x *CreateTZResponse) GetRequestId() string { @@ -153,7 +153,7 @@ type ApproveTZRequest struct { func (x *ApproveTZRequest) Reset() { *x = ApproveTZRequest{} - mi := &file_api_proto_request_request_proto_msgTypes[2] + mi := &file_request_request_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -165,7 +165,7 @@ func (x *ApproveTZRequest) String() string { func (*ApproveTZRequest) ProtoMessage() {} func (x *ApproveTZRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[2] + mi := &file_request_request_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -178,7 +178,7 @@ func (x *ApproveTZRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveTZRequest.ProtoReflect.Descriptor instead. func (*ApproveTZRequest) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{2} + return file_request_request_proto_rawDescGZIP(), []int{2} } func (x *ApproveTZRequest) GetRequestId() string { @@ -212,7 +212,7 @@ type ApproveTZResponse struct { func (x *ApproveTZResponse) Reset() { *x = ApproveTZResponse{} - mi := &file_api_proto_request_request_proto_msgTypes[3] + mi := &file_request_request_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -224,7 +224,7 @@ func (x *ApproveTZResponse) String() string { func (*ApproveTZResponse) ProtoMessage() {} func (x *ApproveTZResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[3] + mi := &file_request_request_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -237,7 +237,7 @@ func (x *ApproveTZResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveTZResponse.ProtoReflect.Descriptor instead. func (*ApproveTZResponse) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{3} + return file_request_request_proto_rawDescGZIP(), []int{3} } func (x *ApproveTZResponse) GetSuccess() bool { @@ -263,7 +263,7 @@ type GetMailingListRequest struct { func (x *GetMailingListRequest) Reset() { *x = GetMailingListRequest{} - mi := &file_api_proto_request_request_proto_msgTypes[4] + mi := &file_request_request_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -275,7 +275,7 @@ func (x *GetMailingListRequest) String() string { func (*GetMailingListRequest) ProtoMessage() {} func (x *GetMailingListRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[4] + mi := &file_request_request_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -288,7 +288,7 @@ func (x *GetMailingListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMailingListRequest.ProtoReflect.Descriptor instead. func (*GetMailingListRequest) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{4} + return file_request_request_proto_rawDescGZIP(), []int{4} } func (x *GetMailingListRequest) GetUserId() int64 { @@ -307,7 +307,7 @@ type GetMailingListResponse struct { func (x *GetMailingListResponse) Reset() { *x = GetMailingListResponse{} - mi := &file_api_proto_request_request_proto_msgTypes[5] + mi := &file_request_request_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -319,7 +319,7 @@ func (x *GetMailingListResponse) String() string { func (*GetMailingListResponse) ProtoMessage() {} func (x *GetMailingListResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[5] + mi := &file_request_request_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -332,7 +332,7 @@ func (x *GetMailingListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMailingListResponse.ProtoReflect.Descriptor instead. func (*GetMailingListResponse) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{5} + return file_request_request_proto_rawDescGZIP(), []int{5} } func (x *GetMailingListResponse) GetItems() []*MailingItem { @@ -352,7 +352,7 @@ type GetMailingListByIDRequest struct { func (x *GetMailingListByIDRequest) Reset() { *x = GetMailingListByIDRequest{} - mi := &file_api_proto_request_request_proto_msgTypes[6] + mi := &file_request_request_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -364,7 +364,7 @@ func (x *GetMailingListByIDRequest) String() string { func (*GetMailingListByIDRequest) ProtoMessage() {} func (x *GetMailingListByIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[6] + mi := &file_request_request_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -377,7 +377,7 @@ func (x *GetMailingListByIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMailingListByIDRequest.ProtoReflect.Descriptor instead. func (*GetMailingListByIDRequest) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{6} + return file_request_request_proto_rawDescGZIP(), []int{6} } func (x *GetMailingListByIDRequest) GetRequestId() string { @@ -403,7 +403,7 @@ type GetMailingListByIDResponse struct { func (x *GetMailingListByIDResponse) Reset() { *x = GetMailingListByIDResponse{} - mi := &file_api_proto_request_request_proto_msgTypes[7] + mi := &file_request_request_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -415,7 +415,7 @@ func (x *GetMailingListByIDResponse) String() string { func (*GetMailingListByIDResponse) ProtoMessage() {} func (x *GetMailingListByIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[7] + mi := &file_request_request_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -428,7 +428,7 @@ func (x *GetMailingListByIDResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMailingListByIDResponse.ProtoReflect.Descriptor instead. func (*GetMailingListByIDResponse) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{7} + return file_request_request_proto_rawDescGZIP(), []int{7} } func (x *GetMailingListByIDResponse) GetItem() *MailingItem { @@ -452,7 +452,7 @@ type MailingItem struct { func (x *MailingItem) Reset() { *x = MailingItem{} - mi := &file_api_proto_request_request_proto_msgTypes[8] + mi := &file_request_request_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -464,7 +464,7 @@ func (x *MailingItem) String() string { func (*MailingItem) ProtoMessage() {} func (x *MailingItem) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_request_request_proto_msgTypes[8] + mi := &file_request_request_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -477,7 +477,7 @@ func (x *MailingItem) ProtoReflect() protoreflect.Message { // Deprecated: Use MailingItem.ProtoReflect.Descriptor instead. func (*MailingItem) Descriptor() ([]byte, []int) { - return file_api_proto_request_request_proto_rawDescGZIP(), []int{8} + return file_request_request_proto_rawDescGZIP(), []int{8} } func (x *MailingItem) GetRequestId() string { @@ -522,11 +522,11 @@ func (x *MailingItem) GetSuppliersFound() int32 { return 0 } -var File_api_proto_request_request_proto protoreflect.FileDescriptor +var File_request_request_proto protoreflect.FileDescriptor -const file_api_proto_request_request_proto_rawDesc = "" + +const file_request_request_proto_rawDesc = "" + "\n" + - "\x1fapi/proto/request/request.proto\x12\arequest\x1a\x1fgoogle/protobuf/timestamp.proto\"\x85\x01\n" + + "\x15request/request.proto\x12\arequest\x1a\x1fgoogle/protobuf/timestamp.proto\"\x85\x01\n" + "\x0fCreateTZRequest\x12\x17\n" + "\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x1f\n" + "\vrequest_txt\x18\x02 \x01(\tR\n" + @@ -569,22 +569,22 @@ const file_api_proto_request_request_proto_rawDesc = "" + "\bCreateTZ\x12\x18.request.CreateTZRequest\x1a\x19.request.CreateTZResponse\x12B\n" + "\tApproveTZ\x12\x19.request.ApproveTZRequest\x1a\x1a.request.ApproveTZResponse\x12Q\n" + "\x0eGetMailingList\x12\x1e.request.GetMailingListRequest\x1a\x1f.request.GetMailingListResponse\x12]\n" + - "\x12GetMailingListByID\x12\".request.GetMailingListByIDRequest\x1a#.request.GetMailingListByIDResponseB;Z9github.com/smart-search-gateway/api/proto/request/requestb\x06proto3" + "\x12GetMailingListByID\x12\".request.GetMailingListByIDRequest\x1a#.request.GetMailingListByIDResponseB?Z=git.techease.ru/Smart-search/smart-search-back/pkg/pb/requestb\x06proto3" var ( - file_api_proto_request_request_proto_rawDescOnce sync.Once - file_api_proto_request_request_proto_rawDescData []byte + file_request_request_proto_rawDescOnce sync.Once + file_request_request_proto_rawDescData []byte ) -func file_api_proto_request_request_proto_rawDescGZIP() []byte { - file_api_proto_request_request_proto_rawDescOnce.Do(func() { - file_api_proto_request_request_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_proto_request_request_proto_rawDesc), len(file_api_proto_request_request_proto_rawDesc))) +func file_request_request_proto_rawDescGZIP() []byte { + file_request_request_proto_rawDescOnce.Do(func() { + file_request_request_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_request_request_proto_rawDesc), len(file_request_request_proto_rawDesc))) }) - return file_api_proto_request_request_proto_rawDescData + return file_request_request_proto_rawDescData } -var file_api_proto_request_request_proto_msgTypes = make([]protoimpl.MessageInfo, 9) -var file_api_proto_request_request_proto_goTypes = []any{ +var file_request_request_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_request_request_proto_goTypes = []any{ (*CreateTZRequest)(nil), // 0: request.CreateTZRequest (*CreateTZResponse)(nil), // 1: request.CreateTZResponse (*ApproveTZRequest)(nil), // 2: request.ApproveTZRequest @@ -596,7 +596,7 @@ var file_api_proto_request_request_proto_goTypes = []any{ (*MailingItem)(nil), // 8: request.MailingItem (*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp } -var file_api_proto_request_request_proto_depIdxs = []int32{ +var file_request_request_proto_depIdxs = []int32{ 8, // 0: request.GetMailingListResponse.items:type_name -> request.MailingItem 8, // 1: request.GetMailingListByIDResponse.item:type_name -> request.MailingItem 9, // 2: request.MailingItem.created_at:type_name -> google.protobuf.Timestamp @@ -615,26 +615,26 @@ var file_api_proto_request_request_proto_depIdxs = []int32{ 0, // [0:3] is the sub-list for field type_name } -func init() { file_api_proto_request_request_proto_init() } -func file_api_proto_request_request_proto_init() { - if File_api_proto_request_request_proto != nil { +func init() { file_request_request_proto_init() } +func file_request_request_proto_init() { + if File_request_request_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_request_request_proto_rawDesc), len(file_api_proto_request_request_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_request_request_proto_rawDesc), len(file_request_request_proto_rawDesc)), NumEnums: 0, NumMessages: 9, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_api_proto_request_request_proto_goTypes, - DependencyIndexes: file_api_proto_request_request_proto_depIdxs, - MessageInfos: file_api_proto_request_request_proto_msgTypes, + GoTypes: file_request_request_proto_goTypes, + DependencyIndexes: file_request_request_proto_depIdxs, + MessageInfos: file_request_request_proto_msgTypes, }.Build() - File_api_proto_request_request_proto = out.File - file_api_proto_request_request_proto_goTypes = nil - file_api_proto_request_request_proto_depIdxs = nil + File_request_request_proto = out.File + file_request_request_proto_goTypes = nil + file_request_request_proto_depIdxs = nil } diff --git a/pkg/pb/api/proto/request/request_grpc.pb.go b/pkg/pb/request/request_grpc.pb.go similarity index 99% rename from pkg/pb/api/proto/request/request_grpc.pb.go rename to pkg/pb/request/request_grpc.pb.go index 1904b2e..c28b720 100644 --- a/pkg/pb/api/proto/request/request_grpc.pb.go +++ b/pkg/pb/request/request_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: api/proto/request/request.proto +// source: request/request.proto package request @@ -231,5 +231,5 @@ var RequestService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "api/proto/request/request.proto", + Metadata: "request/request.proto", } diff --git a/pkg/pb/api/proto/supplier/supplier.pb.go b/pkg/pb/supplier/supplier.pb.go similarity index 68% rename from pkg/pb/api/proto/supplier/supplier.pb.go rename to pkg/pb/supplier/supplier.pb.go index e4a9eec..e9121e5 100644 --- a/pkg/pb/api/proto/supplier/supplier.pb.go +++ b/pkg/pb/supplier/supplier.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.6 // protoc v5.29.3 -// source: api/proto/supplier/supplier.proto +// source: supplier/supplier.proto package supplier @@ -31,7 +31,7 @@ type ExportExcelRequest struct { func (x *ExportExcelRequest) Reset() { *x = ExportExcelRequest{} - mi := &file_api_proto_supplier_supplier_proto_msgTypes[0] + mi := &file_supplier_supplier_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -43,7 +43,7 @@ func (x *ExportExcelRequest) String() string { func (*ExportExcelRequest) ProtoMessage() {} func (x *ExportExcelRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_supplier_supplier_proto_msgTypes[0] + mi := &file_supplier_supplier_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -56,7 +56,7 @@ func (x *ExportExcelRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExportExcelRequest.ProtoReflect.Descriptor instead. func (*ExportExcelRequest) Descriptor() ([]byte, []int) { - return file_api_proto_supplier_supplier_proto_rawDescGZIP(), []int{0} + return file_supplier_supplier_proto_rawDescGZIP(), []int{0} } func (x *ExportExcelRequest) GetRequestId() string { @@ -84,7 +84,7 @@ type ExportExcelResponse struct { func (x *ExportExcelResponse) Reset() { *x = ExportExcelResponse{} - mi := &file_api_proto_supplier_supplier_proto_msgTypes[1] + mi := &file_supplier_supplier_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -96,7 +96,7 @@ func (x *ExportExcelResponse) String() string { func (*ExportExcelResponse) ProtoMessage() {} func (x *ExportExcelResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_supplier_supplier_proto_msgTypes[1] + mi := &file_supplier_supplier_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -109,7 +109,7 @@ func (x *ExportExcelResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExportExcelResponse.ProtoReflect.Descriptor instead. func (*ExportExcelResponse) Descriptor() ([]byte, []int) { - return file_api_proto_supplier_supplier_proto_rawDescGZIP(), []int{1} + return file_supplier_supplier_proto_rawDescGZIP(), []int{1} } func (x *ExportExcelResponse) GetFileData() []byte { @@ -133,11 +133,11 @@ func (x *ExportExcelResponse) GetMimeType() string { return "" } -var File_api_proto_supplier_supplier_proto protoreflect.FileDescriptor +var File_supplier_supplier_proto protoreflect.FileDescriptor -const file_api_proto_supplier_supplier_proto_rawDesc = "" + +const file_supplier_supplier_proto_rawDesc = "" + "\n" + - "!api/proto/supplier/supplier.proto\x12\bsupplier\"L\n" + + "\x17supplier/supplier.proto\x12\bsupplier\"L\n" + "\x12ExportExcelRequest\x12\x1d\n" + "\n" + "request_id\x18\x01 \x01(\tR\trequestId\x12\x17\n" + @@ -147,26 +147,26 @@ const file_api_proto_supplier_supplier_proto_rawDesc = "" + "\tfile_name\x18\x02 \x01(\tR\bfileName\x12\x1b\n" + "\tmime_type\x18\x03 \x01(\tR\bmimeType2]\n" + "\x0fSupplierService\x12J\n" + - "\vExportExcel\x12\x1c.supplier.ExportExcelRequest\x1a\x1d.supplier.ExportExcelResponseB=Z;github.com/smart-search-gateway/api/proto/supplier/supplierb\x06proto3" + "\vExportExcel\x12\x1c.supplier.ExportExcelRequest\x1a\x1d.supplier.ExportExcelResponseB@Z>git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplierb\x06proto3" var ( - file_api_proto_supplier_supplier_proto_rawDescOnce sync.Once - file_api_proto_supplier_supplier_proto_rawDescData []byte + file_supplier_supplier_proto_rawDescOnce sync.Once + file_supplier_supplier_proto_rawDescData []byte ) -func file_api_proto_supplier_supplier_proto_rawDescGZIP() []byte { - file_api_proto_supplier_supplier_proto_rawDescOnce.Do(func() { - file_api_proto_supplier_supplier_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_proto_supplier_supplier_proto_rawDesc), len(file_api_proto_supplier_supplier_proto_rawDesc))) +func file_supplier_supplier_proto_rawDescGZIP() []byte { + file_supplier_supplier_proto_rawDescOnce.Do(func() { + file_supplier_supplier_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_supplier_supplier_proto_rawDesc), len(file_supplier_supplier_proto_rawDesc))) }) - return file_api_proto_supplier_supplier_proto_rawDescData + return file_supplier_supplier_proto_rawDescData } -var file_api_proto_supplier_supplier_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_api_proto_supplier_supplier_proto_goTypes = []any{ +var file_supplier_supplier_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_supplier_supplier_proto_goTypes = []any{ (*ExportExcelRequest)(nil), // 0: supplier.ExportExcelRequest (*ExportExcelResponse)(nil), // 1: supplier.ExportExcelResponse } -var file_api_proto_supplier_supplier_proto_depIdxs = []int32{ +var file_supplier_supplier_proto_depIdxs = []int32{ 0, // 0: supplier.SupplierService.ExportExcel:input_type -> supplier.ExportExcelRequest 1, // 1: supplier.SupplierService.ExportExcel:output_type -> supplier.ExportExcelResponse 1, // [1:2] is the sub-list for method output_type @@ -176,26 +176,26 @@ var file_api_proto_supplier_supplier_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_api_proto_supplier_supplier_proto_init() } -func file_api_proto_supplier_supplier_proto_init() { - if File_api_proto_supplier_supplier_proto != nil { +func init() { file_supplier_supplier_proto_init() } +func file_supplier_supplier_proto_init() { + if File_supplier_supplier_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_supplier_supplier_proto_rawDesc), len(file_api_proto_supplier_supplier_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_supplier_supplier_proto_rawDesc), len(file_supplier_supplier_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_api_proto_supplier_supplier_proto_goTypes, - DependencyIndexes: file_api_proto_supplier_supplier_proto_depIdxs, - MessageInfos: file_api_proto_supplier_supplier_proto_msgTypes, + GoTypes: file_supplier_supplier_proto_goTypes, + DependencyIndexes: file_supplier_supplier_proto_depIdxs, + MessageInfos: file_supplier_supplier_proto_msgTypes, }.Build() - File_api_proto_supplier_supplier_proto = out.File - file_api_proto_supplier_supplier_proto_goTypes = nil - file_api_proto_supplier_supplier_proto_depIdxs = nil + File_supplier_supplier_proto = out.File + file_supplier_supplier_proto_goTypes = nil + file_supplier_supplier_proto_depIdxs = nil } diff --git a/pkg/pb/api/proto/supplier/supplier_grpc.pb.go b/pkg/pb/supplier/supplier_grpc.pb.go similarity index 98% rename from pkg/pb/api/proto/supplier/supplier_grpc.pb.go rename to pkg/pb/supplier/supplier_grpc.pb.go index 0b28696..02bff7e 100644 --- a/pkg/pb/api/proto/supplier/supplier_grpc.pb.go +++ b/pkg/pb/supplier/supplier_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: api/proto/supplier/supplier.proto +// source: supplier/supplier.proto package supplier @@ -117,5 +117,5 @@ var SupplierService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "api/proto/supplier/supplier.proto", + Metadata: "supplier/supplier.proto", } diff --git a/pkg/pb/api/proto/user/user.pb.go b/pkg/pb/user/user.pb.go similarity index 83% rename from pkg/pb/api/proto/user/user.pb.go rename to pkg/pb/user/user.pb.go index 2ef1a88..863b9ba 100644 --- a/pkg/pb/api/proto/user/user.pb.go +++ b/pkg/pb/user/user.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.6 // protoc v5.29.3 -// source: api/proto/user/user.proto +// source: user/user.proto package user @@ -30,7 +30,7 @@ type GetInfoRequest struct { func (x *GetInfoRequest) Reset() { *x = GetInfoRequest{} - mi := &file_api_proto_user_user_proto_msgTypes[0] + mi := &file_user_user_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -42,7 +42,7 @@ func (x *GetInfoRequest) String() string { func (*GetInfoRequest) ProtoMessage() {} func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[0] + mi := &file_user_user_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -55,7 +55,7 @@ func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoRequest.ProtoReflect.Descriptor instead. func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{0} + return file_user_user_proto_rawDescGZIP(), []int{0} } func (x *GetInfoRequest) GetUserId() int64 { @@ -78,7 +78,7 @@ type GetInfoResponse struct { func (x *GetInfoResponse) Reset() { *x = GetInfoResponse{} - mi := &file_api_proto_user_user_proto_msgTypes[1] + mi := &file_user_user_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -90,7 +90,7 @@ func (x *GetInfoResponse) String() string { func (*GetInfoResponse) ProtoMessage() {} func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[1] + mi := &file_user_user_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -103,7 +103,7 @@ func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoResponse.ProtoReflect.Descriptor instead. func (*GetInfoResponse) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{1} + return file_user_user_proto_rawDescGZIP(), []int{1} } func (x *GetInfoResponse) GetEmail() string { @@ -150,7 +150,7 @@ type GetBalanceRequest struct { func (x *GetBalanceRequest) Reset() { *x = GetBalanceRequest{} - mi := &file_api_proto_user_user_proto_msgTypes[2] + mi := &file_user_user_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -162,7 +162,7 @@ func (x *GetBalanceRequest) String() string { func (*GetBalanceRequest) ProtoMessage() {} func (x *GetBalanceRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[2] + mi := &file_user_user_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -175,7 +175,7 @@ func (x *GetBalanceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBalanceRequest.ProtoReflect.Descriptor instead. func (*GetBalanceRequest) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{2} + return file_user_user_proto_rawDescGZIP(), []int{2} } func (x *GetBalanceRequest) GetUserId() int64 { @@ -194,7 +194,7 @@ type GetBalanceResponse struct { func (x *GetBalanceResponse) Reset() { *x = GetBalanceResponse{} - mi := &file_api_proto_user_user_proto_msgTypes[3] + mi := &file_user_user_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -206,7 +206,7 @@ func (x *GetBalanceResponse) String() string { func (*GetBalanceResponse) ProtoMessage() {} func (x *GetBalanceResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[3] + mi := &file_user_user_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -219,7 +219,7 @@ func (x *GetBalanceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBalanceResponse.ProtoReflect.Descriptor instead. func (*GetBalanceResponse) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{3} + return file_user_user_proto_rawDescGZIP(), []int{3} } func (x *GetBalanceResponse) GetBalance() float64 { @@ -238,7 +238,7 @@ type GetStatisticsRequest struct { func (x *GetStatisticsRequest) Reset() { *x = GetStatisticsRequest{} - mi := &file_api_proto_user_user_proto_msgTypes[4] + mi := &file_user_user_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -250,7 +250,7 @@ func (x *GetStatisticsRequest) String() string { func (*GetStatisticsRequest) ProtoMessage() {} func (x *GetStatisticsRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[4] + mi := &file_user_user_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -263,7 +263,7 @@ func (x *GetStatisticsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetStatisticsRequest.ProtoReflect.Descriptor instead. func (*GetStatisticsRequest) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{4} + return file_user_user_proto_rawDescGZIP(), []int{4} } func (x *GetStatisticsRequest) GetUserId() int64 { @@ -285,7 +285,7 @@ type GetStatisticsResponse struct { func (x *GetStatisticsResponse) Reset() { *x = GetStatisticsResponse{} - mi := &file_api_proto_user_user_proto_msgTypes[5] + mi := &file_user_user_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -297,7 +297,7 @@ func (x *GetStatisticsResponse) String() string { func (*GetStatisticsResponse) ProtoMessage() {} func (x *GetStatisticsResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[5] + mi := &file_user_user_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -310,7 +310,7 @@ func (x *GetStatisticsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetStatisticsResponse.ProtoReflect.Descriptor instead. func (*GetStatisticsResponse) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{5} + return file_user_user_proto_rawDescGZIP(), []int{5} } func (x *GetStatisticsResponse) GetTotalRequests() int32 { @@ -350,7 +350,7 @@ type GetBalanceStatisticsRequest struct { func (x *GetBalanceStatisticsRequest) Reset() { *x = GetBalanceStatisticsRequest{} - mi := &file_api_proto_user_user_proto_msgTypes[6] + mi := &file_user_user_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -362,7 +362,7 @@ func (x *GetBalanceStatisticsRequest) String() string { func (*GetBalanceStatisticsRequest) ProtoMessage() {} func (x *GetBalanceStatisticsRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[6] + mi := &file_user_user_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -375,7 +375,7 @@ func (x *GetBalanceStatisticsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBalanceStatisticsRequest.ProtoReflect.Descriptor instead. func (*GetBalanceStatisticsRequest) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{6} + return file_user_user_proto_rawDescGZIP(), []int{6} } func (x *GetBalanceStatisticsRequest) GetUserId() int64 { @@ -396,7 +396,7 @@ type GetBalanceStatisticsResponse struct { func (x *GetBalanceStatisticsResponse) Reset() { *x = GetBalanceStatisticsResponse{} - mi := &file_api_proto_user_user_proto_msgTypes[7] + mi := &file_user_user_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -408,7 +408,7 @@ func (x *GetBalanceStatisticsResponse) String() string { func (*GetBalanceStatisticsResponse) ProtoMessage() {} func (x *GetBalanceStatisticsResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_user_user_proto_msgTypes[7] + mi := &file_user_user_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -421,7 +421,7 @@ func (x *GetBalanceStatisticsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBalanceStatisticsResponse.ProtoReflect.Descriptor instead. func (*GetBalanceStatisticsResponse) Descriptor() ([]byte, []int) { - return file_api_proto_user_user_proto_rawDescGZIP(), []int{7} + return file_user_user_proto_rawDescGZIP(), []int{7} } func (x *GetBalanceStatisticsResponse) GetBalance() float64 { @@ -445,11 +445,11 @@ func (x *GetBalanceStatisticsResponse) GetTotalSpent() float64 { return 0 } -var File_api_proto_user_user_proto protoreflect.FileDescriptor +var File_user_user_proto protoreflect.FileDescriptor -const file_api_proto_user_user_proto_rawDesc = "" + +const file_user_user_proto_rawDesc = "" + "\n" + - "\x19api/proto/user/user.proto\x12\x04user\")\n" + + "\x0fuser/user.proto\x12\x04user\")\n" + "\x0eGetInfoRequest\x12\x17\n" + "\auser_id\x18\x01 \x01(\x03R\x06userId\"\x9b\x01\n" + "\x0fGetInfoResponse\x12\x14\n" + @@ -482,22 +482,22 @@ const file_api_proto_user_user_proto_rawDesc = "" + "\n" + "GetBalance\x12\x17.user.GetBalanceRequest\x1a\x18.user.GetBalanceResponse\x12H\n" + "\rGetStatistics\x12\x1a.user.GetStatisticsRequest\x1a\x1b.user.GetStatisticsResponse\x12]\n" + - "\x14GetBalanceStatistics\x12!.user.GetBalanceStatisticsRequest\x1a\".user.GetBalanceStatisticsResponseB5Z3github.com/smart-search-gateway/api/proto/user/userb\x06proto3" + "\x14GetBalanceStatistics\x12!.user.GetBalanceStatisticsRequest\x1a\".user.GetBalanceStatisticsResponseB user.GetInfoRequest 2, // 1: user.UserService.GetBalance:input_type -> user.GetBalanceRequest 4, // 2: user.UserService.GetStatistics:input_type -> user.GetStatisticsRequest @@ -523,26 +523,26 @@ var file_api_proto_user_user_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_api_proto_user_user_proto_init() } -func file_api_proto_user_user_proto_init() { - if File_api_proto_user_user_proto != nil { +func init() { file_user_user_proto_init() } +func file_user_user_proto_init() { + if File_user_user_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_user_user_proto_rawDesc), len(file_api_proto_user_user_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_user_proto_rawDesc), len(file_user_user_proto_rawDesc)), NumEnums: 0, NumMessages: 8, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_api_proto_user_user_proto_goTypes, - DependencyIndexes: file_api_proto_user_user_proto_depIdxs, - MessageInfos: file_api_proto_user_user_proto_msgTypes, + GoTypes: file_user_user_proto_goTypes, + DependencyIndexes: file_user_user_proto_depIdxs, + MessageInfos: file_user_user_proto_msgTypes, }.Build() - File_api_proto_user_user_proto = out.File - file_api_proto_user_user_proto_goTypes = nil - file_api_proto_user_user_proto_depIdxs = nil + File_user_user_proto = out.File + file_user_user_proto_goTypes = nil + file_user_user_proto_depIdxs = nil } diff --git a/pkg/pb/api/proto/user/user_grpc.pb.go b/pkg/pb/user/user_grpc.pb.go similarity index 99% rename from pkg/pb/api/proto/user/user_grpc.pb.go rename to pkg/pb/user/user_grpc.pb.go index a74cf31..3ad2eb5 100644 --- a/pkg/pb/api/proto/user/user_grpc.pb.go +++ b/pkg/pb/user/user_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: api/proto/user/user.proto +// source: user/user.proto package user @@ -231,5 +231,5 @@ var UserService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "api/proto/user/user.proto", + Metadata: "user/user.proto", }