From 2eecabdbaaf410a5cd9750cde202868a96d08721 Mon Sep 17 00:00:00 2001 From: Pasha Date: Fri, 16 May 2025 16:06:39 +0300 Subject: [PATCH] continue write test spec with ai next:/telegram/pool --- api_test_specification.md | 610 +++++++++++++++++++++++++++++++++++++- 1 file changed, 608 insertions(+), 2 deletions(-) diff --git a/api_test_specification.md b/api_test_specification.md index ae76f6d..4fcc2fd 100644 --- a/api_test_specification.md +++ b/api_test_specification.md @@ -31,6 +31,16 @@ 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 @@ -1797,7 +1807,7 @@ **Входные данные:** - Метод: POST - URL: /question/create -- Headers: +- Headers: - Authorization: Bearer {valid_jwt_token} - Content-Type: application/json - Тело запроса (согласно схеме `#/components/schemas/QuestionCreateRequest`. Пример для типа "variant"): @@ -4477,4 +4487,600 @@ 2. Файл Excel формируется корректно, данные соответствуют фильтрам и структуре. 3. Обработка всех кодов ошибок (200, 400, 401, 402, 500) соответствует спецификации API. 4. Операция экспорта безопасна и не влияет на целостность данных. -5. Логирование и аудит операций экспорта работают корректно. \ No newline at end of file +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 Критерии приёмки + +| Условие | Проверка | +|-------------------------------------------|----------| +| ✅ Авторизация обязательна | Да | +| ✅ Статистика корректно фильтруется по времени | Да | +| ✅ Пустые данные не вызывают ошибок | Да | +| ✅ Значения — в допустимых диапазонах | Да | +| ✅ Все поля валидируются | Да | \ No newline at end of file