#!/usr/bin/env python3 """ Скрипт для тестирования API приложения для безопасности женщин с использованием Python """ import json import requests import time import sys from datetime import datetime, timedelta from termcolor import colored BASE_URLS = { "gateway": "http://localhost:8000", "user": "http://localhost:8001", "emergency": "http://localhost:8002", "location": "http://localhost:8003", "calendar": "http://localhost:8004", "notification": "http://localhost:8005" } # Класс для тестирования API class APITester: def __init__(self): self.token = None self.user_id = None self.emergency_contact_id = None self.alert_id = None self.calendar_entry_id = None self.device_id = None def print_section(self, title): """Печать заголовка секции""" print("\n" + colored("="*50, "yellow")) print(colored(f" {title}", "green", attrs=["bold"])) print(colored("="*50, "yellow")) def print_step(self, title): """Печать шага тестирования""" print(colored(f"\n▶ {title}", "cyan")) def print_response(self, response, title=None): """Печать ответа API""" if title: print(colored(f"● {title}:", "magenta")) try: if response.status_code >= 400: print(colored(f"HTTP Status: {response.status_code}", "red")) else: print(colored(f"HTTP Status: {response.status_code}", "green")) json_response = response.json() print(json.dumps(json_response, indent=2, ensure_ascii=False)) return json_response except: print(colored("Не удалось распарсить JSON ответ", "red")) print(response.text) return {} def check_services(self): """Проверка доступности всех сервисов""" self.print_section("Проверка доступности сервисов") all_up = True for service_name, url in BASE_URLS.items(): print(colored(f"Проверка {service_name.upper()} ({url})...", "cyan"), end=" ") try: # Пробуем разные варианты эндпоинтов health health_endpoints = ["/health", "/api/v1/health"] service_up = False for endpoint in health_endpoints: try: response = requests.get(f"{url}{endpoint}", timeout=5) if response.status_code == 200: if "status" in response.json() and "healthy" in response.json()["status"]: service_up = True break except: pass if service_up: print(colored("OK", "green")) else: print(colored("НЕДОСТУПЕН", "red")) all_up = False except Exception as e: print(colored(f"ОШИБКА: {str(e)}", "red")) all_up = False if not all_up: choice = input(colored("Некоторые сервисы недоступны. Продолжить тестирование? (y/n): ", "yellow")) if choice.lower() != "y": sys.exit(1) def register_user(self): """Регистрация нового пользователя""" self.print_step("Регистрация нового пользователя") data = { "username": f"testuser_{int(time.time())}", # Уникальное имя для каждого запуска "email": f"test{int(time.time())}@example.com", "password": "Test@1234", "full_name": "Тестовый Пользователь", "phone_number": "+79001234567" } response = requests.post(f"{BASE_URLS['user']}/api/v1/users/register", json=data) user_data = self.print_response(response, "Ответ сервера") if response.status_code == 201 or response.status_code == 200: print(colored("✓ Пользователь успешно зарегистрирован", "green")) self.user_id = user_data.get("id") return data else: print(colored("✗ Ошибка при регистрации пользователя", "red")) return None def login_user(self, credentials): """Авторизация пользователя""" self.print_step("Авторизация пользователя") data = { "username": credentials["username"], "password": credentials["password"] } response = requests.post(f"{BASE_URLS['user']}/api/v1/auth/login", json=data) login_data = self.print_response(response, "Ответ сервера") if response.status_code == 200 and "access_token" in login_data: self.token = login_data["access_token"] print(colored("✓ Успешная авторизация", "green")) return True else: print(colored("✗ Ошибка авторизации", "red")) return False def update_profile(self): """Обновление профиля пользователя""" self.print_step("Обновление профиля пользователя") data = { "full_name": "Обновленное Имя", "phone_number": "+79009876543" } headers = {"Authorization": f"Bearer {self.token}"} response = requests.patch(f"{BASE_URLS['user']}/api/v1/users/me", json=data, headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200: print(colored("✓ Профиль успешно обновлен", "green")) return True else: print(colored("✗ Ошибка при обновлении профиля", "red")) return False def add_emergency_contact(self): """Добавление контакта для экстренной связи""" self.print_step("Добавление экстренного контакта") data = { "name": "Экстренный Контакт", "phone_number": "+79991112233", "relationship": "Родственник" } headers = {"Authorization": f"Bearer {self.token}"} response = requests.post(f"{BASE_URLS['user']}/api/v1/users/me/emergency-contacts", json=data, headers=headers) contact_data = self.print_response(response, "Ответ сервера") if response.status_code == 201 or response.status_code == 200: self.emergency_contact_id = contact_data.get("id") print(colored("✓ Экстренный контакт добавлен", "green")) return True else: print(colored("✗ Ошибка при добавлении контакта", "red")) return False def update_location(self): """Обновление местоположения пользователя""" self.print_step("Обновление местоположения") data = { "latitude": 55.7558, "longitude": 37.6173, "accuracy": 10.0 } headers = {"Authorization": f"Bearer {self.token}"} response = requests.post(f"{BASE_URLS['location']}/api/v1/locations/update", json=data, headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200 or response.status_code == 201: print(colored("✓ Местоположение обновлено", "green")) return True else: print(colored("✗ Ошибка при обновлении местоположения", "red")) return False def get_location(self): """Получение текущего местоположения""" self.print_step("Получение местоположения") headers = {"Authorization": f"Bearer {self.token}"} response = requests.get(f"{BASE_URLS['location']}/api/v1/locations/last", headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200: print(colored("✓ Местоположение получено", "green")) return True else: print(colored("✗ Ошибка при получении местоположения", "red")) return False def create_emergency_alert(self): """Создание экстренного оповещения""" self.print_step("Создание экстренного оповещения") data = { "latitude": 55.7558, "longitude": 37.6173, "alert_type": "SOS", "message": "Тестовое экстренное оповещение" } headers = {"Authorization": f"Bearer {self.token}"} response = requests.post(f"{BASE_URLS['emergency']}/api/v1/emergency/alerts", json=data, headers=headers) alert_data = self.print_response(response, "Ответ сервера") if response.status_code == 201 or response.status_code == 200: self.alert_id = alert_data.get("id") print(colored("✓ Экстренное оповещение создано", "green")) return True else: print(colored("✗ Ошибка при создании оповещения", "red")) return False def get_alerts(self): """Получение активных оповещений""" self.print_step("Получение активных оповещений") headers = {"Authorization": f"Bearer {self.token}"} response = requests.get(f"{BASE_URLS['emergency']}/api/v1/emergency/alerts/my", headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200: print(colored("✓ Список оповещений получен", "green")) return True else: print(colored("✗ Ошибка при получении оповещений", "red")) return False def cancel_alert(self): """Отмена экстренного оповещения""" if not self.alert_id: print(colored("⚠ Нет активного оповещения для отмены", "yellow")) return False self.print_step("Отмена экстренного оповещения") headers = {"Authorization": f"Bearer {self.token}"} response = requests.patch(f"{BASE_URLS['emergency']}/api/v1/emergency/alerts/{self.alert_id}/cancel", headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200: print(colored("✓ Оповещение отменено", "green")) return True else: print(colored("✗ Ошибка при отмене оповещения", "red")) return False def create_calendar_entry(self): """Создание записи в календаре""" self.print_step("Создание записи в календаре") data = { "entry_date": datetime.now().strftime("%Y-%m-%d"), "cycle_day": 1, "symptoms": ["HEADACHE", "FATIGUE"], "mood": "NORMAL", "notes": "Тестовая запись" } headers = {"Authorization": f"Bearer {self.token}"} response = requests.post(f"{BASE_URLS['calendar']}/api/v1/calendar/entries", json=data, headers=headers) entry_data = self.print_response(response, "Ответ сервера") if response.status_code == 201 or response.status_code == 200: self.calendar_entry_id = entry_data.get("id") print(colored("✓ Запись в календаре создана", "green")) return True else: print(colored("✗ Ошибка при создании записи в календаре", "red")) return False def get_calendar_entries(self): """Получение записей календаря""" self.print_step("Получение записей календаря") start_date = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d") end_date = (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d") headers = {"Authorization": f"Bearer {self.token}"} response = requests.get( f"{BASE_URLS['calendar']}/api/v1/calendar/entries?start_date={start_date}&end_date={end_date}", headers=headers ) self.print_response(response, "Ответ сервера") if response.status_code == 200: print(colored("✓ Записи календаря получены", "green")) return True else: print(colored("✗ Ошибка при получении записей календаря", "red")) return False def register_device(self): """Регистрация устройства для уведомлений""" self.print_step("Регистрация устройства для уведомлений") data = { "device_token": f"test-token-{int(time.time())}", "device_type": "ANDROID", "app_version": "1.0.0" } headers = {"Authorization": f"Bearer {self.token}"} response = requests.post(f"{BASE_URLS['notification']}/api/v1/notifications/devices", json=data, headers=headers) device_data = self.print_response(response, "Ответ сервера") if response.status_code == 201 or response.status_code == 200: self.device_id = device_data.get("id") print(colored("✓ Устройство зарегистрировано", "green")) return True else: print(colored("✗ Ошибка при регистрации устройства", "red")) return False def set_notification_preferences(self): """Настройка предпочтений уведомлений""" self.print_step("Настройка предпочтений уведомлений") data = { "emergency_alerts": True, "nearby_incidents": True, "calendar_reminders": True, "system_notifications": True } headers = {"Authorization": f"Bearer {self.token}"} response = requests.post(f"{BASE_URLS['notification']}/api/v1/notifications/preferences", json=data, headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200 or response.status_code == 201: print(colored("✓ Предпочтения уведомлений настроены", "green")) return True else: print(colored("✗ Ошибка при настройке предпочтений", "red")) return False def get_gateway_dashboard(self): """Получение данных через API Gateway""" self.print_step("Получение данных пользователя через Gateway") headers = {"Authorization": f"Bearer {self.token}"} response = requests.get(f"{BASE_URLS['gateway']}/api/v1/users/dashboard", headers=headers) self.print_response(response, "Ответ сервера") if response.status_code == 200: print(colored("✓ Данные получены через Gateway", "green")) return True else: print(colored("✗ Ошибка при получении данных через Gateway", "red")) return False def run_tests(self): """Запуск полной серии тестов""" self.print_section("НАЧАЛО ТЕСТИРОВАНИЯ API") # Проверка доступности сервисов self.check_services() # Регистрация и авторизация user_data = self.register_user() if not user_data: print(colored("Критическая ошибка: Не удалось зарегистрировать пользователя", "red")) return False if not self.login_user(user_data): print(colored("Критическая ошибка: Не удалось авторизоваться", "red")) return False # Основные тесты self.update_profile() self.add_emergency_contact() self.update_location() self.get_location() self.create_emergency_alert() self.get_alerts() self.cancel_alert() self.create_calendar_entry() self.get_calendar_entries() self.register_device() self.set_notification_preferences() self.get_gateway_dashboard() self.print_section("ТЕСТИРОВАНИЕ ЗАВЕРШЕНО") print(colored("✓ Тесты API выполнены успешно!", "green", attrs=["bold"])) return True if __name__ == "__main__": tester = APITester() tester.run_tests()