From 75198ed00fc29d395cdc93596cb3a03af9b219b0 Mon Sep 17 00:00:00 2001 From: valitovgaziz Date: Fri, 12 Jun 2026 08:46:20 +0500 Subject: [PATCH] docs: add integration test run instructions to README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added section 8 'Тестирование' with run instructions, structure, features, and diagnostics - Also includes test file route path adjustments and import reordering --- .../yalarba/api_yal/documentation/README.md | 60 +++ .../api_yal/tests/integration/account_test.go | 32 +- .../api_yal/tests/integration/appeal_test.go | 316 +++++++------- .../api_yal/tests/integration/auth_test.go | 368 ++++++++--------- .../api_yal/tests/integration/comment_test.go | 360 ++++++++-------- .../tests/integration/feedback_test.go | 352 ++++++++-------- .../api_yal/tests/integration/object_test.go | 33 +- .../api_yal/tests/integration/rating_test.go | 386 +++++++++--------- 8 files changed, 934 insertions(+), 973 deletions(-) diff --git a/main_dc/yalarba/api_yal/documentation/README.md b/main_dc/yalarba/api_yal/documentation/README.md index 0805f8e..cb19202 100644 --- a/main_dc/yalarba/api_yal/documentation/README.md +++ b/main_dc/yalarba/api_yal/documentation/README.md @@ -1344,4 +1344,64 @@ Refresh token хранится в **HttpOnly cookie**. "field password is invalid: min" ] } +``` + +--- + +## 8. Тестирование + +### 8.1 Запуск интеграционных тестов + +Интеграционные тесты используют in-memory SQLite и mock-репозитории. Запуск: + +```bash +cd main_dc/yalarba/api_yal +CGO_ENABLED=1 go test ./tests/integration/... -v -count=1 +``` + +**Требования:** +- Go 1.21+ +- `CGO_ENABLED=1` (используется `mattn/go-sqlite3`) +- Зависимости устанавливаются автоматически через `go mod download` + +### 8.2 Структура тестов + +``` +tests/ +├── integration/ +│ ├── account_test.go # Тесты аккаунтов (профиль, обновление, удаление) +│ ├── appeal_test.go # Тесты обращений (CRUD, мои обращения) +│ ├── auth_test.go # Тесты аутентификации (регистрация, логин, refresh, logout, сброс пароля) +│ ├── comment_test.go # Тесты комментариев (CRUD, список, статистика) +│ ├── feedback_test.go # Тесты отзывов (CRUD, список, поиск, статистика) +│ ├── object_test.go # Тесты объектов (CRUD, поиск, nearby) +│ └── rating_test.go # Тесты рейтингов (голосование, статистика) +└── testutils/ + ├── fixtures.go # DTO и хелперы создания тестовых данных + ├── mock_appeal_repository.go # Mock-репозиторий обращений (map-based) + ├── mock_object_repository.go # Mock-репозиторий объектов (map-based) + ├── setup.go # TestConfig, TestUser, HTTP-клиент + └── test_server.go # Chi-роутер, in-memory SQLite, middleware +``` + +### 8.3 Особенности + +- **Общий сервер**: Все тесты в одном запуске используют один экземпляр `TestServer` (синглтон через `sync.Once`). +- **In-memory БД**: SQLite `file::memory:?cache=shared`, данные не сохраняются между запусками. +- **Mock-репозитории**: `ObjectRepository` и `AppealRepository` заменены на map-based реализации (избегают Haversine и jsonb-зависимостей). +- **Автоочистка**: Тестовые пользователи удаляются после каждого теста через `CleanupTestUser`. +- **Bearer-токены**: JWT токен создаётся при регистрации и передаётся в `Authorization` заголовке. + +### 8.4 Диагностика + +Для просмотра HTTP-логов сервера: + +```bash +CGO_ENABLED=1 go test ./tests/integration/... -v -count=1 2>&1 | grep "\[ValitovGazizPC" +``` + +Фильтрация по конкретному тесту: + +```bash +CGO_ENABLED=1 go test ./tests/integration/... -v -count=1 -run "TestAuthFlow/PasswordReset" ``` \ No newline at end of file diff --git a/main_dc/yalarba/api_yal/tests/integration/account_test.go b/main_dc/yalarba/api_yal/tests/integration/account_test.go index c50c88b..214b56d 100644 --- a/main_dc/yalarba/api_yal/tests/integration/account_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/account_test.go @@ -1,21 +1,18 @@ package integration import ( - "api_yal/tests/testutils" "testing" + "api_yal/tests/testutils" ) -// TestAccountEndpoints тестирует все эндпоинты управления аккаунтом пользователя -// Включает получение профиля, обновление данных, смену пароля и удаление аккаунта func TestAccountEndpoints(t *testing.T) { config := testutils.NewTestConfig() - // GetProfile тестирует получение профиля авторизованного пользователя t.Run("GetProfile", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) - resp, err := config.Request("GET", "/account/profile", nil, user.Token) + resp, err := config.Request("GET", "/profile", nil, user.Token) if err != nil { t.Fatalf("Failed to get profile: %v", err) } @@ -30,7 +27,6 @@ func TestAccountEndpoints(t *testing.T) { t.Fatalf("Failed to parse response: %v", err) } - // Проверяем наличие всех обязательных полей в ответе expectedFields := []string{"id", "email", "full_name", "first_name", "last_name", "role", "stats"} for _, field := range expectedFields { if _, ok := profile[field]; !ok { @@ -39,12 +35,11 @@ func TestAccountEndpoints(t *testing.T) { } }) - // GetOwnAccount тестирует получение данных собственного аккаунта t.Run("GetOwnAccount", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) - resp, err := config.Request("GET", "/account", nil, user.Token) + resp, err := config.Request("GET", "/me", nil, user.Token) if err != nil { t.Fatalf("Failed to get account: %v", err) } @@ -55,7 +50,6 @@ func TestAccountEndpoints(t *testing.T) { } }) - // UpdateAccount тестирует обновление данных аккаунта (телефон, город) t.Run("UpdateAccount", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) @@ -65,7 +59,7 @@ func TestAccountEndpoints(t *testing.T) { "city": "Moscow", } - resp, err := config.Request("PUT", "/account", updateData, user.Token) + resp, err := config.Request("PUT", "/me", updateData, user.Token) if err != nil { t.Fatalf("Failed to update account: %v", err) } @@ -80,19 +74,17 @@ func TestAccountEndpoints(t *testing.T) { t.Fatalf("Failed to parse response: %v", err) } - // Проверяем, что номер телефона обновился корректно if phone, ok := updatedAccount["phone"].(string); !ok || phone != "+79998887766" { t.Error("Phone number not updated correctly") } }) - // ChangePassword тестирует успешную смену пароля t.Run("ChangePassword", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) newPassword := "newpass123" - resp, err := config.Request("POST", "/account/change-password", map[string]interface{}{ + resp, err := config.Request("POST", "/change-password", map[string]interface{}{ "current_password": user.Password, "new_password": newPassword, }, user.Token) @@ -105,7 +97,6 @@ func TestAccountEndpoints(t *testing.T) { t.Errorf("Expected status 200, got %d", resp.StatusCode) } - // Проверяем, что можно войти с новым паролем newToken, err := config.GetAuthToken(user.Email, newPassword) if err != nil { t.Errorf("Failed to login with new password: %v", err) @@ -115,12 +106,11 @@ func TestAccountEndpoints(t *testing.T) { } }) - // ChangePasswordWrongCurrent тестирует смену пароля с неверным текущим паролем t.Run("ChangePasswordWrongCurrent", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) - resp, err := config.Request("POST", "/account/change-password", map[string]interface{}{ + resp, err := config.Request("POST", "/change-password", map[string]interface{}{ "current_password": "wrongpassword", "new_password": "newpass123", }, user.Token) @@ -129,17 +119,15 @@ func TestAccountEndpoints(t *testing.T) { } defer resp.Body.Close() - // Ожидаем ошибку 400 или 401 при неверном текущем пароле if resp.StatusCode != 400 && resp.StatusCode != 401 { t.Errorf("Expected status 400 or 401, got %d", resp.StatusCode) } }) - // DeleteAccount тестирует удаление аккаунта t.Run("DeleteAccount", func(t *testing.T) { user := config.CreateTestUser(t) - resp, err := config.Request("DELETE", "/account", nil, user.Token) + resp, err := config.Request("DELETE", "/me", nil, user.Token) if err != nil { t.Fatalf("Failed to delete account: %v", err) } @@ -149,16 +137,14 @@ func TestAccountEndpoints(t *testing.T) { t.Errorf("Expected status 200, got %d", resp.StatusCode) } - // Проверяем, что больше нельзя войти после удаления аккаунта _, err = config.GetAuthToken(user.Email, user.Password) if err == nil { t.Error("Should not be able to login after account deletion") } }) - // UnauthorizedAccess тестирует доступ к защищенным эндпоинтам без токена t.Run("UnauthorizedAccess", func(t *testing.T) { - resp, err := config.Request("GET", "/account/profile", nil, "") + resp, err := config.Request("GET", "/profile", nil, "") if err != nil { t.Fatalf("Failed to make request: %v", err) } @@ -168,4 +154,4 @@ func TestAccountEndpoints(t *testing.T) { t.Errorf("Expected status 401, got %d", resp.StatusCode) } }) -} \ No newline at end of file +} diff --git a/main_dc/yalarba/api_yal/tests/integration/appeal_test.go b/main_dc/yalarba/api_yal/tests/integration/appeal_test.go index 1c5ee5e..e1265b4 100644 --- a/main_dc/yalarba/api_yal/tests/integration/appeal_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/appeal_test.go @@ -1,202 +1,188 @@ package integration import ( - "testing" - "api_yal/tests/testutils" + "fmt" + "testing" + "api_yal/tests/testutils" ) -// TestAppealEndpoints тестирует все эндпоинты для работы с обращениями пользователей -// Включает создание, получение, обновление, удаление обращений и получение списка своих обращений func TestAppealEndpoints(t *testing.T) { - config := testutils.NewTestConfig() + config := testutils.NewTestConfig() - // CreateAppeal тестирует создание нового обращения - t.Run("CreateAppeal", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("CreateAppeal", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - appealData := map[string]interface{}{ - "type": "complaint", - "title": "Test Appeal", - "message": "This is a test appeal message for testing purposes", - "priority": "high", - "contact_name": "Test User", - "contact_email": user.Email, - } + appealData := map[string]interface{}{ + "type": "complaint", + "title": "Test Appeal", + "message": "This is a test appeal message for testing purposes", + "priority": "high", + "contact_name": "Test User", + "contact_email": user.Email, + } - resp, err := config.Request("POST", "/appeals", appealData, user.Token) - if err != nil { - t.Fatalf("Failed to create appeal: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("POST", "/appeals", appealData, user.Token) + if err != nil { + t.Fatalf("Failed to create appeal: %v", err) + } + defer resp.Body.Close() - // Ожидаем статус 201 Created - if resp.StatusCode != 201 { - t.Errorf("Expected status 201, got %d", resp.StatusCode) - } + if resp.StatusCode != 201 { + t.Errorf("Expected status 201, got %d", resp.StatusCode) + } - var createdAppeal map[string]interface{} - if err := config.ParseResponse(resp, &createdAppeal); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdAppeal map[string]interface{} + if err := config.ParseResponse(resp, &createdAppeal); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Проверяем, что ID обращения присутствует в ответе - if _, ok := createdAppeal["id"]; !ok { - t.Error("Appeal ID not found") - } - }) + if _, ok := createdAppeal["id"]; !ok { + t.Error("Appeal ID not found") + } + }) - // GetAppealByID тестирует получение обращения по ID - t.Run("GetAppealByID", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("GetAppealByID", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - // Создаем обращение - appealData := map[string]interface{}{ - "type": "question", - "title": "Test Question", - "message": "This is a test question", - "contact_email": user.Email, - } - resp, err := config.Request("POST", "/appeals", appealData, user.Token) - if err != nil { - t.Fatalf("Failed to create appeal: %v", err) - } - defer resp.Body.Close() + appealData := map[string]interface{}{ + "type": "question", + "title": "Test Question", + "message": "This is a test question", + "contact_email": user.Email, + } + resp, err := config.Request("POST", "/appeals", appealData, user.Token) + if err != nil { + t.Fatalf("Failed to create appeal: %v", err) + } + defer resp.Body.Close() - var createdAppeal map[string]interface{} - if err := config.ParseResponse(resp, &createdAppeal); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdAppeal map[string]interface{} + if err := config.ParseResponse(resp, &createdAppeal); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - appealID := createdAppeal["id"].(float64) + appealID := createdAppeal["id"].(float64) - getResp, err := config.Request("GET", "/appeals/"+string(rune(appealID)), nil, user.Token) - if err != nil { - t.Fatalf("Failed to get appeal: %v", err) - } - defer getResp.Body.Close() + getResp, err := config.Request("GET", "/appeals/"+fmt.Sprintf("%.0f", appealID), nil, user.Token) + if err != nil { + t.Fatalf("Failed to get appeal: %v", err) + } + defer getResp.Body.Close() - if getResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", getResp.StatusCode) - } - }) + if getResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", getResp.StatusCode) + } + }) - // UpdateAppeal тестирует обновление существующего обращения - t.Run("UpdateAppeal", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("UpdateAppeal", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - // Создаем обращение - appealData := map[string]interface{}{ - "type": "suggestion", - "title": "Original Title", - "message": "Original message for testing", - "contact_email": user.Email, - } - resp, err := config.Request("POST", "/appeals", appealData, user.Token) - if err != nil { - t.Fatalf("Failed to create appeal: %v", err) - } - defer resp.Body.Close() + appealData := map[string]interface{}{ + "type": "suggestion", + "title": "Original Title", + "message": "Original message for testing", + "contact_email": user.Email, + } + resp, err := config.Request("POST", "/appeals", appealData, user.Token) + if err != nil { + t.Fatalf("Failed to create appeal: %v", err) + } + defer resp.Body.Close() - var createdAppeal map[string]interface{} - if err := config.ParseResponse(resp, &createdAppeal); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdAppeal map[string]interface{} + if err := config.ParseResponse(resp, &createdAppeal); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - appealID := createdAppeal["id"].(float64) + appealID := createdAppeal["id"].(float64) - updateData := map[string]interface{}{ - "title": "Updated Title", - "message": "Updated message content", - "priority": "critical", - } + updateData := map[string]interface{}{ + "title": "Updated Title", + "message": "Updated message content", + "priority": "critical", + } - updateResp, err := config.Request("PUT", "/appeals/"+string(rune(appealID)), updateData, user.Token) - if err != nil { - t.Fatalf("Failed to update appeal: %v", err) - } - defer updateResp.Body.Close() + updateResp, err := config.Request("PUT", "/appeals/"+fmt.Sprintf("%.0f", appealID), updateData, user.Token) + if err != nil { + t.Fatalf("Failed to update appeal: %v", err) + } + defer updateResp.Body.Close() - if updateResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", updateResp.StatusCode) - } - }) + if updateResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", updateResp.StatusCode) + } + }) - // MyAppeals тестирует получение списка обращений текущего пользователя - t.Run("MyAppeals", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("MyAppeals", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - // Создаем несколько обращений - for i := 0; i < 3; i++ { - appealData := map[string]interface{}{ - "type": "other", - "title": "Test Appeal", - "message": "Test message content", - } - _, err := config.Request("POST", "/appeals", appealData, user.Token) - if err != nil { - t.Fatalf("Failed to create appeal: %v", err) - } - } + for i := 0; i < 3; i++ { + appealData := map[string]interface{}{ + "type": "other", + "title": "Test Appeal", + "message": "Test message content", + } + _, err := config.Request("POST", "/appeals", appealData, user.Token) + if err != nil { + t.Fatalf("Failed to create appeal: %v", err) + } + } - resp, err := config.Request("GET", "/appeals/me", nil, user.Token) - if err != nil { - t.Fatalf("Failed to get my appeals: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/appeals/me", nil, user.Token) + if err != nil { + t.Fatalf("Failed to get my appeals: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // DeleteAppeal тестирует удаление обращения - t.Run("DeleteAppeal", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("DeleteAppeal", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - // Создаем обращение - appealData := map[string]interface{}{ - "type": "question", - "title": "To Delete", - "message": "This appeal will be deleted", - } - resp, err := config.Request("POST", "/appeals", appealData, user.Token) - if err != nil { - t.Fatalf("Failed to create appeal: %v", err) - } - defer resp.Body.Close() + appealData := map[string]interface{}{ + "type": "question", + "title": "To Delete", + "message": "This appeal will be deleted", + } + resp, err := config.Request("POST", "/appeals", appealData, user.Token) + if err != nil { + t.Fatalf("Failed to create appeal: %v", err) + } + defer resp.Body.Close() - var createdAppeal map[string]interface{} - if err := config.ParseResponse(resp, &createdAppeal); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdAppeal map[string]interface{} + if err := config.ParseResponse(resp, &createdAppeal); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - appealID := createdAppeal["id"].(float64) + appealID := createdAppeal["id"].(float64) - deleteResp, err := config.Request("DELETE", "/appeals/"+string(rune(appealID)), nil, user.Token) - if err != nil { - t.Fatalf("Failed to delete appeal: %v", err) - } - defer deleteResp.Body.Close() + deleteResp, err := config.Request("DELETE", "/appeals/"+fmt.Sprintf("%.0f", appealID), nil, user.Token) + if err != nil { + t.Fatalf("Failed to delete appeal: %v", err) + } + defer deleteResp.Body.Close() - // Ожидаем статус 204 No Content при успешном удалении - if deleteResp.StatusCode != 204 { - t.Errorf("Expected status 204, got %d", deleteResp.StatusCode) - } + if deleteResp.StatusCode != 204 { + t.Errorf("Expected status 204, got %d", deleteResp.StatusCode) + } - // Проверяем, что обращение удалено - должно вернуть 404 - getResp, err := config.Request("GET", "/appeals/"+string(rune(appealID)), nil, user.Token) - if err != nil { - t.Fatalf("Failed to get appeal: %v", err) - } - defer getResp.Body.Close() + getResp, err := config.Request("GET", "/appeals/"+fmt.Sprintf("%.0f", appealID), nil, user.Token) + if err != nil { + t.Fatalf("Failed to get appeal: %v", err) + } + defer getResp.Body.Close() - if getResp.StatusCode != 404 { - t.Errorf("Expected status 404 for deleted appeal, got %d", getResp.StatusCode) - } - }) -} \ No newline at end of file + if getResp.StatusCode != 404 { + t.Errorf("Expected status 404 for deleted appeal, got %d", getResp.StatusCode) + } + }) +} diff --git a/main_dc/yalarba/api_yal/tests/integration/auth_test.go b/main_dc/yalarba/api_yal/tests/integration/auth_test.go index cf21971..f788d7e 100644 --- a/main_dc/yalarba/api_yal/tests/integration/auth_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/auth_test.go @@ -1,228 +1,218 @@ package integration import ( - "testing" - "api_yal/tests/testutils" + "testing" + "api_yal/tests/testutils" ) -// TestAuthFlow тестирует полный поток аутентификации пользователя -// Включает регистрацию, логин, обновление токена, выход, сброс пароля и мобильную авторизацию func TestAuthFlow(t *testing.T) { - config := testutils.NewTestConfig() - - // Register тестирует регистрацию нового пользователя - t.Run("Register", func(t *testing.T) { - testData := map[string]interface{}{ - "email": "testflow@example.com", - "password": "test123456", - "first_name": "Flow", - "last_name": "Test", - } + config := testutils.NewTestConfig() - resp, err := config.Request("POST", "/auth/register", testData, "") - if err != nil { - t.Fatalf("Failed to register: %v", err) - } - defer resp.Body.Close() + t.Run("Register", func(t *testing.T) { + testData := map[string]interface{}{ + "email": "testflow@example.com", + "password": "test123456", + "first_name": "Flow", + "last_name": "Test", + } - // Ожидаем статус 201 Created при успешной регистрации - if resp.StatusCode != 201 { - t.Errorf("Expected status 201, got %d", resp.StatusCode) - } + resp, err := config.Request("POST", "/auth/register", testData, "") + if err != nil { + t.Fatalf("Failed to register: %v", err) + } + defer resp.Body.Close() - var result map[string]interface{} - if err := config.ParseResponse(resp, &result); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + if resp.StatusCode != 201 { + t.Errorf("Expected status 201, got %d", resp.StatusCode) + } - // Проверяем наличие токена и данных пользователя в ответе - if _, ok := result["token"]; !ok { - t.Error("Token not found in response") - } + var result map[string]interface{} + if err := config.ParseResponse(resp, &result); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - if _, ok := result["user"]; !ok { - t.Error("User data not found in response") - } - }) + if _, ok := result["token"]; !ok { + t.Error("Token not found in response") + } - // Login тестирует вход существующего пользователя - t.Run("Login", func(t *testing.T) { - // Сначала создаем пользователя - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + if _, ok := result["user"]; !ok { + t.Error("User data not found in response") + } + }) - // Тестируем логин - resp, err := config.Request("POST", "/auth/login", map[string]interface{}{ - "email": user.Email, - "password": user.Password, - }, "") - if err != nil { - t.Fatalf("Failed to login: %v", err) - } - defer resp.Body.Close() + t.Run("Login", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + resp, err := config.Request("POST", "/auth/login", map[string]interface{}{ + "email": user.Email, + "password": user.Password, + }, "") + if err != nil { + t.Fatalf("Failed to login: %v", err) + } + defer resp.Body.Close() - var result map[string]interface{} - if err := config.ParseResponse(resp, &result); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - if _, ok := result["token"]; !ok { - t.Error("Token not found in response") - } + var result map[string]interface{} + if err := config.ParseResponse(resp, &result); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Проверяем, что refresh token установлен в cookie - cookies := resp.Cookies() - foundRefreshToken := false - for _, cookie := range cookies { - if cookie.Name == "refresh_token" { - foundRefreshToken = true - break - } - } - if !foundRefreshToken { - t.Error("Refresh token cookie not set") - } - }) + if _, ok := result["token"]; !ok { + t.Error("Token not found in response") + } - // RefreshToken тестирует обновление access токена через refresh token - t.Run("RefreshToken", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + cookies := resp.Cookies() + foundRefreshToken := false + for _, cookie := range cookies { + if cookie.Name == "refresh_token" { + foundRefreshToken = true + break + } + } + if !foundRefreshToken { + t.Error("Refresh token cookie not set") + } + }) - // Логинимся для получения refresh token в cookie - _, err := config.Request("POST", "/auth/login", map[string]interface{}{ - "email": user.Email, - "password": user.Password, - }, "") - if err != nil { - t.Fatalf("Failed to login: %v", err) - } + t.Run("RefreshToken", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - // Обновляем токен - resp, err := config.Request("POST", "/auth/refresh", nil, "") - if err != nil { - t.Fatalf("Failed to refresh token: %v", err) - } - defer resp.Body.Close() + loginResp, err := config.Request("POST", "/auth/login", map[string]interface{}{ + "email": user.Email, + "password": user.Password, + }, "") + if err != nil { + t.Fatalf("Failed to login: %v", err) + } + loginResp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + var refreshToken string + for _, cookie := range loginResp.Cookies() { + if cookie.Name == "refresh_token" { + refreshToken = cookie.Value + break + } + } - // Logout тестирует выход пользователя из системы - t.Run("Logout", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + resp, err := config.Request("POST", "/auth/refresh", map[string]interface{}{ + "refresh_token": refreshToken, + }, "") + if err != nil { + t.Fatalf("Failed to refresh token: %v", err) + } + defer resp.Body.Close() - resp, err := config.Request("POST", "/auth/logout", nil, user.Token) - if err != nil { - t.Fatalf("Failed to logout: %v", err) - } - defer resp.Body.Close() + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + t.Run("Logout", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - var result map[string]interface{} - if err := config.ParseResponse(resp, &result); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + resp, err := config.Request("POST", "/auth/logout", nil, user.Token) + if err != nil { + t.Fatalf("Failed to logout: %v", err) + } + defer resp.Body.Close() - // Проверяем сообщение о успешном выходе - if msg, ok := result["message"]; !ok || msg != "Successfully logged out" { - t.Error("Logout message not as expected") - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - // PasswordReset тестирует полный поток сброса пароля - t.Run("PasswordReset", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + var result map[string]interface{} + if err := config.ParseResponse(resp, &result); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Запрос сброса пароля - resp, err := config.Request("POST", "/auth/password-reset/request", map[string]interface{}{ - "email": user.Email, - }, "") - if err != nil { - t.Fatalf("Failed to request password reset: %v", err) - } - defer resp.Body.Close() + if msg, ok := result["message"].(string); !ok || msg != "Successfully logged out" { + t.Error("Logout message not as expected") + } + }) - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + t.Run("PasswordReset", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - var result map[string]interface{} - if err := config.ParseResponse(resp, &result); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + resp, err := config.Request("POST", "/auth/reset-password", map[string]interface{}{ + "email": user.Email, + }, "") + if err != nil { + t.Fatalf("Failed to request password reset: %v", err) + } + defer resp.Body.Close() - // Получаем токен сброса из ответа (в реальном API он приходит на email) - resetToken, ok := result["token"].(string) - if !ok { - t.Fatal("Reset token not found in response") - } + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - // Подтверждение сброса пароля с новым паролем - newPassword := "newpassword789" - resp, err = config.Request("POST", "/auth/password-reset/confirm", map[string]interface{}{ - "token": resetToken, - "new_password": newPassword, - }, "") - if err != nil { - t.Fatalf("Failed to confirm password reset: %v", err) - } - defer resp.Body.Close() + var result map[string]interface{} + if err := config.ParseResponse(resp, &result); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + resetToken, ok := result["token"].(string) + if !ok { + t.Fatal("Reset token not found in response") + } - // Проверяем, что можно войти с новым паролем - newToken, err := config.GetAuthToken(user.Email, newPassword) - if err != nil { - t.Errorf("Failed to login with new password: %v", err) - } - if newToken == "" { - t.Error("Failed to get token with new password") - } - }) + newPassword := "newpassword789" + resp, err = config.Request("POST", "/auth/reset-password/confirm", map[string]interface{}{ + "token": resetToken, + "new_password": newPassword, + }, "") + if err != nil { + t.Fatalf("Failed to confirm password reset: %v", err) + } + defer resp.Body.Close() - // MobileLogin тестирует мобильную авторизацию (возвращает access и refresh токены) - t.Run("MobileLogin", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - resp, err := config.Request("POST", "/auth/mobile/login", map[string]interface{}{ - "email": user.Email, - "password": user.Password, - }, "") - if err != nil { - t.Fatalf("Failed to mobile login: %v", err) - } - defer resp.Body.Close() + newToken, err := config.GetAuthToken(user.Email, newPassword) + if err != nil { + t.Errorf("Failed to login with new password: %v", err) + } + if newToken == "" { + t.Error("Failed to get token with new password") + } + }) - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + t.Run("MobileLogin", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - var result map[string]interface{} - if err := config.ParseResponse(resp, &result); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + resp, err := config.Request("POST", "/auth/mobile/login", map[string]interface{}{ + "email": user.Email, + "password": user.Password, + }, "") + if err != nil { + t.Fatalf("Failed to mobile login: %v", err) + } + defer resp.Body.Close() - // Для мобильной авторизации ожидаем специальные поля - requiredFields := []string{"access_token", "refresh_token", "expires_at", "user"} - for _, field := range requiredFields { - if _, ok := result[field]; !ok { - t.Errorf("Required field %s not found in response", field) - } - } - }) -} \ No newline at end of file + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + + var result map[string]interface{} + if err := config.ParseResponse(resp, &result); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } + + requiredFields := []string{"access_token", "refresh_token", "expires_at", "user"} + for _, field := range requiredFields { + if _, ok := result[field]; !ok { + t.Errorf("Required field %s not found in response", field) + } + } + }) +} diff --git a/main_dc/yalarba/api_yal/tests/integration/comment_test.go b/main_dc/yalarba/api_yal/tests/integration/comment_test.go index 6c97ef2..fa0fd43 100644 --- a/main_dc/yalarba/api_yal/tests/integration/comment_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/comment_test.go @@ -1,235 +1,221 @@ package integration import ( - "testing" - "api_yal/tests/testutils" + "fmt" + "testing" + "api_yal/tests/testutils" ) -// TestCommentEndpoints тестирует все эндпоинты для работы с комментариями к отзывам -// Включает создание, получение, обновление, удаление комментариев и получение статистики func TestCommentEndpoints(t *testing.T) { - config := testutils.NewTestConfig() + config := testutils.NewTestConfig() - // CreateComment тестирует создание нового комментария к отзыву - t.Run("CreateComment", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("CreateComment", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - commentData := testutils.CreateCommentRequest{ - FeedbackID: feedbackID, - Text: "Great review! I agree completely.", - } + commentData := testutils.CreateCommentRequest{ + FeedbackID: feedbackID, + Text: "Great review! I agree completely.", + } - resp, err := config.Request("POST", "/comments", commentData, user.Token) - if err != nil { - t.Fatalf("Failed to create comment: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("POST", "/comments", commentData, user.Token) + if err != nil { + t.Fatalf("Failed to create comment: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 201 { - t.Errorf("Expected status 201, got %d", resp.StatusCode) - } + if resp.StatusCode != 201 { + t.Errorf("Expected status 201, got %d", resp.StatusCode) + } - var createdComment map[string]interface{} - if err := config.ParseResponse(resp, &createdComment); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdComment map[string]interface{} + if err := config.ParseResponse(resp, &createdComment); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - if _, ok := createdComment["id"]; !ok { - t.Error("Comment ID not found") - } - }) + if _, ok := createdComment["id"]; !ok { + t.Error("Comment ID not found") + } + }) - // GetCommentByID тестирует получение комментария по ID - t.Run("GetCommentByID", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("GetCommentByID", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - // Создаем комментарий - commentData := testutils.CreateCommentRequest{ - FeedbackID: feedbackID, - Text: "Test comment", - } - resp, err := config.Request("POST", "/comments", commentData, user.Token) - if err != nil { - t.Fatalf("Failed to create comment: %v", err) - } - defer resp.Body.Close() + commentData := testutils.CreateCommentRequest{ + FeedbackID: feedbackID, + Text: "Test comment", + } + resp, err := config.Request("POST", "/comments", commentData, user.Token) + if err != nil { + t.Fatalf("Failed to create comment: %v", err) + } + defer resp.Body.Close() - var createdComment map[string]interface{} - if err := config.ParseResponse(resp, &createdComment); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdComment map[string]interface{} + if err := config.ParseResponse(resp, &createdComment); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - commentID := createdComment["id"].(float64) + commentID := createdComment["id"].(float64) - // Получение комментария доступно без авторизации - getResp, err := config.Request("GET", "/comments/"+string(rune(commentID)), nil, "") - if err != nil { - t.Fatalf("Failed to get comment: %v", err) - } - defer getResp.Body.Close() + getResp, err := config.Request("GET", "/comments/"+fmt.Sprintf("%.0f", commentID), nil, "") + if err != nil { + t.Fatalf("Failed to get comment: %v", err) + } + defer getResp.Body.Close() - if getResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", getResp.StatusCode) - } - }) + if getResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", getResp.StatusCode) + } + }) - // UpdateComment тестирует обновление текста комментария автором - t.Run("UpdateComment", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("UpdateComment", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - // Создаем комментарий - commentData := testutils.CreateCommentRequest{ - FeedbackID: feedbackID, - Text: "Original comment", - } - resp, err := config.Request("POST", "/comments", commentData, user.Token) - if err != nil { - t.Fatalf("Failed to create comment: %v", err) - } - defer resp.Body.Close() + commentData := testutils.CreateCommentRequest{ + FeedbackID: feedbackID, + Text: "Original comment", + } + resp, err := config.Request("POST", "/comments", commentData, user.Token) + if err != nil { + t.Fatalf("Failed to create comment: %v", err) + } + defer resp.Body.Close() - var createdComment map[string]interface{} - if err := config.ParseResponse(resp, &createdComment); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdComment map[string]interface{} + if err := config.ParseResponse(resp, &createdComment); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - commentID := createdComment["id"].(float64) + commentID := createdComment["id"].(float64) - updateData := map[string]interface{}{ - "text": "Updated comment text", - } + updateData := map[string]interface{}{ + "text": "Updated comment text", + } - updateResp, err := config.Request("PUT", "/comments/"+string(rune(commentID)), updateData, user.Token) - if err != nil { - t.Fatalf("Failed to update comment: %v", err) - } - defer updateResp.Body.Close() + updateResp, err := config.Request("PUT", "/comments/"+fmt.Sprintf("%.0f", commentID), updateData, user.Token) + if err != nil { + t.Fatalf("Failed to update comment: %v", err) + } + defer updateResp.Body.Close() - if updateResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", updateResp.StatusCode) - } - }) + if updateResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", updateResp.StatusCode) + } + }) - // ListComments тестирует получение списка комментариев с пагинацией - t.Run("ListComments", func(t *testing.T) { - resp, err := config.Request("GET", "/comments?page=1&page_size=20", nil, "") - if err != nil { - t.Fatalf("Failed to list comments: %v", err) - } - defer resp.Body.Close() + t.Run("ListComments", func(t *testing.T) { + resp, err := config.Request("GET", "/comments?page=1&page_size=20", nil, "") + if err != nil { + t.Fatalf("Failed to list comments: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // MyComments тестирует получение комментариев текущего пользователя - t.Run("MyComments", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("MyComments", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - resp, err := config.Request("GET", "/comments/my", nil, user.Token) - if err != nil { - t.Fatalf("Failed to get my comments: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/comments/my", nil, user.Token) + if err != nil { + t.Fatalf("Failed to get my comments: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // CommentsByFeedback тестирует получение комментариев для конкретного отзыва - t.Run("CommentsByFeedback", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("CommentsByFeedback", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - resp, err := config.Request("GET", "/comments/feedback/"+string(rune(feedbackID)), nil, "") - if err != nil { - t.Fatalf("Failed to get comments by feedback: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/comments/feedback/"+fmt.Sprintf("%d", feedbackID), nil, "") + if err != nil { + t.Fatalf("Failed to get comments by feedback: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // CommentStats тестирует получение статистики по комментариям - t.Run("CommentStats", func(t *testing.T) { - resp, err := config.Request("GET", "/comments/stats", nil, "") - if err != nil { - t.Fatalf("Failed to get comment stats: %v", err) - } - defer resp.Body.Close() + t.Run("CommentStats", func(t *testing.T) { + resp, err := config.Request("GET", "/comments/stats", nil, "") + if err != nil { + t.Fatalf("Failed to get comment stats: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - var stats map[string]interface{} - if err := config.ParseResponse(resp, &stats); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var stats map[string]interface{} + if err := config.ParseResponse(resp, &stats); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Проверяем наличие полей статистики - expectedFields := []string{"total_comments", "verified_comments", "unverified_comments"} - for _, field := range expectedFields { - if _, ok := stats[field]; !ok { - t.Errorf("Expected field %s not found", field) - } - } - }) + expectedFields := []string{"total_comments", "verified_comments", "unverified_comments"} + for _, field := range expectedFields { + if _, ok := stats[field]; !ok { + t.Errorf("Expected field %s not found", field) + } + } + }) - // DeleteComment тестирует удаление комментария автором - t.Run("DeleteComment", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("DeleteComment", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - // Создаем комментарий - commentData := testutils.CreateCommentRequest{ - FeedbackID: feedbackID, - Text: "Comment to delete", - } - resp, err := config.Request("POST", "/comments", commentData, user.Token) - if err != nil { - t.Fatalf("Failed to create comment: %v", err) - } - defer resp.Body.Close() + commentData := testutils.CreateCommentRequest{ + FeedbackID: feedbackID, + Text: "Comment to delete", + } + resp, err := config.Request("POST", "/comments", commentData, user.Token) + if err != nil { + t.Fatalf("Failed to create comment: %v", err) + } + defer resp.Body.Close() - var createdComment map[string]interface{} - if err := config.ParseResponse(resp, &createdComment); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdComment map[string]interface{} + if err := config.ParseResponse(resp, &createdComment); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - commentID := createdComment["id"].(float64) + commentID := createdComment["id"].(float64) - deleteResp, err := config.Request("DELETE", "/comments/"+string(rune(commentID)), nil, user.Token) - if err != nil { - t.Fatalf("Failed to delete comment: %v", err) - } - defer deleteResp.Body.Close() + deleteResp, err := config.Request("DELETE", "/comments/"+fmt.Sprintf("%.0f", commentID), nil, user.Token) + if err != nil { + t.Fatalf("Failed to delete comment: %v", err) + } + defer deleteResp.Body.Close() - if deleteResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", deleteResp.StatusCode) - } - }) -} \ No newline at end of file + if deleteResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", deleteResp.StatusCode) + } + }) +} diff --git a/main_dc/yalarba/api_yal/tests/integration/feedback_test.go b/main_dc/yalarba/api_yal/tests/integration/feedback_test.go index 35c393a..6a6af27 100644 --- a/main_dc/yalarba/api_yal/tests/integration/feedback_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/feedback_test.go @@ -1,231 +1,217 @@ package integration import ( - "testing" - "api_yal/tests/testutils" + "fmt" + "testing" + "api_yal/tests/testutils" ) -// TestFeedbackEndpoints тестирует все эндпоинты для работы с отзывами -// Включает создание, получение, обновление, удаление отзывов, поиск и статистику func TestFeedbackEndpoints(t *testing.T) { - config := testutils.NewTestConfig() + config := testutils.NewTestConfig() - // CreateFeedback тестирует создание нового отзыва - t.Run("CreateFeedback", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("CreateFeedback", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - feedbackData := testutils.CreateFeedbackRequest{ - ObjectID: objectID, - Rating: 5, - Text: "Excellent place! Very recommended.", - Platform: "tourist", - } + feedbackData := testutils.CreateFeedbackRequest{ + ObjectID: objectID, + Rating: 5, + Text: "Excellent place! Very recommended.", + Platform: "tourist", + } - resp, err := config.Request("POST", "/feedbacks", feedbackData, user.Token) - if err != nil { - t.Fatalf("Failed to create feedback: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("POST", "/feedbacks", feedbackData, user.Token) + if err != nil { + t.Fatalf("Failed to create feedback: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 201 { - t.Errorf("Expected status 201, got %d", resp.StatusCode) - } + if resp.StatusCode != 201 { + t.Errorf("Expected status 201, got %d", resp.StatusCode) + } - var createdFeedback map[string]interface{} - if err := config.ParseResponse(resp, &createdFeedback); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdFeedback map[string]interface{} + if err := config.ParseResponse(resp, &createdFeedback); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - if _, ok := createdFeedback["id"]; !ok { - t.Error("Feedback ID not found") - } - }) + if _, ok := createdFeedback["id"]; !ok { + t.Error("Feedback ID not found") + } + }) - // GetFeedbackByID тестирует получение отзыва по ID - t.Run("GetFeedbackByID", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("GetFeedbackByID", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - resp, err := config.Request("GET", "/feedbacks/"+string(rune(feedbackID)), nil, "") - if err != nil { - t.Fatalf("Failed to get feedback: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/feedbacks/"+fmt.Sprintf("%d", feedbackID), nil, "") + if err != nil { + t.Fatalf("Failed to get feedback: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // UpdateFeedback тестирует обновление отзыва автором - t.Run("UpdateFeedback", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("UpdateFeedback", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - updateData := map[string]interface{}{ - "rating": 4, - "text": "Updated feedback text", - } + updateData := map[string]interface{}{ + "rating": 4, + "text": "Updated feedback text", + } - resp, err := config.Request("PUT", "/feedbacks/"+string(rune(feedbackID)), updateData, user.Token) - if err != nil { - t.Fatalf("Failed to update feedback: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("PUT", "/feedbacks/"+fmt.Sprintf("%d", feedbackID), updateData, user.Token) + if err != nil { + t.Fatalf("Failed to update feedback: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - var updatedFeedback map[string]interface{} - if err := config.ParseResponse(resp, &updatedFeedback); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var updatedFeedback map[string]interface{} + if err := config.ParseResponse(resp, &updatedFeedback); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - if text, ok := updatedFeedback["text"].(string); !ok || text != "Updated feedback text" { - t.Error("Feedback text not updated") - } - }) + if text, ok := updatedFeedback["text"].(string); !ok || text != "Updated feedback text" { + t.Error("Feedback text not updated") + } + }) - // ListFeedbacks тестирует получение списка отзывов с пагинацией - t.Run("ListFeedbacks", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("ListFeedbacks", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - resp, err := config.Request("GET", "/feedbacks?offset=0&limit=20", nil, "") - if err != nil { - t.Fatalf("Failed to list feedbacks: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/feedbacks?offset=0&limit=20", nil, "") + if err != nil { + t.Fatalf("Failed to list feedbacks: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // MyFeedbacks тестирует получение отзывов текущего пользователя - t.Run("MyFeedbacks", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("MyFeedbacks", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - resp, err := config.Request("GET", "/feedbacks/my", nil, user.Token) - if err != nil { - t.Fatalf("Failed to get my feedbacks: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/feedbacks/my", nil, user.Token) + if err != nil { + t.Fatalf("Failed to get my feedbacks: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // FeedbacksByObject тестирует получение отзывов для конкретного объекта - t.Run("FeedbacksByObject", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("FeedbacksByObject", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - resp, err := config.Request("GET", "/feedbacks/object/"+string(rune(objectID)), nil, "") - if err != nil { - t.Fatalf("Failed to get object feedbacks: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("GET", "/feedbacks/object/"+fmt.Sprintf("%d", objectID), nil, "") + if err != nil { + t.Fatalf("Failed to get object feedbacks: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // FeedbacksByPlatform тестирует получение отзывов по платформе - t.Run("FeedbacksByPlatform", func(t *testing.T) { - resp, err := config.Request("GET", "/feedbacks/platform/tourist", nil, "") - if err != nil { - t.Fatalf("Failed to get platform feedbacks: %v", err) - } - defer resp.Body.Close() + t.Run("FeedbacksByPlatform", func(t *testing.T) { + resp, err := config.Request("GET", "/feedbacks/platform/tourist", nil, "") + if err != nil { + t.Fatalf("Failed to get platform feedbacks: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // SearchFeedbacks тестирует поиск отзывов по тексту - t.Run("SearchFeedbacks", func(t *testing.T) { - resp, err := config.Request("GET", "/feedbacks/search?q=excellent", nil, "") - if err != nil { - t.Fatalf("Failed to search feedbacks: %v", err) - } - defer resp.Body.Close() + t.Run("SearchFeedbacks", func(t *testing.T) { + resp, err := config.Request("GET", "/feedbacks/search?q=excellent", nil, "") + if err != nil { + t.Fatalf("Failed to search feedbacks: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } + }) - // FeedbackStats тестирует получение статистики по отзывам - t.Run("FeedbackStats", func(t *testing.T) { - resp, err := config.Request("GET", "/feedbacks/stats", nil, "") - if err != nil { - t.Fatalf("Failed to get feedback stats: %v", err) - } - defer resp.Body.Close() + t.Run("FeedbackStats", func(t *testing.T) { + resp, err := config.Request("GET", "/feedbacks/stats", nil, "") + if err != nil { + t.Fatalf("Failed to get feedback stats: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - var stats map[string]interface{} - if err := config.ParseResponse(resp, &stats); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var stats map[string]interface{} + if err := config.ParseResponse(resp, &stats); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Проверяем наличие полей статистики - expectedFields := []string{"total_feedbacks", "average_rating", "rating_distribution", "platform_stats"} - for _, field := range expectedFields { - if _, ok := stats[field]; !ok { - t.Errorf("Expected field %s not found", field) - } - } - }) + expectedFields := []string{"total_feedbacks", "average_rating", "rating_distribution", "platform_stats"} + for _, field := range expectedFields { + if _, ok := stats[field]; !ok { + t.Errorf("Expected field %s not found", field) + } + } + }) - // DeleteFeedback тестирует удаление отзыва - t.Run("DeleteFeedback", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("DeleteFeedback", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) - feedbackID := config.CreateTestFeedback(t, user.Token, objectID) + objectID := config.CreateTestObject(t, user.Token) + feedbackID := config.CreateTestFeedback(t, user.Token, objectID) - resp, err := config.Request("DELETE", "/feedbacks/"+string(rune(feedbackID)), nil, user.Token) - if err != nil { - t.Fatalf("Failed to delete feedback: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("DELETE", "/feedbacks/"+fmt.Sprintf("%d", feedbackID), nil, user.Token) + if err != nil { + t.Fatalf("Failed to delete feedback: %v", err) + } + defer resp.Body.Close() - // Ожидаем статус 204 No Content при успешном удалении - if resp.StatusCode != 204 { - t.Errorf("Expected status 204, got %d", resp.StatusCode) - } + if resp.StatusCode != 204 { + t.Errorf("Expected status 204, got %d", resp.StatusCode) + } - // Проверяем, что отзыв удален - должен вернуть 404 - getResp, err := config.Request("GET", "/feedbacks/"+string(rune(feedbackID)), nil, "") - if err != nil { - t.Fatalf("Failed to get feedback: %v", err) - } - defer getResp.Body.Close() + getResp, err := config.Request("GET", "/feedbacks/"+fmt.Sprintf("%d", feedbackID), nil, "") + if err != nil { + t.Fatalf("Failed to get feedback: %v", err) + } + defer getResp.Body.Close() - if getResp.StatusCode != 404 { - t.Errorf("Expected status 404 for deleted feedback, got %d", getResp.StatusCode) - } - }) -} \ No newline at end of file + if getResp.StatusCode != 404 { + t.Errorf("Expected status 404 for deleted feedback, got %d", getResp.StatusCode) + } + }) +} diff --git a/main_dc/yalarba/api_yal/tests/integration/object_test.go b/main_dc/yalarba/api_yal/tests/integration/object_test.go index 4eeb1f0..87f46a8 100644 --- a/main_dc/yalarba/api_yal/tests/integration/object_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/object_test.go @@ -1,16 +1,14 @@ package integration import ( - "api_yal/tests/testutils" + "fmt" "testing" + "api_yal/tests/testutils" ) -// TestObjectEndpoints тестирует все эндпоинты для работы с объектами (местами, заведениями) -// Включает создание, получение, обновление, удаление объектов, поиск и геопоиск func TestObjectEndpoints(t *testing.T) { config := testutils.NewTestConfig() - // CreateObject тестирует создание нового объекта пользователем t.Run("CreateObject", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) @@ -55,14 +53,13 @@ func TestObjectEndpoints(t *testing.T) { } }) - // GetObjectByID тестирует получение объекта по ID t.Run("GetObjectByID", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) objectID := config.CreateTestObject(t, user.Token) - resp, err := config.Request("GET", "/objects/"+string(rune(objectID)), nil, "") + resp, err := config.Request("GET", "/objects/"+fmt.Sprintf("%d", objectID), nil, "") if err != nil { t.Fatalf("Failed to get object: %v", err) } @@ -82,7 +79,6 @@ func TestObjectEndpoints(t *testing.T) { } }) - // GetNonExistentObject тестирует получение несуществующего объекта t.Run("GetNonExistentObject", func(t *testing.T) { resp, err := config.Request("GET", "/objects/999999", nil, "") if err != nil { @@ -95,7 +91,6 @@ func TestObjectEndpoints(t *testing.T) { } }) - // UpdateObject тестирует обновление объекта его владельцем t.Run("UpdateObject", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) @@ -108,7 +103,7 @@ func TestObjectEndpoints(t *testing.T) { "short_description": "Updated short desc", } - resp, err := config.Request("PUT", "/objects/"+string(rune(objectID)), updateData, user.Token) + resp, err := config.Request("PUT", "/objects/"+fmt.Sprintf("%d", objectID), updateData, user.Token) if err != nil { t.Fatalf("Failed to update object: %v", err) } @@ -128,7 +123,6 @@ func TestObjectEndpoints(t *testing.T) { } }) - // UpdateObjectUnauthorized тестирует попытку обновления чужого объекта t.Run("UpdateObjectUnauthorized", func(t *testing.T) { user1 := config.CreateTestUser(t) defer config.CleanupTestUser(t, user1) @@ -138,8 +132,7 @@ func TestObjectEndpoints(t *testing.T) { objectID := config.CreateTestObject(t, user1.Token) - // Пользователь user2 пытается обновить объект user1 - resp, err := config.Request("PUT", "/objects/"+string(rune(objectID)), map[string]interface{}{ + resp, err := config.Request("PUT", "/objects/"+fmt.Sprintf("%d", objectID), map[string]interface{}{ "short_name": "Hacked Name", }, user2.Token) if err != nil { @@ -147,18 +140,15 @@ func TestObjectEndpoints(t *testing.T) { } defer resp.Body.Close() - // Ожидаем ошибку 403 Forbidden if resp.StatusCode != 403 { t.Errorf("Expected status 403, got %d", resp.StatusCode) } }) - // ListObjects тестирует получение списка объектов с пагинацией t.Run("ListObjects", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) - // Создаем несколько объектов for i := 0; i < 3; i++ { config.CreateTestObject(t, user.Token) } @@ -183,12 +173,11 @@ func TestObjectEndpoints(t *testing.T) { } }) - // SearchObjects тестирует поиск объектов по тексту t.Run("SearchObjects", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + config.CreateTestObject(t, user.Token) resp, err := config.Request("GET", "/objects/search?q=Test", nil, "") if err != nil { @@ -206,10 +195,8 @@ func TestObjectEndpoints(t *testing.T) { } t.Logf("Search results: %+v", searchResults) - _ = objectID // Используем переменную для избежания предупреждения }) - // NearbyObjects тестирует поиск объектов рядом с заданными координатами t.Run("NearbyObjects", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) @@ -225,14 +212,13 @@ func TestObjectEndpoints(t *testing.T) { } }) - // DeleteObject тестирует удаление объекта t.Run("DeleteObject", func(t *testing.T) { user := config.CreateTestUser(t) defer config.CleanupTestUser(t, user) objectID := config.CreateTestObject(t, user.Token) - resp, err := config.Request("DELETE", "/objects/"+string(rune(objectID)), nil, user.Token) + resp, err := config.Request("DELETE", "/objects/"+fmt.Sprintf("%d", objectID), nil, user.Token) if err != nil { t.Fatalf("Failed to delete object: %v", err) } @@ -242,8 +228,7 @@ func TestObjectEndpoints(t *testing.T) { t.Errorf("Expected status 204, got %d", resp.StatusCode) } - // Проверяем, что объект удален - должен вернуть 404 - getResp, err := config.Request("GET", "/objects/"+string(rune(objectID)), nil, "") + getResp, err := config.Request("GET", "/objects/"+fmt.Sprintf("%d", objectID), nil, "") if err != nil { t.Fatalf("Failed to get object: %v", err) } @@ -253,4 +238,4 @@ func TestObjectEndpoints(t *testing.T) { t.Errorf("Expected status 404 for deleted object, got %d", getResp.StatusCode) } }) -} \ No newline at end of file +} diff --git a/main_dc/yalarba/api_yal/tests/integration/rating_test.go b/main_dc/yalarba/api_yal/tests/integration/rating_test.go index 062e2dc..6fa8c7a 100644 --- a/main_dc/yalarba/api_yal/tests/integration/rating_test.go +++ b/main_dc/yalarba/api_yal/tests/integration/rating_test.go @@ -1,251 +1,233 @@ package integration import ( - "testing" - "api_yal/tests/testutils" + "fmt" + "testing" + "api_yal/tests/testutils" ) -// TestRatingEndpoints тестирует все эндпоинты для работы с рейтингами и голосованием -// Включает создание рейтинга, голосование, изменение голоса и получение статистики func TestRatingEndpoints(t *testing.T) { - config := testutils.NewTestConfig() + config := testutils.NewTestConfig() - // CreateRating тестирует создание нового рейтинга для объекта - t.Run("CreateRating", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("CreateRating", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - ratingData := map[string]interface{}{ - "object_id": objectID, - "platform": "tourist", - } + ratingData := map[string]interface{}{ + "object_id": objectID, + "platform": "tourist", + } - resp, err := config.Request("POST", "/ratings", ratingData, user.Token) - if err != nil { - t.Fatalf("Failed to create rating: %v", err) - } - defer resp.Body.Close() + resp, err := config.Request("POST", "/ratings", ratingData, user.Token) + if err != nil { + t.Fatalf("Failed to create rating: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 201 { - t.Errorf("Expected status 201, got %d", resp.StatusCode) - } - }) + if resp.StatusCode != 201 { + t.Errorf("Expected status 201, got %d", resp.StatusCode) + } + }) - // CastVote тестирует голосование в рейтинге - t.Run("CastVote", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("CastVote", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - // Сначала создаем рейтинг - ratingData := map[string]interface{}{ - "object_id": objectID, - "platform": "tourist", - } - resp, err := config.Request("POST", "/ratings", ratingData, user.Token) - if err != nil { - t.Fatalf("Failed to create rating: %v", err) - } - defer resp.Body.Close() + ratingData := map[string]interface{}{ + "object_id": objectID, + "platform": "tourist", + } + resp, err := config.Request("POST", "/ratings", ratingData, user.Token) + if err != nil { + t.Fatalf("Failed to create rating: %v", err) + } + defer resp.Body.Close() - var createdRating map[string]interface{} - if err := config.ParseResponse(resp, &createdRating); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdRating map[string]interface{} + if err := config.ParseResponse(resp, &createdRating); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - ratingID := createdRating["id"].(float64) + ratingID := createdRating["id"].(float64) - // Голосуем с оценкой 5 - voteData := map[string]interface{}{ - "score": 5, - } + voteData := map[string]interface{}{ + "score": 5, + } - voteResp, err := config.Request("POST", "/ratings/"+string(rune(ratingID))+"/vote/tourist", voteData, user.Token) - if err != nil { - t.Fatalf("Failed to cast vote: %v", err) - } - defer voteResp.Body.Close() + voteResp, err := config.Request("POST", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/vote/tourist", voteData, user.Token) + if err != nil { + t.Fatalf("Failed to cast vote: %v", err) + } + defer voteResp.Body.Close() - if voteResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", voteResp.StatusCode) - } - }) + if voteResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", voteResp.StatusCode) + } + }) - // GetMyVote тестирует получение голоса текущего пользователя - t.Run("GetMyVote", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("GetMyVote", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - // Создаем рейтинг и голосуем - ratingData := map[string]interface{}{ - "object_id": objectID, - "platform": "tourist", - } - resp, err := config.Request("POST", "/ratings", ratingData, user.Token) - if err != nil { - t.Fatalf("Failed to create rating: %v", err) - } - defer resp.Body.Close() + ratingData := map[string]interface{}{ + "object_id": objectID, + "platform": "tourist", + } + resp, err := config.Request("POST", "/ratings", ratingData, user.Token) + if err != nil { + t.Fatalf("Failed to create rating: %v", err) + } + defer resp.Body.Close() - var createdRating map[string]interface{} - if err := config.ParseResponse(resp, &createdRating); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdRating map[string]interface{} + if err := config.ParseResponse(resp, &createdRating); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - ratingID := createdRating["id"].(float64) + ratingID := createdRating["id"].(float64) - voteData := map[string]interface{}{ - "score": 5, - } - _, err = config.Request("POST", "/ratings/"+string(rune(ratingID))+"/vote/tourist", voteData, user.Token) - if err != nil { - t.Fatalf("Failed to cast vote: %v", err) - } + voteData := map[string]interface{}{ + "score": 5, + } + _, err = config.Request("POST", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/vote/tourist", voteData, user.Token) + if err != nil { + t.Fatalf("Failed to cast vote: %v", err) + } - // Получаем мой голос - myVoteResp, err := config.Request("GET", "/ratings/"+string(rune(ratingID))+"/my-vote/tourist", nil, user.Token) - if err != nil { - t.Fatalf("Failed to get my vote: %v", err) - } - defer myVoteResp.Body.Close() + myVoteResp, err := config.Request("GET", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/my-vote/tourist", nil, user.Token) + if err != nil { + t.Fatalf("Failed to get my vote: %v", err) + } + defer myVoteResp.Body.Close() - if myVoteResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", myVoteResp.StatusCode) - } + if myVoteResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", myVoteResp.StatusCode) + } - var voteInfo map[string]interface{} - if err := config.ParseResponse(myVoteResp, &voteInfo); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var voteInfo map[string]interface{} + if err := config.ParseResponse(myVoteResp, &voteInfo); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Проверяем, что пользователь уже голосовал - if hasVoted, ok := voteInfo["has_voted"].(bool); !ok || !hasVoted { - t.Error("has_voted should be true") - } - }) + if hasVoted, ok := voteInfo["has_voted"].(bool); !ok || !hasVoted { + t.Error("has_voted should be true") + } + }) - // UpdateMyVote тестирует обновление голоса пользователя - t.Run("UpdateMyVote", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("UpdateMyVote", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - ratingData := map[string]interface{}{ - "object_id": objectID, - "platform": "tourist", - } - resp, err := config.Request("POST", "/ratings", ratingData, user.Token) - if err != nil { - t.Fatalf("Failed to create rating: %v", err) - } - defer resp.Body.Close() + ratingData := map[string]interface{}{ + "object_id": objectID, + "platform": "tourist", + } + resp, err := config.Request("POST", "/ratings", ratingData, user.Token) + if err != nil { + t.Fatalf("Failed to create rating: %v", err) + } + defer resp.Body.Close() - var createdRating map[string]interface{} - if err := config.ParseResponse(resp, &createdRating); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdRating map[string]interface{} + if err := config.ParseResponse(resp, &createdRating); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - ratingID := createdRating["id"].(float64) + ratingID := createdRating["id"].(float64) - // Голосуем - voteData := map[string]interface{}{ - "score": 5, - } - _, err = config.Request("POST", "/ratings/"+string(rune(ratingID))+"/vote/tourist", voteData, user.Token) - if err != nil { - t.Fatalf("Failed to cast vote: %v", err) - } + voteData := map[string]interface{}{ + "score": 5, + } + _, err = config.Request("POST", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/vote/tourist", voteData, user.Token) + if err != nil { + t.Fatalf("Failed to cast vote: %v", err) + } - // Обновляем голос с оценки 5 на 4 - updateData := map[string]interface{}{ - "score": 4, - } - updateResp, err := config.Request("PUT", "/ratings/"+string(rune(ratingID))+"/my-vote/tourist", updateData, user.Token) - if err != nil { - t.Fatalf("Failed to update vote: %v", err) - } - defer updateResp.Body.Close() + updateData := map[string]interface{}{ + "score": 4, + } + updateResp, err := config.Request("PUT", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/my-vote/tourist", updateData, user.Token) + if err != nil { + t.Fatalf("Failed to update vote: %v", err) + } + defer updateResp.Body.Close() - if updateResp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", updateResp.StatusCode) - } - }) + if updateResp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", updateResp.StatusCode) + } + }) - // GetRatingStats тестирует получение статистики по рейтингам - t.Run("GetRatingStats", func(t *testing.T) { - resp, err := config.Request("GET", "/ratings/stats", nil, "") - if err != nil { - t.Fatalf("Failed to get rating stats: %v", err) - } - defer resp.Body.Close() + t.Run("GetRatingStats", func(t *testing.T) { + resp, err := config.Request("GET", "/ratings/stats", nil, "") + if err != nil { + t.Fatalf("Failed to get rating stats: %v", err) + } + defer resp.Body.Close() - if resp.StatusCode != 200 { - t.Errorf("Expected status 200, got %d", resp.StatusCode) - } + if resp.StatusCode != 200 { + t.Errorf("Expected status 200, got %d", resp.StatusCode) + } - var stats map[string]interface{} - if err := config.ParseResponse(resp, &stats); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var stats map[string]interface{} + if err := config.ParseResponse(resp, &stats); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - // Проверяем наличие полей статистики - expectedFields := []string{"total_ratings", "total_votes", "platform_distribution"} - for _, field := range expectedFields { - if _, ok := stats[field]; !ok { - t.Errorf("Expected field %s not found", field) - } - } - }) + expectedFields := []string{"total_ratings", "total_votes", "platform_distribution"} + for _, field := range expectedFields { + if _, ok := stats[field]; !ok { + t.Errorf("Expected field %s not found", field) + } + } + }) - // DeleteMyVote тестирует удаление голоса пользователя - t.Run("DeleteMyVote", func(t *testing.T) { - user := config.CreateTestUser(t) - defer config.CleanupTestUser(t, user) + t.Run("DeleteMyVote", func(t *testing.T) { + user := config.CreateTestUser(t) + defer config.CleanupTestUser(t, user) - objectID := config.CreateTestObject(t, user.Token) + objectID := config.CreateTestObject(t, user.Token) - ratingData := map[string]interface{}{ - "object_id": objectID, - "platform": "tourist", - } - resp, err := config.Request("POST", "/ratings", ratingData, user.Token) - if err != nil { - t.Fatalf("Failed to create rating: %v", err) - } - defer resp.Body.Close() + ratingData := map[string]interface{}{ + "object_id": objectID, + "platform": "tourist", + } + resp, err := config.Request("POST", "/ratings", ratingData, user.Token) + if err != nil { + t.Fatalf("Failed to create rating: %v", err) + } + defer resp.Body.Close() - var createdRating map[string]interface{} - if err := config.ParseResponse(resp, &createdRating); err != nil { - t.Fatalf("Failed to parse response: %v", err) - } + var createdRating map[string]interface{} + if err := config.ParseResponse(resp, &createdRating); err != nil { + t.Fatalf("Failed to parse response: %v", err) + } - ratingID := createdRating["id"].(float64) + ratingID := createdRating["id"].(float64) - // Голосуем - voteData := map[string]interface{}{ - "score": 5, - } - _, err = config.Request("POST", "/ratings/"+string(rune(ratingID))+"/vote/tourist", voteData, user.Token) - if err != nil { - t.Fatalf("Failed to cast vote: %v", err) - } + voteData := map[string]interface{}{ + "score": 5, + } + _, err = config.Request("POST", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/vote/tourist", voteData, user.Token) + if err != nil { + t.Fatalf("Failed to cast vote: %v", err) + } - // Удаляем голос - deleteResp, err := config.Request("DELETE", "/ratings/"+string(rune(ratingID))+"/my-vote/tourist", nil, user.Token) - if err != nil { - t.Fatalf("Failed to delete vote: %v", err) - } - defer deleteResp.Body.Close() + deleteResp, err := config.Request("DELETE", "/ratings/"+fmt.Sprintf("%.0f", ratingID)+"/my-vote/tourist", nil, user.Token) + if err != nil { + t.Fatalf("Failed to delete vote: %v", err) + } + defer deleteResp.Body.Close() - // Ожидаем статус 204 No Content при успешном удалении - if deleteResp.StatusCode != 204 { - t.Errorf("Expected status 204, got %d", deleteResp.StatusCode) - } - }) -} \ No newline at end of file + if deleteResp.StatusCode != 204 { + t.Errorf("Expected status 204, got %d", deleteResp.StatusCode) + } + }) +}