This commit is contained in:
47
tests/setup_mobile_test.py
Executable file
47
tests/setup_mobile_test.py
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import requests
|
||||
import sys
|
||||
import traceback
|
||||
from datetime import date
|
||||
|
||||
# Запрашиваем токен авторизации (предполагается, что он уже есть в системе)
|
||||
TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyOSIsImVtYWlsIjoidGVzdDJAZXhhbXBsZS5jb20iLCJleHAiOjE3NTg4NjY5ODJ9._AXkBLeMI4zxC9shFUS3744miuyO8CDnJD1X1AqbLsw"
|
||||
|
||||
# Данные для мобильного запроса
|
||||
mobile_data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3,
|
||||
"symptoms": ["CRAMPS", "HEADACHE"],
|
||||
"mood": "NORMAL",
|
||||
"notes": "Запись из мобильного приложения"
|
||||
}
|
||||
|
||||
# Заголовки с токеном авторизации
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {TOKEN}"
|
||||
}
|
||||
|
||||
# Сохраняем токен в файл для повторного использования
|
||||
with open('auth_token.txt', 'w') as f:
|
||||
f.write(TOKEN)
|
||||
|
||||
print(f"Токен сохранен в файл auth_token.txt")
|
||||
print(f"Данные для запроса к мобильному API сохранены в переменной mobile_data")
|
||||
print("\nПример использования:")
|
||||
print('curl -v -X POST http://localhost:8004/api/v1/calendar/entries/mobile -H "Content-Type: application/json" -H "Authorization: Bearer $(cat auth_token.txt)" -d \'{"date": "2025-09-26", "type": "MENSTRUATION", "flow_intensity": 3, "symptoms": ["CRAMPS", "HEADACHE"], "mood": "NORMAL", "notes": "Тестовая запись"}\'')
|
||||
|
||||
# Сохраняем пример запроса в файл для удобства
|
||||
with open('mobile_api_example.sh', 'w') as f:
|
||||
f.write('#!/bin/bash\n\n')
|
||||
f.write('# Пример запроса к мобильному API календарного сервиса\n')
|
||||
f.write('curl -v -X POST http://localhost:8004/api/v1/calendar/entries/mobile \\\n')
|
||||
f.write(' -H "Content-Type: application/json" \\\n')
|
||||
f.write(' -H "Authorization: Bearer $(cat auth_token.txt)" \\\n')
|
||||
f.write(' -d \'{"date": "2025-09-26", "type": "MENSTRUATION", "flow_intensity": 3, "symptoms": ["CRAMPS", "HEADACHE"], "mood": "NORMAL", "notes": "Тестовая запись"}\'\n')
|
||||
|
||||
print("\nПример запроса также сохранен в файле mobile_api_example.sh")
|
||||
print("Можно выполнить: chmod +x mobile_api_example.sh && ./mobile_api_example.sh")
|
||||
66
tests/simple_test.py
Normal file
66
tests/simple_test.py
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
import traceback
|
||||
from datetime import date
|
||||
|
||||
# API Gateway endpoint
|
||||
BASE_URL = "http://localhost:8004"
|
||||
|
||||
def main():
|
||||
try:
|
||||
print("Начинаем тест мобильного эндпоинта...")
|
||||
|
||||
# Проверка работоспособности сервиса
|
||||
print("Проверяем работоспособность сервиса...")
|
||||
health_response = requests.get(f"{BASE_URL}/health")
|
||||
print(f"Ответ о статусе: {health_response.status_code}")
|
||||
print(f"Тело ответа: {health_response.text}")
|
||||
|
||||
# Данные в формате мобильного приложения
|
||||
mobile_data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3, # средний (1-5)
|
||||
"symptoms": ["CRAMPS", "HEADACHE"], # массив строк
|
||||
"mood": "NORMAL",
|
||||
"notes": "Тестовая запись из мобильного приложения"
|
||||
}
|
||||
|
||||
print(f"Отправляемые данные: {json.dumps(mobile_data, indent=2)}")
|
||||
|
||||
# Отправляем запрос к тестовому эндпоинту
|
||||
print(f"Отправляем запрос на {BASE_URL}/debug/mobile-entry")
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/debug/mobile-entry",
|
||||
json=mobile_data
|
||||
)
|
||||
|
||||
print(f"Статус ответа: {response.status_code}")
|
||||
print(f"Заголовки ответа: {response.headers}")
|
||||
|
||||
try:
|
||||
response_json = response.json()
|
||||
print(f"Тело ответа: {json.dumps(response_json, indent=2)}")
|
||||
except json.JSONDecodeError:
|
||||
print(f"Ответ не является JSON: {response.text}")
|
||||
|
||||
if response.status_code >= 200 and response.status_code < 300:
|
||||
print("Тест успешно завершен!")
|
||||
else:
|
||||
print("Тест завершился с ошибкой.")
|
||||
sys.exit(1)
|
||||
|
||||
except requests.exceptions.ConnectionError:
|
||||
print(f"Ошибка подключения к {BASE_URL}. Убедитесь, что сервис запущен.")
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Неожиданная ошибка: {e}")
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
103
tests/test_calendar_mobile.py
Executable file
103
tests/test_calendar_mobile.py
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from datetime import date, datetime
|
||||
import time
|
||||
|
||||
# Настройки для тестирования
|
||||
BASE_URL = "http://localhost:8000" # URL API Gateway
|
||||
TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyOSIsImVtYWlsIjoidGVzdDJAZXhhbXBsZS5jb20iLCJleHAiOjE3NTg4NjY5ODJ9._AXkBLeMI4zxC9shFUS3744miuyO8CDnJD1X1AqbLsw"
|
||||
|
||||
# Функция для добавления записи в календарь через мобильный эндпоинт
|
||||
def create_mobile_calendar_entry():
|
||||
url = f"{BASE_URL}/api/v1/calendar/entries/mobile"
|
||||
|
||||
# Данные для создания записи в формате мобильного приложения
|
||||
today_str = date.today().isoformat()
|
||||
|
||||
data = {
|
||||
"date": today_str,
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3, # medium
|
||||
"symptoms": ["CRAMPS", "HEADACHE"],
|
||||
"mood": "HAPPY",
|
||||
"notes": "Тестовая запись из мобильного приложения"
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
print(f"\n=== Тест мобильного эндпоинта ===")
|
||||
print(f"Отправка запроса POST на {url}")
|
||||
print(f"Данные: {json.dumps(data, indent=2, ensure_ascii=False)}")
|
||||
|
||||
response = requests.post(url, json=data, headers=headers)
|
||||
|
||||
print(f"Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code == 201:
|
||||
print("✓ Запрос успешно выполнен")
|
||||
print(f"Ответ: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ Ошибка при выполнении запроса: {response.text}")
|
||||
return False
|
||||
|
||||
# Функция для получения записей календаря
|
||||
def get_calendar_entries():
|
||||
url = f"{BASE_URL}/api/v1/entries"
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}"
|
||||
}
|
||||
|
||||
print(f"\n=== Получение записей календаря ===")
|
||||
print(f"Отправка запроса GET на {url}")
|
||||
|
||||
response = requests.get(url, headers=headers)
|
||||
|
||||
print(f"Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✓ Запрос успешно выполнен")
|
||||
entries = response.json()
|
||||
print(f"Количество записей: {len(entries)}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ Ошибка при выполнении запроса: {response.text}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Тестирование API календаря для мобильного приложения")
|
||||
|
||||
# Проверяем, что сервисы запущены
|
||||
try:
|
||||
health_check = requests.get(f"{BASE_URL}/api/v1/gateway/health")
|
||||
if health_check.status_code != 200:
|
||||
print("API Gateway недоступен. Убедитесь, что сервисы запущены.")
|
||||
sys.exit(1)
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Не удалось подключиться к API Gateway. Убедитесь, что сервисы запущены.")
|
||||
sys.exit(1)
|
||||
|
||||
# Запускаем тесты
|
||||
success = True
|
||||
|
||||
# Тест 1: Создание записи в календаре через мобильный эндпоинт
|
||||
if not create_mobile_calendar_entry():
|
||||
success = False
|
||||
|
||||
# Тест 2: Проверка получения записей
|
||||
if not get_calendar_entries():
|
||||
success = False
|
||||
|
||||
# Выводим общий результат
|
||||
if success:
|
||||
print("\n✅ Все тесты пройдены успешно!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n❌ Некоторые тесты не пройдены.")
|
||||
sys.exit(1)
|
||||
30
tests/test_debug_endpoint.sh
Executable file
30
tests/test_debug_endpoint.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Проверяем, запущен ли сервер календаря
|
||||
if ! curl -s http://localhost:8004/health > /dev/null; then
|
||||
echo "Сервер календаря не запущен. Запускаем..."
|
||||
cd /home/trevor/dev/chat
|
||||
source .venv/bin/activate
|
||||
PYTHONPATH=/home/trevor/dev/chat python -m uvicorn services.calendar_service.main:app --host 0.0.0.0 --port 8004 &
|
||||
sleep 5
|
||||
echo "Сервер запущен в фоновом режиме"
|
||||
fi
|
||||
|
||||
echo "Проверка работоспособности сервера..."
|
||||
HEALTH_RESPONSE=$(curl -s http://localhost:8004/health)
|
||||
echo "Ответ сервера: $HEALTH_RESPONSE"
|
||||
|
||||
echo -e "\n=== Тестирование отладочного эндпоинта (без аутентификации) ==="
|
||||
curl -v -X POST http://localhost:8004/debug/mobile-entry \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"date": "2023-09-26",
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3,
|
||||
"symptoms": ["CRAMPS", "HEADACHE"],
|
||||
"mood": "NORMAL",
|
||||
"notes": "Тестовая запись из скрипта"
|
||||
}'
|
||||
|
||||
echo -e "\n\n=== Проверка созданных записей ==="
|
||||
curl -s http://localhost:8004/debug/entries | head -n 20
|
||||
121
tests/test_mobile_api.py
Executable file
121
tests/test_mobile_api.py
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import requests
|
||||
from datetime import date
|
||||
|
||||
# Используем сохраненный токен авторизации
|
||||
with open('auth_token.txt', 'r') as f:
|
||||
TOKEN = f.read().strip()
|
||||
|
||||
# Базовый URL для тестирования
|
||||
BASE_URL = "http://localhost:8004"
|
||||
HEADERS = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {TOKEN}"
|
||||
}
|
||||
|
||||
# Функция для тестирования мобильного эндпоинта
|
||||
def test_mobile_endpoint():
|
||||
url = f"{BASE_URL}/api/v1/calendar/entries/mobile"
|
||||
|
||||
# Данные для мобильного запроса
|
||||
data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3,
|
||||
"symptoms": ["CRAMPS", "HEADACHE"],
|
||||
"mood": "NORMAL",
|
||||
"notes": "Тест мобильного API"
|
||||
}
|
||||
|
||||
print("\n1. Тестирование создания записи через мобильный API...")
|
||||
print(f"POST {url}")
|
||||
print(f"Данные: {json.dumps(data, ensure_ascii=False)}")
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=data, headers=HEADERS)
|
||||
|
||||
if response.status_code == 201:
|
||||
print(f"✅ Успешно! Статус: {response.status_code}")
|
||||
print(f"Ответ: {json.dumps(response.json(), ensure_ascii=False, indent=2)}")
|
||||
|
||||
# Теперь проверим, что мы можем получить запись
|
||||
entry_id = response.json().get("id")
|
||||
return entry_id
|
||||
else:
|
||||
print(f"❌ Ошибка! Статус: {response.status_code}")
|
||||
print(f"Ответ: {response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение: {str(e)}")
|
||||
return None
|
||||
|
||||
# Функция для проверки получения всех записей
|
||||
def test_get_entries(entry_id=None):
|
||||
url = f"{BASE_URL}/api/v1/calendar/entries"
|
||||
|
||||
print("\n2. Проверка получения записей календаря...")
|
||||
print(f"GET {url}")
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=HEADERS)
|
||||
|
||||
if response.status_code == 200:
|
||||
print(f"✅ Успешно! Статус: {response.status_code}")
|
||||
entries = response.json()
|
||||
print(f"Получено записей: {len(entries)}")
|
||||
|
||||
# Если у нас есть ID записи, которую мы создали ранее, проверим ее наличие
|
||||
if entry_id:
|
||||
found = False
|
||||
for entry in entries:
|
||||
if entry.get("id") == entry_id:
|
||||
found = True
|
||||
print(f"✅ Созданная запись найдена в списке (ID: {entry_id})")
|
||||
break
|
||||
|
||||
if not found:
|
||||
print(f"❌ Созданная запись не найдена в списке (ID: {entry_id})")
|
||||
else:
|
||||
print(f"❌ Ошибка! Статус: {response.status_code}")
|
||||
print(f"Ответ: {response.text}")
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение: {str(e)}")
|
||||
|
||||
# Тестирование отладочного эндпоинта (без аутентификации)
|
||||
def test_debug_endpoint():
|
||||
url = f"{BASE_URL}/debug/mobile-entry"
|
||||
|
||||
# Данные для мобильного запроса
|
||||
data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3,
|
||||
"symptoms": ["CRAMPS", "HEADACHE"],
|
||||
"mood": "NORMAL",
|
||||
"notes": "Тест отладочного API"
|
||||
}
|
||||
|
||||
print("\n3. Тестирование отладочного эндпоинта...")
|
||||
print(f"POST {url}")
|
||||
print(f"Данные: {json.dumps(data, ensure_ascii=False)}")
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
print(f"✅ Успешно! Статус: {response.status_code}")
|
||||
print(f"Ответ: {json.dumps(response.json(), ensure_ascii=False, indent=2)}")
|
||||
else:
|
||||
print(f"❌ Ошибка! Статус: {response.status_code}")
|
||||
print(f"Ответ: {response.text}")
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== Тестирование мобильного API календарного сервиса ===")
|
||||
entry_id = test_mobile_endpoint()
|
||||
test_get_entries(entry_id)
|
||||
test_debug_endpoint()
|
||||
print("\nТестирование завершено!")
|
||||
103
tests/test_mobile_endpoint.py
Executable file
103
tests/test_mobile_endpoint.py
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python
|
||||
import json
|
||||
import requests
|
||||
import sys
|
||||
from datetime import date
|
||||
|
||||
# API Gateway endpoint
|
||||
BASE_URL = "http://localhost:8004"
|
||||
|
||||
# Имя пользователя и пароль для аутентификации
|
||||
# (предполагается, что у вас есть настроенный доступ)
|
||||
AUTH_DATA = {
|
||||
"username": "test_user",
|
||||
"password": "test_password"
|
||||
}
|
||||
|
||||
# Получение токена аутентификации
|
||||
def get_token():
|
||||
# Обычно мы бы получили токен из сервиса аутентификации,
|
||||
# но для теста будем использовать фиктивный токен
|
||||
# или можем запросить его из user_service
|
||||
return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRlc3RfdXNlciIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImV4cCI6MTY5ODI0OTc2Mn0.HS5-cPVZwv55h0CZO0q_Z_1vNY9w8B6YsPJytj4UI0A"
|
||||
|
||||
# Проверка работоспособности сервиса
|
||||
def check_health():
|
||||
try:
|
||||
response = requests.get(f"{BASE_URL}/health")
|
||||
if response.status_code == 200:
|
||||
print(f"Сервис календаря работает. Ответ: {response.json()}")
|
||||
return True
|
||||
else:
|
||||
print(f"Сервис календаря доступен, но возвращает ошибку: {response.status_code}")
|
||||
return False
|
||||
except requests.exceptions.ConnectionError:
|
||||
print(f"Ошибка подключения к {BASE_URL}. Убедитесь, что сервис запущен.")
|
||||
return False
|
||||
|
||||
# Тестовые данные для мобильного приложения
|
||||
def test_create_calendar_entry_mobile():
|
||||
try:
|
||||
token = get_token()
|
||||
print(f"Токен получен: {token[:15]}...")
|
||||
|
||||
# Данные в формате мобильного приложения
|
||||
mobile_data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3, # средний (1-5)
|
||||
"symptoms": ["CRAMPS", "HEADACHE"], # массив строк
|
||||
"mood": "NORMAL",
|
||||
"notes": "Тестовая запись из мобильного приложения"
|
||||
}
|
||||
|
||||
print(f"Отправляемые данные: {json.dumps(mobile_data, indent=2)}")
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {token}"
|
||||
}
|
||||
|
||||
print(f"Отправляем запрос на {BASE_URL}/debug/mobile-entry")
|
||||
|
||||
# Используем тестовый эндпоинт без аутентификации
|
||||
print(f"Отправляем запрос на {BASE_URL}/debug/mobile-entry")
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/debug/mobile-entry",
|
||||
json=mobile_data
|
||||
)
|
||||
|
||||
print(f"Статус ответа: {response.status_code}")
|
||||
|
||||
if response.status_code >= 200 and response.status_code < 300:
|
||||
print(f"Тело успешного ответа: {json.dumps(response.json(), indent=2)}")
|
||||
return response.json()
|
||||
else:
|
||||
print("Ошибка при создании записи")
|
||||
try:
|
||||
print(f"Тело ответа с ошибкой: {json.dumps(response.json(), indent=2)}")
|
||||
except json.JSONDecodeError:
|
||||
print(f"Тело ответа не является JSON: {response.text}")
|
||||
return None
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Ошибка при выполнении запроса: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Неожиданная ошибка: {e}")
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Тестирование создания записи календаря из мобильного приложения...")
|
||||
|
||||
if not check_health():
|
||||
print("Сервис недоступен. Тестирование прекращено.")
|
||||
sys.exit(1)
|
||||
|
||||
result = test_create_calendar_entry_mobile()
|
||||
|
||||
if result:
|
||||
print("Тест успешно завершен!")
|
||||
else:
|
||||
print("Тест завершился с ошибкой.")
|
||||
sys.exit(1)
|
||||
171
tests/test_mobile_endpoints.py
Normal file
171
tests/test_mobile_endpoints.py
Normal file
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import requests
|
||||
import sys
|
||||
import traceback
|
||||
from datetime import date
|
||||
|
||||
# API Gateway endpoint
|
||||
BASE_URL = "http://localhost:8004"
|
||||
|
||||
# Токен для аутентификации - замените на действующий токен
|
||||
AUTH_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyOSIsImVtYWlsIjoidGVzdDJAZXhhbXBsZS5jb20iLCJleHAiOjE3NTg4NjY5ODJ9._AXkBLeMI4zxC9shFUS3744miuyO8CDnJD1X1AqbLsw"
|
||||
|
||||
def test_health():
|
||||
"""Проверка доступности сервиса"""
|
||||
try:
|
||||
response = requests.get(f"{BASE_URL}/health")
|
||||
print(f"Статус сервиса: {response.status_code}")
|
||||
print(f"Ответ: {response.text}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Ошибка при проверке сервиса: {e}")
|
||||
return False
|
||||
|
||||
def test_authenticated_endpoint():
|
||||
"""Тестирование аутентифицированного эндпоинта для мобильного приложения"""
|
||||
print("\n=== Тестирование аутентифицированного эндпоинта ===")
|
||||
|
||||
# Данные в формате мобильного приложения
|
||||
mobile_data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3,
|
||||
"symptoms": ["CRAMPS", "HEADACHE"],
|
||||
"mood": "NORMAL",
|
||||
"notes": "Запись из мобильного приложения через аутентифицированный эндпоинт"
|
||||
}
|
||||
|
||||
print(f"Отправляемые данные: {json.dumps(mobile_data, indent=2)}")
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {AUTH_TOKEN}"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/api/v1/calendar/entries/mobile",
|
||||
headers=headers,
|
||||
json=mobile_data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
print(f"Статус ответа: {response.status_code}")
|
||||
|
||||
if response.status_code >= 200 and response.status_code < 300:
|
||||
print(f"Тело успешного ответа: {json.dumps(response.json(), indent=2)}")
|
||||
return True
|
||||
else:
|
||||
print("Ошибка при создании записи через аутентифицированный эндпоинт")
|
||||
try:
|
||||
print(f"Тело ответа с ошибкой: {json.dumps(response.json(), indent=2)}")
|
||||
except:
|
||||
print(f"Тело ответа не является JSON: {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Ошибка при выполнении запроса: {e}")
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def test_debug_endpoint():
|
||||
"""Тестирование отладочного эндпоинта для мобильного приложения (без аутентификации)"""
|
||||
print("\n=== Тестирование отладочного эндпоинта (без аутентификации) ===")
|
||||
|
||||
# Данные в формате мобильного приложения
|
||||
mobile_data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 4,
|
||||
"symptoms": ["BACKACHE", "BLOATING"],
|
||||
"mood": "HAPPY",
|
||||
"notes": "Запись из мобильного приложения через отладочный эндпоинт"
|
||||
}
|
||||
|
||||
print(f"Отправляемые данные: {json.dumps(mobile_data, indent=2)}")
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/debug/mobile-entry",
|
||||
headers=headers,
|
||||
json=mobile_data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
print(f"Статус ответа: {response.status_code}")
|
||||
|
||||
if response.status_code >= 200 and response.status_code < 300:
|
||||
print(f"Тело успешного ответа: {json.dumps(response.json(), indent=2)}")
|
||||
return True
|
||||
else:
|
||||
print("Ошибка при создании записи через отладочный эндпоинт")
|
||||
try:
|
||||
print(f"Тело ответа с ошибкой: {json.dumps(response.json(), indent=2)}")
|
||||
except:
|
||||
print(f"Тело ответа не является JSON: {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Ошибка при выполнении запроса: {e}")
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def verify_entries_created():
|
||||
"""Проверка, что записи были созданы в БД"""
|
||||
print("\n=== Проверка созданных записей ===")
|
||||
|
||||
try:
|
||||
response = requests.get(f"{BASE_URL}/debug/entries")
|
||||
|
||||
print(f"Статус ответа: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
entries = response.json()
|
||||
print(f"Количество записей в БД: {len(entries)}")
|
||||
print("Последние 2 записи:")
|
||||
for entry in entries[-2:]:
|
||||
print(json.dumps(entry, indent=2))
|
||||
return True
|
||||
else:
|
||||
print(f"Ошибка при получении записей: {response.status_code}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Ошибка при проверке записей: {e}")
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def main():
|
||||
print("=== Тестирование мобильных эндпоинтов календарного сервиса ===")
|
||||
|
||||
if not test_health():
|
||||
print("Сервис недоступен. Завершение тестирования.")
|
||||
return 1
|
||||
|
||||
debug_result = test_debug_endpoint()
|
||||
auth_result = test_authenticated_endpoint()
|
||||
|
||||
if debug_result and auth_result:
|
||||
print("\nВсе тесты успешно пройдены!")
|
||||
verify_entries_created()
|
||||
return 0
|
||||
else:
|
||||
print("\nНекоторые тесты не пройдены.")
|
||||
if debug_result:
|
||||
print("✓ Отладочный эндпоинт работает")
|
||||
else:
|
||||
print("✗ Отладочный эндпоинт не работает")
|
||||
|
||||
if auth_result:
|
||||
print("✓ Аутентифицированный эндпоинт работает")
|
||||
else:
|
||||
print("✗ Аутентифицированный эндпоинт не работает")
|
||||
|
||||
verify_entries_created()
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
347
tests/test_nutrition_api.py
Executable file
347
tests/test_nutrition_api.py
Executable file
@@ -0,0 +1,347 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для тестирования API сервиса питания (Nutrition Service)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Загружаем .env файл
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
env_path = os.path.join(current_dir, ".env")
|
||||
load_dotenv(env_path)
|
||||
print(f"✅ Загружен .env из: {env_path}")
|
||||
|
||||
# Базовый URL API
|
||||
BASE_URL = os.environ.get("NUTRITION_API_URL", "http://localhost:8006/api/v1/nutrition")
|
||||
AUTH_URL = os.environ.get("AUTH_API_URL", "http://localhost:8001/api/v1/auth")
|
||||
|
||||
# Настройки для тестовых данных
|
||||
TEST_USER = {
|
||||
"username": "test_nutrition_user",
|
||||
"password": "Test123!",
|
||||
"email": "test_nutrition@example.com",
|
||||
"first_name": "Test",
|
||||
"last_name": "Nutrition",
|
||||
"phone": "+79991234999"
|
||||
}
|
||||
|
||||
def get_auth_token():
|
||||
"""Получение токена авторизации"""
|
||||
print("\n🔑 Получаем токен авторизации...")
|
||||
|
||||
# Пытаемся сначала войти
|
||||
try:
|
||||
login_data = {
|
||||
"username": TEST_USER["username"],
|
||||
"password": TEST_USER["password"]
|
||||
}
|
||||
|
||||
login_response = requests.post(
|
||||
f"{AUTH_URL}/login",
|
||||
json=login_data
|
||||
)
|
||||
|
||||
if login_response.status_code == 200:
|
||||
token = login_response.json().get("access_token")
|
||||
print("✅ Успешный вход в систему!")
|
||||
return token
|
||||
except Exception as e:
|
||||
print(f"⚠️ Ошибка при попытке входа: {e}")
|
||||
|
||||
# Если вход не удался, пробуем регистрацию
|
||||
try:
|
||||
register_response = requests.post(
|
||||
f"{AUTH_URL}/register",
|
||||
json=TEST_USER
|
||||
)
|
||||
|
||||
if register_response.status_code == 201:
|
||||
print("✅ Пользователь успешно зарегистрирован!")
|
||||
|
||||
# Теперь входим с новыми учетными данными
|
||||
login_data = {
|
||||
"username": TEST_USER["username"],
|
||||
"password": TEST_USER["password"]
|
||||
}
|
||||
|
||||
login_response = requests.post(
|
||||
f"{AUTH_URL}/login",
|
||||
json=login_data
|
||||
)
|
||||
|
||||
if login_response.status_code == 200:
|
||||
token = login_response.json().get("access_token")
|
||||
print("✅ Успешный вход в систему!")
|
||||
return token
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка при регистрации: {e}")
|
||||
|
||||
print("❌ Не удалось получить токен авторизации")
|
||||
return None
|
||||
|
||||
def search_food(token, query="apple", max_results=5):
|
||||
"""Поиск продуктов питания"""
|
||||
print(f"\n🔍 Поиск продуктов по запросу '{query}'...")
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
data = {
|
||||
"query": query,
|
||||
"max_results": max_results
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/search",
|
||||
json=data,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"📥 Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
results = response.json()
|
||||
print(f"✅ Найдено продуктов: {len(results)}")
|
||||
|
||||
# Выводим первые 3 результата
|
||||
for i, food in enumerate(results[:3]):
|
||||
print(f" {i+1}. [{food.get('id')}] {food.get('name')}")
|
||||
print(f" {food.get('description')}")
|
||||
print(f" Калории: {food.get('calories')} ккал/100г")
|
||||
|
||||
return results
|
||||
else:
|
||||
print(f"❌ Ошибка при поиске: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение при поиске: {e}")
|
||||
return None
|
||||
|
||||
def add_diary_entry(token, food_id=1):
|
||||
"""Добавление записи в дневник питания"""
|
||||
print(f"\n📝 Добавление записи в дневник питания (продукт ID: {food_id})...")
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
data = {
|
||||
"food_item_id": food_id,
|
||||
"entry_date": today,
|
||||
"meal_type": "breakfast",
|
||||
"quantity": 1.0,
|
||||
"unit": "piece",
|
||||
"notes": "Тестовая запись"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/diary",
|
||||
json=data,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"📥 Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code in [200, 201]:
|
||||
result = response.json()
|
||||
print("✅ Запись успешно добавлена в дневник питания!")
|
||||
print(f" ID записи: {result.get('id')}")
|
||||
print(f" Калории: {result.get('calories')} ккал")
|
||||
return result
|
||||
else:
|
||||
print(f"❌ Ошибка при добавлении записи: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение при добавлении записи: {e}")
|
||||
return None
|
||||
|
||||
def get_diary_entries(token):
|
||||
"""Получение записей дневника за текущий день"""
|
||||
print("\n📋 Получение записей дневника питания...")
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{BASE_URL}/diary?date={today}",
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"📥 Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
results = response.json()
|
||||
print(f"✅ Получено записей: {len(results)}")
|
||||
|
||||
# Выводим записи
|
||||
for i, entry in enumerate(results):
|
||||
print(f" {i+1}. Прием пищи: {entry.get('meal_type')}")
|
||||
print(f" Продукт ID: {entry.get('food_item_id')}")
|
||||
print(f" Калории: {entry.get('calories')} ккал")
|
||||
|
||||
return results
|
||||
else:
|
||||
print(f"❌ Ошибка при получении записей: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение при получении записей: {e}")
|
||||
return None
|
||||
|
||||
def add_water_entry(token, amount_ml=250):
|
||||
"""Добавление записи о потреблении воды"""
|
||||
print(f"\n💧 Добавление записи о потреблении воды ({amount_ml} мл)...")
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
data = {
|
||||
"amount_ml": amount_ml,
|
||||
"entry_date": today,
|
||||
"notes": "Тестовая запись"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/water",
|
||||
json=data,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"📥 Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code in [200, 201]:
|
||||
result = response.json()
|
||||
print("✅ Запись о потреблении воды успешно добавлена!")
|
||||
print(f" ID записи: {result.get('id')}")
|
||||
print(f" Объем: {result.get('amount_ml')} мл")
|
||||
return result
|
||||
else:
|
||||
print(f"❌ Ошибка при добавлении записи о воде: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение при добавлении записи о воде: {e}")
|
||||
return None
|
||||
|
||||
def add_activity_entry(token):
|
||||
"""Добавление записи о физической активности"""
|
||||
print("\n🏃♀️ Добавление записи о физической активности...")
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
data = {
|
||||
"entry_date": today,
|
||||
"activity_type": "walking",
|
||||
"duration_minutes": 30,
|
||||
"distance_km": 2.5,
|
||||
"intensity": "medium",
|
||||
"notes": "Тестовая активность"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/activity",
|
||||
json=data,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"📥 Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code in [200, 201]:
|
||||
result = response.json()
|
||||
print("✅ Запись о физической активности успешно добавлена!")
|
||||
print(f" ID записи: {result.get('id')}")
|
||||
print(f" Тип: {result.get('activity_type')}")
|
||||
print(f" Продолжительность: {result.get('duration_minutes')} мин")
|
||||
print(f" Потрачено калорий: {result.get('calories_burned')} ккал")
|
||||
return result
|
||||
else:
|
||||
print(f"❌ Ошибка при добавлении записи об активности: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение при добавлении записи об активности: {e}")
|
||||
return None
|
||||
|
||||
def get_daily_summary(token):
|
||||
"""Получение дневной сводки"""
|
||||
print("\n📊 Получение сводки за день...")
|
||||
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
f"{BASE_URL}/summary?date={today}",
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print(f"📥 Код ответа: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
print("✅ Сводка за день успешно получена!")
|
||||
print(f" Всего калорий: {result.get('total_calories')} ккал")
|
||||
print(f" Всего белка: {result.get('total_protein')} г")
|
||||
print(f" Всего жиров: {result.get('total_fat')} г")
|
||||
print(f" Всего углеводов: {result.get('total_carbs')} г")
|
||||
print(f" Потреблено воды: {result.get('water_consumed_ml')} мл")
|
||||
print(f" Активность: {result.get('activity_minutes')} мин")
|
||||
print(f" Сожжено калорий: {result.get('calories_burned')} ккал")
|
||||
return result
|
||||
else:
|
||||
print(f"❌ Ошибка при получении сводки: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ Исключение при получении сводки: {e}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
"""Основная функция для тестирования API сервиса питания"""
|
||||
print("\n🚀 Запуск тестирования API сервиса питания...\n")
|
||||
|
||||
# Получаем токен авторизации
|
||||
token = get_auth_token()
|
||||
if not token:
|
||||
print("❌ Невозможно продолжить тестирование без авторизации")
|
||||
sys.exit(1)
|
||||
|
||||
# Выполняем поиск продуктов
|
||||
search_results = search_food(token, "apple")
|
||||
|
||||
if search_results and len(search_results) > 0:
|
||||
# Используем первый найденный продукт для дальнейшего тестирования
|
||||
food_id = search_results[0].get("id")
|
||||
|
||||
# Добавляем запись в дневник питания
|
||||
add_diary_entry(token, food_id)
|
||||
|
||||
# Получаем записи дневника
|
||||
get_diary_entries(token)
|
||||
else:
|
||||
# Если поиск не дал результатов, продолжаем тестирование с предполагаемым ID продукта
|
||||
print("⚠️ Используем предполагаемый ID продукта для дальнейших тестов")
|
||||
add_diary_entry(token, 1)
|
||||
|
||||
# Добавляем записи о воде и активности
|
||||
add_water_entry(token)
|
||||
add_activity_entry(token)
|
||||
|
||||
# Получаем дневную сводку
|
||||
get_daily_summary(token)
|
||||
|
||||
print("\n✅ Тестирование API сервиса питания завершено!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
189
tests/test_nutrition_service.sh
Executable file
189
tests/test_nutrition_service.sh
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Скрипт для тестирования API сервиса питания через cURL
|
||||
|
||||
# Настройки
|
||||
API_BASE_URL="http://localhost:8006/api/v1/nutrition"
|
||||
AUTH_URL="http://localhost:8001/api/v1/auth"
|
||||
TODAY=$(date +"%Y-%m-%d")
|
||||
TEST_USERNAME="test_nutrition_user"
|
||||
TEST_PASSWORD="Test123!"
|
||||
|
||||
# Цветной вывод
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}🚀 Запуск тестов для Nutrition Service API${NC}"
|
||||
echo "---------------------------------------------"
|
||||
|
||||
# Шаг 1: Авторизация и получение токена
|
||||
echo -e "${BLUE}📝 Шаг 1: Получение токена авторизации${NC}"
|
||||
|
||||
# Попытка входа
|
||||
login_response=$(curl -s -X POST "${AUTH_URL}/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "'"${TEST_USERNAME}"'",
|
||||
"password": "'"${TEST_PASSWORD}"'"
|
||||
}')
|
||||
|
||||
# Проверяем, успешен ли вход
|
||||
if [[ $login_response == *"access_token"* ]]; then
|
||||
TOKEN=$(echo $login_response | grep -o '"access_token":"[^"]*' | sed 's/"access_token":"//')
|
||||
echo -e "${GREEN}✅ Вход успешен!${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Вход не удался, пробуем регистрацию...${NC}"
|
||||
|
||||
# Пробуем зарегистрировать пользователя
|
||||
curl -s -X POST "${AUTH_URL}/register" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "'"${TEST_USERNAME}@example.com"'",
|
||||
"username": "'"${TEST_USERNAME}"'",
|
||||
"password": "'"${TEST_PASSWORD}"'",
|
||||
"first_name": "Test",
|
||||
"last_name": "Nutrition",
|
||||
"phone": "+79991234999"
|
||||
}' > /dev/null
|
||||
|
||||
# После регистрации пробуем войти снова
|
||||
login_response=$(curl -s -X POST "${AUTH_URL}/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "'"${TEST_USERNAME}"'",
|
||||
"password": "'"${TEST_PASSWORD}"'"
|
||||
}')
|
||||
|
||||
if [[ $login_response == *"access_token"* ]]; then
|
||||
TOKEN=$(echo $login_response | grep -o '"access_token":"[^"]*' | sed 's/"access_token":"//')
|
||||
echo -e "${GREEN}✅ Регистрация и вход успешны!${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Не удалось получить токен авторизации${NC}"
|
||||
echo "Ответ сервера: $login_response"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Шаг 2: Поиск продуктов
|
||||
echo -e "\n${BLUE}📝 Шаг 2: Поиск продуктов${NC}"
|
||||
search_response=$(curl -s -X POST "${API_BASE_URL}/search" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-d '{
|
||||
"query": "apple",
|
||||
"max_results": 5
|
||||
}')
|
||||
|
||||
echo "Результат поиска:"
|
||||
echo "$search_response" | grep -o '"name":"[^"]*' | head -3 | sed 's/"name":"/- /'
|
||||
echo "..."
|
||||
|
||||
# Получаем ID первого продукта из результатов поиска
|
||||
FOOD_ID=$(echo $search_response | grep -o '"id":[0-9]*' | head -1 | sed 's/"id"://')
|
||||
if [[ -z "$FOOD_ID" ]]; then
|
||||
echo -e "${YELLOW}⚠️ Не удалось получить ID продукта, используем значение по умолчанию${NC}"
|
||||
FOOD_ID=1
|
||||
else
|
||||
echo -e "${GREEN}✅ Получен ID продукта: ${FOOD_ID}${NC}"
|
||||
fi
|
||||
|
||||
# Шаг 3: Добавление записи в дневник питания
|
||||
echo -e "\n${BLUE}📝 Шаг 3: Добавление записи в дневник питания${NC}"
|
||||
diary_response=$(curl -s -X POST "${API_BASE_URL}/diary" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-d '{
|
||||
"food_item_id": '"${FOOD_ID}"',
|
||||
"entry_date": "'"${TODAY}"'",
|
||||
"meal_type": "breakfast",
|
||||
"quantity": 1.5,
|
||||
"unit": "piece",
|
||||
"notes": "Тестовая запись"
|
||||
}')
|
||||
|
||||
if [[ $diary_response == *"id"* ]]; then
|
||||
echo -e "${GREEN}✅ Запись добавлена в дневник питания${NC}"
|
||||
echo "Детали записи:"
|
||||
echo "$diary_response" | grep -o '"calories":[0-9.]*' | sed 's/"calories":/Калории: /'
|
||||
else
|
||||
echo -e "${RED}❌ Ошибка при добавлении записи в дневник${NC}"
|
||||
echo "Ответ сервера: $diary_response"
|
||||
fi
|
||||
|
||||
# Шаг 4: Получение записей дневника
|
||||
echo -e "\n${BLUE}📝 Шаг 4: Получение записей дневника${NC}"
|
||||
get_diary_response=$(curl -s -X GET "${API_BASE_URL}/diary?date=${TODAY}" \
|
||||
-H "Authorization: Bearer ${TOKEN}")
|
||||
|
||||
if [[ $get_diary_response == *"meal_type"* ]]; then
|
||||
echo -e "${GREEN}✅ Записи дневника успешно получены${NC}"
|
||||
echo "Количество записей: $(echo $get_diary_response | grep -o '"meal_type"' | wc -l)"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Нет записей в дневнике или ошибка получения${NC}"
|
||||
echo "Ответ сервера: $get_diary_response"
|
||||
fi
|
||||
|
||||
# Шаг 5: Добавление записи о потреблении воды
|
||||
echo -e "\n${BLUE}📝 Шаг 5: Добавление записи о потреблении воды${NC}"
|
||||
water_response=$(curl -s -X POST "${API_BASE_URL}/water" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-d '{
|
||||
"amount_ml": 250,
|
||||
"entry_date": "'"${TODAY}"'",
|
||||
"notes": "Утренний стакан воды"
|
||||
}')
|
||||
|
||||
if [[ $water_response == *"id"* ]]; then
|
||||
echo -e "${GREEN}✅ Запись о потреблении воды добавлена${NC}"
|
||||
echo "Детали записи:"
|
||||
echo "$water_response" | grep -o '"amount_ml":[0-9]*' | sed 's/"amount_ml":/Объем (мл): /'
|
||||
else
|
||||
echo -e "${RED}❌ Ошибка при добавлении записи о воде${NC}"
|
||||
echo "Ответ сервера: $water_response"
|
||||
fi
|
||||
|
||||
# Шаг 6: Добавление записи о физической активности
|
||||
echo -e "\n${BLUE}📝 Шаг 6: Добавление записи о физической активности${NC}"
|
||||
activity_response=$(curl -s -X POST "${API_BASE_URL}/activity" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-d '{
|
||||
"entry_date": "'"${TODAY}"'",
|
||||
"activity_type": "running",
|
||||
"duration_minutes": 30,
|
||||
"distance_km": 5.2,
|
||||
"intensity": "medium",
|
||||
"notes": "Утренняя пробежка"
|
||||
}')
|
||||
|
||||
if [[ $activity_response == *"id"* ]]; then
|
||||
echo -e "${GREEN}✅ Запись о физической активности добавлена${NC}"
|
||||
echo "Детали записи:"
|
||||
echo "$activity_response" | grep -o '"duration_minutes":[0-9]*' | sed 's/"duration_minutes":/Продолжительность (мин): /'
|
||||
echo "$activity_response" | grep -o '"calories_burned":[0-9.]*' | sed 's/"calories_burned":/Сожжено калорий: /'
|
||||
else
|
||||
echo -e "${RED}❌ Ошибка при добавлении записи об активности${NC}"
|
||||
echo "Ответ сервера: $activity_response"
|
||||
fi
|
||||
|
||||
# Шаг 7: Получение сводки за день
|
||||
echo -e "\n${BLUE}📝 Шаг 7: Получение сводки за день${NC}"
|
||||
summary_response=$(curl -s -X GET "${API_BASE_URL}/summary?date=${TODAY}" \
|
||||
-H "Authorization: Bearer ${TOKEN}")
|
||||
|
||||
if [[ $summary_response == *"total_calories"* ]]; then
|
||||
echo -e "${GREEN}✅ Дневная сводка успешно получена${NC}"
|
||||
echo "Детали сводки:"
|
||||
echo "$summary_response" | grep -o '"total_calories":[0-9.]*' | sed 's/"total_calories":/Всего калорий: /'
|
||||
echo "$summary_response" | grep -o '"water_consumed_ml":[0-9]*' | sed 's/"water_consumed_ml":/Потреблено воды (мл): /'
|
||||
echo "$summary_response" | grep -o '"activity_minutes":[0-9]*' | sed 's/"activity_minutes":/Минуты активности: /'
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Нет данных для сводки или ошибка получения${NC}"
|
||||
echo "Ответ сервера: $summary_response"
|
||||
fi
|
||||
|
||||
echo -e "\n${GREEN}✅ Тестирование API сервиса питания завершено!${NC}"
|
||||
184
tests/test_standalone.py
Normal file
184
tests/test_standalone.py
Normal file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import sys
|
||||
import asyncio
|
||||
import uvicorn
|
||||
from fastapi import FastAPI, Depends, HTTPException
|
||||
from datetime import date
|
||||
from typing import Dict, Optional, List
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
# Импортируем необходимые модули из календарного сервиса
|
||||
from services.calendar_service.schemas import (
|
||||
EntryType, FlowIntensity, MoodType, CalendarEntryCreate, CalendarEntryResponse
|
||||
)
|
||||
from services.calendar_service.mobile_endpoint import MobileCalendarEntryCreate
|
||||
from shared.database import get_db
|
||||
|
||||
# Создаем тестовое приложение
|
||||
app = FastAPI(title="Test Mobile Endpoint")
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
"""Health check endpoint"""
|
||||
return {"status": "healthy", "service": "test_mobile_endpoint"}
|
||||
|
||||
@app.post("/debug/mobile-entry", status_code=201)
|
||||
async def test_mobile_endpoint(
|
||||
mobile_entry: MobileCalendarEntryCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Test mobile endpoint without authentication"""
|
||||
|
||||
# Преобразуем симптомы из списка в строку
|
||||
symptoms_str = ""
|
||||
if mobile_entry.symptoms:
|
||||
symptoms_str = ", ".join(mobile_entry.symptoms)
|
||||
|
||||
# Преобразуем данные из мобильного формата в формат сервера
|
||||
entry_type = EntryType.PERIOD
|
||||
if mobile_entry.type == "MENSTRUATION":
|
||||
entry_type = EntryType.PERIOD
|
||||
elif mobile_entry.type == "OVULATION":
|
||||
entry_type = EntryType.OVULATION
|
||||
else:
|
||||
entry_type = EntryType.SYMPTOMS
|
||||
|
||||
# Преобразуем интенсивность потока
|
||||
flow_intensity = None
|
||||
if mobile_entry.flow_intensity is not None:
|
||||
if mobile_entry.flow_intensity <= 1:
|
||||
flow_intensity = FlowIntensity.SPOTTING
|
||||
elif mobile_entry.flow_intensity <= 2:
|
||||
flow_intensity = FlowIntensity.LIGHT
|
||||
elif mobile_entry.flow_intensity <= 4:
|
||||
flow_intensity = FlowIntensity.MEDIUM
|
||||
else:
|
||||
flow_intensity = FlowIntensity.HEAVY
|
||||
|
||||
# Преобразуем настроение
|
||||
mood = None
|
||||
if mobile_entry.mood:
|
||||
if mobile_entry.mood == "HAPPY":
|
||||
mood = MoodType.HAPPY
|
||||
elif mobile_entry.mood == "SAD":
|
||||
mood = MoodType.SAD
|
||||
elif mobile_entry.mood == "NORMAL":
|
||||
mood = MoodType.HAPPY # NORMAL мапится на HAPPY
|
||||
elif mobile_entry.mood == "ANXIOUS":
|
||||
mood = MoodType.ANXIOUS
|
||||
elif mobile_entry.mood == "IRRITATED":
|
||||
mood = MoodType.IRRITATED
|
||||
elif mobile_entry.mood == "ENERGETIC":
|
||||
mood = MoodType.ENERGETIC
|
||||
elif mobile_entry.mood == "TIRED":
|
||||
mood = MoodType.TIRED
|
||||
|
||||
# Создаем объект CalendarEntryResponse для возврата
|
||||
response = {
|
||||
"id": 1,
|
||||
"user_id": 1,
|
||||
"entry_date": mobile_entry.date.isoformat(),
|
||||
"entry_type": entry_type.value,
|
||||
"flow_intensity": flow_intensity.value if flow_intensity else None,
|
||||
"period_symptoms": "",
|
||||
"mood": mood.value if mood else None,
|
||||
"energy_level": 1, # Минимальное значение должно быть 1
|
||||
"sleep_hours": 0,
|
||||
"symptoms": symptoms_str,
|
||||
"medications": "",
|
||||
"notes": mobile_entry.notes or "",
|
||||
"created_at": date.today().isoformat(),
|
||||
"updated_at": date.today().isoformat(),
|
||||
}
|
||||
|
||||
return response
|
||||
|
||||
# Функция для отправки тестового запроса
|
||||
async def send_test_request():
|
||||
"""Отправка тестового запроса к эндпоинту"""
|
||||
import httpx
|
||||
|
||||
# Данные в формате мобильного приложения
|
||||
mobile_data = {
|
||||
"date": date.today().isoformat(),
|
||||
"type": "MENSTRUATION",
|
||||
"flow_intensity": 3, # средний (1-5)
|
||||
"symptoms": ["CRAMPS", "HEADACHE"], # массив строк
|
||||
"mood": "NORMAL",
|
||||
"notes": "Тестовая запись из мобильного приложения"
|
||||
}
|
||||
|
||||
print(f"Отправляемые данные: {json.dumps(mobile_data, indent=2)}")
|
||||
|
||||
# Подождем, пока сервис запустится
|
||||
await asyncio.sleep(2)
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
# Проверяем работоспособность сервиса
|
||||
health_response = await client.get("http://localhost:8080/health")
|
||||
print(f"Проверка работоспособности: {health_response.status_code}")
|
||||
print(f"Ответ сервиса: {health_response.text}")
|
||||
|
||||
# Отправляем запрос к тестовому эндпоинту
|
||||
response = await client.post(
|
||||
"http://localhost:8080/debug/mobile-entry",
|
||||
json=mobile_data
|
||||
)
|
||||
|
||||
print(f"Статус ответа: {response.status_code}")
|
||||
|
||||
if response.status_code >= 200 and response.status_code < 300:
|
||||
print(f"Тело успешного ответа: {json.dumps(response.json(), indent=2)}")
|
||||
return True
|
||||
else:
|
||||
print("Ошибка при создании записи")
|
||||
try:
|
||||
print(f"Тело ответа с ошибкой: {json.dumps(response.json(), indent=2)}")
|
||||
except:
|
||||
print(f"Тело ответа не является JSON: {response.text}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка при выполнении запроса: {e}")
|
||||
return False
|
||||
|
||||
# Основная функция
|
||||
async def main():
|
||||
# Запускаем сервер в отдельном процессе
|
||||
config = uvicorn.Config(app, host="0.0.0.0", port=8080, log_level="info")
|
||||
server = uvicorn.Server(config)
|
||||
|
||||
# Создаем задачу для запуска сервера
|
||||
server_task = asyncio.create_task(server.serve())
|
||||
|
||||
# Дадим серверу немного времени на запуск
|
||||
await asyncio.sleep(1)
|
||||
|
||||
try:
|
||||
# Отправляем тестовый запрос
|
||||
result = await send_test_request()
|
||||
|
||||
if result:
|
||||
print("Тест успешно завершен!")
|
||||
return 0
|
||||
else:
|
||||
print("Тест завершился с ошибкой.")
|
||||
return 1
|
||||
finally:
|
||||
# Останавливаем сервер
|
||||
server.should_exit = True
|
||||
await server_task
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Запускаем асинхронную функцию main()
|
||||
import asyncio
|
||||
try:
|
||||
exit_code = asyncio.run(main())
|
||||
sys.exit(exit_code)
|
||||
except KeyboardInterrupt:
|
||||
print("Выполнение прервано")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user