/
Pepegator
/
task-api
Обзор
Документация
Войти
/
Pepegator
/
task-api
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
lab4
client/test_comprehensive.py
543 строки
21 KB
Pol136
fix bugs
30 дек 2025, 14:46
30 дек 2025, 14:46
c8d3e65
Код
Авторство
О чём код?
import uuid import time import sys from client import BookShareClient class TestRunner: def __init__(self, base_url: str = "http://localhost:8000"): self.base_url = base_url self.passed = 0 self.failed = 0 self.results = [] def log(self, message: str, level: str = "info"): symbols = { "info": "[INFO] ", "success": "[PASS] ", "error": "[FAIL] ", "warning": "[WARN] ", "test": "[TEST] " } print(f"{symbols.get(level, '→')} {message}") def assert_eq(self, actual, expected, msg: str): if actual != expected: raise AssertionError(f"{msg}: expected {expected}, got {actual}") def assert_in(self, item, collection, msg: str): if item not in collection: raise AssertionError(f"{msg}: {item} not in {collection}") def assert_true(self, condition, msg: str): if not condition: raise AssertionError(msg) def run_test(self, test_func, test_name: str): try: test_func() self.passed += 1 self.log(f"{test_name}: PASS", "success") self.results.append((test_name, True, None)) return True except Exception as e: self.failed += 1 self.log(f"{test_name}: FAIL", "error") self.log(f" Причина: {str(e)}", "error") self.results.append((test_name, False, str(e))) return False def setup_test_user_v1(self) -> tuple: email = f"test_v1_{uuid.uuid4().hex[:8]}@example.com" password = "StrongPass123!" client = BookShareClient(self.base_url, "v1") user = client.register(email, password, "Test User V1", "Test bio") client.login(email, password) return client, email, password, user def setup_test_user_v2(self) -> tuple: email = f"test_v2_{uuid.uuid4().hex[:8]}@example.com" password = "StrongPass123!" client = BookShareClient(self.base_url, "v2") user = client.register(email, password, "Test User V2", "Test bio") client.login(email, password) return client, email, password, user def test_health(self): client = BookShareClient(self.base_url, "v1") self.assert_true( client.wait_for_api(timeout=5), "API не доступен" ) def test_v1_register_success(self): email = f"register_{uuid.uuid4().hex[:8]}@example.com" client = BookShareClient(self.base_url, "v1") user = client.register(email, "StrongPass123!", "New User", "Bio") self.assert_eq(user["email"], email, "Email не совпадает") self.assert_true("id" in user, "ID отсутствует") def test_v1_register_duplicate(self): email = f"dup_{uuid.uuid4().hex[:8]}@example.com" client = BookShareClient(self.base_url, "v1") client.register(email, "StrongPass123!", "User", "Bio") try: client.register(email, "StrongPass123!", "User", "Bio") raise AssertionError("Дублирующаяся регистрация должна быть отклонена") except Exception as e: self.assert_true( "400" in str(e) or "409" in str(e) or "422" in str(e), f"Ожидали 400/409/422, получили: {e}" ) def test_v1_token_success(self): client, email, password, _ = self.setup_test_user_v1() token_resp = client.login(email, password) self.assert_true("access_token" in token_resp, "access_token отсутствует") self.assert_eq(token_resp.get("token_type", "").lower(), "bearer", "token_type должен быть bearer") def test_v1_token_invalid_credentials(self): client = BookShareClient(self.base_url, "v1") try: client.login("invalid@example.com", "wrongpassword") raise AssertionError("Должна быть ошибка при неверных учётных данных") except Exception as e: self.assert_true( "401" in str(e) or "403" in str(e) or "422" in str(e), f"Ожидали 401/403/422, получили: {e}" ) def test_v2_register_success(self): email = f"register_v2_{uuid.uuid4().hex[:8]}@example.com" client = BookShareClient(self.base_url, "v2") user = client.register(email, "StrongPass123!", "V2 User", "V2 Bio") self.assert_eq(user["email"], email, "Email не совпадает") self.assert_true("id" in user, "ID отсутствует") def test_v2_token_success(self): client, email, password, _ = self.setup_test_user_v2() self.assert_true(client.token is not None, "Токен не получен") def test_v1_profile_get(self): client, _, _, _ = self.setup_test_user_v1() profile = client.get_profile() self.assert_true("email" in profile, "Email отсутствует в профиле") def test_v1_profile_get_with_include(self): client, _, _, _ = self.setup_test_user_v1() profile = client.get_profile(include="email,full_name") self.assert_true("email" in profile, "Email должен быть включён") self.assert_true("full_name" in profile, "full_name должен быть включён") def test_v1_profile_patch(self): client, _, _, _ = self.setup_test_user_v1() updated = client.update_profile(full_name="Updated Name", bio="Updated bio") self.assert_eq(updated["full_name"], "Updated Name", "full_name не обновлён") self.assert_eq(updated["bio"], "Updated bio", "bio не обновлён") def test_v1_profile_patch_with_include(self): client, _, _, _ = self.setup_test_user_v1() updated = client.update_profile( full_name="New Name", include="full_name,bio" ) self.assert_true("full_name" in updated, "full_name должен быть в ответе") def test_v1_profile_unauthorized(self): client = BookShareClient(self.base_url, "v1") client.token = None try: client.get_profile() raise AssertionError("Должна быть 401 без токена") except Exception as e: self.assert_true( "401" in str(e) or "403" in str(e), f"Ожидали 401/403, получили: {e}" ) def test_v2_profile_get(self): client, _, _, _ = self.setup_test_user_v2() profile = client.get_profile() self.assert_true("email" in profile, "Email отсутствует") def test_v2_profile_get_with_include(self): client, _, _, _ = self.setup_test_user_v2() profile = client.get_profile(include="email") self.assert_true("email" in profile, "Email должен быть") def test_v2_profile_patch(self): client, _, _, _ = self.setup_test_user_v2() updated = client.update_profile(full_name="V2 Name") self.assert_eq(updated["full_name"], "V2 Name", "full_name не обновлён") def test_v1_create_book_success(self): client, _, _, _ = self.setup_test_user_v1() book = client.create_book( title="Test Book V1", author="Author One", description="Some description", tags=["tag1", "tag2"] ) self.assert_eq(book["title"], "Test Book V1", "Title не совпадает") self.assert_eq(book["author"], "Author One", "Author не совпадает") self.assert_true("id" in book, "ID отсутствует") def test_v1_create_book_with_include(self): client, _, _, _ = self.setup_test_user_v1() book = client.create_book( title="Filtered Book", author="Author", include="id,title,author" ) self.assert_true("id" in book, "ID должен быть") self.assert_true("title" in book, "Title должен быть") def test_v1_list_books_pagination(self): client, _, _, _ = self.setup_test_user_v1() for i in range(3): client.create_book(f"Book {i}", f"Author {i}") page1 = client.list_books(limit=2, offset=0) self.assert_true("total" in page1, "total отсутствует") self.assert_true("items" in page1, "items отсутствует") self.assert_eq(page1["limit"], 2, "limit не совпадает") self.assert_eq(page1["offset"], 0, "offset не совпадает") def test_v1_list_books_with_include(self): client, _, _, _ = self.setup_test_user_v1() client.create_book("Filtered List", "Author") books = client.list_books(limit=5, include="id,title") if books["items"]: first = books["items"][0] self.assert_true("id" in first, "ID должен быть в ответе") self.assert_true("title" in first, "Title должен быть в ответе") def test_v1_get_book_detail(self): client, _, _, _ = self.setup_test_user_v1() created = client.create_book("Detail Book", "Author") book_id = created["id"] detail = client.get_book(book_id) self.assert_eq(detail["id"], book_id, "ID не совпадает") self.assert_eq(detail["title"], "Detail Book", "Title не совпадает") def test_v1_get_book_detail_with_include(self): client, _, _, _ = self.setup_test_user_v1() created = client.create_book("Filtered Detail", "Author") book_id = created["id"] detail = client.get_book(book_id, include="id,title") self.assert_true("id" in detail, "ID должен быть") self.assert_true("title" in detail, "Title должен быть") def test_v1_book_qr_generation(self): client, _, _, _ = self.setup_test_user_v1() created = client.create_book("QR Book", "Author") book_id = created["id"] qr_data = client.generate_qr(book_id) self.assert_eq(qr_data["book_id"], book_id, "book_id не совпадает") self.assert_true("qr_png_base64" in qr_data, "QR code отсутствует") self.assert_true(len(qr_data["qr_png_base64"]) > 0, "QR code пуст") def test_v1_borrow_book(self): client, _, _, _ = self.setup_test_user_v1() created = client.create_book("Borrow Book", "Author") book_id = created["id"] result = client.borrow_book(book_id) self.assert_true( "status" in result or "message" in result or result.get("id"), "Ответ не содержит ожидаемых полей" ) def test_v1_return_book(self): client, _, _, _ = self.setup_test_user_v1() created = client.create_book("Return Book", "Author") book_id = created["id"] result = client.return_book(book_id) self.assert_true( isinstance(result, dict), "Ответ должен быть словарём" ) def test_v2_create_book_with_condition(self): client, _, _, _ = self.setup_test_user_v2() book = client.create_book( title="V2 Book", author="Author V2", condition="good" ) self.assert_eq(book["title"], "V2 Book", "Title не совпадает") self.assert_eq(book["condition"], "good", "Condition не совпадает") def test_v2_create_book_condition_values(self): client, _, _, _ = self.setup_test_user_v2() conditions = ["new", "good", "fair", "worn"] for condition in conditions: book = client.create_book( title=f"Book {condition}", author="Author", condition=condition ) self.assert_eq( book["condition"], condition, f"Condition {condition} не совпадает" ) def test_v2_create_book_with_include(self): client, _, _, _ = self.setup_test_user_v2() book = client.create_book( title="V2 Book", author="Author", condition="good", include="id,title,condition" ) self.assert_true("condition" in book, "Condition должен быть в ответе") def test_v2_list_books_with_condition_filter(self): client, _, _, _ = self.setup_test_user_v2() client.create_book("Good Book", "Author", condition="good") client.create_book("New Book", "Author", condition="new") books = client.list_books(limit=10, condition="good") self.assert_true("items" in books, "items отсутствует") for book in books["items"]: if "condition" in book: self.assert_eq( book["condition"], "good", "Фильтр по condition не работает" ) def test_v2_list_books_with_include(self): client, _, _, _ = self.setup_test_user_v2() client.create_book("V2 List", "Author", condition="good") books = client.list_books(limit=5, include="id,condition") if books["items"]: first = books["items"][0] self.assert_true("condition" in first, "Condition должен быть") def test_v2_get_book_detail(self): client, _, _, _ = self.setup_test_user_v2() created = client.create_book("V2 Detail", "Author", condition="new") book_id = created["id"] detail = client.get_book(book_id) self.assert_eq(detail["condition"], "new", "Condition не совпадает") def test_v2_get_book_detail_with_include(self): client, _, _, _ = self.setup_test_user_v2() created = client.create_book("V2 Filtered Detail", "Author", condition="fair") book_id = created["id"] detail = client.get_book(book_id, include="id,condition") self.assert_true("condition" in detail, "Condition должен быть") def test_v2_book_qr_generation(self): client, _, _, _ = self.setup_test_user_v2() created = client.create_book("V2 QR", "Author", condition="good") book_id = created["id"] qr_data = client.generate_qr(book_id) self.assert_eq(qr_data["book_id"], book_id, "book_id не совпадает") self.assert_true("qr_png_base64" in qr_data, "QR code отсутствует") def test_v2_borrow_book(self): client, _, _, _ = self.setup_test_user_v2() created = client.create_book("V2 Borrow", "Author", condition="good") book_id = created["id"] result = client.borrow_book(book_id) self.assert_true(isinstance(result, dict), "Результат должен быть словарём") def test_version_compatibility(self): client_v1, _, _, _ = self.setup_test_user_v1() client_v2, _, _, _ = self.setup_test_user_v2() self.assert_true(client_v1.token is not None, "v1 токен отсутствует") self.assert_true(client_v2.token is not None, "v2 токен отсутствует") def test_books_fields_v1_vs_v2(self): client_v1, _, _, _ = self.setup_test_user_v1() client_v2, _, _, _ = self.setup_test_user_v2() book_v1 = client_v1.create_book("V1 Book", "Author") book_v2 = client_v2.create_book("V2 Book", "Author", condition="good") self.assert_true("condition" in book_v2, "v2 книга должна иметь condition") def run_all(self): print("\n" + "="*70) print("ЗАПУСК ПОЛНОГО НАБОРА ТЕСТОВ") print("="*70) client = BookShareClient(self.base_url) if not client.wait_for_api(timeout=10): print("API не доступен") return test_groups = [ ("Health Check", [ (self.test_health, "Health Check"), ]), ("Authentication V1", [ (self.test_v1_register_success, "V1 Register Success"), (self.test_v1_register_duplicate, "V1 Register Duplicate"), (self.test_v1_token_success, "V1 Token Success"), (self.test_v1_token_invalid_credentials, "V1 Token Invalid"), ]), ("Authentication V2", [ (self.test_v2_register_success, "V2 Register Success"), (self.test_v2_token_success, "V2 Token Success"), ]), ("Profile V1", [ (self.test_v1_profile_get, "V1 Profile Get"), (self.test_v1_profile_get_with_include, "V1 Profile Get with Include"), (self.test_v1_profile_patch, "V1 Profile Patch"), (self.test_v1_profile_patch_with_include, "V1 Profile Patch with Include"), (self.test_v1_profile_unauthorized, "V1 Profile Unauthorized"), ]), ("Profile V2", [ (self.test_v2_profile_get, "V2 Profile Get"), (self.test_v2_profile_get_with_include, "V2 Profile Get with Include"), (self.test_v2_profile_patch, "V2 Profile Patch"), ]), ("Books V1", [ (self.test_v1_create_book_success, "V1 Create Book Success"), (self.test_v1_create_book_with_include, "V1 Create Book with Include"), (self.test_v1_list_books_pagination, "V1 List Books Pagination"), (self.test_v1_list_books_with_include, "V1 List Books with Include"), (self.test_v1_get_book_detail, "V1 Get Book Detail"), (self.test_v1_get_book_detail_with_include, "V1 Get Book Detail with Include"), (self.test_v1_book_qr_generation, "V1 Book QR Generation"), (self.test_v1_borrow_book, "V1 Borrow Book"), (self.test_v1_return_book, "V1 Return Book"), ]), ("Books V2", [ (self.test_v2_create_book_with_condition, "V2 Create Book with Condition"), (self.test_v2_create_book_condition_values, "V2 Create Book Condition Values"), (self.test_v2_create_book_with_include, "V2 Create Book with Include"), (self.test_v2_list_books_with_condition_filter, "V2 List Books Condition Filter"), (self.test_v2_list_books_with_include, "V2 List Books with Include"), (self.test_v2_get_book_detail, "V2 Get Book Detail"), (self.test_v2_get_book_detail_with_include, "V2 Get Book Detail with Include"), (self.test_v2_book_qr_generation, "V2 Book QR Generation"), (self.test_v2_borrow_book, "V2 Borrow Book"), ]), ("Versioning", [ (self.test_version_compatibility, "Version Compatibility"), (self.test_books_fields_v1_vs_v2, "Books Fields V1 vs V2"), ]), ] for group_name, tests in test_groups: print(f"\n{'─'*70}") print(f"{group_name}") print(f"{'─'*70}") for test_func, test_name in tests: self.run_test(test_func, test_name) time.sleep(0.5) print("\n" + "="*70) print("ИТОГИ ТЕСТИРОВАНИЯ") print("="*70) total = self.passed + self.failed print(f"Пройдено: {self.passed}") print(f"Не пройдено: {self.failed}") print(f"Всего: {total}") if self.failed == 0: print(f"\nВсе {total} тестов пройдены!") return True else: percentage = int((self.passed / total) * 100) print(f"\n⚠ {percentage}% тестов пройдено ({self.passed}/{total})") print("\nНе пройденные тесты:") for name, passed, error in self.results: if not passed: print(f" - {name}") if error: print(f" {error[:100]}") return False if __name__ == "__main__": runner = TestRunner("http://localhost:8000") success = runner.run_all() sys.exit(0 if success else 1)