Initial commit

This commit is contained in:
KamilM1205 2026-01-19 23:32:11 +04:00
commit 9795660e1f
43 changed files with 2757 additions and 0 deletions

0
tests/api/__init__.py Normal file
View file

64
tests/api/conftest.py Normal file
View file

@ -0,0 +1,64 @@
import logging
import allure
import pytest
from config.session_config import session_config
from tests.api.utils.api_client import APIClient
logger = logging.getLogger(__name__)
@pytest.fixture(scope="class")
def api_client(api_base_url):
"""Клиент для работы с API"""
return APIClient(base_url=api_base_url)
@pytest.fixture(scope="class")
def admin_credentials():
"""Учетные данные администратора"""
return session_config.get_admin_credentials()
@pytest.fixture(scope="class")
def auth_admin(api_client: APIClient, admin_credentials):
with allure.step("Admin authentication fixture"):
logger.info("Authentificate admin")
success = api_client.login(
admin_credentials["username"],
admin_credentials["password"]
)
assert success is True
assert api_client.logged_in is True
logger.info("Admin authenticated")
yield api_client
api_client.logout()
@pytest.fixture(scope="class")
def auth_user(api_client: APIClient, auth_admin: APIClient, api_user_auth_data):
id = ''
with allure.step("User auth fixture"):
logger.info("Creating new user for auth")
resp = auth_admin.create_user(api_user_auth_data)
assert resp.status_code is 201
id = resp.json()['id']
logger.info(f"Auth as user: {api_user_auth_data['username']}")
resp = api_client.login(
api_user_auth_data['username'],
api_user_auth_data['password']
)
assert resp
assert api_client.logged_in
yield api_client
api_client.logout()
auth_admin.delete_user(id)

206
tests/api/test_posts.py Normal file
View file

@ -0,0 +1,206 @@
from typing import Any, Dict
import pytest
import allure
import logging
from tests.api.utils.api_client import APIClient
logger = logging.getLogger(__name__)
# Фикстура для получения списка постов из API
@pytest.fixture(scope="function")
def list_of_posts(api_client):
with allure.step("Get all posts"):
resp = api_client.get_all_posts()
assert resp.status_code == 200
return resp.json()
# Отдельные классы вариант
@allure.feature("Posts")
@allure.story("Guest permissions")
class TestGuestPosts:
"""Тестирование операций с постами под гостем (неавторизованный доступ)"""
@allure.title("Guest: Creating new posts - should fail")
def test_guest_posts_creating(self, api_client, api_post_data):
with allure.step("Logged as guest"):
logger.info("Guest trying to create posts")
for post in api_post_data:
resp = api_client.create_post(post)
assert resp.status_code == 401
@allure.title("Guest: Update posts - should fail")
def test_guest_posts_update(self, api_client, list_of_posts):
posts = list_of_posts
with allure.step("Guest trying to change posts data"):
for post in posts:
logger.info(f"Guest changing post: {post['title']}")
post["title"] = "Changed by guest"
post["description"] = "Changed by guest"
post["content"] = "Changed by guest"
resp = api_client.update_post(post["id"], post)
assert resp.status_code == 401
@allure.title("Guest: Get all posts - should succeed")
def test_guest_get_all_posts(self, api_client):
with allure.step("Guest getting all posts"):
logger.info("Guest getting all posts")
resp = api_client.get_all_posts()
assert resp.status_code == 200
@allure.title("Guest: Get post by ID - should succeed")
def test_guest_get_post_by_id(self, api_client, list_of_posts):
posts = list_of_posts
if posts:
post_id = posts[0]["id"]
with allure.step(f"Guest getting post with ID {post_id}"):
logger.info(f"Guest getting post: {post_id}")
resp = api_client.get_post(post_id)
assert resp.status_code == 200
@allure.title("Guest: Delete posts - should fail")
def test_guest_posts_deleting(self, api_client, list_of_posts):
posts = list_of_posts
with allure.step("Guest trying to delete posts"):
for post in posts:
logger.info(f"Guest deleting post: {post['title']}")
resp = api_client.delete_post(post["id"])
assert resp.status_code == 401
@allure.feature("Posts")
@allure.story("Admin permissions")
class TestAdminPosts:
"""Тестирование операций с постами под администратором"""
@allure.title("Admin: Creating new posts - should succeed")
def test_admin_posts_creating(self, auth_admin, api_post_data, api_user_data):
id = ''
with allure.step("Logged as admin"):
pass
with allure.step("Create new user"):
user = api_user_data[0]
resp = auth_admin.create_user(user)
assert resp.status_code == 201
id = resp.json()['id']
with allure.step("Create posts"):
logger.info("Admin creating posts")
for post in api_post_data:
post['userId'] = id
resp = auth_admin.create_post(post)
assert resp.status_code == 201
@allure.title("Admin: Update posts - should succeed")
def test_admin_posts_update(self, auth_admin, list_of_posts):
posts = list_of_posts
with allure.step("Admin changing posts data"):
for post in posts:
logger.info(f"Admin changing post: {post['title']}")
new_post: Dict[str, Any] = {}
new_post["title"] = "Changed by admin."
new_post["description"] = "Changed by admin. Test data."
new_post["content"] = "Changed by admin."
resp = auth_admin.update_post(post["id"], new_post)
assert resp.status_code == 200
@allure.title("Admin: Get all posts - should succeed")
def test_admin_get_all_posts(self, auth_admin):
with allure.step("Admin getting all posts"):
logger.info("Admin getting all posts")
resp = auth_admin.get_all_posts()
assert resp.status_code == 200
@allure.title("Admin: Get post by ID - should succeed")
def test_admin_get_post_by_id(self, auth_admin, list_of_posts):
posts = list_of_posts
if posts:
post_id = posts[0]["id"]
with allure.step(f"Admin getting post with ID {post_id}"):
logger.info(f"Admin getting post: {post_id}")
resp = auth_admin.get_post(post_id)
assert resp.status_code == 200
@allure.title("Admin: Delete posts - should succeed")
def test_admin_posts_deleting(self, auth_admin, list_of_posts):
posts = list_of_posts
id = posts[0]['userId']
with allure.step("Admin deleting posts"):
for post in posts:
logger.info(f"Admin deleting post: {post['title']}")
resp = auth_admin.delete_post(post["id"])
assert resp.status_code == 200
with allure.step("Delete user"):
resp = auth_admin.delete_user(id)
assert resp.status_code == 200
@allure.feature("Posts")
@allure.story("Regular user permissions")
class TestRegularUserPosts:
"""Тестирование операций с постами под обычным пользователем"""
@allure.title("User: Creating new posts - should succeed")
def test_user_posts_creating(self, auth_user: APIClient, api_post_data):
id = auth_user.get_all_users().json()[0]['id']
with allure.step("Logged as user"):
pass
with allure.step("Create new posts"):
logger.info("User creating posts")
for post in api_post_data:
post['userId'] = id
resp = auth_user.create_post(post)
assert resp.status_code == 201
@allure.title("User: Update posts - should succeed")
def test_user_posts_update(self, auth_user, list_of_posts):
posts = list_of_posts
with allure.step("User changing posts data"):
for post in posts:
logger.info(f"User changing post: {post['title']}")
post["title"] = "Changed by user"
post["description"] = "Changed by user"
post["content"] = "Changed by user"
resp = auth_user.update_post(post["id"], post)
assert resp.status_code == 200
@allure.title("User: Get all posts - should succeed")
def test_user_get_all_posts(self, auth_user):
with allure.step("User getting all posts"):
logger.info("User getting all posts")
resp = auth_user.get_all_posts()
assert resp.status_code == 200
@allure.title("User: Get post by ID - should succeed")
def test_user_get_post_by_id(self, auth_user, list_of_posts):
posts = list_of_posts
if posts:
post_id = posts[0]["id"]
with allure.step(f"User getting post with ID {post_id}"):
logger.info(f"User getting post: {post_id}")
resp = auth_user.get_post(post_id)
assert resp.status_code == 200
@allure.title("User: Delete posts - should succeed")
def test_user_posts_deleting(self, auth_user, list_of_posts):
posts = list_of_posts
with allure.step("User deleting posts"):
for post in posts:
logger.info(f"User deleting post: {post['title']}")
resp = auth_user.delete_post(post["id"])
assert resp.status_code == 200

133
tests/api/test_users.py Normal file
View file

@ -0,0 +1,133 @@
import pytest
import allure
import logging
from tests.api.utils.api_client import APIClient
logger = logging.getLogger(__name__)
# Фикстура для получения списка пользователей
@pytest.fixture(scope="class")
def list_of_users(api_client):
with allure.step("Get all users"):
resp = api_client.get_all_users()
assert resp.status_code == 200
return resp.json()
# Тест для гостя (неавторизованный пользователь)
@allure.story("Guest permissions")
class TestGuestUsers:
"""Тестирование операций с пользователями под гостем (неавторизованный доступ)"""
@allure.title("Guest: Creating new user - should fail")
def test_guest_users_creating(self, api_client: APIClient, api_user_data):
assert api_client.logged_in == False
with allure.step("Logged as guest - trying to create users"):
logger.info("Guest trying to create users")
for user in api_user_data:
resp = api_client.create_user(user)
assert resp.status_code == 401, \
f"Guest should not be able to create users. Got {resp.status_code}"
@allure.title("Guest: Update user - should fail")
def test_guest_users_update(self, api_client: APIClient, list_of_users):
users = list_of_users
with allure.step("Guest trying to change users data"):
for user in users:
logger.info(f"Guest changing user: {user['username']}")
user["motto"] = "Changed by guest"
resp = api_client.update_user(user["id"], user)
assert resp.status_code == 401, \
f"Guest should not be able to update users. Got {resp.status_code}"
@allure.title("Guest: Deleting users - should fail")
def test_guest_users_deleting(self, api_client: APIClient, list_of_users):
users = list_of_users
with allure.step("Guest trying to delete users"):
for user in users:
logger.info(f"Guest deleting user: {user['username']}")
resp = api_client.delete_user(user["id"])
assert resp.status_code == 401, \
f"Guest should not be able to delete users. Got {resp.status_code}"
# Тест для администратора
@allure.story("Admin permissions")
class TestAdminUsers:
"""Тестирование операций с пользователями под администратором"""
@allure.title("Admin: Creating new user - should succeed")
def test_admin_users_creating(self, auth_admin, api_user_data):
with allure.step("Logged as admin - creating users"):
logger.info("Admin creating users")
for user in api_user_data:
resp = auth_admin.create_user(user)
assert resp.status_code == 201, \
f"Admin should be able to create users. Got {resp.status_code}"
@allure.title("Admin: Update user - should succeed")
def test_admin_users_update(self, auth_admin, list_of_users):
users = list_of_users
with allure.step("Admin changing users data"):
for user in users:
logger.info(f"Admin changing user: {user['username']}")
user["motto"] = "Changed by admin"
user["password"] = "SomeRandomPass1205"
resp = auth_admin.update_user(user["id"], user)
assert resp.status_code == 200, \
f"Admin should be able to update users. Got {resp.status_code}"
@allure.title("Admin: Deleting users - should succeed")
def test_admin_users_deleting(self, auth_admin, list_of_users):
users = list_of_users
with allure.step("Admin deleting users"):
for user in users:
logger.info(f"Admin deleting user: {user['username']}")
resp = auth_admin.delete_user(user["id"])
assert resp.status_code == 200, \
f"Admin should be able to delete users. Got {resp.status_code}"
# Тест для обычного пользователя
@allure.story("Regular user permissions")
class TestRegularUserUsers:
"""Тестирование операций с пользователями под обычным пользователем"""
@allure.title("User: Creating new user - should succeed")
def test_user_users_creating(self, auth_user, api_user_data):
with allure.step("Logged as regular user - creating users"):
logger.info("Regular user creating users")
for user in api_user_data:
resp = auth_user.create_user(user)
assert resp.status_code == 201, \
f"Regular user should be able to create users. Got {resp.status_code}"
@allure.title("User: Update user - should succeed")
def test_user_users_update(self, auth_user, list_of_users):
users = list_of_users
with allure.step("Regular user changing users data"):
for user in users:
logger.info(f"Regular user changing: {user['username']}")
user["motto"] = "Changed by regular user"
user["password"] = "SomeRandomPass1205"
resp = auth_user.update_user(user["id"], user)
assert resp.status_code == 200, \
f"Regular user should be able to update users. Got {resp.status_code}"
@allure.title("User: Deleting users - should succeed")
def test_user_users_deleting(self, auth_user, list_of_users):
users = list_of_users
with allure.step("Regular user deleting users"):
for user in users:
logger.info(f"Regular user deleting: {user['username']}")
resp = auth_user.delete_user(user["id"])
assert resp.status_code == 200, \
f"Regular user should be able to delete users. Got {resp.status_code}"

View file

@ -0,0 +1,213 @@
import json
import requests
import allure
import logging
from typing import Optional, Dict, Any
from urllib.parse import urljoin
from config.api_config import api_config
from config.session_config import session_config
logger = logging.getLogger(__name__)
class APIClient:
def __init__(self, base_url: Optional[str] = None):
self.base_url = base_url or api_config.API_BASE_URL
self.session = requests.Session()
self.session.cookies.clear()
self.logged_in = False
logger.info("New API created.")
# Настройка сессии
self._configure_session()
def _configure_session(self):
"""Настройка HTTP сессии"""
# Установка заголовков по умолчанию
self.session.headers.update(api_config.DEFAULT_HEADERS)
self.session.headers.update(session_config.get_session_headers())
logger.debug(f"API Client configured for {self.base_url}")
def login(self, username: str, password: str) -> bool:
"""Логин пользователя (создание сессии)"""
login_data = {
"username": username,
"password": password
}
endpoint = api_config.get_endpoint('auth_login')
response = self.post(endpoint, json=login_data)
if response.status_code == 200:
self.logged_in = True
logger.info(f"Successfully logged in as {username}")
# Логирование cookies для отладки
if self.session.cookies:
cookies_info = dict(self.session.cookies)
logger.info(f"Session cookies: {cookies_info}")
# Проверяем наличие сессионного cookie
session_cookie = session_config.SESSION_COOKIE_NAME
if session_cookie in cookies_info:
logger.info(f"Session cookie '{session_cookie}' is set")
return True
else:
logger.error(f"Login failed for {username}: {response.status_code}")
logger.debug(f"Response: {response.text}")
return False
def logout(self) -> bool:
"""Выход из системы (закрытие сессии)"""
if not self.logged_in:
logger.warning("Attempted logout without being logged in")
return True
endpoint = api_config.get_endpoint('auth_logout')
response = self.get(endpoint)
if response.status_code == 200:
self.logged_in = False
# Очищаем cookies
self.session.cookies.clear()
logger.info("Successfully logged out")
return True
else:
logger.error(f"Logout failed: {response.status_code}")
return False
def ensure_logged_in(self, username: str, password: str):
"""Убедиться, что пользователь залогинен"""
if not self.logged_in:
return self.login(username, password)
return True
def _send_request(
self,
method: str,
endpoint: str,
**kwargs
) -> requests.Response:
"""Отправка HTTP запроса с поддержкой сессий"""
url = urljoin(self.base_url, endpoint)
with allure.step(f"{method.upper()} {endpoint}"):
# Добавляем логирование
self._log_request(method, url, kwargs)
try:
response = self.session.request(method, url, headers=api_config.DEFAULT_HEADERS, **kwargs)
except requests.exceptions.RequestException as e:
logger.error(f"Request failed: {e}")
raise
# Логирование ответа
self._log_response(response)
return response
def _log_request(self, method: str, url: str, kwargs: Dict[str, Any]):
"""Логирование деталей запроса"""
request_details = (
f"Request: {method} {url}\n"
f"Headers: {dict(self.session.headers)}\n"
f"Cookies: {dict(self.session.cookies)}\n"
f"Body: {kwargs.get('json', 'N/A')}"
)
allure.attach(
request_details,
name="Request Details",
attachment_type=allure.attachment_type.TEXT
)
logger.debug(f"{method} {url}")
def _log_response(self, response: requests.Response):
"""Логирование деталей ответа"""
response_details = (
f"Status Code: {response.status_code}\n"
f"Response Headers: {dict(response.headers)}\n"
f"Response Cookies: {dict(response.cookies)}\n"
f"Response Body: {response.text[:500]}..."
)
allure.attach(
response_details,
name="Response Details",
attachment_type=allure.attachment_type.TEXT
)
logger.debug(f"Response: {response.status_code}")
# Логирование ошибок
if response.status_code >= 400:
logger.warning(f"Request failed with status {response.status_code}")
logger.debug(f"Error response: {response.text}")
# Методы HTTP запросов
def get(self, endpoint: str, **kwargs) -> requests.Response:
return self._send_request("GET", endpoint, **kwargs)
def post(self, endpoint: str, **kwargs) -> requests.Response:
return self._send_request("POST", endpoint, **kwargs)
def put(self, endpoint: str, **kwargs) -> requests.Response:
return self._send_request("PUT", endpoint, **kwargs)
def delete(self, endpoint: str, **kwargs) -> requests.Response:
return self._send_request("DELETE", endpoint, **kwargs)
def patch(self, endpoint: str, **kwargs) -> requests.Response:
return self._send_request("PATCH", endpoint, **kwargs)
# Специальные методы для endpoints
def create_user(self, user_data: Dict[str, Any]) -> requests.Response:
endpoint = api_config.get_endpoint('users_create')
return self.post(endpoint, json=user_data)
def get_user(self, user_id: str) -> requests.Response:
endpoint = api_config.get_endpoint('users_get_by_id', id=user_id)
return self.get(endpoint)
def get_all_users(self) -> requests.Response:
endpoint = api_config.get_endpoint('users_get_all')
return self.get(endpoint)
def update_user(self, user_id: str, user_data: Dict[str, Any]) -> requests.Response:
endpoint = api_config.get_endpoint('users_update', id=user_id)
return self.put(endpoint, json=user_data)
def delete_user(self, user_id: str) -> requests.Response:
endpoint = api_config.get_endpoint('users_delete', id=user_id)
return self.delete(endpoint)
def create_post(self, post_data: Dict[str, Any]) -> requests.Response:
endpoint = api_config.get_endpoint('posts_create')
return self.post(endpoint, json=post_data)
def get_post(self, post_id: str) -> requests.Response:
endpoint = api_config.get_endpoint('posts_get_by_id', id=post_id)
return self.get(endpoint)
def get_all_posts(self) -> requests.Response:
endpoint = api_config.get_endpoint('posts_get_all')
return self.get(endpoint)
def update_post(self, post_id: str, post_data: Dict[str, Any]) -> requests.Response:
endpoint = api_config.get_endpoint('posts_update', id=post_id)
return self.put(endpoint, json=post_data)
def delete_post(self, post_id: str) -> requests.Response:
endpoint = api_config.get_endpoint("posts_delete", id=post_id)
return self.delete(endpoint)
def upload_image(self, file_path: str, field_name: str = "file") -> requests.Response:
endpoint = api_config.get_endpoint('images_upload')
with open(file_path, 'rb') as f:
files = {field_name: (file_path, f)}
return self.post(endpoint, files=files)