5086 lines
303 KiB
Markdown
5086 lines
303 KiB
Markdown
# Тестовая спецификация API
|
||
|
||
## Содержание
|
||
1. [GET /account/get](#1-get-accountget)
|
||
2. [POST /account/create](#2-post-accountcreate)
|
||
3. [DELETE /account/delete](#3-delete-accountdelete)
|
||
4. [GET /accounts](#4-get-accounts)
|
||
5. [GET /privilege/{userId}](#5-get-privilegeuserid)
|
||
6. [DELETE /account/{userId}](#6-delete-accountuserid)
|
||
7. [POST /account/manualdone](#7-post-accountmanualdone)
|
||
8. [POST /account/leadtarget](#8-post-accountleadtarget)
|
||
9. [PUT /account/leadtarget](#9-put-accountleadtarget)
|
||
10. [DELETE /account/leadtarget/{id}](#10-delete-accountleadtargetid)
|
||
11. [GET /account/leadtarget/{quizID}](#11-get-accountleadtargetquizid)
|
||
12. [POST /question/create](#12-post-questioncreate)
|
||
13. [POST /question/getList](#13-post-questiongetlist)
|
||
14. [PATCH /question/edit](#14-patch-questionedit)
|
||
15. [POST /question/copy](#15-post-questioncopy)
|
||
16. [POST /question/history](#16-post-questionhistory)
|
||
17. [DELETE /question/delete](#17-delete-questiondelete)
|
||
18. [POST /quiz/create](#18-post-quizcreate)
|
||
19. [POST /quiz/getList](#19-post-quizgetlist)
|
||
20. [PATCH /quiz/edit](#20-patch-quizedit)
|
||
21. [POST /quiz/copy](#21-post-quizcopy)
|
||
22. [POST /quiz/history](#22-post-quizhistory)
|
||
23. [DELETE /quiz/delete](#23-delete-quizdelete)
|
||
24. [PATCH /quiz/archive](#24-patch-quizarchive)
|
||
25. [POST /quiz/move](#25-post-quizmove)
|
||
26. [POST /quiz/template](#26-post-quiztemplate)
|
||
27. [POST /results/getResults/{quizId}](#27-post-resultsgetresultsquizid)
|
||
28. [DELETE /results/{resultId}](#28-delete-resultsresultid)
|
||
29. [PATCH /result/seen](#29-patch-resultseen)
|
||
30. [POST /results/{quizID}/export](#30-post-resultsquizidexport)
|
||
31. [GET /result/{resultID}](#31-get-resultresultid)
|
||
32. [POST /statistic/{quizID}/devices](#32-post-statisticquiziddevices)
|
||
33. [POST /statistic/{quizID}/general](#33-post-statisticquizidgeneral)
|
||
34. [POST /statistic/{quizID}/questions](#34-post-statisticquizidquestions)
|
||
35. [POST /statistic](#35-post-statistic)
|
||
36. [GET /statistics/{quizID}/pipelines](#36-get-statisticsquizidpipelines)
|
||
37. [GET /telegram/pool](#37-get-telegrampool)
|
||
38. [POST /telegram/create](#38-post-telegramcreate)
|
||
39. [DELETE /telegram/{id}](#39-delete-telegramid)
|
||
40. [POST /telegram/setCode](#40-post-telegramsetcode)
|
||
|
||
## 1. GET /account/get
|
||
|
||
### 1.1 Описание
|
||
Получение информации о текущем аккаунте пользователя.
|
||
|
||
### 1.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Возвращает детальную информацию об аккаунте в формате JSON
|
||
- Поддерживает стандартные HTTP коды ответа: 200, 401, 404, 500
|
||
|
||
### 1.3 Тестовые сценарии
|
||
|
||
#### 1.3.1 Успешное получение информации об аккаунте
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- Аккаунт существует и активен
|
||
- JWT токен валиден
|
||
|
||
**Входные данные:**
|
||
- Метод: GET
|
||
- URL: /account/get
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект Account со следующими полями:
|
||
- id (string)
|
||
- user_id (string)
|
||
- created_at (date-time)
|
||
- privileges (object)
|
||
|
||
**Проверки:**
|
||
1. Все обязательные поля присутствуют в ответе
|
||
2. Формат даты created_at соответствует ISO 8601
|
||
3. Структура privileges соответствует схеме ShortPrivilege
|
||
4. Значения полей соответствуют данным в базе
|
||
|
||
#### 1.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 1.3.3 Проверка существования аккаунта
|
||
**Сценарий 3.1: Аккаунт не найден**
|
||
- Предусловие: Аккаунт удален или не существует
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Аккаунт деактивирован**
|
||
- Предусловие: Аккаунт помечен как deleted=true
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 1.3.4 Проверка привилегий
|
||
**Сценарий 4.1: Аккаунт без привилегий**
|
||
- Предусловие: Аккаунт существует, но не имеет привилегий
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: privileges = {}
|
||
|
||
**Сценарий 4.2: Аккаунт с множеством привилегий**
|
||
- Предусловие: Аккаунт имеет несколько активных привилегий
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка структуры и содержимого privileges
|
||
|
||
#### 1.3.5 Проверка производительности
|
||
**Сценарий 5.1: Время ответа**
|
||
- Проверка: время ответа < 500ms
|
||
- Проверка: стабильность времени ответа при повторных запросах
|
||
|
||
**Сценарий 5.2: Нагрузочное тестирование**
|
||
- Проверка: система выдерживает 100 последовательных запросов
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 1.3.6 Проверка безопасности
|
||
**Сценарий 6.1: XSS уязвимости**
|
||
- Проверка: экранирование специальных символов в ответе
|
||
- Проверка: корректные заголовки безопасности
|
||
|
||
**Сценарий 6.2: CSRF защита**
|
||
- Проверка: наличие и валидность CSRF токена
|
||
- Проверка: корректная обработка невалидного CSRF токена
|
||
|
||
#### 1.3.7 Граничные случаи
|
||
**Сценарий 7.1: Очень длинные значения полей**
|
||
- Проверка: обработка полей с максимально допустимой длиной
|
||
- Проверка: корректное обрезание/валидация длинных значений
|
||
|
||
**Сценарий 7.2: Специальные символы в данных**
|
||
- Проверка: корректная обработка Unicode символов
|
||
- Проверка: обработка специальных символов в именах полей
|
||
|
||
#### 1.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 1.4 Особые моменты для тестирования
|
||
|
||
1. **Валидация JWT токена:**
|
||
- Проверка подписи токена
|
||
- Проверка срока действия
|
||
- Проверка структуры claims
|
||
|
||
2. **Кэширование:**
|
||
- Проверка правильности кэширования ответов
|
||
- Проверка инвалидации кэша при изменении данных
|
||
|
||
3. **Логирование:**
|
||
- Проверка записи всех важных событий
|
||
- Проверка корректности логов
|
||
|
||
4. **Мониторинг:**
|
||
- Проверка метрик производительности
|
||
- Проверка алертов при ошибках
|
||
|
||
### 1.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время ответа соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
|
||
## 2. POST /account/create
|
||
|
||
### 2.1 Описание
|
||
Создание нового аккаунта пользователя.
|
||
|
||
### 2.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Создает новый аккаунт в системе
|
||
- Поддерживает HTTP коды ответа: 200, 401, 409, 500
|
||
|
||
### 2.3 Тестовые сценарии
|
||
|
||
#### 2.3.1 Успешное создание аккаунта
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- Аккаунт с таким user_id еще не существует
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /account/create
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект Account со следующими полями:
|
||
- id (string)
|
||
- user_id (string)
|
||
- created_at (date-time)
|
||
- privileges (object)
|
||
|
||
**Проверки:**
|
||
1. Аккаунт успешно создан в базе данных
|
||
2. Все обязательные поля присутствуют в ответе
|
||
3. Формат даты created_at соответствует ISO 8601
|
||
4. Значения полей соответствуют переданным данным
|
||
|
||
#### 2.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 2.3.3 Проверка конфликтов
|
||
**Сценарий 3.1: Создание дублирующегося аккаунта**
|
||
- Предусловие: Аккаунт с таким user_id уже существует
|
||
- Ожидаемый результат: 409 Conflict
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Попытка создания аккаунта с существующим ID**
|
||
- Предусловие: Передан ID существующего аккаунта
|
||
- Ожидаемый результат: 409 Conflict
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 2.3.4 Проверка валидации данных
|
||
**Сценарий 4.1: Отсутствие обязательных полей**
|
||
- Входные данные: пустой JSON объект
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 4.2: Некорректный формат данных**
|
||
- Входные данные: неверный формат полей
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 2.3.5 Проверка безопасности
|
||
**Сценарий 5.1: SQL-инъекции**
|
||
- Входные данные: SQL-инъекция в полях
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 5.2: XSS-атаки**
|
||
- Входные данные: XSS-код в полях
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 2.3.6 Проверка производительности
|
||
**Сценарий 6.1: Время создания**
|
||
- Проверка: время создания аккаунта < 1s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 6.2: Нагрузочное тестирование**
|
||
- Проверка: система выдерживает создание 100 аккаунтов подряд
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 2.3.7 Граничные случаи
|
||
**Сценарий 7.1: Очень длинные значения полей**
|
||
- Входные данные: поля с максимально допустимой длиной
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: данные сохранены корректно
|
||
|
||
**Сценарий 7.2: Специальные символы**
|
||
- Входные данные: Unicode символы в полях
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: данные сохранены корректно
|
||
|
||
#### 2.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 2.4 Особые моменты для тестирования
|
||
|
||
1. **Валидация данных:**
|
||
- Проверка всех обязательных полей
|
||
- Проверка форматов данных
|
||
- Проверка уникальности user_id
|
||
|
||
2. **Транзакционность:**
|
||
- Проверка атомарности операции создания
|
||
- Проверка отката при ошибках
|
||
|
||
3. **Логирование:**
|
||
- Проверка записи создания аккаунта
|
||
- Проверка аудит-логов
|
||
|
||
4. **Мониторинг:**
|
||
- Проверка метрик создания аккаунтов
|
||
- Проверка алертов при ошибках
|
||
|
||
### 2.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время создания аккаунта соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
|
||
## 3. DELETE /account/delete
|
||
|
||
### 3.1 Описание
|
||
Удаление текущего аккаунта пользователя.
|
||
|
||
### 3.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Удаляет текущий аккаунт пользователя
|
||
- Поддерживает HTTP коды ответа: 200, 401, 500
|
||
|
||
### 3.3 Тестовые сценарии
|
||
|
||
#### 3.3.1 Успешное удаление аккаунта
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- Аккаунт существует и активен
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /account/delete
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект с полем accountId (string)
|
||
|
||
**Проверки:**
|
||
1. Аккаунт успешно удален из базы данных
|
||
2. Все связанные данные аккаунта удалены или помечены как удаленные
|
||
3. Поле accountId в ответе соответствует ID удаленного аккаунта
|
||
4. Последующие запросы к аккаунту возвращают 404
|
||
|
||
#### 3.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 3.3.3 Проверка состояния аккаунта
|
||
**Сценарий 3.1: Удаление уже удаленного аккаунта**
|
||
- Предусловие: Аккаунт уже помечен как удаленный
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: повторное удаление не вызывает ошибок
|
||
|
||
**Сценарий 3.2: Удаление несуществующего аккаунта**
|
||
- Предусловие: Аккаунт не существует
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: операция завершается успешно
|
||
|
||
#### 3.3.4 Проверка каскадного удаления
|
||
**Сценарий 4.1: Удаление связанных данных**
|
||
- Проверка: все связанные квизы удалены или помечены как удаленные
|
||
- Проверка: все связанные вопросы удалены или помечены как удаленные
|
||
- Проверка: все связанные результаты удалены или помечены как удаленные
|
||
|
||
**Сценарий 4.2: Сохранение статистики**
|
||
- Проверка: статистические данные сохранены для аналитики
|
||
- Проверка: исторические данные доступны для отчетов
|
||
|
||
#### 3.3.5 Проверка безопасности
|
||
**Сценарий 5.1: Попытка удаления чужого аккаунта**
|
||
- Предусловие: Попытка удаления аккаунта другого пользователя
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: операция отклонена
|
||
|
||
**Сценарий 5.2: Проверка CSRF защиты**
|
||
- Проверка: наличие и валидность CSRF токена
|
||
- Проверка: отклонение запросов без валидного CSRF токена
|
||
|
||
#### 3.3.6 Проверка производительности
|
||
**Сценарий 6.1: Время удаления**
|
||
- Проверка: время удаления аккаунта < 2s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 6.2: Нагрузочное тестирование**
|
||
- Проверка: система корректно обрабатывает множественные запросы на удаление
|
||
- Проверка: отсутствие утечек памяти при массовом удалении
|
||
|
||
#### 3.3.7 Граничные случаи
|
||
**Сценарий 7.1: Удаление аккаунта с большим количеством данных**
|
||
- Предусловие: Аккаунт имеет множество связанных данных
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все данные успешно удалены
|
||
|
||
**Сценарий 7.2: Удаление во время активных операций**
|
||
- Предусловие: Активные операции с аккаунтом
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: корректная обработка конкурентных запросов
|
||
|
||
#### 3.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 3.4 Особые моменты для тестирования
|
||
|
||
1. **Транзакционность:**
|
||
- Проверка атомарности операции удаления
|
||
- Проверка отката при частичном удалении
|
||
- Проверка целостности данных после удаления
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи операции удаления
|
||
- Проверка аудит-логов
|
||
- Проверка логов связанных операций
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик удаления аккаунтов
|
||
- Проверка алертов при ошибках
|
||
- Проверка мониторинга связанных операций
|
||
|
||
4. **Восстановление:**
|
||
- Проверка возможности восстановления данных
|
||
- Проверка периода хранения удаленных данных
|
||
|
||
### 3.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время удаления аккаунта соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Каскадное удаление работает корректно
|
||
7. Данные успешно удаляются или помечаются как удаленные
|
||
|
||
## 4. GET /accounts
|
||
|
||
### 4.1 Описание
|
||
Получение списка аккаунтов с поддержкой пагинации.
|
||
|
||
### 4.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Поддерживает пагинацию через параметры limit и page
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 500
|
||
|
||
### 4.3 Тестовые сценарии
|
||
|
||
#### 4.3.1 Успешное получение списка аккаунтов
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- В системе есть несколько аккаунтов
|
||
|
||
**Входные данные:**
|
||
- Метод: GET
|
||
- URL: /accounts
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Body:
|
||
```json
|
||
{
|
||
"limit": 10,
|
||
"page": 1
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект со следующими полями:
|
||
- count (integer) - общее количество аккаунтов
|
||
- items (array) - массив объектов Account
|
||
|
||
**Проверки:**
|
||
1. Количество возвращаемых элементов не превышает limit
|
||
2. Все обязательные поля присутствуют в каждом объекте Account
|
||
3. Значение count соответствует общему количеству аккаунтов
|
||
4. Элементы отсортированы по дате создания (новые первые)
|
||
|
||
#### 4.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 4.3.3 Проверка пагинации
|
||
**Сценарий 3.1: Корректные параметры пагинации**
|
||
- Входные данные: limit=10, page=1
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: возвращается корректное количество элементов
|
||
|
||
**Сценарий 3.2: Некорректные параметры пагинации**
|
||
- Входные данные: limit=0, page=0
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Превышение максимального лимита**
|
||
- Входные данные: limit=1000
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 4.3.4 Проверка фильтрации
|
||
**Сценарий 4.1: Пустой результат**
|
||
- Предусловие: Нет аккаунтов в системе
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: count=0, items=[]
|
||
|
||
**Сценарий 4.2: Последняя страница**
|
||
- Входные данные: page с большим номером
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: items=[]
|
||
|
||
#### 4.3.5 Проверка безопасности
|
||
**Сценарий 5.1: Проверка прав доступа**
|
||
- Проверка: пользователь видит только разрешенные аккаунты
|
||
- Проверка: конфиденциальные данные скрыты
|
||
|
||
**Сценарий 5.2: CSRF защита**
|
||
- Проверка: наличие и валидность CSRF токена
|
||
- Проверка: отклонение запросов без валидного CSRF токена
|
||
|
||
#### 4.3.6 Проверка производительности
|
||
**Сценарий 6.1: Время ответа**
|
||
- Проверка: время ответа < 500ms
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 6.2: Нагрузочное тестирование**
|
||
- Проверка: система выдерживает 100 последовательных запросов
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 4.3.7 Граничные случаи
|
||
**Сценарий 7.1: Большое количество аккаунтов**
|
||
- Предусловие: В системе 1000+ аккаунтов
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: корректная работа пагинации
|
||
|
||
**Сценарий 7.2: Специальные символы в данных**
|
||
- Проверка: корректная обработка Unicode символов
|
||
- Проверка: корректное отображение специальных символов
|
||
|
||
#### 4.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 4.4 Особые моменты для тестирования
|
||
|
||
1. **Кэширование:**
|
||
- Проверка правильности кэширования результатов
|
||
- Проверка инвалидации кэша при изменении данных
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи запросов к списку аккаунтов
|
||
- Проверка аудит-логов
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик производительности
|
||
- Проверка алертов при ошибках
|
||
|
||
4. **Оптимизация:**
|
||
- Проверка эффективности запросов к БД
|
||
- Проверка использования индексов
|
||
|
||
### 4.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время ответа соответствует требованиям
|
||
3. Пагинация работает корректно
|
||
4. Обработка ошибок соответствует спецификации
|
||
5. Безопасность соответствует стандартам
|
||
6. Логирование и мониторинг работают корректно
|
||
7. Кэширование работает эффективно
|
||
|
||
## 5. GET /privilege/{userId}
|
||
|
||
### 5.1 Описание
|
||
Получение списка привилегий для указанного пользователя по его ID.
|
||
|
||
### 5.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Требуется передача userId в теле запроса
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 500
|
||
|
||
### 5.3 Тестовые сценарии
|
||
|
||
#### 5.3.1 Успешное получение привилегий
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- Указанный пользователь существует
|
||
- У пользователя есть привилегии
|
||
|
||
**Входные данные:**
|
||
- Метод: GET
|
||
- URL: /privilege/{userId}
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Body:
|
||
```json
|
||
{
|
||
"userId": "valid_user_id"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит массив объектов ShortPrivilege со следующими полями:
|
||
- id (string)
|
||
- privilege_id (string)
|
||
- privilege_name (string)
|
||
- amount (integer)
|
||
- created_at (date-time)
|
||
|
||
**Проверки:**
|
||
1. Все привилегии пользователя возвращены
|
||
2. Все обязательные поля присутствуют в каждом объекте
|
||
3. Формат даты created_at соответствует ISO 8601
|
||
4. Значения полей соответствуют данным в базе
|
||
|
||
#### 5.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 5.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Отсутствие userId**
|
||
- Body: пустой JSON объект
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Невалидный userId**
|
||
- Body: { "userId": "invalid_id" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Несуществующий userId**
|
||
- Body: { "userId": "non_existent_id" }
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: возвращается пустой массив
|
||
|
||
#### 5.3.4 Проверка прав доступа
|
||
**Сценарий 4.1: Запрос привилегий другого пользователя**
|
||
- Предусловие: Запрос привилегий пользователя с другим ID
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
**Сценарий 4.2: Запрос привилегий с недостаточными правами**
|
||
- Предусловие: У запрашивающего пользователя нет прав на просмотр привилегий
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
#### 5.3.5 Проверка безопасности
|
||
**Сценарий 5.1: SQL-инъекции**
|
||
- Body: { "userId": "1' OR '1'='1" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 5.2: XSS-атаки**
|
||
- Body: { "userId": "<script>alert('xss')</script>" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 5.3.6 Проверка производительности
|
||
**Сценарий 6.1: Время ответа**
|
||
- Проверка: время ответа < 300ms
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 6.2: Нагрузочное тестирование**
|
||
- Проверка: система выдерживает 100 последовательных запросов
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 5.3.7 Граничные случаи
|
||
**Сценарий 7.1: Пользователь с большим количеством привилегий**
|
||
- Предусловие: У пользователя 100+ привилегий
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все привилегии возвращены корректно
|
||
|
||
**Сценарий 7.2: Пользователь без привилегий**
|
||
- Предусловие: У пользователя нет привилегий
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: возвращается пустой массив
|
||
|
||
#### 5.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 5.4 Особые моменты для тестирования
|
||
|
||
1. **Кэширование:**
|
||
- Проверка кэширования результатов запроса
|
||
- Проверка инвалидации кэша при изменении привилегий
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи запросов к привилегиям
|
||
- Проверка аудит-логов доступа
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик производительности
|
||
- Проверка алертов при ошибках
|
||
|
||
4. **Безопасность:**
|
||
- Проверка контроля доступа
|
||
- Проверка валидации входных данных
|
||
|
||
### 5.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время ответа соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Кэширование работает эффективно
|
||
7. Контроль доступа работает корректно
|
||
|
||
## 6. DELETE /account/{userId}
|
||
|
||
### 6.1 Описание
|
||
Удаление аккаунта пользователя по его ID.
|
||
|
||
### 6.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Требуется передача userId в теле запроса
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 500
|
||
|
||
### 6.3 Тестовые сценарии
|
||
|
||
#### 6.3.1 Успешное удаление аккаунта
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- У запрашивающего пользователя есть права на удаление аккаунтов
|
||
- Удаляемый аккаунт существует и активен
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /account/{userId}
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Body:
|
||
```json
|
||
{
|
||
"userId": "valid_user_id"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект с полем userId (string)
|
||
|
||
**Проверки:**
|
||
1. Аккаунт успешно удален из базы данных
|
||
2. Все связанные данные аккаунта удалены или помечены как удаленные
|
||
3. Поле userId в ответе соответствует ID удаленного аккаунта
|
||
4. Последующие запросы к аккаунту возвращают 404
|
||
|
||
#### 6.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 6.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Отсутствие userId**
|
||
- Body: пустой JSON объект
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Невалидный userId**
|
||
- Body: { "userId": "invalid_id" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Несуществующий userId**
|
||
- Body: { "userId": "non_existent_id" }
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: операция завершается успешно
|
||
|
||
#### 6.3.4 Проверка прав доступа
|
||
**Сценарий 4.1: Удаление без необходимых прав**
|
||
- Предусловие: У пользователя нет прав на удаление аккаунтов
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
**Сценарий 4.2: Попытка удаления системного аккаунта**
|
||
- Предусловие: Попытка удаления системного аккаунта
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
#### 6.3.5 Проверка каскадного удаления
|
||
**Сценарий 5.1: Удаление связанных данных**
|
||
- Проверка: все связанные квизы удалены или помечены как удаленные
|
||
- Проверка: все связанные вопросы удалены или помечены как удаленные
|
||
- Проверка: все связанные результаты удалены или помечены как удаленные
|
||
|
||
**Сценарий 5.2: Сохранение статистики**
|
||
- Проверка: статистические данные сохранены для аналитики
|
||
- Проверка: исторические данные доступны для отчетов
|
||
|
||
#### 6.3.6 Проверка безопасности
|
||
**Сценарий 6.1: SQL-инъекции**
|
||
- Body: { "userId": "1' OR '1'='1" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 6.2: XSS-атаки**
|
||
- Body: { "userId": "<script>alert('xss')</script>" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 6.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время удаления**
|
||
- Проверка: время удаления аккаунта < 2s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: система корректно обрабатывает множественные запросы на удаление
|
||
- Проверка: отсутствие утечек памяти при массовом удалении
|
||
|
||
#### 6.3.8 Граничные случаи
|
||
**Сценарий 8.1: Удаление аккаунта с большим количеством данных**
|
||
- Предусловие: Аккаунт имеет множество связанных данных
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все данные успешно удалены
|
||
|
||
**Сценарий 8.2: Удаление во время активных операций**
|
||
- Предусловие: Активные операции с аккаунтом
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: корректная обработка конкурентных запросов
|
||
|
||
#### 6.3.9 Обработка ошибок
|
||
**Сценарий 9.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 9.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 6.4 Особые моменты для тестирования
|
||
|
||
1. **Транзакционность:**
|
||
- Проверка атомарности операции удаления
|
||
- Проверка отката при частичном удалении
|
||
- Проверка целостности данных после удаления
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи операции удаления
|
||
- Проверка аудит-логов
|
||
- Проверка логов связанных операций
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик удаления аккаунтов
|
||
- Проверка алертов при ошибках
|
||
- Проверка мониторинга связанных операций
|
||
|
||
4. **Восстановление:**
|
||
- Проверка возможности восстановления данных
|
||
- Проверка периода хранения удаленных данных
|
||
|
||
### 6.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время удаления аккаунта соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Каскадное удаление работает корректно
|
||
7. Данные успешно удаляются или помечаются как удаленные
|
||
8. Контроль доступа работает корректно
|
||
|
||
## 7. POST /account/manualdone
|
||
|
||
### 7.1 Описание
|
||
Ручная пометка аккаунта как завершенного.
|
||
|
||
### 7.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Требуется передача id пользователя в теле запроса
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 404, 500
|
||
|
||
### 7.3 Тестовые сценарии
|
||
|
||
#### 7.3.1 Успешная пометка аккаунта как завершенного
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- У запрашивающего пользователя есть права на пометку аккаунтов
|
||
- Аккаунт существует и активен
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /account/manualdone
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Body:
|
||
```json
|
||
{
|
||
"id": "valid_user_id"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
|
||
**Проверки:**
|
||
1. Аккаунт успешно помечен как завершенный
|
||
2. Статус аккаунта обновлен в базе данных
|
||
3. Все связанные операции завершены
|
||
4. Последующие запросы к аккаунту показывают обновленный статус
|
||
|
||
#### 7.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 7.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Отсутствие id**
|
||
- Body: пустой JSON объект
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Невалидный id**
|
||
- Body: { "id": "invalid_id" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Несуществующий id**
|
||
- Body: { "id": "non_existent_id" }
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 7.3.4 Проверка прав доступа
|
||
**Сценарий 4.1: Отметка без необходимых прав**
|
||
- Предусловие: У пользователя нет прав на пометку аккаунтов
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
**Сценарий 4.2: Попытка пометки системного аккаунта**
|
||
- Предусловие: Попытка пометки системного аккаунта
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
#### 7.3.5 Проверка состояния аккаунта
|
||
**Сценарий 5.1: Пометка уже завершенного аккаунта**
|
||
- Предусловие: Аккаунт уже помечен как завершенный
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: повторная пометка не вызывает ошибок
|
||
|
||
**Сценарий 5.2: Пометка удаленного аккаунта**
|
||
- Предусловие: Аккаунт помечен как удаленный
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка: операция отклонена
|
||
|
||
#### 7.3.6 Проверка безопасности
|
||
**Сценарий 6.1: SQL-инъекции**
|
||
- Body: { "id": "1' OR '1'='1" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 6.2: XSS-атаки**
|
||
- Body: { "id": "<script>alert('xss')</script>" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 7.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время выполнения**
|
||
- Проверка: время выполнения операции < 1s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: система корректно обрабатывает множественные запросы
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 7.3.8 Граничные случаи
|
||
**Сценарий 8.1: Пометка аккаунта с большим количеством данных**
|
||
- Предусловие: Аккаунт имеет множество связанных данных
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все данные успешно обработаны
|
||
|
||
**Сценарий 8.2: Пометка во время активных операций**
|
||
- Предусловие: Активные операции с аккаунтом
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: корректная обработка конкурентных запросов
|
||
|
||
#### 7.3.9 Обработка ошибок
|
||
**Сценарий 9.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 9.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 7.4 Особые моменты для тестирования
|
||
|
||
1. **Транзакционность:**
|
||
- Проверка атомарности операции пометки
|
||
- Проверка отката при частичном выполнении
|
||
- Проверка целостности данных после пометки
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи операции пометки
|
||
- Проверка аудит-логов
|
||
- Проверка логов связанных операций
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик выполнения операций
|
||
- Проверка алертов при ошибках
|
||
- Проверка мониторинга связанных операций
|
||
|
||
4. **Восстановление:**
|
||
- Проверка возможности отмены пометки
|
||
- Проверка истории изменений статуса
|
||
|
||
### 7.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время выполнения операции соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Транзакционность работает корректно
|
||
7. Статус аккаунта успешно обновляется
|
||
8. Контроль доступа работает корректно
|
||
|
||
## 8. POST /account/leadtarget
|
||
|
||
### 8.1 Описание
|
||
Добавление целевого адреса для отправки клиентских запросов.
|
||
|
||
### 8.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Обязательные поля в теле запроса: type, quizID, target
|
||
- Поддерживает HTTP коды ответа: 200, 208, 400, 401, 404, 500
|
||
|
||
### 8.3 Тестовые сценарии
|
||
|
||
#### 8.3.1 Успешное добавление целевого адреса
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- У пользователя есть права на добавление целевых адресов
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /account/leadtarget
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Body:
|
||
```json
|
||
{
|
||
"type": "mail",
|
||
"quizID": 123,
|
||
"target": "example@mail.com",
|
||
"name": "Example Channel"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
|
||
**Проверки:**
|
||
1. Целевой адрес успешно добавлен
|
||
2. Данные корректно сохранены в базе
|
||
3. Все обязательные поля присутствуют
|
||
4. Значения полей соответствуют переданным данным
|
||
|
||
#### 8.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 8.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Отсутствие обязательных полей**
|
||
- Body: { "type": "mail" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Невалидный тип**
|
||
- Body: { "type": "invalid", "quizID": 123, "target": "example@mail.com" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Невалидный формат target**
|
||
- Body: { "type": "mail", "quizID": 123, "target": "invalid_email" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 8.3.4 Проверка дублирования
|
||
**Сценарий 4.1: Добавление существующего target**
|
||
- Предусловие: Target уже существует
|
||
- Ожидаемый результат: 208 Already Reported
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 4.2: Добавление с разным регистром**
|
||
- Предусловие: Target существует с другим регистром
|
||
- Ожидаемый результат: 208 Already Reported
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 8.3.5 Проверка безопасности
|
||
**Сценарий 5.1: SQL-инъекции**
|
||
- Body: { "type": "mail", "quizID": "1' OR '1'='1", "target": "example@mail.com" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 5.2: XSS-атаки**
|
||
- Body: { "type": "mail", "quizID": 123, "target": "<script>alert('xss')</script>" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 8.3.6 Проверка производительности
|
||
**Сценарий 6.1: Время выполнения**
|
||
- Проверка: время выполнения операции < 1s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 6.2: Нагрузочное тестирование**
|
||
- Проверка: система корректно обрабатывает множественные запросы
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 8.3.7 Граничные случаи
|
||
**Сценарий 7.1: Максимальная длина полей**
|
||
- Body: { "type": "mail", "quizID": 123, "target": "very_long_email@domain.com", "name": "very_long_name" }
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: данные сохранены корректно
|
||
|
||
**Сценарий 7.2: Специальные символы**
|
||
- Body: { "type": "mail", "quizID": 123, "target": "special!@#$%^&*()@domain.com", "name": "Special Name!" }
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: данные сохранены корректно
|
||
|
||
#### 8.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 8.4 Особые моменты для тестирования
|
||
|
||
1. **Валидация данных:**
|
||
- Проверка форматов email, телефона, ID канала
|
||
- Проверка уникальности target
|
||
- Проверка допустимых значений type
|
||
|
||
2. **Транзакционность:**
|
||
- Проверка атомарности операции добавления
|
||
- Проверка отката при ошибках
|
||
|
||
3. **Логирование:**
|
||
- Проверка записи операции добавления
|
||
- Проверка аудит-логов
|
||
|
||
4. **Мониторинг:**
|
||
- Проверка метрик добавления target
|
||
- Проверка алертов при ошибках
|
||
|
||
### 8.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время выполнения операции соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Валидация данных работает корректно
|
||
7. Дублирование target обрабатывается корректно
|
||
|
||
## 9. PUT /account/leadtarget
|
||
|
||
### 9.1 Описание
|
||
Обновление существующего целевого адреса.
|
||
|
||
### 9.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- Обязательные поля в теле запроса: id, target
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 404, 500
|
||
|
||
### 9.3 Тестовые сценарии
|
||
|
||
#### 9.3.1 Успешное обновление целевого адреса
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- У пользователя есть права на обновление целевых адресов
|
||
- Целевой адрес существует
|
||
|
||
**Входные данные:**
|
||
- Метод: PUT
|
||
- URL: /account/leadtarget
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Body:
|
||
```json
|
||
{
|
||
"id": 123,
|
||
"target": "new_target@mail.com"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
|
||
**Проверки:**
|
||
1. Целевой адрес успешно обновлен
|
||
2. Данные корректно сохранены в базе
|
||
3. Старое значение target заменено на новое
|
||
4. Остальные поля остались без изменений
|
||
|
||
#### 9.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 9.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Отсутствие обязательных полей**
|
||
- Body: { "id": 123 }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Невалидный id**
|
||
- Body: { "id": "invalid", "target": "example@mail.com" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Невалидный формат target**
|
||
- Body: { "id": 123, "target": "invalid_email" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 9.3.4 Проверка существования
|
||
**Сценарий 4.1: Обновление несуществующего target**
|
||
- Body: { "id": 999999, "target": "example@mail.com" }
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 4.2: Обновление удаленного target**
|
||
- Предусловие: Target помечен как удаленный
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 9.3.5 Проверка безопасности
|
||
**Сценарий 5.1: SQL-инъекции**
|
||
- Body: { "id": "1' OR '1'='1", "target": "example@mail.com" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 5.2: XSS-атаки**
|
||
- Body: { "id": 123, "target": "<script>alert('xss')</script>" }
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 9.3.6 Проверка производительности
|
||
**Сценарий 6.1: Время выполнения**
|
||
- Проверка: время выполнения операции < 1s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 6.2: Нагрузочное тестирование**
|
||
- Проверка: система корректно обрабатывает множественные запросы
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 9.3.7 Граничные случаи
|
||
**Сценарий 7.1: Максимальная длина target**
|
||
- Body: { "id": 123, "target": "very_long_email@very_long_domain.com" }
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: данные сохранены корректно
|
||
|
||
**Сценарий 7.2: Специальные символы**
|
||
- Body: { "id": 123, "target": "special!@#$%^&*()@domain.com" }
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: данные сохранены корректно
|
||
|
||
#### 9.3.8 Обработка ошибок
|
||
**Сценарий 8.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 8.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 9.4 Особые моменты для тестирования
|
||
|
||
1. **Валидация данных:**
|
||
- Проверка форматов email, телефона, ID канала
|
||
- Проверка уникальности нового target
|
||
- Проверка существования id
|
||
|
||
2. **Транзакционность:**
|
||
- Проверка атомарности операции обновления
|
||
- Проверка отката при ошибках
|
||
|
||
3. **Логирование:**
|
||
- Проверка записи операции обновления
|
||
- Проверка аудит-логов
|
||
- Проверка истории изменений
|
||
|
||
4. **Мониторинг:**
|
||
- Проверка метрик обновления target
|
||
- Проверка алертов при ошибках
|
||
|
||
### 9.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время выполнения операции соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Валидация данных работает корректно
|
||
7. Обновление target выполняется корректно
|
||
8. История изменений сохраняется
|
||
|
||
## 10. DELETE /account/leadtarget/{id}
|
||
|
||
### 10.1 Описание
|
||
Удаление целевого адреса по его ID.
|
||
|
||
### 10.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- ID целевого адреса передается в пути URL
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 500
|
||
|
||
### 10.3 Тестовые сценарии
|
||
|
||
#### 10.3.1 Успешное удаление целевого адреса
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- У пользователя есть права на удаление целевых адресов
|
||
- Целевой адрес существует и активен
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /account/leadtarget/{valid_id}
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
|
||
**Проверки:**
|
||
1. Целевой адрес успешно удален
|
||
2. Данные корректно удалены из базы
|
||
3. Последующие запросы к этому ID возвращают 404
|
||
4. Все связанные данные обработаны корректно
|
||
|
||
#### 10.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 10.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Невалидный ID**
|
||
- URL: /account/leadtarget/invalid_id
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Отсутствующий ID**
|
||
- URL: /account/leadtarget/
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Несуществующий ID**
|
||
- URL: /account/leadtarget/999999
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: операция завершается успешно
|
||
|
||
#### 10.3.4 Проверка прав доступа
|
||
**Сценарий 4.1: Удаление без необходимых прав**
|
||
- Предусловие: У пользователя нет прав на удаление целевых адресов
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
**Сценарий 4.2: Попытка удаления чужого целевого адреса**
|
||
- Предусловие: Целевой адрес принадлежит другому пользователю
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
#### 10.3.5 Проверка состояния целевого адреса
|
||
**Сценарий 5.1: Удаление уже удаленного целевого адреса**
|
||
- Предусловие: Целевой адрес уже помечен как удаленный
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: повторное удаление не вызывает ошибок
|
||
|
||
**Сценарий 5.2: Удаление активного целевого адреса**
|
||
- Предусловие: Целевой адрес активен и используется
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все связанные операции обработаны корректно
|
||
|
||
#### 10.3.6 Проверка безопасности
|
||
**Сценарий 6.1: SQL-инъекции**
|
||
- URL: /account/leadtarget/1' OR '1'='1
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 6.2: XSS-атаки**
|
||
- URL: /account/leadtarget/<script>alert('xss')</script>
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 10.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время выполнения**
|
||
- Проверка: время выполнения операции < 1s
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: система корректно обрабатывает множественные запросы на удаление
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 10.3.8 Граничные случаи
|
||
**Сценарий 8.1: Удаление целевого адреса с большим количеством связанных данных**
|
||
- Предусловие: Целевой адрес имеет множество связанных данных
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все данные успешно удалены
|
||
|
||
**Сценарий 8.2: Удаление во время активных операций**
|
||
- Предусловие: Активные операции с целевым адресом
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: корректная обработка конкурентных запросов
|
||
|
||
#### 10.3.9 Обработка ошибок
|
||
**Сценарий 9.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 9.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 10.4 Особые моменты для тестирования
|
||
|
||
1. **Транзакционность:**
|
||
- Проверка атомарности операции удаления
|
||
- Проверка отката при частичном удалении
|
||
- Проверка целостности данных после удаления
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи операции удаления
|
||
- Проверка аудит-логов
|
||
- Проверка логов связанных операций
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик удаления целевых адресов
|
||
- Проверка алертов при ошибках
|
||
- Проверка мониторинга связанных операций
|
||
|
||
4. **Восстановление:**
|
||
- Проверка возможности восстановления данных
|
||
- Проверка периода хранения удаленных данных
|
||
|
||
### 10.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время выполнения операции соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Транзакционность работает корректно
|
||
7. Целевой адрес успешно удаляется
|
||
8. Контроль доступа работает корректно
|
||
|
||
## 11. GET /account/leadtarget/{quizID}
|
||
|
||
### 11.1 Описание
|
||
Получение целевого адреса по ID квиза.
|
||
|
||
### 11.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth)
|
||
- ID квиза передается в пути URL
|
||
- Поддерживает HTTP коды ответа: 200, 400, 401, 404, 500
|
||
|
||
### 11.3 Тестовые сценарии
|
||
|
||
#### 11.3.1 Успешное получение целевого адреса
|
||
**Предусловия:**
|
||
- Пользователь авторизован
|
||
- JWT токен валиден
|
||
- У пользователя есть права на просмотр целевых адресов
|
||
- Квиз существует и имеет связанный целевой адрес
|
||
|
||
**Входные данные:**
|
||
- Метод: GET
|
||
- URL: /account/leadtarget/{valid_quiz_id}
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект LeadTarget со следующими полями:
|
||
- id (integer)
|
||
- accountID (string)
|
||
- type (string)
|
||
- target (string)
|
||
- quizID (integer)
|
||
- inviteLink (string, опционально)
|
||
- deleted (boolean)
|
||
- createdAt (date-time)
|
||
|
||
**Проверки:**
|
||
1. Все обязательные поля присутствуют в ответе
|
||
2. Формат даты createdAt соответствует ISO 8601
|
||
3. Значения полей соответствуют данным в базе
|
||
4. Тип целевого адреса соответствует ожидаемому
|
||
|
||
#### 11.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 11.3.3 Проверка входных данных
|
||
**Сценарий 3.1: Невалидный quizID**
|
||
- URL: /account/leadtarget/invalid_id
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.2: Отсутствующий quizID**
|
||
- URL: /account/leadtarget/
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 3.3: Несуществующий quizID**
|
||
- URL: /account/leadtarget/999999
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
#### 11.3.4 Проверка прав доступа
|
||
**Сценарий 4.1: Просмотр без необходимых прав**
|
||
- Предусловие: У пользователя нет прав на просмотр целевых адресов
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
**Сценарий 4.2: Попытка просмотра чужого целевого адреса**
|
||
- Предусловие: Целевой адрес принадлежит другому пользователю
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
- Проверка: доступ запрещен
|
||
|
||
#### 11.3.5 Проверка состояния целевого адреса
|
||
**Сценарий 5.1: Получение удаленного целевого адреса**
|
||
- Предусловие: Целевой адрес помечен как удаленный
|
||
- Ожидаемый результат: 404 Not Found
|
||
- Проверка сообщения об ошибке
|
||
|
||
**Сценарий 5.2: Получение активного целевого адреса**
|
||
- Предусловие: Целевой адрес активен
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все данные возвращены корректно
|
||
|
||
#### 11.3.6 Проверка безопасности
|
||
**Сценарий 6.1: SQL-инъекции**
|
||
- URL: /account/leadtarget/1' OR '1'='1
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: инъекция не выполнена
|
||
|
||
**Сценарий 6.2: XSS-атаки**
|
||
- URL: /account/leadtarget/<script>alert('xss')</script>
|
||
- Ожидаемый результат: 400 Bad Request
|
||
- Проверка: XSS-код не выполнен
|
||
|
||
#### 11.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время выполнения**
|
||
- Проверка: время выполнения операции < 300ms
|
||
- Проверка: стабильность времени при повторных запросах
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: система выдерживает 100 последовательных запросов
|
||
- Проверка: отсутствие утечек памяти
|
||
|
||
#### 11.3.8 Граничные случаи
|
||
**Сценарий 8.1: Получение целевого адреса с большим количеством данных**
|
||
- Предусловие: Целевой адрес имеет множество связанных данных
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: все данные возвращены корректно
|
||
|
||
**Сценарий 8.2: Получение во время активных операций**
|
||
- Предусловие: Активные операции с целевым адресом
|
||
- Ожидаемый результат: 200 OK
|
||
- Проверка: корректная обработка конкурентных запросов
|
||
|
||
#### 11.3.9 Обработка ошибок
|
||
**Сценарий 9.1: Внутренняя ошибка сервера**
|
||
- Предусловие: Имитация сбоя базы данных
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: информативное сообщение об ошибке
|
||
|
||
**Сценарий 9.2: Таймаут соединения**
|
||
- Предусловие: Имитация таймаута
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
- Проверка: корректная обработка таймаута
|
||
|
||
### 11.4 Особые моменты для тестирования
|
||
|
||
1. **Кэширование:**
|
||
- Проверка правильности кэширования результатов
|
||
- Проверка инвалидации кэша при изменении данных
|
||
- Проверка TTL кэша
|
||
|
||
2. **Логирование:**
|
||
- Проверка записи запросов к целевым адресам
|
||
- Проверка аудит-логов
|
||
- Проверка логов доступа
|
||
|
||
3. **Мониторинг:**
|
||
- Проверка метрик производительности
|
||
- Проверка алертов при ошибках
|
||
- Проверка мониторинга доступа
|
||
|
||
4. **Безопасность:**
|
||
- Проверка контроля доступа
|
||
- Проверка валидации входных данных
|
||
- Проверка защиты от атак
|
||
|
||
### 11.5 Критерии приемки
|
||
|
||
1. Все тестовые сценарии пройдены успешно
|
||
2. Время ответа соответствует требованиям
|
||
3. Обработка ошибок соответствует спецификации
|
||
4. Безопасность соответствует стандартам
|
||
5. Логирование и мониторинг работают корректно
|
||
6. Кэширование работает эффективно
|
||
7. Контроль доступа работает корректно
|
||
8. Данные возвращаются в корректном формате
|
||
|
||
## 12. POST /question/create
|
||
|
||
### 12.1 Описание
|
||
Создание нового вопроса в системе. Эндпоинт позволяет добавлять вопросы к существующим квизам или как независимые сущности, в зависимости от логики приложения и схемы `QuestionCreateRequest`.
|
||
|
||
### 12.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Создает новый вопрос в системе.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/QuestionCreateRequest`.
|
||
- В случае успеха возвращает созданный вопрос согласно схеме `#/components/schemas/Question`.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable), 422 (Unprocessable Entity), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 12.3 Тестовые сценарии
|
||
|
||
#### 12.3.1 Успешное создание вопроса
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Данные для создания вопроса корректны и полны (например, указан существующий `quiz_id`).
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /question/create
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно схеме `#/components/schemas/QuestionCreateRequest`. Пример для типа "variant"):
|
||
```json
|
||
{
|
||
"quiz_id": 12345, // integer, обязательное поле
|
||
"title": "Какой основной компонент воздуха?", // string, обязательное поле (max 512 chars)
|
||
"type": "variant", // string, обязательное поле, enum: [text, variant, images, select, varimg, emoji, date, number, page, rating, result, file]
|
||
"description": "Выберите один правильный ответ.", // string, опционально
|
||
"required": true, // boolean, опционально
|
||
"page": 1, // integer, опционально
|
||
"content": "{}" // string, JSON serialized config, опционально. В данном примере - строка, содержащая пустой JSON объект.
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект созданного вопроса (структура и поля зависят от схемы `#/components/schemas/Question`. Пример, который может потребовать уточнений на основе схемы `Question`):
|
||
```json
|
||
{
|
||
"id": "generated_question_id",
|
||
"quiz_id": 12345,
|
||
"title": "Какой основной компонент воздуха?",
|
||
"type": "variant",
|
||
"description": "Выберите один правильный ответ.",
|
||
"required": true,
|
||
"page": 1,
|
||
"content": "{}", // В данном примере - строка, содержащая пустой JSON объект.
|
||
"created_at": "YYYY-MM-DDTHH:mm:ssZ"
|
||
// ...другие поля в соответствии со схемой Question
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Вопрос успешно создан в базе данных с переданными атрибутами.
|
||
2. Ответ содержит все обязательные поля согласно схеме `Question`.
|
||
3. `id` созданного вопроса уникален.
|
||
4. `quiz_id` в ответе соответствует переданному значению и имеет тип integer.
|
||
5. `title`, `type`, `description`, `required`, `page` в ответе соответствуют переданным значениям.
|
||
6. Поле `content` в ответе содержит строку с JSON-конфигурацией. В данном примере ожидается строка "{}".
|
||
7. Если вопрос привязан к квизу (`quiz_id`), эта связь корректно установлена.
|
||
8. Формат `created_at` (и других дат) соответствует ISO 8601.
|
||
|
||
#### 12.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации (согласно `#/components/responses/UnauthorizedError`).
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации.
|
||
|
||
#### 12.3.3 Проверка валидации данных (Ответ 400 Bad Request или 422 Unprocessable Entity)
|
||
**Сценарий 3.1: Отсутствие обязательных полей в `QuestionCreateRequest`**
|
||
- Входные данные: Тело запроса без одного или нескольких обязательных полей (например, без `title`, `quiz_id` или `type`).
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствующие или невалидные поля (для 422, тело ответа должно содержать `message` со деталями).
|
||
|
||
**Сценарий 3.2: Некорректный формат данных в полях `QuestionCreateRequest`**
|
||
- Входные данные: Тело запроса с полями неправильного типа (например, `quiz_id` не integer, `type` не из списка enum, `required` не boolean, `content` - невалидный JSON в строке).
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на поля с некорректным форматом.
|
||
|
||
**Сценарий 3.3: Некорректные значения полей (нарушение бизнес-логики)**
|
||
- Входные данные: Например, попытка создать вопрос для несуществующего `quiz_id`. `title` превышает 512 символов. Некорректная структура JSON в поле `content` для выбранного `type` вопроса.
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке описывает проблему валидации.
|
||
|
||
#### 12.3.4 Проверка ответа 406 Not Acceptable
|
||
**Сценарий 4.1: Условия, приводящие к 406 Not Acceptable**
|
||
- Предусловия: (Необходимо определить конкретные условия на основе спецификации `StatusNotAcceptableError`. Например, квиз, к которому добавляется вопрос, находится в статусе, не допускающем изменений, или превышен лимит вопросов).
|
||
- Входные данные: Корректный запрос на создание вопроса, но выполнены условия для ответа 406.
|
||
- Ожидаемый результат: 406 Not Acceptable.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusNotAcceptableError` и содержит информативное сообщение.
|
||
|
||
#### 12.3.5 Проверка ответа 424 Failed Dependency
|
||
**Сценарий 5.1: Имитация сбоя внешней зависимости**
|
||
- Предусловия: Имитация сбоя критической внешней службы или ресурса, от которого зависит создание вопроса (например, недоступность базы данных для проверки `quiz_id` или генерации ID).
|
||
- Входные данные: Корректный запрос на создание вопроса.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusFailedDependencyError` и содержит информативное сообщение.
|
||
|
||
#### 12.3.6 Проверка безопасности
|
||
**Сценарий 6.1: SQL-инъекции**
|
||
- Входные данные: В строковых полях запроса передаются SQL-инъекции.
|
||
- Ожидаемый результат: 400 Bad Request / 422 Unprocessable Entity, либо запрос обработан без выполнения инъекции, данные сохранены корректно (экранированы).
|
||
- Проверка: Отсутствие уязвимости к SQL-инъекциям. Данные в БД не повреждены.
|
||
|
||
**Сценарий 6.2: XSS-атаки**
|
||
- Входные данные: В строковых полях запроса передаются XSS-скрипты.
|
||
- Ожидаемый результат: 400 Bad Request / 422 Unprocessable Entity, либо данные сохранены корректно (экранированы), и XSS не выполняется при отображении этих данных.
|
||
- Проверка: Отсутствие уязвимости к XSS.
|
||
|
||
#### 12.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время создания вопроса**
|
||
- Проверка: Время ответа на запрос создания вопроса < N ms (например, < 500ms).
|
||
- Проверка: Стабильность времени ответа при многократных запросах.
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: Система способна обработать X запросов на создание вопросов в секунду/минуту без значительного ухудшения производительности или ошибок.
|
||
|
||
#### 12.3.8 Обработка ошибок (Общие)
|
||
**Сценарий 8.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация непредвиденного сбоя на сервере при обработке запроса (например, исключение в коде, не связанное с зависимостями или валидацией).
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/InternalServerError` и содержит общее сообщение об ошибке, не раскрывая чувствительной информации.
|
||
|
||
### 12.4 Особые моменты для тестирования
|
||
1. **Валидация схемы `QuestionCreateRequest`:**
|
||
* Тщательная проверка всех обязательных (`quiz_id`, `title`, `type`) и опциональных (`description`, `required`, `page`, `content`) полей.
|
||
* Проверка типов данных: `quiz_id` (integer), `title` (string, max 512), `description` (string), `type` (string, enum: `[text, variant, images, select, varimg, emoji, date, number, page, rating, result, file]`), `required` (boolean), `page` (integer), `content` (string, должен быть валидным JSON; для примера достаточно "{}").
|
||
* Проверка граничных значений: длина `title`.
|
||
* Валидация JSON-структуры внутри строки `content` в зависимости от `type` вопроса (например, для `variant` или `select` JSON может содержать массив опций, для `rating` - параметры шкалы и т.д.; для общего случая или если структура не определена, строка "{}" является валидным значением).
|
||
* Проверка поведения при отсутствии опциональных полей.
|
||
2. **Логика типов вопросов:**
|
||
* Корректное создание и сохранение вопросов всех поддерживаемых типов.
|
||
* Проверка, что для каждого типа вопроса сохраняется и обрабатывается релевантная информация (например, `options` для типов с выбором ответа).
|
||
3. **Привязка к квизу (если применимо):**
|
||
* Успешное создание вопроса с корректным `quiz_id`.
|
||
* Поведение системы при указании несуществующего `quiz_id` (ожидается ошибка 400/422 или 404, в зависимости от реализации).
|
||
* Поведение при попытке создать вопрос без `quiz_id` (если это поле опционально).
|
||
4. **Конкурентное создание:**
|
||
* Попытка одновременного создания нескольких вопросов (особенно если есть генерация порядковых номеров или другие неатомарные операции).
|
||
5. **Интеграционные проверки:**
|
||
* Убедиться, что созданный вопрос корректно отображается при запросе квиза, к которому он был добавлен (если есть такая связь).
|
||
* Проверить, как вопрос влияет на другие части системы (например, подсчет вопросов в квизе).
|
||
|
||
### 12.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 12.3 пройдены успешно.
|
||
2. Время ответа на создание вопроса соответствует установленным требованиям производительности.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 406, 422, 424, 500) соответствует спецификации API и предоставляет корректные сообщения.
|
||
4. Обеспечена защита от основных уязвимостей безопасности (SQL-инъекции, XSS).
|
||
5. Созданный вопрос корректно сохраняется в базе данных со всеми указанными атрибутами и доступен для последующего использования.
|
||
6. Логирование операций по созданию вопросов информативно и покрывает как успешные случаи, так и ошибки.
|
||
|
||
## 13. POST /question/getList
|
||
|
||
### 13.1 Описание
|
||
Получение списка вопросов с поддержкой пагинации и возможной фильтрацией. Эндпоинт используется для отображения вопросов в интерфейсах администрирования, привязки к квизам или других сценариях, где требуется доступ к списку вопросов.
|
||
|
||
### 13.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/GetQuestionListRequest` (обычно включает параметры пагинации `page`, `limit` и опциональные фильтры).
|
||
- В случае успеха возвращает список вопросов и метаданные пагинации согласно схеме `#/components/schemas/GetQuestionListResponse`.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable), 500 (Internal Server Error).
|
||
|
||
### 13.3 Тестовые сценарии
|
||
|
||
#### 13.3.1 Успешное получение списка вопросов (с пагинацией)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- В системе существуют вопросы, соответствующие критериям запроса (если есть фильтры).
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /question/getList
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (пример, структура соответствует `#/components/schemas/GetQuestionListRequest`. Все поля опциональны, если не указано иное в схеме.):
|
||
```json
|
||
{
|
||
"limit": 10, // integer, формат uint64
|
||
"page": 1, // integer, формат uint64
|
||
"quiz_id": 123, // integer, формат uint64, ID квиза
|
||
"type": "variant", // string, enum: [text, variant, images, select, varimg, emoji, date, number, page, rating, result, file]
|
||
"from": 1678886400, // integer, int64, начало периода (timestamp)
|
||
"to": 1679145600, // integer, int4, конец периода (timestamp)
|
||
"search": "воздух", // string, строка для поиска
|
||
"deleted": false, // boolean, получить только удаленные (true) или только не удаленные (false/отсутствует)
|
||
"required": true // boolean, фильтр по обязательности вопроса
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
-- Тело ответа (пример, структура соответствует `#/components/schemas/GetQuestionListResponse` и `#/components/schemas/Question`):
|
||
```json
|
||
{
|
||
"count": 1, // integer, uint64 - Общее количество вопросов, соответствующих фильтрам
|
||
"items": [
|
||
{
|
||
"id": 101, // integer, uint64
|
||
"quiz_id": 123, // integer, uint64
|
||
"title": "Какой основной компонент воздуха?", // string
|
||
"description": "Выберите один правильный ответ из предложенных.", // string
|
||
"type": "variant", // string, enum
|
||
"required": true, // boolean
|
||
"deleted": false, // boolean
|
||
"page": 1, // integer
|
||
"content": "{\"options\":[{\"text\":\"Азот\"},{\"text\":\"Кислород\"}], \"answer\":\"Азот\"}", // string, Serialized JSON content
|
||
"version": 1, // integer
|
||
"parent_ids": [], // array of integers (int32)
|
||
"created_at": "2023-03-15T10:00:00Z", // string, date-time
|
||
"updated_at": "2023-03-15T11:30:00Z" // string, date-time
|
||
}
|
||
// ...могут быть другие вопросы, если limit > 1 и count > 1
|
||
]
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Ответ содержит корректное количество вопросов в массиве `items`, не превышающее запрошенный `limit` (если `limit` был в запросе и меньше, чем `count`).
|
||
-2. Поля `total_count`, `page`, `limit` в ответе соответствуют запрошенным и реальным данным.
|
||
-3. Каждый объект вопроса в массиве `items` соответствует схеме `Question` и содержит все ожидаемые поля.
|
||
+2. Поле `count` в ответе содержит общее количество вопросов, соответствующих критериям фильтрации.
|
||
+3. Каждый объект вопроса в массиве `items` соответствует схеме `Question` и содержит все поля: `id`, `quiz_id`, `title`, `description`, `type`, `required`, `deleted`, `page`, `content`, `version`, `parent_ids`, `created_at`, `updated_at`, с корректными типами данных.
|
||
4. Если применялись фильтры (`quiz_id`, `type`, `from`/`to`, `search`, `deleted`, `required`), то все возвращенные вопросы соответствуют этим фильтрам (например, созданы в указанный период `from`-`to`, содержат `search` строку в релевантных полях, имеют соответствующий статус `deleted` и `required`).
|
||
|
||
#### 13.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации (согласно `#/components/responses/UnauthorizedError`).
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации.
|
||
|
||
#### 13.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
(Все поля в `GetQuestionListRequest` являются опциональными, если не указано иное в схеме. Проверки ниже касаются корректности форматов и значений, если поля предоставлены.)
|
||
|
||
**Сценарий 3.1: Некорректные параметры пагинации**
|
||
-- Входные данные: `page` или `limit` не являются integer, или имеют некорректный формат (например, отрицательные значения, если не разрешены).
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на невалидные параметры пагинации.
|
||
|
||
**Сценарий 3.2: Некорректный формат фильтров**
|
||
-- Входные данные:
|
||
+ - `quiz_id`, `from`, `to` не являются integer.
|
||
+ - `type` не из списка допустимых enum значений.
|
||
+ - `deleted` или `required` не являются boolean.
|
||
+ - `search` имеет недопустимый формат (если есть ограничения, например, по длине).
|
||
+ - `from` > `to` (некорректный временной диапазон).
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на невалидные параметры фильтрации.
|
||
|
||
-**Сценарий 3.3: Отсутствие обязательных полей в запросе (если есть)**
|
||
-- Входные данные: Тело запроса без обязательных полей (например, если `page` и `limit` обязательны).
|
||
-- Ожидаемый результат: 400 Bad Request.
|
||
-- Проверка: Сообщение об ошибке указывает на отсутствующие поля.
|
||
+**Сценарий 3.3: Невалидные значения для логических фильтров**
|
||
+- Входные данные: `deleted` или `required` переданы как строки (например, "true") вместо boolean `true`.
|
||
+ Ожидаемый результат: 400 Bad Request.
|
||
+ Проверка: Сообщение об ошибке указывает на невалидный тип данных для булевых фильтров.
|
||
|
||
#### 13.3.4 Проверка ответа 406 Not Acceptable
|
||
**Сценарий 4.1: Условия, приводящие к 406 Not Acceptable**
|
||
- Предусловия: (Необходимо определить конкретные условия на основе спецификации `StatusNotAcceptableError`. Например, запрос специфических данных, которые не могут быть предоставлены в текущем контексте).
|
||
- Входные данные: Корректный запрос на получение списка, но выполнены условия для ответа 406.
|
||
- Ожидаемый результат: 406 Not Acceptable.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusNotAcceptableError` и содержит информативное сообщение.
|
||
|
||
#### 13.3.5 Проверка ответа 424 Failed Dependency
|
||
**Сценарий 5.1: Имитация сбоя внешней зависимости**
|
||
- Предусловия: Имитация сбоя критической внешней службы или ресурса, от которого зависит создание вопроса (например, недоступность базы данных для проверки `quiz_id` или генерации ID).
|
||
- Входные данные: Корректный запрос на создание вопроса.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusFailedDependencyError` и содержит информативное сообщение.
|
||
|
||
#### 13.3.6 Обработка ошибок (Общие)
|
||
**Сценарий 6.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация непредвиденного сбоя на сервере (например, ошибка подключения к БД при выборке данных).
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/InternalServerError`.
|
||
|
||
### 13.4 Особые моменты для тестирования
|
||
1. **Логика пагинации:**
|
||
* Корректность `total_count` при наличии/отсутствии фильтров.
|
||
* Правильность выдачи данных на первой, последней и промежуточных страницах.
|
||
* Поведение при запросе страницы, превышающей общее количество страниц (например, `items` - пустой массив, `page` равен запрошенному).
|
||
* Поведение при `limit=0` или очень большом `limit` (если есть ограничения).
|
||
2. **Логика фильтрации (согласно схеме `GetQuestionListRequest`):**
|
||
* Корректность работы каждого отдельного фильтра:
|
||
- `quiz_id`: выборка вопросов только для указанного квиза.
|
||
- `type`: выборка вопросов только указанного типа.
|
||
- `from`/`to`: выборка вопросов, созданных/измененных в указанном временном диапазоне. Проверить граничные условия.
|
||
- `search`: поиск по релевантным текстовым полям вопроса (например, `title`, `description`, текстовое содержимое в `content`). Проверить поиск по части слова, полному слову, нескольким словам. Чувствительность к регистру (если определено).
|
||
- `deleted`: корректная выборка только удаленных (`true`) или только неудаленных (`false` или отсутствие поля) вопросов.
|
||
- `required`: корректная выборка вопросов по флагу обязательности.
|
||
* Корректность работы комбинации нескольких фильтров одновременно (например, `quiz_id` + `type` + `search`).
|
||
* Поведение при передаче несуществующих значений для фильтров (например, `quiz_id`, которого нет; тип вопроса, который не используется).
|
||
* Поведение фильтров при наличии пустого значения (например, `search: ""`).
|
||
3. **Сортировка (если поддерживается):**
|
||
* Проверка сортировки по умолчанию (например, по дате создания).
|
||
* Проверка работы явной сортировки по различным полям и направлениям (ASC/DESC), если это предусмотрено в `GetQuestionListRequest`.
|
||
4. **Структура и полнота данных в ответе:**
|
||
* Каждый вопрос в списке `items` должен содержать все поля, определенные схемой `Question`.
|
||
* Проверка корректности данных для каждого поля вопроса (типы, форматы).
|
||
|
||
### 13.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 13.3 пройдены успешно.
|
||
2. Время ответа на получение списка вопросов соответствует установленным требованиям производительности.
|
||
3. Пагинация и фильтрация (если реализованы) работают корректно и в соответствии с ожиданиями.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 406, 500) соответствует спецификации API и предоставляет корректные сообщения.
|
||
5. Данные в ответе полны, корректны и соответствуют схеме `GetQuestionListResponse` и `Question`.
|
||
6. Логирование запросов на получение списка вопросов информативно.
|
||
|
||
## 14. PATCH /question/edit
|
||
|
||
### 14.1 Описание
|
||
Обновление существующего вопроса. Позволяет изменять одно или несколько полей вопроса по его ID.
|
||
|
||
### 14.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: PATCH.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/UpdateQuestionRequest` и содержать обязательное поле `id` вопроса.
|
||
- В случае успеха возвращает объект согласно схеме `#/components/schemas/UpdateQuestionResponse`, содержащий `updated` (ID обновленного вопроса).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable), 422 (Unprocessable Entity), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 14.3 Тестовые сценарии
|
||
|
||
#### 14.3.1 Успешное обновление вопроса (изменение нескольких полей)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Вопрос с указанным `id` существует в системе.
|
||
|
||
**Входные данные:**
|
||
- Метод: PATCH
|
||
- URL: /question/edit
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/UpdateQuestionRequest`):
|
||
```json
|
||
{
|
||
"id": 101, // integer, uint64 - ID существующего вопроса
|
||
"title": "Обновленный заголовок вопроса?",
|
||
"desc": "Новое описание для вопроса.",
|
||
"type": "text",
|
||
"required": false,
|
||
"content": "{\"placeholder\":\"Введите ваш ответ здесь\"}",
|
||
"page": 2
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (согласно `#/components/schemas/UpdateQuestionResponse`):
|
||
```json
|
||
{
|
||
"updated": 101 // integer, uint64 - ID обновленного вопроса
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Поле `updated` в ответе содержит `id` обновленного вопроса.
|
||
2. Данные вопроса в базе данных (или при последующем GET запросе вопроса) обновлены в соответствии с переданными в запросе полями (`title`, `desc`, `type`, `required`, `content`, `page`).
|
||
3. Поля, которые не были переданы в запросе на обновление, остались без изменений в базе данных.
|
||
4. Поле `updated_at` для вопроса в базе данных обновлено.
|
||
|
||
#### 14.3.2 Успешное обновление одного поля вопроса
|
||
**Предусловия:**
|
||
- Пользователь авторизован, JWT токен валиден.
|
||
- Вопрос с `id` = 102 существует.
|
||
|
||
**Входные данные:**
|
||
- Метод: PATCH
|
||
- URL: /question/edit
|
||
- Headers: Authorization: Bearer {valid_jwt_token}, Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{
|
||
"id": 102,
|
||
"title": "Только заголовок обновлен"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Тело ответа: `{"updated": 102}`
|
||
|
||
**Проверки:**
|
||
1. `updated` в ответе равен 102.
|
||
2. В базе данных для вопроса с `id`=102 обновлен только `title`, остальные поля (desc, type, required и т.д.) не изменились.
|
||
3. `updated_at` обновлен.
|
||
|
||
#### 14.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request или 422 Unprocessable Entity)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса без поля `id`.
|
||
```json
|
||
{
|
||
"title": "Запрос без ID"
|
||
}
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity (в зависимости от того, как сервер обрабатывает отсутствие `id` до валидации остальных полей).
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие или невалидность поля `id` (для 422, тело ответа может содержать `message` с деталями).
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`**
|
||
- Входные данные: `id` передано как строка.
|
||
```json
|
||
{
|
||
"id": "not_an_integer",
|
||
"title": "Невалидный ID"
|
||
}
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для `id`.
|
||
|
||
**Сценарий 3.3: Попытка обновления несуществующего вопроса**
|
||
- Входные данные: `id` = 99999 (несуществующий).
|
||
```json
|
||
{
|
||
"id": 99999,
|
||
"title": "Несуществующий вопрос"
|
||
}
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity (так как 404 не заявлен, возможно, ошибка валидации ID).
|
||
- Проверка: Сообщение об ошибке указывает, что вопрос с таким `id` не найден или `id` невалиден.
|
||
|
||
**Сценарий 3.4: Некорректные значения для обновляемых полей**
|
||
- Входные данные (примеры, тестировать каждое поле отдельно):
|
||
- `title` длиннее 512 символов.
|
||
- `type` не из списка допустимых enum значений.
|
||
- `required` не boolean (например, строка "true").
|
||
- `content` не является валидной JSON-строкой.
|
||
- `page` не integer (например, строка "2").
|
||
- `desc` имеет недопустимый формат (если есть ограничения).
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на конкретное поле и характер ошибки валидации.
|
||
|
||
#### 14.3.4 Проверка авторизации
|
||
**Сценарий 4.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 4.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 4.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 14.3.5 Проверка специфических кодов ответа
|
||
**Сценарий 5.1: Условия для 406 Not Acceptable**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusNotAcceptableError`. Например, попытка изменить вопрос, который заблокирован для редактирования).
|
||
- Ожидаемый результат: 406 Not Acceptable.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusNotAcceptableError`.
|
||
|
||
**Сценарий 5.2: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой внешней системы, от которой зависит обновление вопроса).
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 14.3.6 Проверка безопасности (SQL-инъекции, XSS)
|
||
**Сценарий 6.1: SQL-инъекции в строковых полях**
|
||
- Входные данные: В полях `title`, `desc`, `content` передаются SQL-инъекции.
|
||
- Ожидаемый результат: 400/422, либо запрос обработан без выполнения инъекции, данные корректно сохранены/обновлены (экранированы).
|
||
- Проверка: Отсутствие уязвимости.
|
||
|
||
**Сценарий 6.2: XSS-атаки в строковых полях**
|
||
- Входные данные: В полях `title`, `desc`, `content` передаются XSS-скрипты.
|
||
- Ожидаемый результат: 400/422, либо данные корректно сохранены/обновлены (экранированы), XSS не выполняется при отображении этих данных.
|
||
- Проверка: Отсутствие уязвимости.
|
||
|
||
#### 14.3.7 Обработка ошибок (Общие)
|
||
**Сценарий 7.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация сбоя на сервере при обновлении (например, ошибка БД).
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 14.4 Особые моменты для тестирования
|
||
1. **Частичное обновление**: Убедиться, что при обновлении только некоторых полей остальные поля вопроса не затрагиваются и сохраняют свои предыдущие значения.
|
||
2. **Валидация `id`**: Тщательная проверка того, что `id` существует и принадлежит текущему пользователю/аккаунту (если есть такая логика авторизации на уровне записи).
|
||
3. **Валидация полей `UpdateQuestionRequest`**:
|
||
* Проверка всех полей на соответствие типам и форматам (`id` uint64, `title` string<=512, `desc` string, `type` enum, `required` boolean, `content` JSON string, `page` integer).
|
||
* Корректная обработка пустых значений для опциональных полей (например, если передать `title: ""` или `desc: null` - как это должно обрабатываться).
|
||
4. **Конкурентное обновление**: Попытка одновременного обновления одного и того же вопроса разными запросами. Проверить на наличие race conditions, корректность блокировок (если используются), и итоговое состояние данных.
|
||
5. **Поле `updated_at`**: Проверить, что это поле автоматически обновляется при любом успешном изменении вопроса.
|
||
6. **Влияние на связанные сущности**: Если изменение вопроса (например, типа или содержимого) может влиять на квизы, в которых он используется, или на ответы пользователей, это необходимо проверить (может выходить за рамки юнит-теста этого эндпоинта).
|
||
|
||
### 14.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 14.3 пройдены успешно.
|
||
2. Вопрос корректно обновляется в базе данных, затрагиваются только переданные поля.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 406, 422, 424, 500) соответствует спецификации API.
|
||
4. Обеспечена защита от основных уязвимостей безопасности.
|
||
5. Поле `updated_at` вопроса обновляется корректно.
|
||
6. Логирование операций по обновлению вопросов информативно.
|
||
|
||
## 15. POST /question/copy
|
||
|
||
### 15.1 Описание
|
||
Создание копии существующего вопроса и привязка этой копии к указанному квизу. Оригинальный вопрос остается без изменений.
|
||
|
||
### 15.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/CopyQuestionRequest` и содержать обязательные поля: `id` (ID оригинального вопроса) и `quiz_id` (ID целевого квиза для копии).
|
||
- В случае успеха (200 OK) возвращает полный объект нового, скопированного вопроса согласно схеме `#/components/schemas/Question`.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 15.3 Тестовые сценарии
|
||
|
||
#### 15.3.1 Успешное копирование вопроса
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Существует вопрос с `id`, указанным в запросе (оригинальный вопрос).
|
||
- Существует квиз с `quiz_id`, указанным в запросе (целевой квиз).
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /question/copy
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/CopyQuestionRequest`):
|
||
```json
|
||
{
|
||
"id": 101, // integer, uint64 - ID существующего вопроса для копирования
|
||
"quiz_id": 202 // integer, uint64 - ID квиза, в который будет помещена копия
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (новый скопированный вопрос, согласно `#/components/schemas/Question`. Пример):
|
||
```json
|
||
{
|
||
"id": 303, // integer, uint64 - НОВЫЙ ID для скопированного вопроса
|
||
"quiz_id": 202, // integer, uint64 - ID целевого квиза из запроса
|
||
"title": "Копия: Какой основной компонент воздуха?", // string - title оригинального вопроса (может быть с префиксом)
|
||
"description": "Выберите один правильный ответ из предложенных.", // string - description оригинального вопроса
|
||
"type": "variant", // string, enum - type оригинального вопроса
|
||
"required": true, // boolean - required оригинального вопроса
|
||
"deleted": false, // boolean - всегда false для новой копии
|
||
"page": 1, // integer - page оригинального вопроса (или сброшено/пересчитано для нового квиза)
|
||
"content": "{}", // string - content оригинального вопроса
|
||
"version": 1, // integer - version оригинального вопроса (или сброшено до 1)
|
||
"parent_ids": [], // array of integers - parent_ids оригинального вопроса (или очищено)
|
||
"created_at": "2023-03-16T12:00:00Z", // string, date-time - НОВАЯ дата создания
|
||
"updated_at": "2023-03-16T12:00:00Z" // string, date-time - НОВАЯ дата обновления (равна created_at)
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. В базе данных создан новый вопрос.
|
||
2. Возвращенный объект вопроса имеет новый, уникальный `id` (не равен `id` оригинала).
|
||
3. `quiz_id` в возвращенном объекте соответствует `quiz_id`, указанному в запросе.
|
||
4. Поля `title`, `description`, `type`, `required`, `content`, `page`, `version` (и возможно `parent_ids`) скопированы из оригинального вопроса (с возможными модификациями, например, префикс к `title` или сброс `version`/`page`/`parent_ids` – уточнить ожидаемое поведение).
|
||
5. Поле `deleted` у новой копии установлено в `false`.
|
||
6. Поля `created_at` и `updated_at` у новой копии являются свежими временными метками.
|
||
7. Оригинальный вопрос (с `id` из запроса) остался без изменений в базе данных.
|
||
|
||
#### 15.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 15.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательных полей**
|
||
- Входные данные: Тело запроса без `id` или без `quiz_id`.
|
||
```json
|
||
// Пример без id
|
||
{ "quiz_id": 202 }
|
||
// Пример без quiz_id
|
||
{ "id": 101 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствующее обязательное поле.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id` или `quiz_id`**
|
||
- Входные данные: `id` или `quiz_id` переданы как строка или другой невалидный тип.
|
||
```json
|
||
{ "id": "not_an_integer", "quiz_id": 202 }
|
||
{ "id": 101, "quiz_id": "not_an_integer" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для соответствующего поля.
|
||
|
||
**Сценарий 3.3: Копирование несуществующего вопроса**
|
||
- Входные данные: `id` = 99999 (несуществующий оригинальный вопрос).
|
||
```json
|
||
{ "id": 99999, "quiz_id": 202 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request (или 404, если бы он был заявлен; в данном случае OpenAPI указывает 400).
|
||
- Проверка: Сообщение об ошибке указывает, что оригинальный вопрос с таким `id` не найден.
|
||
|
||
**Сценарий 3.4: Копирование в несуществующий квиз**
|
||
- Входные данные: `quiz_id` = 88888 (несуществующий целевой квиз).
|
||
```json
|
||
{ "id": 101, "quiz_id": 88888 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request (или 404, если бы он был заявлен).
|
||
- Проверка: Сообщение об ошибке указывает, что целевой квиз с таким `quiz_id` не найден.
|
||
|
||
#### 15.3.4 Проверка специфических кодов ответа
|
||
**Сценарий 4.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой при записи в базу данных из-за внешних проблем, не связанных с валидацией входных данных).
|
||
- Входные данные: Корректный запрос на копирование.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 15.3.5 Обработка ошибок (Общие)
|
||
**Сценарий 5.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере в процессе копирования.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 15.4 Особые моменты для тестирования
|
||
1. **Генерация нового ID**: Убедиться, что у скопированного вопроса всегда генерируется новый, уникальный `id`.
|
||
2. **Копирование данных**: Детально проверить, какие именно поля копируются из оригинала, а какие устанавливаются по умолчанию или пересчитываются для новой копии (например, `title`, `description`, `type`, `required`, `content`, `page`, `version`, `parent_ids`). Уточнить политику копирования этих полей.
|
||
3. **Поле `deleted`**: Убедиться, что у новой копии поле `deleted` всегда `false`.
|
||
4. **Временные метки**: `created_at` и `updated_at` для копии должны быть новыми.
|
||
5. **Иммутабельность оригинала**: Оригинальный вопрос не должен быть затронут операцией копирования.
|
||
6. **Копирование в тот же квиз**: Проверить поведение, если `quiz_id` в запросе совпадает с `quiz_id` оригинального вопроса. Должна ли создаваться копия в том же квизе? Будут ли конфликты имен (если есть уникальность `title` в рамках квиза)?
|
||
7. **Права доступа**: Если есть ограничения на доступ к оригинальному вопросу или к целевому квизу, проверить их соблюдение.
|
||
|
||
### 15.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 15.3 пройдены успешно.
|
||
2. Новый вопрос корректно создается в базе данных как копия оригинала, со всеми необходимыми изменениями (новый ID, целевой `quiz_id`, свежие timestamp'ы).
|
||
3. Оригинальный вопрос остается неизменным.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
5. Логирование операций по копированию вопросов информативно.
|
||
|
||
## 16. POST /question/history
|
||
|
||
### 16.1 Описание
|
||
Получение истории изменений для указанного вопроса. Каждая запись в истории представляет собой состояние (версию) вопроса на определенный момент времени.
|
||
|
||
### 16.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/GetQuestionHistoryRequest` и содержать обязательное поле `id` вопроса, а также опциональные поля для пагинации `l` (limit) и `p` (page).
|
||
- В случае успеха (200 OK) возвращает объект, содержащий поле `items`. Поле `items` является массивом, где каждый элемент - это объект `Question`, представляющий одну версию из истории вопроса.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 16.3 Тестовые сценарии
|
||
|
||
#### 16.3.1 Успешное получение истории вопроса (с пагинацией)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Вопрос с указанным `id` существует и имеет несколько записей в истории (несколько версий).
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /question/history
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/GetQuestionHistoryRequest`):
|
||
```json
|
||
{
|
||
"id": 101, // integer, uint64 - ID вопроса
|
||
"l": 10, // integer, uint64 - Limit (количество записей на странице)
|
||
"p": 1 // integer, uint64 - Page (номер страницы, например, 1-based)
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (объект с полем `items`, содержащим массив версий вопроса):
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"id": 101, // integer, uint64 - ID оригинального вопроса
|
||
"quiz_id": 123,
|
||
"title": "Обновленный заголовок вопроса (Версия 2)",
|
||
"description": "Новое описание для вопроса (Версия 2).",
|
||
"type": "text",
|
||
"required": false,
|
||
"deleted": false, // или true, если версия была удалена, а потом восстановлена
|
||
"page": 2,
|
||
"content": "{\"placeholder\":\"Версия 2\"}",
|
||
"version": 2, // integer - номер версии
|
||
"parent_ids": [],
|
||
"created_at": "2023-03-15T11:30:00Z", // Время создания/фиксации этой версии
|
||
"updated_at": "2023-03-15T11:30:00Z" // Обычно совпадает с created_at для записи истории
|
||
},
|
||
{
|
||
"id": 101, // ID оригинального вопроса
|
||
"quiz_id": 123,
|
||
"title": "Исходный заголовок вопроса (Версия 1)",
|
||
"description": "Начальное описание (Версия 1).",
|
||
"type": "variant",
|
||
"required": true,
|
||
"deleted": false,
|
||
"page": 1,
|
||
"content": "{\"options\":[...]}",
|
||
"version": 1,
|
||
"parent_ids": [],
|
||
"created_at": "2023-03-15T10:00:00Z",
|
||
"updated_at": "2023-03-15T10:00:00Z"
|
||
}
|
||
// ... другие версии, если l > 2 ...
|
||
]
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Массив `items` в ответе содержит записи истории для вопроса с запрошенным `id`.
|
||
2. Количество элементов в массиве `items` не превышает значение `l` (limit) из запроса.
|
||
3. Если `p` (page) и `l` (limit) используются, пагинация работает корректно, возвращая соответствующий срез истории.
|
||
4. Каждая запись в массиве `items` является полным объектом `Question`, представляющим состояние вопроса на момент этой версии.
|
||
5. Поле `version` в каждой записи истории корректно отражает номер версии.
|
||
6. Записи истории отсортированы в ожидаемом порядке (например, по убыванию `version` или `created_at`/`updated_at` этой записи истории).
|
||
7. Если у вопроса нет истории (например, он только что создан и не изменялся), массив `items` содержит одну запись, представляющую текущее состояние вопроса с `version: 1`.
|
||
8. Если запрос сделан с `l=0` или без `l` и `p`, проверить поведение по умолчанию (например, возврат всех версий или первой страницы с лимитом по умолчанию).
|
||
|
||
#### 16.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 16.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса без поля `id`.
|
||
```json
|
||
{ "l": 10, "p": 1 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательного поля `id`.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`, `l`, или `p`**
|
||
- Входные данные (примеры):
|
||
- `id` как строка: `{ "id": "not_an_integer", "l": 10, "p": 1 }`
|
||
- `l` как строка: `{ "id": 101, "l": "ten", "p": 1 }`
|
||
- `p` как строка: `{ "id": 101, "l": 10, "p": "one" }`
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для соответствующего поля.
|
||
|
||
**Сценарий 3.3: Некорректные значения для `l` или `p` (если есть ограничения)**
|
||
- Входные данные (примеры):
|
||
- `l` отрицательное: `{ "id": 101, "l": -5, "p": 1 }`
|
||
- `p` отрицательное или нулевое (если нумерация с 1): `{ "id": 101, "l": 10, "p": 0 }`
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на недопустимое значение для `l` или `p`.
|
||
|
||
**Сценарий 3.4: Запрос истории для несуществующего вопроса**
|
||
- Входные данные: `id` = 99999 (несуществующий вопрос).
|
||
```json
|
||
{ "id": 99999, "l": 10, "p": 1 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request (или возможно пустой массив `items` в ответе 200 OK, если это допустимое поведение для несуществующего ID – уточнить).
|
||
- Проверка: Если 400, сообщение об ошибке указывает, что вопрос не найден. Если 200 OK, `items` должен быть пустым.
|
||
|
||
#### 16.3.4 Проверка специфических кодов ответа
|
||
**Сценарий 4.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой при чтении из базы данных истории).
|
||
- Входные данные: Корректный запрос на получение истории.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 16.3.5 Обработка ошибок (Общие)
|
||
**Сценарий 5.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 16.4 Особые моменты для тестирования
|
||
1. **Порядок версий**: Убедиться, что версии в истории отсортированы последовательно и предсказуемо (например, по убыванию номера `version` или по убыванию `created_at` записи истории).
|
||
2. **Полнота данных в версиях**: Каждая версия вопроса в `items` должна содержать все поля из схемы `Question` и отражать состояние вопроса на момент создания этой версии.
|
||
3. **Пагинация (`l` и `p`)**: Тщательно проверить работу пагинации: корректность количества возвращаемых элементов, переход по страницам, поведение на первой и последней странице, поведение при запросе страницы за пределами существующей истории.
|
||
4. **История для нового/неизмененного вопроса**: Если вопрос только создан и не редактировался, эндпоинт должен вернуть массив `items` с одной записью (текущее состояние, `version: 1`).
|
||
5. **Глубина/ограничения истории**: Если система накладывает ограничения на количество хранимых версий или глубину истории, это необходимо проверить.
|
||
6. **Согласованность данных**: Поля `id` и `quiz_id` в объектах истории должны соответствовать оригинальному вопросу. Поле `version` должно быть уникальным для каждой записи истории одного вопроса и увеличиваться (или изменяться предсказуемо).
|
||
|
||
### 16.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 16.3 пройдены успешно.
|
||
2. История вопроса возвращается корректно, со всеми версиями и точными данными для каждой версии.
|
||
3. Параметры пагинации `l` и `p` работают правильно.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
5. Данные в ответе структурированы правильно (объект с полем `items`, которое является массивом объектов `Question`).
|
||
6. Логирование запросов к истории вопросов информативно.
|
||
|
||
## 17. DELETE /question/delete
|
||
|
||
### 17.1 Описание
|
||
Удаление (или деактивация) существующего вопроса по его ID. В зависимости от реализации, это может быть физическое удаление или "мягкое" удаление (пометка вопроса как удаленного).
|
||
|
||
### 17.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: DELETE.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/DeactivateQuestionRequest` и содержать обязательное поле `id` удаляемого вопроса.
|
||
- В случае успеха (200 OK) возвращает объект согласно схеме `#/components/schemas/DeactivateQuestionResponse`, содержащий `deactivated` (ID удаленного/деактивированного вопроса).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 17.3 Тестовые сценарии
|
||
|
||
#### 17.3.1 Успешное удаление (деактивация) вопроса
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Вопрос с указанным `id` существует в системе и не помечен как удаленный.
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /question/delete
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/DeactivateQuestionRequest`):
|
||
```json
|
||
{
|
||
"id": 101 // integer, uint64 - ID существующего вопроса
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (согласно `#/components/schemas/DeactivateQuestionResponse`):
|
||
```json
|
||
{
|
||
"deactivated": 101 // integer, uint64 - ID деактивированного вопроса
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Поле `deactivated` в ответе содержит `id` удаленного/деактивированного вопроса.
|
||
2. Вопрос в базе данных помечен как удаленный (например, поле `deleted` у объекта Question установлено в `true`, обновлено поле `updated_at`).
|
||
3. При попытке получить этот вопрос через GET-запросы (например, `/question/get/{id}` или в списках `/question/getList` без специального флага для удаленных) он либо не возвращается, либо возвращается с отметкой об удалении.
|
||
4. Повторный запрос на удаление этого же вопроса обрабатывается корректно (см. сценарий идемпотентности).
|
||
|
||
#### 17.3.2 Проверка идемпотентности удаления
|
||
**Предусловия:**
|
||
- Пользователь авторизован, JWT токен валиден.
|
||
- Вопрос с `id` = 101 уже был удален/деактивирован.
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /question/delete
|
||
- Headers: Authorization: Bearer {valid_jwt_token}, Content-Type: application/json
|
||
- Тело запроса: `{"id": 101}`
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK (или другой код, если система явно сообщает о том, что ресурс уже удален, но 200 OK для идемпотентности предпочтителен).
|
||
- Тело ответа: `{"deactivated": 101}`.
|
||
|
||
**Проверки:**
|
||
1. Операция не вызывает ошибок.
|
||
2. Состояние вопроса в базе данных не изменяется (он остается удаленным).
|
||
|
||
#### 17.3.3 Проверка авторизации
|
||
**Сценарий 3.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 3.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 3.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 17.3.4 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 4.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса - пустой JSON `{}`.
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательного поля `id`.
|
||
|
||
**Сценарий 4.2: Некорректный тип данных для `id`**
|
||
- Входные данные: `id` передано как строка.
|
||
```json
|
||
{ "id": "not_an_integer" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для `id`.
|
||
|
||
**Сценарий 4.3: Попытка удаления несуществующего вопроса**
|
||
- Входные данные: `id` = 99999 (несуществующий).
|
||
```json
|
||
{ "id": 99999 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request (или 404, если бы он был заявлен; OpenAPI указывает 400 для этого эндпоинта, что может означать ошибку валидации ID или что ресурс не найден, но обрабатывается как Bad Request).
|
||
- Проверка: Сообщение об ошибке указывает, что вопрос с таким `id` не найден или `id` невалиден.
|
||
|
||
#### 17.3.5 Проверка специфических кодов ответа
|
||
**Сценарий 5.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой при обновлении статуса вопроса в базе данных из-за внешних проблем).
|
||
- Входные данные: Корректный запрос на удаление.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 17.3.6 Обработка ошибок (Общие)
|
||
**Сценарий 6.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере в процессе удаления/деактивации.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 17.4 Особые моменты для тестирования
|
||
1. **Механизм удаления**: Подтвердить, используется ли "мягкое" удаление (установка флага `deleted: true` и обновление `updated_at` у объекта `Question`) или физическое удаление из базы данных. Схемы `DeactivateQuestionRequest` и `DeactivateQuestionResponse` сильно намекают на мягкое удаление.
|
||
2. **Идемпотентность**: Повторное удаление уже удаленного вопроса не должно приводить к ошибке и не должно изменять состояние системы.
|
||
3. **Влияние на связанные сущности**: Проверить, как удаление/деактивация вопроса влияет на квизы, в которых он используется (например, удаляется ли он из квизов, или квизы перестают его отображать). Как это влияет на уже существующие ответы пользователей на этот вопрос?
|
||
4. **Права доступа**: Если существуют специфические права на удаление вопросов (например, только автор вопроса или администратор), их необходимо проверить.
|
||
5. **Восстановление вопроса**: Если используется "мягкое" удаление, проверить, существует ли механизм восстановления вопроса и как он работает (это может быть другой эндпоинт).
|
||
|
||
### 17.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 17.3 пройдены успешно.
|
||
2. Вопрос корректно помечается как удаленный в базе данных (или удаляется физически, в зависимости от реализации).
|
||
3. Операция идемпотентна.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
5. Логирование операций по удалению/деактивации вопросов информативно.
|
||
|
||
## 18. POST /quiz/create
|
||
|
||
### 18.1 Описание
|
||
Создание нового квиза в системе. Эндпоинт позволяет определить различные параметры квиза, включая его название, описание, настройки поведения и статус.
|
||
|
||
### 18.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Создает новый квиз в системе.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/CreateQuizRequest`.
|
||
- В случае успеха возвращает созданный квиз согласно схеме `#/components/schemas/Quiz` со статусом 201 Created.
|
||
- Поддерживает HTTP коды ответа: 201 (Created), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable), 409 (Conflict), 422 (Unprocessable Entity), 500 (Internal Server Error).
|
||
|
||
### 18.3 Тестовые сценарии
|
||
|
||
#### 18.3.1 Успешное создание квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Данные для создания квиза корректны и полны.
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /quiz/create
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно схеме `#/components/schemas/CreateQuizRequest`. Пример минимального набора):
|
||
```json
|
||
{
|
||
"name": "Новый квиз по истории",
|
||
"description": "Тест на знание ключевых дат.",
|
||
"status": "draft",
|
||
"config": "{\"rules\":[]}"
|
||
}
|
||
```
|
||
- Пример запроса со всеми опциональными полями:
|
||
```json
|
||
{
|
||
"name": "Полный квиз по географии",
|
||
"description": "Детальный тест на знание столиц и стран.",
|
||
"fingerprinting": true,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"config": "{\"showCorrectAnswers\": true}",
|
||
"status": "start",
|
||
"limit": 100,
|
||
"due_to": 1700000000,
|
||
"question_cnt": 10,
|
||
"time_of_passing": 3600,
|
||
"pausable": true,
|
||
"super": false,
|
||
"group_id": null
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 201 Created
|
||
- Content-Type: application/json
|
||
- Тело ответа содержит объект созданного квиза (согласно схеме `#/components/schemas/Quiz`):
|
||
```json
|
||
{
|
||
"id": 123, // integer, uint64 - Новый ID квиза
|
||
"qid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", // string - UUID
|
||
"accountid": "user_account_id", // string - ID аккаунта создателя
|
||
"deleted": false,
|
||
"archived": false,
|
||
"fingerprinting": true, // или false, в зависимости от запроса
|
||
"repeatable": true, // или false
|
||
"note_prevented": false, // или true
|
||
"mail_notifications": true, // или false
|
||
"unique_answers": false, // или true
|
||
"name": "Полный квиз по географии",
|
||
"description": "Детальный тест на знание столиц и стран.",
|
||
"config": "{\"showCorrectAnswers\": true}",
|
||
"status": "start", // или другой статус из запроса
|
||
"limit": 100,
|
||
"due_to": 1700000000,
|
||
"time_of_passing": 3600,
|
||
"pausable": true,
|
||
"version": 1,
|
||
"version_comment": null, // или начальный комментарий
|
||
"parent_ids": [],
|
||
"created_at": "YYYY-MM-DDTHH:mm:ssZ", // Текущая дата и время
|
||
"updated_at": "YYYY-MM-DDTHH:mm:ssZ", // Текущая дата и время
|
||
"questions_count": 0, // Изначально 0, если question_cnt не создает их сразу
|
||
"session_count": 0,
|
||
"passed_count": 0,
|
||
"average_time": 0,
|
||
"super": false,
|
||
"group_id": null
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Квиз успешно создан в базе данных с переданными атрибутами.
|
||
2. Ответ содержит все обязательные поля согласно схеме `Quiz`.
|
||
3. `id` созданного квиза уникален.
|
||
4. Поля, для которых в `CreateQuizRequest` есть значения по умолчанию (`fingerprinting`, `repeatable`, `note_prevented`, `status`, `pausable`, `super`), установлены в эти значения по умолчанию, если они не были переданы в запросе.
|
||
5. Сервер-генерируемые поля (`qid`, `accountid`, `version`, `created_at`, `updated_at`, счетчики) корректно заполнены.
|
||
6. Поле `status` в ответе соответствует запрошенному или значению по умолчанию (`draft`).
|
||
|
||
#### 18.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации (согласно `#/components/responses/UnauthorizedError`).
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 18.3.3 Проверка валидации данных (Ответ 400 Bad Request или 422 Unprocessable Entity)
|
||
**Сценарий 3.1: Отсутствие обязательных полей в `CreateQuizRequest`**
|
||
- Входные данные: Тело запроса без обязательного поля `name`.
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствующее поле `name` (для 422, тело ответа должно содержать `message` с деталями).
|
||
|
||
**Сценарий 3.2: Некорректный формат данных в полях `CreateQuizRequest`**
|
||
- Входные данные (примеры):
|
||
- `name` длиннее 700 символов.
|
||
- `fingerprinting` не boolean (например, строка "true").
|
||
- `status` не из списка enum (`draft`, `template`, `stop`, `start`).
|
||
- `limit` не integer или отрицательное.
|
||
- `due_to` не integer (timestamp).
|
||
- `config` - невалидный JSON в строке.
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на поля с некорректным форматом или значением.
|
||
|
||
#### 18.3.4 Проверка ответа 406 Not Acceptable
|
||
**Сценарий 4.1: Условия, приводящие к 406 Not Acceptable**
|
||
- Предусловия: (Необходимо определить конкретные условия на основе спецификации `StatusNotAcceptableError`. Например, попытка создать квиз с параметрами, которые несовместимы с текущими настройками аккаунта или системы).
|
||
- Входные данные: Корректный запрос на создание квиза, но выполнены условия для ответа 406.
|
||
- Ожидаемый результат: 406 Not Acceptable.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusNotAcceptableError` и содержит информативное сообщение.
|
||
|
||
#### 18.3.5 Проверка ответа 409 Conflict
|
||
**Сценарий 5.1: Создание квиза с уже существующим уникальным идентификатором (если применимо)**
|
||
- Предусловия: (Необходимо определить, какие поля, кроме `id`, должны быть уникальными. Например, если `name` должно быть уникальным в рамках аккаунта). Попытка создать квиз с `name`, который уже существует у другого квиза этого же пользователя.
|
||
- Входные данные: Запрос на создание квиза с `name`, которое уже занято.
|
||
- Ожидаемый результат: 409 Conflict.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusConflictError` и содержит информативное сообщение.
|
||
|
||
#### 18.3.6 Проверка безопасности
|
||
**Сценарий 6.1: SQL-инъекции**
|
||
- Входные данные: В строковых полях запроса (`name`, `description`, `config`) передаются SQL-инъекции.
|
||
- Ожидаемый результат: 400/422, либо запрос обработан без выполнения инъекции, данные сохранены корректно (экранированы).
|
||
- Проверка: Отсутствие уязвимости к SQL-инъекциям.
|
||
|
||
**Сценарий 6.2: XSS-атаки**
|
||
- Входные данные: В строковых полях запроса (`name`, `description`, `config`) передаются XSS-скрипты.
|
||
- Ожидаемый результат: 400/422, либо данные сохранены корректно (экранированы), и XSS не выполняется при отображении этих данных.
|
||
- Проверка: Отсутствие уязвимости к XSS.
|
||
|
||
#### 18.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время создания квиза**
|
||
- Проверка: Время ответа на запрос создания квиза < N ms (например, < 500ms).
|
||
- Проверка: Стабильность времени ответа при многократных запросах.
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: Система способна обработать X запросов на создание квизов в секунду/минуту без значительного ухудшения производительности или ошибок.
|
||
|
||
#### 18.3.8 Обработка ошибок (Общие)
|
||
**Сценарий 8.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация непредвиденного сбоя на сервере при обработке запроса.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/InternalServerError`.
|
||
|
||
### 18.4 Особые моменты для тестирования
|
||
1. **Валидация схемы `CreateQuizRequest`:**
|
||
* Тщательная проверка всех обязательных (`name`) и опциональных полей.
|
||
* Проверка типов данных и ограничений (например, `name` maxLength: 700, `status` enum).
|
||
* Проверка обработки значений по умолчанию для опциональных полей.
|
||
* Валидация JSON-структуры внутри строки `config`.
|
||
2. **Логика статусов квиза (`status`):**
|
||
* Корректное создание квиза с каждым из допустимых статусов (`draft`, `template`, `stop`, `start`).
|
||
* Проверка статуса по умолчанию (`draft`), если не передан.
|
||
3. **Влияние `question_cnt`:** Если `question_cnt` предназначен для автоматического создания пустого набора вопросов, проверить, что это происходит. Если это просто метаданные, проверить, что поле сохраняется. (В схеме `Quiz` есть поле `questions_count`, которое может быть связано).
|
||
4. **Настройки квиза:** Проверить, как различные булевы флаги (`fingerprinting`, `repeatable`, `note_prevented`, `mail_notifications`, `unique_answers`, `pausable`, `super`) влияют на созданный квиз и его последующее поведение (может требовать интеграционных тестов).
|
||
5. **Связь с `group_id`:** Если `super: true`, то `group_id` может быть `null`. Если `super: false` и квиз является частью группы, `group_id` должен указывать на существующий "супер-квиз". Проверить логику валидации этих полей.
|
||
|
||
### 18.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 18.3 пройдены успешно.
|
||
2. Время ответа на создание квиза соответствует установленным требованиям производительности.
|
||
3. Обработка всех кодов ошибок (201, 400, 401, 406, 409, 422, 500) соответствует спецификации API и предоставляет корректные сообщения.
|
||
4. Обеспечена защита от основных уязвимостей безопасности (SQL-инъекции, XSS).
|
||
5. Созданный квиз корректно сохраняется в базе данных со всеми указанными атрибутами и доступен для последующего использования.
|
||
6. Логирование операций по созданию квизов информативно и покрывает как успешные случаи, так и ошибки.
|
||
7. Значения по умолчанию для полей `CreateQuizRequest` применяются корректно.
|
||
|
||
## 19. POST /quiz/getList
|
||
|
||
### 19.1 Описание
|
||
Получение списка квизов с поддержкой пагинации и расширенной фильтрацией. Эндпоинт предназначен для отображения квизов в различных представлениях, учитывая их статус, временные рамки, принадлежность к группам и другие атрибуты.
|
||
|
||
### 19.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/GetQuizListRequest`.
|
||
- В случае успеха возвращает список квизов и метаданные пагинации согласно схеме `#/components/schemas/GetQuizListResponse` (статус 200 OK).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable), 500 (Internal Server Error).
|
||
|
||
### 19.3 Тестовые сценарии
|
||
|
||
#### 19.3.1 Успешное получение списка квизов (с пагинацией и фильтрами)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- В системе существуют квизы, соответствующие критериям запроса.
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /quiz/getList
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (пример, все поля опциональны, используя значения по умолчанию, если не указаны `limit: 10`, `page: 1`):
|
||
```json
|
||
{
|
||
"limit": 5,
|
||
"page": 1,
|
||
"from": 1672531200, // Пример timestamp (1 Jan 2023)
|
||
"to": 1675209600, // Пример timestamp (1 Feb 2023)
|
||
"search": "география",
|
||
"status": "start",
|
||
"deleted": false,
|
||
"archived": false,
|
||
"super": false,
|
||
"group_id": null
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (согласно `#/components/schemas/GetQuizListResponse` и `#/components/schemas/Quiz`):
|
||
```json
|
||
{
|
||
"count": 20, // integer, uint64 - Общее количество квизов, соответствующих фильтрам
|
||
"items": [
|
||
{
|
||
"id": 101,
|
||
"qid": "uuid-quiz-101",
|
||
"accountid": "user-account-id",
|
||
"deleted": false,
|
||
"archived": false,
|
||
"fingerprinting": true,
|
||
"repeatable": true,
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"name": "Квиз по географии Европы",
|
||
"description": "Проверьте свои знания о странах Европы.",
|
||
"config": "{\"rules\":{}}",
|
||
"status": "start",
|
||
"limit": 50,
|
||
"due_to": 1675000000,
|
||
"time_of_passing": 1800,
|
||
"pausable": true,
|
||
"version": 2,
|
||
"version_comment": "Обновлены вопросы",
|
||
"parent_ids": [],
|
||
"created_at": "2023-01-15T10:00:00Z",
|
||
"updated_at": "2023-01-20T11:30:00Z",
|
||
"questions_count": 15,
|
||
"session_count": 150,
|
||
"passed_count": 120,
|
||
"average_time": 1200,
|
||
"super": false,
|
||
"group_id": null
|
||
}
|
||
// ... другие квизы, если count > 1 и limit позволяет
|
||
]
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Ответ содержит корректное поле `count`, отражающее общее количество квизов по заданным фильтрам.
|
||
2. Количество квизов в массиве `items` не превышает запрошенный `limit` (или значение по умолчанию 10).
|
||
3. Пагинация работает корректно: при изменении `page` возвращаются соответствующие срезы данных.
|
||
4. Каждый объект квиза в массиве `items` соответствует схеме `Quiz` и содержит все ожидаемые поля с корректными типами данных.
|
||
5. Если применялись фильтры (`from`/`to`, `search`, `status`, `deleted`, `archived`, `super`, `group_id`), то все возвращенные квизы соответствуют этим фильтрам.
|
||
6. Поля `limit` и `page` по умолчанию равны 10 и 1 соответственно, если не указаны в запросе.
|
||
|
||
#### 19.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа содержит сообщение об ошибке авторизации (согласно `#/components/responses/UnauthorizedError`).
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 19.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
(Большинство полей в `GetQuizListRequest` опциональны. Проверки касаются корректности форматов и значений, если поля предоставлены.)
|
||
|
||
**Сценарий 3.1: Некорректные параметры пагинации**
|
||
- Входные данные: `page` или `limit` не являются integer (uint64), или имеют некорректный формат/значение (например, `limit: 0`, `page: 0`, если `minimum: 1`).
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на невалидные параметры пагинации.
|
||
|
||
**Сценарий 3.2: Некорректный формат фильтров**
|
||
- Входные данные (примеры):
|
||
- `from` или `to` не являются integer (int64).
|
||
- `status` не из списка допустимых enum значений (`stop`, `start`, `draft`, `template`, `timeout`, `offlimit`).
|
||
- `deleted`, `archived`, `super` не являются boolean.
|
||
- `group_id` не integer (uint64).
|
||
- `from` > `to` (некорректный временной диапазон).
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на невалидные параметры фильтрации.
|
||
|
||
#### 19.3.4 Проверка ответа 406 Not Acceptable
|
||
**Сценарий 4.1: Условия, приводящие к 406 Not Acceptable**
|
||
- Предусловия: (Необходимо определить конкретные условия на основе спецификации `StatusNotAcceptableError`. Например, запрос на получение данных в формате, который сервер не может предоставить, или комбинация фильтров, которая является недопустимой по бизнес-логике).
|
||
- Входные данные: Корректный запрос на получение списка, но выполнены условия для ответа 406.
|
||
- Ожидаемый результат: 406 Not Acceptable.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/StatusNotAcceptableError`.
|
||
|
||
#### 19.3.5 Проверка производительности
|
||
**Сценарий 5.1: Время ответа на получение списка**
|
||
- Проверка: Время ответа < N ms (например, < 1000ms) при запросе стандартной страницы с `limit=10` и без сложных фильтров.
|
||
- Проверка: Время ответа при запросе с большим количеством фильтров и на разные страницы, особенно при большом общем количестве квизов.
|
||
|
||
**Сценарий 5.2: Нагрузочное тестирование**
|
||
- Проверка: Система способна обработать X запросов на получение списка квизов в секунду/минуту без значительного ухудшения производительности или ошибок.
|
||
|
||
#### 19.3.6 Обработка ошибок (Общие)
|
||
**Сценарий 6.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация непредвиденного сбоя на сервере (например, ошибка подключения к БД при выборке данных).
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа соответствует схеме `#/components/responses/InternalServerError`.
|
||
|
||
### 19.4 Особые моменты для тестирования
|
||
1. **Логика пагинации (`limit`, `page`):**
|
||
* Корректность `count` при наличии/отсутствии фильтров.
|
||
* Правильность выдачи данных на первой, последней и промежуточных страницах.
|
||
* Поведение при запросе страницы, превышающей общее количество страниц (ожидается `items` - пустой массив, `page` равен запрошенному, `count` корректен).
|
||
* Проверка значений по умолчанию для `limit` (10) и `page` (1).
|
||
* Проверка минимальных значений `limit: 1`, `page: 1`.
|
||
2. **Логика фильтрации (согласно `GetQuizListRequest`):**
|
||
* Корректность работы каждого отдельного фильтра:
|
||
- `from`/`to`: выборка квизов, созданных/измененных в указанном временном диапазоне (проверить по `created_at` или `updated_at` в зависимости от логики).
|
||
- `search`: поиск по релевантным текстовым полям квиза (например, `name`, `description`). Проверить чувствительность к регистру, поиск по части слова.
|
||
- `status`: выборка квизов только с указанным статусом.
|
||
- `deleted`: выборка только удаленных (`true`) или только неудаленных (`false`/отсутствие) квизов.
|
||
- `archived`: выборка только архивированных (`true`) или только неархивированных (`false`/отсутствие) квизов.
|
||
- `super`: выборка "супер-квизов" (`true`) или обычных (`false`/отсутствие).
|
||
- `group_id`: выборка квизов, принадлежащих указанной группе.
|
||
* Корректность работы комбинации нескольких фильтров одновременно.
|
||
* Поведение при передаче несуществующих значений для фильтров (например, `group_id`, которого нет).
|
||
3. **Сортировка (если поддерживается):**
|
||
* Проверка сортировки по умолчанию (например, по дате создания).
|
||
* Если API позволяет задавать параметры сортировки, протестировать их.
|
||
4. **Полнота данных в ответе:**
|
||
* Каждый квиз в списке `items` должен содержать все поля, определенные схемой `Quiz`.
|
||
|
||
### 19.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 19.3 пройдены успешно.
|
||
2. Время ответа на получение списка квизов соответствует требованиям производительности.
|
||
3. Пагинация и все заявленные фильтры работают корректно.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 406, 500) соответствует спецификации API.
|
||
5. Данные в ответе полны, корректны и соответствуют схемам `GetQuizListResponse` и `Quiz`.
|
||
6. Логирование запросов на получение списка квизов информативно.
|
||
|
||
## 20. PATCH /quiz/edit
|
||
|
||
### 20.1 Описание
|
||
Обновление существующего квиза. Позволяет изменять одно или несколько полей квиза по его ID. Используется для модификации настроек, статуса, контента или метаданных квиза.
|
||
|
||
### 20.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: PATCH.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/UpdateQuizRequest` и содержать обязательное поле `id` квиза.
|
||
- В случае успеха (200 OK) возвращает объект согласно схеме `#/components/schemas/UpdateQuizResponse`, содержащий `updated` (ID обновленного квиза).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable), 409 (Conflict), 422 (Unprocessable Entity), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 20.3 Тестовые сценарии
|
||
|
||
#### 20.3.1 Успешное обновление квиза (изменение нескольких полей)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Квиз с указанным `id` существует в системе.
|
||
|
||
**Входные данные:**
|
||
- Метод: PATCH
|
||
- URL: /quiz/edit
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/UpdateQuizRequest`):
|
||
```json
|
||
{
|
||
"id": 101, // integer, uint64 - ID существующего квиза
|
||
"name": "Обновленное название квиза",
|
||
"desc": "Новое детальное описание для квиза.",
|
||
"status": "start",
|
||
"limit": 150,
|
||
"fp": true,
|
||
"rep": false,
|
||
"conf": "{}"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (согласно `#/components/schemas/UpdateQuizResponse`):
|
||
```json
|
||
{
|
||
"updated": 101 // integer, uint64 - ID обновленного квиза
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Поле `updated` в ответе содержит `id` обновленного квиза.
|
||
2. Данные квиза в базе данных (или при последующем GET запросе квиза) обновлены в соответствии с переданными в запросе полями.
|
||
Соответствие полей `UpdateQuizRequest` полям `Quiz`:
|
||
- `fp` -> `fingerprinting`
|
||
- `rep` -> `repeatable`
|
||
- `note_prevented` -> `note_prevented`
|
||
- `mailing` -> `mail_notifications`
|
||
- `uniq` -> `unique_answers`
|
||
- `name` -> `name`
|
||
- `desc` -> `description`
|
||
- `conf` -> `config`
|
||
- `status` -> `status` (enum: [draft, template, stop, start])
|
||
- `limit` -> `limit`
|
||
- `due_to` -> `due_to`
|
||
- `time_of_passing` -> `time_of_passing`
|
||
- `pausable` -> `pausable`
|
||
- `question_cnt` -> `questions_count` (или другая логика, если `question_cnt` изменяет количество вопросов)
|
||
- `super` -> `super`
|
||
- `group_id` -> `group_id`
|
||
3. Поля, которые не были переданы в запросе на обновление, остались без изменений в базе данных.
|
||
4. Поле `updated_at` для квиза в базе данных обновлено.
|
||
|
||
#### 20.3.2 Успешное обновление одного поля квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован, JWT токен валиден.
|
||
- Квиз с `id` = 102 существует.
|
||
|
||
**Входные данные:**
|
||
- Метод: PATCH
|
||
- URL: /quiz/edit
|
||
- Headers: Authorization: Bearer {valid_jwt_token}, Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{
|
||
"id": 102,
|
||
"status": "stop"
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Тело ответа: `{"updated": 102}`
|
||
|
||
**Проверки:**
|
||
1. `updated` в ответе равен 102.
|
||
2. В базе данных для квиза с `id`=102 обновлен только `status`, остальные поля не изменились.
|
||
3. `updated_at` обновлен.
|
||
|
||
#### 20.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request или 422 Unprocessable Entity)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса без поля `id`.
|
||
```json
|
||
{ "name": "Запрос без ID" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие или невалидность поля `id`.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`**
|
||
- Входные данные: `id` передано как строка.
|
||
```json
|
||
{ "id": "not_an_integer", "name": "Невалидный ID" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для `id`.
|
||
|
||
**Сценарий 3.3: Попытка обновления несуществующего квиза**
|
||
- Входные данные: `id` = 99999 (несуществующий).
|
||
```json
|
||
{ "id": 99999, "name": "Несуществующий квиз" }
|
||
```
|
||
- Ожидаемый результат: 400, 422 (или 404, если бы был заявлен и сервер так реагировал).
|
||
- Проверка: Сообщение об ошибке указывает, что квиз с таким `id` не найден или `id` невалиден.
|
||
|
||
**Сценарий 3.4: Некорректные значения для обновляемых полей**
|
||
- Входные данные (примеры, тестировать каждое поле отдельно):
|
||
- `name` длиннее 700 символов.
|
||
- `status` не из списка допустимых enum значений (`draft`, `template`, `stop`, `start`).
|
||
- `fp`, `rep`, `note_prevented`, `mailing`, `uniq`, `pausable`, `super` не boolean.
|
||
- `limit`, `due_to`, `time_of_passing`, `question_cnt`, `group_id` не integer/uint64 или отрицательные, если не разрешено.
|
||
- `conf` не является валидной JSON-строкой.
|
||
- Ожидаемый результат: 400 Bad Request или 422 Unprocessable Entity.
|
||
- Проверка: Сообщение об ошибке указывает на конкретное поле и характер ошибки валидации (для 422, тело ответа может содержать `message` с деталями).
|
||
|
||
#### 20.3.4 Проверка авторизации
|
||
**Сценарий 4.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 4.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 4.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 20.3.5 Проверка специфических кодов ответа
|
||
**Сценарий 5.1: Условия для 406 Not Acceptable**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusNotAcceptableError`. Например, попытка изменить квиз, который заблокирован для редактирования из-за его статуса или активных сессий).
|
||
- Ожидаемый результат: 406 Not Acceptable.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusNotAcceptableError`.
|
||
|
||
**Сценарий 5.2: Условия для 409 Conflict**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusConflictError`. Например, попытка установить `name`, которое уже используется другим квизом, если `name` должно быть уникальным).
|
||
- Ожидаемый результат: 409 Conflict.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusConflictError`.
|
||
|
||
**Сценарий 5.3: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой внешней системы, от которой зависит обновление данных квиза, например, при обновлении счетчиков вопросов).
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 20.3.6 Проверка безопасности (SQL-инъекции, XSS)
|
||
**Сценарий 6.1: SQL-инъекции в строковых полях**
|
||
- Входные данные: В полях `name`, `desc`, `conf` передаются SQL-инъекции.
|
||
- Ожидаемый результат: 400/422, либо запрос обработан без выполнения инъекции.
|
||
- Проверка: Отсутствие уязвимости.
|
||
|
||
**Сценарий 6.2: XSS-атаки в строковых полях**
|
||
- Входные данные: В полях `name`, `desc`, `conf` передаются XSS-скрипты.
|
||
- Ожидаемый результат: 400/422, либо данные корректно сохранены/обновлены (экранированы), XSS не выполняется при отображении.
|
||
- Проверка: Отсутствие уязвимости.
|
||
|
||
#### 20.3.7 Проверка производительности
|
||
**Сценарий 7.1: Время обновления квиза**
|
||
- Проверка: Время ответа на запрос обновления < N ms (например, < 500ms).
|
||
|
||
**Сценарий 7.2: Нагрузочное тестирование**
|
||
- Проверка: Система выдерживает X одновременных запросов на обновление различных квизов.
|
||
|
||
#### 20.3.8 Обработка ошибок (Общие)
|
||
**Сценарий 8.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация сбоя на сервере при обновлении (например, ошибка БД).
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 20.4 Особые моменты для тестирования
|
||
1. **Частичное обновление**: Убедиться, что при обновлении только некоторых полей остальные поля квиза не затрагиваются и сохраняют свои предыдущие значения.
|
||
2. **Валидация `id`**: Тщательная проверка того, что `id` существует и принадлежит текущему пользователю/аккаунту (если есть такая логика авторизации на уровне записи).
|
||
3. **Валидация всех полей `UpdateQuizRequest`**: Проверить каждое поле на соответствие типам, форматам и допустимым значениям.
|
||
4. **Обновление `status`**: Проверить корректность перехода между различными статусами квиза (`draft`, `template`, `stop`, `start`) и возможные ограничения (например, можно ли перевести активный квиз в `draft`).
|
||
5. **Поле `updated_at`**: Проверить, что это поле автоматически обновляется при любом успешном изменении квиза.
|
||
6. **Влияние `question_cnt`**: Если это поле предназначено для изменения количества связанных вопросов (например, добавление/удаление пустых слотов), проверить эту логику. Если это просто обновление метаданных, убедиться, что значение `questions_count` в объекте `Quiz` обновляется соответствующим образом или поле `question_cnt` просто сохраняется.
|
||
7. **Логика `super` и `group_id`**: Проверить корректность обновления этих полей и их взаимное влияние.
|
||
|
||
### 20.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 20.3 пройдены успешно.
|
||
2. Квиз корректно обновляется в базе данных, затрагиваются только переданные поля.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 406, 409, 422, 424, 500) соответствует спецификации API.
|
||
4. Обеспечена защита от основных уязвимостей безопасности.
|
||
5. Поле `updated_at` квиза обновляется корректно.
|
||
6. Логирование операций по обновлению квизов информативно.
|
||
|
||
## 21. POST /quiz/copy
|
||
|
||
### 21.1 Описание
|
||
Создание копии существующего квиза. Новый квиз создается со всеми настройками и атрибутами оригинального квиза, но получает новый уникальный идентификатор (`id`, `qid`) и некоторые поля сбрасываются или устанавливаются в начальные значения (например, версия, счетчики прохождений, даты создания/обновления).
|
||
|
||
### 21.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/CopyQuizRequest` и содержать обязательное поле `id` (ID оригинального квиза).
|
||
- В случае успеха (200 OK) возвращает полный объект нового, скопированного квиза согласно схеме `#/components/schemas/Quiz`.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 21.3 Тестовые сценарии
|
||
|
||
#### 21.3.1 Успешное копирование квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Существует квиз с `id`, указанным в запросе (оригинальный квиз).
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /quiz/copy
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/CopyQuizRequest`):
|
||
```json
|
||
{
|
||
"id": 101 // integer, uint64 - ID существующего квиза для копирования
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (новый скопированный квиз, согласно `#/components/schemas/Quiz`. Пример):
|
||
```json
|
||
{
|
||
"id": 202, // integer, uint64 - НОВЫЙ ID для скопированного квиза
|
||
"qid": "new-uuid-for-quiz-202", // string - НОВЫЙ UUID
|
||
"accountid": "user-account-id", // string - ID аккаунта создателя (копируется)
|
||
"deleted": false, // boolean - всегда false для новой копии
|
||
"archived": false, // boolean - всегда false для новой копии
|
||
"fingerprinting": true, // boolean - копируется из оригинала
|
||
"repeatable": true, // boolean - копируется из оригинала
|
||
"note_prevented": false, // boolean - копируется из оригинала
|
||
"mail_notifications": true, // boolean - копируется из оригинала
|
||
"unique_answers": false, // boolean - копируется из оригинала
|
||
"name": "Копия: Оригинальное название квиза", // string - name оригинала, возможно с префиксом "Копия: "
|
||
"description": "Описание оригинального квиза.", // string - копируется из оригинала
|
||
"config": "{}", // string - копируется из оригинала
|
||
"status": "draft", // string, enum - статус новой копии (вероятно, 'draft' по умолчанию)
|
||
"limit": 50, // integer, uint64 - копируется из оригинала
|
||
"due_to": 1675000000, // integer, uint64 - копируется из оригинала
|
||
"time_of_passing": 1800, // integer, uint64 - копируется из оригинала
|
||
"pausable": true, // boolean - копируется из оригинала
|
||
"version": 1, // integer - версия сбрасывается до 1 для новой копии
|
||
"version_comment": null, // string - комментарий к версии сбрасывается
|
||
"parent_ids": [], // array of integers - parent_ids сбрасываются или копируются (уточнить логику, скорее всего сбрасываются)
|
||
"created_at": "YYYY-MM-DDTHH:mm:ssZ", // string, date-time - НОВАЯ дата создания
|
||
"updated_at": "YYYY-MM-DDTHH:mm:ssZ", // string, date-time - НОВАЯ дата обновления (равна created_at)
|
||
"questions_count": 0, // integer, uint64 - счетчик вопросов (копируется от оригинала или сбрасывается - уточнить, скорее всего копируется, но вопросы сами не копируются этой операцией)
|
||
"session_count": 0, // integer, uint64 - сбрасывается до 0
|
||
"passed_count": 0, // integer, uint64 - сбрасывается до 0
|
||
"average_time": 0, // integer, uint64 - сбрасывается до 0
|
||
"super": false, // boolean - копируется из оригинала
|
||
"group_id": null // integer, uint64 - копируется из оригинала (если был)
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. В базе данных создан новый квиз.
|
||
2. Возвращенный объект квиза имеет новый, уникальный `id` и `qid`.
|
||
3. Поля `accountid`, `fingerprinting`, `repeatable`, `note_prevented`, `mail_notifications`, `unique_answers`, `name` (с возможным префиксом), `description`, `config`, `limit`, `due_to`, `time_of_passing`, `pausable`, `super`, `group_id`, `questions_count` (значение копируется, но не сами вопросы) скопированы из оригинального квиза.
|
||
4. Поле `status` у новой копии установлено в ожидаемое значение (например, `draft`).
|
||
5. Поля `deleted` и `archived` у новой копии установлены в `false`.
|
||
6. Поле `version` у новой копии установлено в `1`, а `version_comment` - `null` (или пустое).
|
||
7. Поля `session_count`, `passed_count`, `average_time` у новой копии сброшены в `0`.
|
||
8. Поля `created_at` и `updated_at` у новой копии являются свежими временными метками.
|
||
9. Оригинальный квиз (с `id` из запроса) остался без изменений в базе данных.
|
||
10. Поле `parent_ids` для копии либо пустое, либо содержит скопированные значения (уточнить ожидаемое поведение).
|
||
|
||
#### 21.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 21.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса - пустой JSON `{}`.
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательного поля `id`.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`**
|
||
- Входные данные: `id` передано как строка.
|
||
```json
|
||
{ "id": "not_an_integer" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для `id`.
|
||
|
||
**Сценарий 3.3: Копирование несуществующего квиза**
|
||
- Входные данные: `id` = 99999 (несуществующий оригинальный квиз).
|
||
```json
|
||
{ "id": 99999 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request (или 404, если бы он был заявлен и API так отвечал бы).
|
||
- Проверка: Сообщение об ошибке указывает, что оригинальный квиз с таким `id` не найден.
|
||
|
||
#### 21.3.4 Проверка специфических кодов ответа
|
||
**Сценарий 4.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой при записи в базу данных нового квиза из-за внешних проблем, не связанных с валидацией входных данных).
|
||
- Входные данные: Корректный запрос на копирование.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 21.3.5 Обработка ошибок (Общие)
|
||
**Сценарий 5.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере в процессе копирования.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 21.4 Особые моменты для тестирования
|
||
1. **Генерация новых идентификаторов**: Убедиться, что у скопированного квиза всегда генерируются новые, уникальные `id` и `qid`.
|
||
2. **Копирование атрибутов**: Детально проверить, какие именно поля копируются из оригинала, какие устанавливаются по умолчанию (`deleted`, `archived`, `status`), а какие сбрасываются (`version`, `version_comment`, счетчики статистики `session_count`, `passed_count`, `average_time`).
|
||
3. **Имя копии**: Уточнить, добавляется ли префикс (например, "Копия: ") к полю `name` скопированного квиза, или имя копируется без изменений.
|
||
4. **Временные метки**: `created_at` и `updated_at` для копии должны быть новыми.
|
||
5. **Иммутабельность оригинала**: Оригинальный квиз не должен быть затронут операцией копирования.
|
||
6. **Связанные сущности (вопросы)**: Этот эндпоинт, скорее всего, копирует только сам "контейнер" квиза. Убедиться, что вопросы из оригинального квиза не копируются автоматически вместе с квизом этой операцией (их нужно будет добавлять/копировать отдельно). Поле `questions_count` в копии должно отражать это (если `questions_count` оригинала копируется, это может быть ожидаемым поведением, но сами вопросы не должны быть связаны с новой копией без отдельных действий).
|
||
7. **Статус копии**: Убедиться, что новый квиз создается в предопределенном статусе (например, `draft`), независимо от статуса оригинала.
|
||
8. **Поле `parent_ids`**: Уточнить, копируется ли это поле, или оно всегда сбрасывается для копии.
|
||
|
||
### 21.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 21.3 пройдены успешно.
|
||
2. Новый квиз корректно создается в базе данных как копия оригинала, с соответствующими изменениями (новый ID, qid, статус, сброшенные счетчики, свежие timestamp'ы).
|
||
3. Оригинальный квиз остается неизменным.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
5. Логирование операций по копированию квизов информативно.
|
||
|
||
## 22. POST /quiz/history
|
||
|
||
### 22.1 Описание
|
||
Получение истории изменений для указанного квиза. Каждая запись в истории представляет собой состояние (версию) квиза на определенный момент времени. Эндпоинт возвращает массив версий квиза.
|
||
|
||
### 22.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/GetQuizHistoryRequest` и содержать обязательное поле `id` квиза, а также опциональные поля для пагинации `l` (limit) и `p` (page).
|
||
- В случае успеха (200 OK) возвращает массив объектов `Quiz`, где каждый элемент - это одна версия из истории квиза.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 22.3 Тестовые сценарии
|
||
|
||
#### 22.3.1 Успешное получение истории квиза (с пагинацией)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Квиз с указанным `id` существует и имеет несколько записей в истории (несколько версий).
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /quiz/history
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса (согласно `#/components/schemas/GetQuizHistoryRequest`):
|
||
```json
|
||
{
|
||
"id": 101, // integer, uint64 - ID квиза
|
||
"l": 5, // integer, uint64 - Limit (количество записей на странице)
|
||
"p": 1 // integer, uint64 - Page (номер страницы, например, 1-based)
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа (массив объектов `Quiz`):
|
||
```json
|
||
[
|
||
{
|
||
"id": 101, // integer, uint64 - ID оригинального квиза
|
||
"qid": "uuid-quiz-101",
|
||
"accountid": "user-account-id",
|
||
"deleted": false,
|
||
"archived": false,
|
||
"fingerprinting": true,
|
||
"repeatable": false, // Значение из Версии 2
|
||
"note_prevented": false,
|
||
"mail_notifications": true,
|
||
"unique_answers": false,
|
||
"name": "Обновленное название квиза (Версия 2)",
|
||
"description": "Новое описание для квиза (Версия 2).",
|
||
"config": "{\"rules\":{\"v2\":true}}",
|
||
"status": "start", // Статус из Версии 2
|
||
"limit": 150,
|
||
"due_to": 1680000000,
|
||
"time_of_passing": 3600,
|
||
"pausable": false,
|
||
"version": 2, // integer - номер версии
|
||
"version_comment": "Вторая редакция, изменен статус и лимиты",
|
||
"parent_ids": [],
|
||
"created_at": "2023-01-15T10:00:00Z", // Время создания оригинального квиза
|
||
"updated_at": "2023-01-20T14:30:00Z", // Время фиксации этой версии
|
||
"questions_count": 12,
|
||
"session_count": 25, // Статистика может быть специфична для версии или общей (уточнить)
|
||
"passed_count": 10,
|
||
"average_time": 1500,
|
||
"super": false,
|
||
"group_id": null
|
||
},
|
||
{
|
||
"id": 101, // ID оригинального квиза
|
||
"qid": "uuid-quiz-101",
|
||
"accountid": "user-account-id",
|
||
// ... остальные поля для Версии 1 ...
|
||
"name": "Начальное название квиза (Версия 1)",
|
||
"status": "draft", // Статус из Версии 1
|
||
"version": 1,
|
||
"version_comment": "Первая версия",
|
||
"updated_at": "2023-01-15T10:00:00Z" // Время фиксации этой версии
|
||
}
|
||
// ... другие версии, если l > 2 ...
|
||
]
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Ответ является JSON массивом.
|
||
2. Каждый элемент массива является полным объектом `Quiz`, представляющим состояние квиза на момент этой версии.
|
||
3. Количество элементов в массиве не превышает значение `l` (limit) из запроса.
|
||
4. Если `p` (page) и `l` (limit) используются, пагинация работает корректно, возвращая соответствующий срез истории.
|
||
5. Поле `version` в каждой записи истории корректно отражает номер версии (или другое поле, идентифицирующее версию, например, `updated_at` этой записи истории).
|
||
6. Записи истории отсортированы в ожидаемом порядке (например, по убыванию `version` или `updated_at` этой записи истории).
|
||
7. Если у квиза нет истории (например, он только что создан и не изменялся), массив содержит одну запись, представляющую текущее состояние квиза с `version: 1`.
|
||
8. Если запрос сделан с `l=0` или без `l` и `p`, проверить поведение по умолчанию (например, возврат всех версий или первой страницы с лимитом по умолчанию).
|
||
9. Поле `id` во всех объектах истории одинаково и соответствует `id` запрошенного квиза.
|
||
|
||
#### 22.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 22.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса без поля `id`.
|
||
```json
|
||
{ "l": 10, "p": 1 }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательного поля `id`.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`, `l`, или `p`**
|
||
- Входные данные (примеры):
|
||
- `id` как строка: `{ "id": "not_an_integer", "l": 10, "p": 1 }`
|
||
- `l` как строка: `{ "id": 101, "l": "ten", "p": 1 }`
|
||
- `p` как строка: `{ "id": 101, "l": 10, "p": "one" }`
|
||
- `l` или `p` отрицательные (если не разрешено).
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных или недопустимое значение для соответствующего поля.
|
||
|
||
**Сценарий 3.3: Запрос истории для несуществующего квиза**
|
||
- Входные данные: `id` = 99999 (несуществующий квиз).
|
||
```json
|
||
{ "id": 99999, "l": 10, "p": 1 }
|
||
```
|
||
- Ожидаемый результат: 200 OK и пустой массив `[]` в теле ответа (или 404, если бы он был заявлен, но OpenAPI указывает на 200 для успешного, даже если данных нет, или 400 для ошибки запроса).
|
||
- Проверка: Если 200 OK, тело ответа - пустой массив. Если 400, сообщение указывает, что квиз не найден.
|
||
|
||
#### 22.3.4 Проверка специфических кодов ответа
|
||
**Сценарий 4.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Определить условия на основе спецификации `StatusFailedDependencyError`. Например, сбой при чтении из базы данных истории).
|
||
- Входные данные: Корректный запрос на получение истории.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 22.3.5 Обработка ошибок (Общие)
|
||
**Сценарий 5.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 22.4 Особые моменты для тестирования
|
||
1. **Порядок версий**: Убедиться, что версии в истории отсортированы последовательно и предсказуемо (например, по убыванию номера `version` или по убыванию `updated_at` записи истории).
|
||
2. **Полнота данных в версиях**: Каждая версия квиза в массиве должна содержать все поля из схемы `Quiz` и отражать состояние квиза на момент создания этой версии.
|
||
3. **Пагинация (`l` и `p`)**: Тщательно проверить работу пагинации: корректность количества возвращаемых элементов, переход по страницам, поведение на первой и последней странице, поведение при запросе страницы за пределами существующей истории.
|
||
4. **История для нового/неизмененного квиза**: Если квиз только создан и не редактировался, эндпоинт должен вернуть массив с одной записью (текущее состояние, `version: 1`).
|
||
5. **Глубина/ограничения истории**: Если система накладывает ограничения на количество хранимых версий или глубину истории, это необходимо проверить.
|
||
6. **Согласованность данных**: Поля `id`, `qid`, `accountid` в объектах истории должны соответствовать оригинальному квизу. Поле `version` должно быть уникальным для каждой записи истории одного квиза и увеличиваться (или изменяться предсказуемо).
|
||
7. **`created_at` vs `updated_at` в истории**: Убедиться, что `created_at` в записях истории остается временем создания самого квиза, а `updated_at` отражает время сохранения конкретной версии.
|
||
|
||
### 22.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 22.3 пройдены успешно.
|
||
2. История квиза возвращается корректно, со всеми версиями и точными данными для каждой версии.
|
||
3. Параметры пагинации `l` и `p` работают правильно.
|
||
4. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
5. Данные в ответе структурированы правильно (массив объектов `Quiz`).
|
||
6. Логирование запросов к истории квизов информативно.
|
||
|
||
## 23. DELETE /quiz/delete
|
||
|
||
### 23.1 Описание
|
||
Удаление (деактивация) квиза по его идентификатору. Операция требует авторизации и принимает в теле запроса объект с обязательным полем `id` (ID квиза для удаления).
|
||
|
||
### 23.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: DELETE.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/DeleteQuizRequest` и содержать обязательное поле `id` (ID квиза).
|
||
- В случае успеха (200 OK) возвращает объект с полем `deactivated` (ID деактивированного квиза) согласно схеме `#/components/schemas/DeleteQuizResponse`.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 23.3 Тестовые сценарии
|
||
|
||
#### 23.3.1 Успешное удаление квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Существует квиз с указанным `id`, и он не удалён.
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /quiz/delete
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{ "id": 101 }
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
{ "deactivated": 101 }
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Квиз с указанным `id` помечен как удалённый (`deleted: true`) в базе данных.
|
||
2. Возвращённое значение `deactivated` совпадает с `id` удалённого квиза.
|
||
3. Повторный запрос на удаление этого же квиза возвращает 200 OK и тот же результат (операция идемпотентна).
|
||
4. Квиз больше не отображается в списках активных квизов (например, в /quiz/getList без фильтра deleted=true).
|
||
5. Связанные вопросы и результаты также помечены как удалённые (если реализовано каскадное удаление).
|
||
|
||
#### 23.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 23.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса - пустой JSON `{}`.
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательного поля `id`.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`**
|
||
- Входные данные: `id` передано как строка.
|
||
```json
|
||
{ "id": "not_an_integer" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для `id`.
|
||
|
||
**Сценарий 3.3: Удаление несуществующего квиза**
|
||
- Входные данные: `id` = 99999 (несуществующий квиз).
|
||
```json
|
||
{ "id": 99999 }
|
||
```
|
||
- Ожидаемый результат: 200 OK (или 400/404, если реализовано иначе).
|
||
- Проверка: Если 200 OK — операция идемпотентна, если 400/404 — сообщение указывает, что квиз не найден.
|
||
|
||
#### 23.3.4 Проверка специфических кодов ответа
|
||
|
||
**Сценарий 4.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Имитация сбоя внешней системы или базы данных при удалении квиза).
|
||
- Входные данные: Корректный запрос на удаление.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 23.3.5 Обработка ошибок (Общие)
|
||
**Сценарий 5.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 23.4 Особые моменты для тестирования
|
||
1. **Идемпотентность**: Повторное удаление одного и того же квиза не приводит к ошибке.
|
||
2. **Каскадное удаление**: Проверить, что связанные вопросы и результаты также помечаются как удалённые (если реализовано).
|
||
3. **Видимость**: Удалённый квиз не отображается в списках активных квизов.
|
||
4. **Восстановление**: Если предусмотрено восстановление, проверить возможность восстановления удалённого квиза.
|
||
5. **Логирование**: Проверить запись операции удаления в логах.
|
||
6. **Мониторинг**: Проверить метрики и алерты по операциям удаления.
|
||
|
||
### 23.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 23.3 пройдены успешно.
|
||
2. Квиз корректно помечается как удалённый в базе данных.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
4. Операция удаления идемпотентна.
|
||
5. Логирование и мониторинг операций удаления работают корректно.
|
||
|
||
## 24. PATCH /quiz/archive
|
||
|
||
### 24.1 Описание
|
||
Архивация квиза по его идентификатору. Операция требует авторизации и принимает в теле запроса объект с обязательным полем `id` (ID квиза для архивации).
|
||
|
||
### 24.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: PATCH.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/DeleteQuizRequest` и содержать обязательное поле `id` (ID квиза).
|
||
- В случае успеха (200 OK) возвращает объект с полем `deactivated` (ID заархивированного квиза) согласно схеме `#/components/schemas/DeleteQuizResponse`.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 424 (Failed Dependency), 500 (Internal Server Error).
|
||
|
||
### 24.3 Тестовые сценарии
|
||
|
||
#### 24.3.1 Успешная архивация квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Существует квиз с указанным `id`, и он не заархивирован.
|
||
|
||
**Входные данные:**
|
||
- Метод: PATCH
|
||
- URL: /quiz/archive
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{ "id": 101 }
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
{ "deactivated": 101 }
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Квиз с указанным `id` помечен как заархивированный (`archived: true`) в базе данных.
|
||
2. Возвращённое значение `deactivated` совпадает с `id` заархивированного квиза.
|
||
3. Повторный запрос на архивацию этого же квиза возвращает 200 OK и тот же результат (операция идемпотентна).
|
||
4. Квиз больше не отображается в списках активных квизов (например, в /quiz/getList без фильтра archived=true).
|
||
5. Связанные вопросы и результаты остаются без изменений (если не реализовано каскадное архивирование).
|
||
|
||
#### 24.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
**Сценарий 2.3: Истекший токен**
|
||
- Headers: Authorization: Bearer expired_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 24.3.3 Проверка валидации данных запроса (Ответ 400 Bad Request)
|
||
|
||
**Сценарий 3.1: Отсутствие обязательного поля `id`**
|
||
- Входные данные: Тело запроса - пустой JSON `{}`.
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательного поля `id`.
|
||
|
||
**Сценарий 3.2: Некорректный тип данных для `id`**
|
||
- Входные данные: `id` передано как строка.
|
||
```json
|
||
{ "id": "not_an_integer" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных для `id`.
|
||
|
||
**Сценарий 3.3: Архивация несуществующего квиза**
|
||
- Входные данные: `id` = 99999 (несуществующий квиз).
|
||
```json
|
||
{ "id": 99999 }
|
||
```
|
||
- Ожидаемый результат: 200 OK (или 400/404, если реализовано иначе).
|
||
- Проверка: Если 200 OK — операция идемпотентна, если 400/404 — сообщение указывает, что квиз не найден.
|
||
|
||
#### 24.3.4 Проверка специфических кодов ответа
|
||
|
||
**Сценарий 4.1: Условия для 424 Failed Dependency**
|
||
- Предусловия: (Имитация сбоя внешней системы или базы данных при архивации квиза).
|
||
- Входные данные: Корректный запрос на архивацию.
|
||
- Ожидаемый результат: 424 Failed Dependency.
|
||
- Проверка: Тело ответа согласно `#/components/responses/StatusFailedDependencyError`.
|
||
|
||
#### 24.3.5 Обработка ошибок (Общие)
|
||
**Сценарий 5.1: Внутренняя ошибка сервера (500 Internal Server Error)**
|
||
- Предусловия: Имитация неожиданного сбоя на сервере.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 24.4 Особые моменты для тестирования
|
||
1. **Идемпотентность**: Повторная архивация одного и того же квиза не приводит к ошибке.
|
||
2. **Видимость**: Заархивированный квиз не отображается в списках активных квизов.
|
||
3. **Восстановление**: Если предусмотрено восстановление, проверить возможность восстановления заархивированного квиза.
|
||
4. **Логирование**: Проверить запись операции архивации в логах.
|
||
5. **Мониторинг**: Проверить метрики и алерты по операциям архивации.
|
||
|
||
### 24.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 24.3 пройдены успешно.
|
||
2. Квиз корректно помечается как заархивированный в базе данных.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 424, 500) соответствует спецификации API.
|
||
4. Операция архивации идемпотентна.
|
||
5. Логирование и мониторинг операций архивации работают корректно.
|
||
|
||
|
||
## 25. POST /quiz/move
|
||
|
||
### 25.1 Описание
|
||
Перенос квиза на другой аккаунт. Позволяет изменить владельца квиза, указав идентификатор квиза (`qid`) и новый `accountID`.
|
||
|
||
### 25.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/QuizMoveRequest` и содержать обязательные поля: `qid` (string), `accountID` (string).
|
||
- В случае успеха (200 OK) возвращает подтверждение переноса.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 500 (Internal Server Error).
|
||
|
||
### 25.3 Тестовые сценарии
|
||
|
||
#### 25.3.1 Успешный перенос квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- Квиз с указанным `qid` существует и принадлежит текущему пользователю.
|
||
- Новый `accountID` существует.
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /quiz/move
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{ "qid": "uuid-quiz-101", "accountID": "user-2" }
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Квиз теперь принадлежит новому аккаунту (`accountID`).
|
||
|
||
**Проверки:**
|
||
1. В базе данных у квиза обновлён `accountID`.
|
||
2. Квиз больше не доступен старому владельцу (если нет прав).
|
||
3. Новый владелец видит квиз в списке своих квизов.
|
||
|
||
#### 25.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 25.3.3 Проверка валидации данных запроса (400 Bad Request)
|
||
**Сценарий 3.1: Отсутствие обязательных полей**
|
||
- Тело запроса: `{}` или без одного из полей.
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на отсутствие обязательных полей.
|
||
|
||
**Сценарий 3.2: Несуществующий квиз или аккаунт**
|
||
- Тело запроса: несуществующий `qid` или `accountID`.
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на несуществующий квиз или аккаунт.
|
||
|
||
#### 25.3.4 Обработка ошибок (500 Internal Server Error)
|
||
**Сценарий 4.1: Внутренняя ошибка сервера**
|
||
- Имитация сбоя.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 25.4 Особые моменты для тестирования
|
||
1. Проверить, что перенос невозможен без прав на квиз.
|
||
2. Проверить, что все связанные сущности (например, результаты) корректно отображаются новому владельцу.
|
||
3. Проверить, что квиз не дублируется, а именно переносится.
|
||
4. Проверить корректность передачи всех обязательных полей (`qid`, `accountID`).
|
||
|
||
### 25.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 25.3 пройдены успешно.
|
||
2. Квиз корректно переносится новому владельцу.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 500) соответствует спецификации API.
|
||
4. Логирование и мониторинг операций переноса работают корректно.
|
||
|
||
|
||
## 26. POST /quiz/template
|
||
|
||
### 26.1 Описание
|
||
Создание копии шаблона квиза. Возвращает новый идентификатор шаблона.
|
||
|
||
### 26.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- В случае успеха (200 OK) возвращает объект с новым `id` шаблона.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 401 (Unauthorized), 500 (Internal Server Error).
|
||
|
||
### 26.3 Тестовые сценарии
|
||
|
||
#### 26.3.1 Успешное копирование шаблона
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- Существует шаблон для копирования.
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /quiz/template
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
{ "id": 12345 }
|
||
```
|
||
|
||
**Проверки:**
|
||
1. В базе данных создан новый шаблон с уникальным `id`.
|
||
2. Новый шаблон доступен пользователю.
|
||
3. Оригинальный шаблон не изменён.
|
||
|
||
#### 26.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 26.3.3 Обработка ошибок (500 Internal Server Error)
|
||
**Сценарий 3.1: Внутренняя ошибка сервера**
|
||
- Имитация сбоя.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 26.4 Особые моменты для тестирования
|
||
1. Проверить, что копия шаблона создаётся с новым идентификатором.
|
||
2. Проверить, что оригинальный шаблон не изменяется.
|
||
3. Проверить корректность структуры ответа (`id` — integer).
|
||
|
||
### 26.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 26.3 пройдены успешно.
|
||
2. Новый шаблон корректно создаётся и доступен пользователю.
|
||
3. Оригинальный шаблон не изменяется.
|
||
4. Обработка всех кодов ошибок (200, 401, 500) соответствует спецификации API.
|
||
5. Логирование и мониторинг операций копирования работают корректно.
|
||
|
||
## 27. POST /results/getResults/{quizId}
|
||
|
||
### 27.1 Описание
|
||
Получение результатов по конкретному квизу. Позволяет получить список результатов (ответов) для указанного квиза с поддержкой фильтрации и пагинации.
|
||
|
||
### 27.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Параметр пути: `quizId` (string, обязательный) — идентификатор квиза.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/GetResultsRequest` (опциональные поля: `To`, `From`, `New`, `Page`, `Limit`).
|
||
- В случае успеха (200 OK) возвращает объект по схеме `#/components/schemas/GetResultsResponse` (поля: `total_count`, `results` — массив объектов `AnswerExport`).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 500 (Internal Server Error).
|
||
|
||
### 27.3 Тестовые сценарии
|
||
|
||
#### 27.3.1 Успешное получение результатов квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- Квиз с указанным `quizId` существует и содержит результаты.
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /results/getResults/{quizId}
|
||
- Path parameter: quizId = "12345"
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{ "Page": 1, "Limit": 10 }
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
{
|
||
"total_count": 100,
|
||
"results": [
|
||
{
|
||
"content": "{...}",
|
||
"id": 1,
|
||
"new": false,
|
||
"created_at": "2024-06-01T12:00:00Z",
|
||
"Version": 1
|
||
}
|
||
// ... другие объекты AnswerExport ...
|
||
]
|
||
}
|
||
```
|
||
|
||
**Проверки:**
|
||
1. Количество элементов в массиве `results` не превышает значение `Limit` из запроса.
|
||
2. Все объекты в массиве `results` соответствуют схеме `AnswerExport` (поля: `content`, `id`, `new`, `created_at`, `Version`).
|
||
3. Значение `total_count` соответствует общему количеству результатов для данного квиза.
|
||
4. Если указаны фильтры (`From`, `To`, `New`), возвращаются только соответствующие результаты.
|
||
5. Пагинация работает корректно: при изменении `Page` возвращаются разные срезы данных.
|
||
|
||
#### 27.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 27.3.3 Проверка валидации данных запроса (400 Bad Request)
|
||
**Сценарий 3.1: Некорректный формат параметра `quizId`**
|
||
- Path parameter: quizId = "not_a_number"
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный формат идентификатора.
|
||
|
||
**Сценарий 3.2: Некорректные значения в теле запроса**
|
||
- Тело запроса: поля с неверными типами (например, `Page` = "one").
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный тип данных.
|
||
|
||
**Сценарий 3.3: Несуществующий квиз**
|
||
- Path parameter: quizId = "99999"
|
||
- Ожидаемый результат: 200 OK и пустой массив `results` (или 400/404, если реализовано иначе).
|
||
- Проверка: Если 200 OK — массив `results` пустой, если 400/404 — сообщение указывает, что квиз не найден.
|
||
|
||
#### 27.3.4 Обработка ошибок (500 Internal Server Error)
|
||
**Сценарий 4.1: Внутренняя ошибка сервера**
|
||
- Имитация сбоя.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 27.4 Особые моменты для тестирования
|
||
1. Проверить корректность работы пагинации (`Page`, `Limit`).
|
||
2. Проверить фильтрацию по датам (`From`, `To`) и по признаку `New`.
|
||
3. Проверить, что все объекты в массиве `results` соответствуют схеме `AnswerExport`.
|
||
4. Проверить корректность значения `total_count`.
|
||
5. Проверить работу при большом количестве результатов (нагрузочное тестирование).
|
||
|
||
### 27.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 27.3 пройдены успешно.
|
||
2. Результаты корректно возвращаются и соответствуют фильтрам и пагинации.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 500) соответствует спецификации API.
|
||
4. Логирование и мониторинг операций получения результатов работают корректно.
|
||
|
||
## 28. DELETE /results/{resultId}
|
||
|
||
### 28.1 Описание
|
||
Удаление (деактивация) конкретного результата (ответа) по его идентификатору. Операция требует авторизации и принимает идентификатор результата в path-параметре.
|
||
|
||
### 28.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: DELETE.
|
||
- Path-параметр: `resultId` (string, обязательный) — идентификатор результата.
|
||
- В случае успеха (200 OK) возвращает подтверждение удаления.
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 500 (Internal Server Error).
|
||
|
||
### 28.3 Тестовые сценарии
|
||
|
||
#### 28.3.1 Успешное удаление результата
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- Результат с указанным `resultId` существует и принадлежит пользователю (или у пользователя есть права на удаление).
|
||
|
||
**Входные данные:**
|
||
- Метод: DELETE
|
||
- URL: /results/{resultId}
|
||
- Path parameter: resultId = "123456"
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- (Тело ответа может быть пустым или содержать подтверждение удаления)
|
||
|
||
**Проверки:**
|
||
1. Результат с указанным `resultId` помечен как удалённый или физически удалён из базы данных.
|
||
2. Повторный запрос на удаление этого же результата возвращает 200 OK (операция идемпотентна) или 400/404 (если реализовано иначе).
|
||
3. Удалённый результат больше не отображается в списках результатов (например, в /results/getResults/{quizId}).
|
||
4. Связанные данные (например, статистика) обновляются корректно (если требуется).
|
||
|
||
#### 28.3.2 Проверка авторизации
|
||
**Сценарий 2.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 2.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 28.3.3 Проверка валидации данных запроса (400 Bad Request)
|
||
**Сценарий 3.1: Некорректный формат параметра `resultId`**
|
||
- Path parameter: resultId = "not_a_number"
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение об ошибке указывает на неверный формат идентификатора.
|
||
|
||
**Сценарий 3.2: Несуществующий результат**
|
||
- Path parameter: resultId = "99999999"
|
||
- Ожидаемый результат: 200 OK (или 400/404, если реализовано иначе).
|
||
- Проверка: Если 200 OK — операция идемпотентна, если 400/404 — сообщение указывает, что результат не найден.
|
||
|
||
#### 28.3.4 Проверка безопасности
|
||
**Сценарий 4.1: Попытка удаления чужого результата**
|
||
- Предусловие: Пользователь пытается удалить результат, который ему не принадлежит и на который нет прав.
|
||
- Ожидаемый результат: 401 Unauthorized или 403 Forbidden (если реализовано).
|
||
- Проверка: Операция отклонена, результат не удалён.
|
||
|
||
#### 28.3.5 Граничные случаи и устойчивость
|
||
**Сценарий 5.1: Массовое удаление**
|
||
- Последовательное удаление большого количества результатов.
|
||
- Ожидаемый результат: Все результаты корректно удаляются, система устойчива к нагрузке.
|
||
|
||
**Сценарий 5.2: Удаление во время активных операций**
|
||
- Попытка удалить результат, который используется в отчёте или статистике.
|
||
- Ожидаемый результат: Корректная обработка конкурентных запросов, отсутствие ошибок согласованности.
|
||
|
||
#### 28.3.6 Обработка ошибок (500 Internal Server Error)
|
||
**Сценарий 6.1: Внутренняя ошибка сервера**
|
||
- Имитация сбоя.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 28.4 Особые моменты для тестирования
|
||
1. Проверить идемпотентность операции удаления.
|
||
2. Проверить корректность прав доступа (нельзя удалить чужой результат).
|
||
3. Проверить корректность обновления связанных данных (статистика, отчёты).
|
||
4. Проверить устойчивость к массовым и конкурентным операциям удаления.
|
||
5. Проверить логирование и аудит операций удаления.
|
||
6. Проверить мониторинг и алерты по ошибкам удаления.
|
||
|
||
### 28.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 28.3 пройдены успешно.
|
||
2. Результаты корректно удаляются и не отображаются в списках.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 500) соответствует спецификации API.
|
||
4. Операция удаления идемпотентна и безопасна.
|
||
5. Логирование и мониторинг операций удаления работают корректно.
|
||
|
||
## 29. PATCH /result/seen
|
||
|
||
### 29.1 Описание
|
||
Массовое обновление статуса (например, "просмотрено") для набора результатов (ответов) по их идентификаторам. Используется для отметки нескольких результатов как просмотренных или изменённых одним запросом. Требует авторизации.
|
||
|
||
### 29.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: PATCH.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/UpdateResultsStatusRequest` и содержать обязательное поле `Answers` — массив идентификаторов результатов (integer, int64).
|
||
- В случае успеха (200 OK) статус указанных результатов обновляется (например, поле `new` становится false).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 406 (Not Acceptable, если часть результатов недоступна по правам), 500 (Internal Server Error).
|
||
|
||
### 29.3 Тестовые сценарии
|
||
|
||
#### 29.3.1 Успешное массовое обновление статуса результатов
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- JWT токен валиден.
|
||
- Все результаты с переданными id существуют и доступны пользователю для изменения.
|
||
|
||
**Входные данные:**
|
||
- Метод: PATCH
|
||
- URL: /result/seen
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{
|
||
"Answers": [101, 102, 103]
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Тело ответа: (может быть пустым или содержать информацию об успешном обновлении)
|
||
- В базе данных у всех указанных результатов обновлён статус (например, поле `new` стало false).
|
||
|
||
**Проверки:**
|
||
1. Все указанные id действительно обновлены.
|
||
2. Повторный запрос с теми же id не вызывает ошибку (идемпотентность).
|
||
3. В истории действий пользователя фиксируется операция.
|
||
|
||
#### 29.3.2 Частичное отсутствие прав на некоторые результаты (406 Not Acceptable)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- В массиве `Answers` есть id, к которым у пользователя нет доступа.
|
||
|
||
**Входные данные:**
|
||
```json
|
||
{
|
||
"Answers": [201, 202, 9999]
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 406 Not Acceptable
|
||
- Тело ответа: сообщение о невозможности обновить часть результатов из-за недостаточных прав.
|
||
|
||
**Проверки:**
|
||
1. Только доступные результаты обновлены.
|
||
2. В журнале безопасности фиксируется попытка доступа к чужим данным.
|
||
|
||
#### 29.3.3 Переданы несуществующие id результатов (400 Bad Request)
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- В массиве `Answers` есть несуществующие id.
|
||
|
||
**Входные данные:**
|
||
```json
|
||
{
|
||
"Answers": [301, 302, 999999]
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 400 Bad Request
|
||
- Тело ответа: сообщение об ошибке ("Некоторые id не найдены").
|
||
|
||
**Проверки:**
|
||
1. Существующие результаты не изменяются.
|
||
2. В журнале ошибок фиксируется попытка обновления несуществующих результатов.
|
||
|
||
#### 29.3.4 Проверка авторизации (401 Unauthorized)
|
||
**Сценарий 4.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 4.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 29.3.5 Проверка валидации данных запроса (400 Bad Request)
|
||
**Сценарий 5.1: Пустой массив Answers**
|
||
- Входные данные:
|
||
```json
|
||
{ "Answers": [] }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение — "Список id не может быть пустым".
|
||
|
||
**Сценарий 5.2: Отсутствует поле Answers**
|
||
- Входные данные:
|
||
```json
|
||
{ "ids": [501, 502] }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение — "Некорректный формат запроса".
|
||
|
||
**Сценарий 5.3: Некорректный тип данных в массиве Answers**
|
||
- Входные данные:
|
||
```json
|
||
{ "Answers": ["not_an_integer", 123] }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
- Проверка: Сообщение — "Некорректный тип данных".
|
||
|
||
#### 29.3.6 Обработка ошибок (500 Internal Server Error)
|
||
**Сценарий 6.1: Внутренняя ошибка сервера**
|
||
- Предусловия: Имитация сбоя на сервере.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 29.4 Особые моменты для тестирования
|
||
1. **Идемпотентность**: Повторный PATCH с теми же id не должен приводить к ошибке.
|
||
2. **Массовое обновление**: Проверить работу с большим количеством id (например, 1000 за раз).
|
||
3. **Корректность логирования и аудита**: Все операции фиксируются.
|
||
4. **Права доступа**: Нельзя обновить результаты, принадлежащие другому аккаунту.
|
||
5. **Валидация**: Проверить все граничные случаи для массива Answers (пустой, отсутствует, неверный тип).
|
||
|
||
### 29.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 29.3 пройдены успешно.
|
||
2. Статусы результатов обновляются корректно.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 406, 500) соответствует спецификации API.
|
||
4. Операция идемпотентна и безопасна.
|
||
5. Логирование и аудит операций обновления работают корректно.
|
||
|
||
## 30. POST /results/{quizID}/export
|
||
|
||
### 30.1 Описание
|
||
Экспорт результатов квиза в формате Excel (XLSX) по идентификатору квиза. Позволяет выгрузить ответы пользователей с возможностью фильтрации по дате, новизне, пагинации. Требует авторизации.
|
||
|
||
### 30.2 Базовые требования
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST.
|
||
- Параметр пути: `quizID` (string) — идентификатор квиза, результаты которого экспортируются.
|
||
- Тело запроса должно соответствовать схеме `#/components/schemas/GetResultsRequest` и может содержать поля:
|
||
- `To` (string, date-time) — верхняя граница даты.
|
||
- `From` (string, date-time) — нижняя граница даты.
|
||
- `New` (boolean) — фильтр только по новым результатам.
|
||
- `Page` (integer, uint64) — номер страницы.
|
||
- `Limit` (integer, uint64) — количество результатов на странице.
|
||
- В случае успеха (200 OK) возвращает файл Excel (MIME: `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`).
|
||
- Поддерживает HTTP коды ответа: 200 (OK), 400 (Bad Request), 401 (Unauthorized), 402 (Payment Required), 500 (Internal Server Error).
|
||
|
||
### 30.3 Тестовые сценарии
|
||
|
||
#### 30.3.1 Успешный экспорт результатов квиза
|
||
**Предусловия:**
|
||
- Пользователь авторизован.
|
||
- Квиз с указанным `quizID` существует и доступен пользователю.
|
||
- В базе есть результаты для экспорта.
|
||
|
||
**Входные данные:**
|
||
- Метод: POST
|
||
- URL: /results/{quizID}/export (например, /results/123/export)
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{
|
||
"From": "2023-01-01T00:00:00Z",
|
||
"To": "2023-01-31T23:59:59Z",
|
||
"New": false,
|
||
"Page": 1,
|
||
"Limit": 100
|
||
}
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||
- В ответе — бинарный файл Excel с выгруженными результатами (структура и количество строк соответствуют фильтрам).
|
||
|
||
**Проверки:**
|
||
1. Файл корректно открывается в Excel.
|
||
2. Количество строк соответствует ожидаемому количеству результатов.
|
||
3. Данные в файле соответствуют фильтрам (даты, новизна, пагинация).
|
||
4. Названия столбцов и формат данных соответствуют спецификации.
|
||
|
||
#### 30.3.2 Экспорт с фильтрацией по новым результатам
|
||
**Входные данные:**
|
||
```json
|
||
{
|
||
"New": true
|
||
}
|
||
```
|
||
- Ожидаемый результат: В файле только новые результаты.
|
||
|
||
#### 30.3.3 Экспорт с пагинацией
|
||
**Входные данные:**
|
||
```json
|
||
{
|
||
"Page": 2,
|
||
"Limit": 50
|
||
}
|
||
```
|
||
- Ожидаемый результат: В файле только результаты второй страницы (51-100).
|
||
|
||
#### 30.3.4 Экспорт с фильтрацией по диапазону дат
|
||
**Входные данные:**
|
||
```json
|
||
{
|
||
"From": "2023-02-01T00:00:00Z",
|
||
"To": "2023-02-28T23:59:59Z"
|
||
}
|
||
```
|
||
- Ожидаемый результат: В файле только результаты, попавшие в указанный диапазон дат.
|
||
|
||
#### 30.3.5 Проверка авторизации (401 Unauthorized)
|
||
**Сценарий 5.1: Отсутствие токена**
|
||
- Headers: без Authorization.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
- Проверка: Тело ответа согласно `#/components/responses/UnauthorizedError`.
|
||
|
||
**Сценарий 5.2: Невалидный токен**
|
||
- Headers: Authorization: Bearer invalid_jwt_token.
|
||
- Ожидаемый результат: 401 Unauthorized.
|
||
|
||
#### 30.3.6 Проверка оплаты (402 Payment Required)
|
||
- Предусловие: У пользователя нет необходимой подписки/прав для экспорта.
|
||
- Ожидаемый результат: 402 Payment Required.
|
||
|
||
#### 30.3.7 Проверка валидации данных запроса (400 Bad Request)
|
||
**Сценарий 7.1: Некорректный формат даты**
|
||
- Входные данные:
|
||
```json
|
||
{ "From": "not-a-date" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
|
||
**Сценарий 7.2: Некорректный тип данных**
|
||
- Входные данные:
|
||
```json
|
||
{ "Page": "one", "Limit": "ten" }
|
||
```
|
||
- Ожидаемый результат: 400 Bad Request.
|
||
|
||
**Сценарий 7.3: Несуществующий quizID**
|
||
- URL: /results/999999/export
|
||
- Ожидаемый результат: 400 Bad Request или пустой файл (уточнить по реализации).
|
||
|
||
#### 30.3.8 Обработка ошибок (500 Internal Server Error)
|
||
- Предусловие: Имитация сбоя на сервере.
|
||
- Ожидаемый результат: 500 Internal Server Error.
|
||
- Проверка: Тело ответа согласно `#/components/responses/InternalServerError`.
|
||
|
||
### 30.4 Особые моменты для тестирования
|
||
1. **Корректность структуры файла**: Проверить, что все ожидаемые столбцы присутствуют, формат данных соответствует требованиям.
|
||
2. **Фильтрация и пагинация**: Проверить, что фильтры и пагинация работают корректно и не влияют на целостность данных.
|
||
3. **Большой объём данных**: Проверить экспорт при большом количестве результатов (например, 10 000+ строк).
|
||
4. **Права доступа**: Проверить, что нельзя экспортировать результаты чужого квиза.
|
||
5. **Логирование и аудит**: Проверить, что операция экспорта фиксируется в логах.
|
||
|
||
### 30.5 Критерии приемки
|
||
1. Все тестовые сценарии из раздела 30.3 пройдены успешно.
|
||
2. Файл Excel формируется корректно, данные соответствуют фильтрам и структуре.
|
||
3. Обработка всех кодов ошибок (200, 400, 401, 402, 500) соответствует спецификации API.
|
||
4. Операция экспорта безопасна и не влияет на целостность данных.
|
||
5. Логирование и аудит операций экспорта работают корректно
|
||
|
||
## 31. GET /result/{resultID}
|
||
|
||
31.1 Описание
|
||
|
||
Получение списка ответов (Answer) для указанного resultID. Ответы включают информацию о выбранных пользователем вариантах, устройстве, сессии и мета-данных (например, UTM-метки).
|
||
|
||
31.2 Базовые требования
|
||
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: GET.
|
||
- Параметр resultID передается в path и является обязательным (string).
|
||
- В случае успеха (200 OK) возвращает массив объектов Answer.
|
||
- Поддерживает HTTP коды ответа:
|
||
- 200 OK — Успешное получение данных.
|
||
- 400 Bad Request — Некорректный resultID.
|
||
- 401 Unauthorized — Отсутствие или невалидный токен.
|
||
- 402 Payment Required — Требуется оплата (например, при превышении квоты).
|
||
- 500 Internal Server Error — Внутренняя ошибка сервера.
|
||
|
||
31.3 Тестовые сценарии
|
||
|
||
**31.3.1 Успешное получение списка ответов по resultID**
|
||
|
||
_Предусловия:_
|
||
- Пользователь авторизован.
|
||
- resultID существует и соответствует завершенному прохождению квиза.
|
||
- В базе данных имеются связанные ответы.
|
||
|
||
_Входные данные:_
|
||
- Метод: GET
|
||
- URL: /result/abc123xyz
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
|
||
_Ожидаемый результат:_
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
[
|
||
{
|
||
"Id": 98765,
|
||
"content": "{\"selected\": [1, 2]}",
|
||
"question_id": 321,
|
||
"QuizId": 101,
|
||
"Fingerprint": "device-fp-001",
|
||
"Session": "session-uuid-001",
|
||
"Result": true,
|
||
"CreatedAt": "2024-12-01T12:00:00Z",
|
||
"new": false,
|
||
"Deleted": false,
|
||
"Email": "user@example.com",
|
||
"DeviceType": "mobile",
|
||
"Device": "iPhone 13",
|
||
"Browser": "Safari",
|
||
"IP": "192.168.1.10",
|
||
"OS": "iOS 17",
|
||
"Start": false,
|
||
"Utm": {
|
||
"utm_source": "newsletter",
|
||
"utm_campaign": "winter_sale"
|
||
},
|
||
"Version": 3
|
||
}
|
||
]
|
||
```
|
||
_Проверки:_
|
||
- Ответ — JSON-массив.
|
||
- Каждый элемент соответствует объекту Answer по схеме.
|
||
- Указан корректный resultID, и все ответы относятся к нему.
|
||
- Присутствуют все поля, включая Session, Device, IP, content, Utm и др.
|
||
- В поле content корректно сериализован JSON, соответствующий типу вопроса.
|
||
- Поля Deleted, Start, Result, new — логические, отражают статус ответа.
|
||
- Если Utm присутствует, он представлен как объект с произвольными ключами и строковыми значениями.
|
||
- Убедиться в правильности формата поля CreatedAt (RFC 3339).
|
||
|
||
**31.3.2 Проверка авторизации**
|
||
|
||
_Сценарий 2.1: Отсутствие токена_
|
||
- Headers: отсутствует Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
|
||
_Сценарий 2.2: Невалидный токен_
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
|
||
**31.3.3 Проверка обработки ошибок (400, 402, 500)**
|
||
|
||
_Сценарий 3.1: Некорректный resultID (например, пустая строка или недопустимый UUID)_
|
||
- URL: /result/
|
||
- Ожидаемый результат: 400 Bad Request
|
||
|
||
_Сценарий 3.2: resultID не существует_
|
||
- URL: /result/nonexistent123
|
||
- Ожидаемый результат: 200 OK, но пустой массив []
|
||
|
||
_Сценарий 3.3: Требуется оплата_
|
||
- Предусловия: Квота использования исчерпана или аккаунт не активен.
|
||
- Ожидаемый результат: 402 Payment Required
|
||
|
||
_Сценарий 3.4: Внутренняя ошибка сервера_
|
||
- Предусловия: Имитация сбоя на уровне БД
|
||
- Ожидаемый результат: 500 Internal Server Error
|
||
|
||
31.4 Особые моменты для тестирования
|
||
|
||
- Структура Answer: Проверить наличие всех полей, особенно content, Utm, Email, DeviceType, Browser.
|
||
- Массив ответов может быть пустым: Проверить поведение при отсутствии ответов.
|
||
- Согласованность данных: Все ответы должны относиться к одному resultID.
|
||
- UTM-метки: Должны корректно отображаться и соответствовать параметрам в момент начала прохождения квиза.
|
||
- Безопасность: Нельзя получить данные по resultID, если токен не авторизован.
|
||
- Поля с типом boolean: Проверить логическую корректность (Result, Start, Deleted, new).
|
||
- Формат времени: CreatedAt должен быть корректно сериализован в формате date-time.
|
||
|
||
31.5 Критерии приемки
|
||
|
||
- Эндпоинт возвращает ответы, соответствующие resultID.
|
||
- Все поля объекта Answer соответствуют описанию схемы.
|
||
- Работает авторизация: без токена — 401, с невалидным токеном — 401.
|
||
- Ошибки при недопустимом resultID возвращают 400, при проблемах оплаты — 402.
|
||
- При пустом результате возвращается пустой JSON-массив.
|
||
- Внутренние сбои сервера корректно обрабатываются с кодом 500.
|
||
- UTM-данные корректно отображаются, если присутствуют.
|
||
- Проверка структуры и типов данных пройдена.
|
||
- Все поля имеют предсказуемую структуру, включая вложенные объекты.
|
||
|
||
## 32. POST /statistic/{quizID}/devices
|
||
|
||
32.1 Описание
|
||
|
||
Получение статистики по устройствам, операционным системам и браузерам, использованным участниками при прохождении квиза с указанным quizID. Статистика рассчитывается на основе ответов, у которых res = true (итоговые ответы).
|
||
|
||
32.2 Базовые требования
|
||
|
||
- Требуется JWT токен авторизации (bearerAuth).
|
||
- Метод запроса: POST
|
||
- Путь должен содержать обязательный параметр quizID (string).
|
||
- Тело запроса должно соответствовать схеме DeviceStatRequest:
|
||
- From — начало временного диапазона (timestamp, опционально)
|
||
- To — конец временного диапазона (timestamp, опционально)
|
||
- В случае успеха (200 OK) возвращается объект, содержащий три словаря с процентным распределением:
|
||
- Device, OS, Browser
|
||
- Поддерживаемые коды ответа:
|
||
- 200 OK
|
||
- 400 Bad Request (например, неверный формат дат или параметров)
|
||
- 401 Unauthorized (отсутствие или невалидный токен)
|
||
- 500 Internal Server Error (непредвиденная ошибка на сервере)
|
||
|
||
32.3 Тестовые сценарии
|
||
|
||
**32.3.1 Успешное получение статистики по устройствам**
|
||
|
||
_Предусловия:_
|
||
- Пользователь авторизован.
|
||
- quizID существует.
|
||
- В базе есть ответы с res=true в указанном диапазоне дат или без фильтрации по времени.
|
||
|
||
_Входные данные:_
|
||
- Метод: POST
|
||
- URL: /statistic/12345/devices
|
||
- Headers:
|
||
- Authorization: Bearer {valid_jwt_token}
|
||
- Content-Type: application/json
|
||
- Тело запроса:
|
||
```json
|
||
{
|
||
"From": 1700000000,
|
||
"To": 1709999999
|
||
}
|
||
```
|
||
|
||
_Ожидаемый результат:_
|
||
- HTTP Status: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"Device": {
|
||
"mobile": 65.5,
|
||
"desktop": 30.2,
|
||
"tablet": 4.3
|
||
},
|
||
"OS": {
|
||
"iOS": 40.1,
|
||
"Android": 25.4,
|
||
"Windows": 20.0,
|
||
"macOS": 14.5
|
||
},
|
||
"Browser": {
|
||
"Chrome": 60.0,
|
||
"Safari": 25.0,
|
||
"Firefox": 10.0,
|
||
"Edge": 5.0
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
_Проверки:_
|
||
- Код ответа — 200 OK.
|
||
- Поле devices — массив длиной 1, содержащий объект.
|
||
- Все вложенные объекты Device, OS, Browser представлены как словари (object) с ключами-строками и значениями с типом float.
|
||
- Все значения — проценты (0–100), в сумме могут (но не обязаны) давать 100 по каждому разделу.
|
||
- Устройства, ОС и браузеры перечислены корректно, названия в формате строк (например, "iOS", "Chrome").
|
||
- При наличии фильтра From и To, данные учитываются только в этом диапазоне.
|
||
- Если ответов с res=true нет, вернётся пустые объекты или объекты с нулями:
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"Device": {},
|
||
"OS": {},
|
||
"Browser": {}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**32.3.2 Без временного диапазона (все данные)**
|
||
|
||
_Входные данные:_
|
||
```json
|
||
{}
|
||
```
|
||
_Ожидаемый результат:_
|
||
- HTTP Status: 200 OK
|
||
- Возвращается статистика по всем ответам res=true без фильтрации по времени.
|
||
|
||
**32.3.3 Проверка авторизации**
|
||
|
||
_Сценарий 3.1: Отсутствие токена_
|
||
- Headers: без Authorization
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
|
||
_Сценарий 3.2: Невалидный токен_
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ожидаемый результат: 401 Unauthorized
|
||
|
||
**32.3.4 Проверка валидации (400 Bad Request)**
|
||
|
||
_Сценарий 4.1: Некорректный формат timestamp_
|
||
```json
|
||
{
|
||
"From": "not_a_timestamp",
|
||
"To": 1700000000
|
||
}
|
||
```
|
||
_Сценарий 4.2: quizID некорректного формата_
|
||
- URL: /statistic/!!invalid/devices
|
||
|
||
_Ожидаемый результат (для обоих):_
|
||
- HTTP Status: 400 Bad Request
|
||
- Сообщение об ошибке указывает на некорректный формат входных данных.
|
||
|
||
**32.3.5 Внутренняя ошибка сервера**
|
||
|
||
_Сценарий 5.1: Ошибка чтения из базы_
|
||
- Эмуляция сбоя на уровне БД.
|
||
|
||
_Ожидаемый результат:_
|
||
- HTTP Status: 500 Internal Server Error
|
||
|
||
32.4 Особые моменты для тестирования
|
||
|
||
- Корректность расчетов: Проверить, что доли рассчитаны правильно (например, из 100 ответов: 60 мобильных → 60%).
|
||
- Диапазон значений: Убедиться, что значения в процентах, тип float, в пределах 0–100.
|
||
- Сумма значений: Проверить, что сумма по каждой категории не превышает 100 (но допускается < 100 из-за округления или пропущенных значений).
|
||
- Поведение при отсутствии данных: Убедиться, что возвращается пустая статистика, а не ошибка.
|
||
- Большие объемы данных: Проверить производительность и корректность при большом числе ответов.
|
||
- Безопасность: Нельзя получить статистику без авторизации.
|
||
- Точность по времени: Проверить корректную фильтрацию по From и To, включая граничные значения.
|
||
|
||
32.5 Критерии приемки
|
||
|
||
- Все тестовые сценарии из раздела 32.3 выполняются успешно.
|
||
- Результаты статистики корректны по значениям и структуре.
|
||
- Поля Device, OS, Browser соответствуют требованиям по типам и форматам.
|
||
- Диапазон дат фильтрует данные правильно.
|
||
- Ошибки в запросах возвращают 400, отсутствие авторизации — 401.
|
||
- Сервер обрабатывает сбои корректно с кодом 500.
|
||
|
||
## 33. POST /statistic/{quizID}/general
|
||
|
||
33.1 Описание
|
||
|
||
Получение общей статистики по квизу с указанным quizID, включая:
|
||
- количество открытий (Open)
|
||
- количество завершений (Result)
|
||
- среднее время прохождения (AvTime)
|
||
- конверсию (Conversion)
|
||
|
||
Все значения сгруппированы по дате/временным меткам. Поддерживается фильтрация по диапазону времени с помощью полей From и To.
|
||
|
||
33.2 Базовые требования
|
||
|
||
- Метод: POST
|
||
- Аутентификация: bearerAuth (JWT токен обязателен)
|
||
- Параметры пути:
|
||
- quizID — идентификатор квиза (обязателен, string)
|
||
- Тело запроса: JSON по схеме DeviceStatRequest:
|
||
- From — начало диапазона (timestamp)
|
||
- To — конец диапазона (timestamp)
|
||
- Код ответа 200 OK содержит объект с полями:
|
||
- Open, Result, AvTime, Conversion — объекты вида { timestamp: value }
|
||
|
||
33.3 Тестовые сценарии
|
||
|
||
**33.3.1 Успешное получение общей статистики**
|
||
|
||
_Предусловия:_
|
||
- Пользователь авторизован
|
||
- Существуют записи статистики для указанного quizID
|
||
|
||
_Входные данные:_
|
||
- URL: /statistic/12345/general
|
||
- Headers:
|
||
- Authorization: Bearer {valid_token}
|
||
- Content-Type: application/json
|
||
- Тело:
|
||
```json
|
||
{
|
||
"From": 1700000000,
|
||
"To": 1709999999
|
||
}
|
||
```
|
||
|
||
_Ожидаемый результат:_
|
||
- Код: 200 OK
|
||
- Content-Type: application/json
|
||
- Тело ответа:
|
||
```json
|
||
{
|
||
"Open": {
|
||
"1700010000": 150,
|
||
"1700020000": 175
|
||
},
|
||
"Result": {
|
||
"1700010000": 80,
|
||
"1700020000": 90
|
||
},
|
||
"AvTime": {
|
||
"1700010000": 45000,
|
||
"1700020000": 48000
|
||
},
|
||
"Conversion": {
|
||
"1700010000": 53,
|
||
"1700020000": 51
|
||
}
|
||
}
|
||
```
|
||
|
||
_Проверки:_
|
||
- Код — 200 OK
|
||
- Все поля (Open, Result, AvTime, Conversion) — объекты (object)
|
||
- Ключи — строки, представляющие timestamp (можно дополнительно валидировать диапазон)
|
||
- Значения:
|
||
- Open и Result — целые числа (uint64)
|
||
- AvTime — среднее время в миллисекундах (uint64)
|
||
- Conversion — проценты (0–100), округленные целые числа (uint64)
|
||
- Даты фильтруются по диапазону From–To
|
||
|
||
**33.3.2 Без временного диапазона (все данные)**
|
||
|
||
_Вход:_
|
||
```json
|
||
{}
|
||
```
|
||
_Ожидаемый результат:_
|
||
- Код: 200 OK
|
||
- Данные по всей доступной статистике
|
||
|
||
**33.3.3 Нет данных в указанном диапазоне**
|
||
|
||
_Вход:_
|
||
```json
|
||
{
|
||
"From": 1500000000,
|
||
"To": 1500003600
|
||
}
|
||
```
|
||
_Ожидаемый результат:_
|
||
```json
|
||
{
|
||
"Open": {},
|
||
"Result": {},
|
||
"AvTime": {},
|
||
"Conversion": {}
|
||
}
|
||
```
|
||
|
||
**33.3.4 Ошибки авторизации**
|
||
|
||
_Сценарий 1: Без токена_
|
||
- Headers: отсутствует Authorization
|
||
- Ответ: 401 Unauthorized
|
||
|
||
_Сценарий 2: Невалидный токен_
|
||
- Headers: Authorization: Bearer invalid_token
|
||
- Ответ: 401 Unauthorized
|
||
|
||
**33.3.5 Ошибка валидации (400 Bad Request)**
|
||
|
||
_Примеры:_
|
||
- From или To не число:
|
||
```json
|
||
{
|
||
"From": "invalid",
|
||
"To": 1700000000
|
||
}
|
||
```
|
||
- quizID содержит запрещённые символы:
|
||
/statistic/!!bad_id/general
|
||
|
||
_Ожидаемый результат:_
|
||
- Код: 400 Bad Request
|
||
|
||
**33.3.6 Внутренняя ошибка сервера**
|
||
|
||
_Например:_
|
||
- Ошибка доступа к базе
|
||
- Исключение во время обработки статистики
|
||
|
||
_Ожидаемый результат:_
|
||
- Код: 500 Internal Server Error
|
||
|
||
33.4 Особенности и проверки
|
||
|
||
| Поле | Описание | Проверки |
|
||
|-----------|-----------------------------------------------|--------------------------------------------------------|
|
||
| Open | Количество открытий квиза по timestamp'ам | timestamp: uint64 |
|
||
| Result | Кол-во завершений (ответов с res=true) | timestamp: uint64 |
|
||
| AvTime | Среднее время прохождения (в мс) | Значения > 0, логично по отношению к Result |
|
||
| Conversion| Конверсия: Result / Open * 100 округлённое | От 0 до 100, должно коррелировать с Open и Result |
|
||
|
||
33.5 Критерии приёмки
|
||
|
||
- Авторизация обязательна
|
||
- Корректный диапазон по времени работает
|
||
- Формат timestamp и значений верный
|
||
- Конверсия адекватна (Open > 0)
|
||
- Ошибки корректно обрабатываются (400, 401, 500)
|
||
- Пустая статистика не вызывает ошибок
|
||
- Статистика агрегируется по временным ключам (по дню/часу, в зависимости от реализации)
|
||
|
||
34. POST /statistic/{quizID}/questions
|
||
|
||
34.1 Описание
|
||
|
||
Запрос возвращает подробную статистику по вопросам квиза, включая:
|
||
- Метрики воронки (Funnel)
|
||
- Подробные данные воронки (FunnelData)
|
||
- Процент завершений по каждому вопросу (Results)
|
||
- Распределение ответов по каждому вопросу (Questions)
|
||
|
||
Фильтрация осуществляется по диапазону времени (From – To), и применяется только к ответам с Result=true.
|
||
|
||
34.2 Параметры
|
||
|
||
- Метод: POST
|
||
- Аутентификация: bearerAuth
|
||
- Путь: /statistic/{quizID}/questions
|
||
- quizID — string (обязателен)
|
||
- Тело запроса: JSON по схеме DeviceStatRequest
|
||
```json
|
||
{
|
||
"From": 1700000000,
|
||
"To": 1709999999
|
||
}
|
||
```
|
||
|
||
34.3 Описание структуры ответа (QuestionStat)
|
||
|
||
```json
|
||
{
|
||
"Funnel": [95.5, 78.3, 60.1],
|
||
"FunnelData": [1200, 900, 750, 600],
|
||
"Results": {
|
||
"Как вы оцениваете наш сервис?": 87.5,
|
||
"Сколько вам лет?": 92.0
|
||
},
|
||
"Questions": {
|
||
"Как вы оцениваете наш сервис?": {
|
||
"Отлично": 65.2,
|
||
"Хорошо": 25.3,
|
||
"Удовлетворительно": 9.5
|
||
},
|
||
"Сколько вам лет?": {
|
||
"18-24": 40.0,
|
||
"25-34": 30.0,
|
||
"35-44": 20.0,
|
||
"45+": 10.0
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
| Поле | Тип | Описание |
|
||
|-----------|----------|-------------------------------------------------------|
|
||
| Funnel | float[] | Метрики воронки (максимум 3 значения) — в процентах |
|
||
| FunnelData| float[] | Дополнительные данные воронки (максимум 4 знач.) |
|
||
| Results | object | Карта вопрос: % завершивших |
|
||
| Questions | object | Карта вопрос: { ответ: % распределения } |
|
||
|
||
34.4 Тест-кейсы
|
||
|
||
**✅ 34.4.1 Успешное получение статистики по вопросам**
|
||
|
||
_Вход:_
|
||
|
||
POST /statistic/12345/questions
|
||
Authorization: Bearer valid_token
|
||
Content-Type: application/json
|
||
|
||
Тело:
|
||
```json
|
||
{
|
||
"From": 1700000000,
|
||
"To": 1709999999
|
||
}
|
||
```
|
||
|
||
_Ожидаемый ответ:_
|
||
- Код: 200 OK
|
||
- Тип: application/json
|
||
- Структура: массив объектов QuestionStat (в большинстве случаев массив из 1 элемента)
|
||
|
||
_Проверки:_
|
||
- Funnel.length <= 3, FunnelData.length <= 4
|
||
- Значения — float
|
||
- Results: ключи — строки, значения — float (0.0 – 100.0)
|
||
- Questions: ключи — строки (вопросы), значения — объекты с ответ: % (в пределах 0.0–100.0)
|
||
- Сумма распределения по каждому вопросу ≈ 100 (можно ±0.1)
|
||
|
||
**✅ 34.4.2 Пустая статистика по диапазону**
|
||
|
||
_Тело запроса:_
|
||
```json
|
||
{
|
||
"From": 1500000000,
|
||
"To": 1500003600
|
||
}
|
||
```
|
||
_Ожидаемый результат:_
|
||
```json
|
||
[
|
||
{
|
||
"Funnel": [],
|
||
"FunnelData": [],
|
||
"Results": {},
|
||
"Questions": {}
|
||
}
|
||
]
|
||
```
|
||
|
||
**🔒 34.4.3 Ошибка авторизации**
|
||
|
||
_Сценарии:_
|
||
- Без токена → 401 Unauthorized
|
||
- С невалидным токеном → 401 Unauthorized
|
||
|
||
**⚠️ 34.4.4 Ошибка валидации запроса**
|
||
|
||
_Примеры:_
|
||
- From и To не числа:
|
||
```json
|
||
{
|
||
"From": "abc",
|
||
"To": 123
|
||
}
|
||
```
|
||
- quizID некорректен:
|
||
/statistic/<>/questions
|
||
|
||
_Ожидаемый результат:_ 400 Bad Request
|
||
|
||
**💥 34.4.5 Внутренняя ошибка**
|
||
|
||
_Примеры:_
|
||
- Ошибка агрегации данных
|
||
- Сбой базы
|
||
|
||
_Ожидаемый результат:_ 500 Internal Server Error
|
||
|
||
34.5 Критерии приёмки
|
||
|
||
| Условие | Проверка |
|
||
|-------------------------------------------|----------|
|
||
| ✅ Авторизация обязательна | Да |
|
||
| ✅ Статистика корректно фильтруется по времени | Да |
|
||
| ✅ Пустые данные не вызывают ошибок | Да |
|
||
| ✅ Значения — в допустимых диапазонах | Да |
|
||
| ✅ Все поля валидируются | Да | |