This commit is contained in:
55
tests/conftest.py
Normal file
55
tests/conftest.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import asyncio
|
||||
import os
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from main import app
|
||||
from services.db import Base
|
||||
from services.redis import redis
|
||||
from settings import DB_URL
|
||||
|
||||
# Use SQLite for testing
|
||||
TEST_DB_URL = "sqlite:///test.db"
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def event_loop():
|
||||
"""Create an instance of the default event loop for the test session."""
|
||||
loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||
yield loop
|
||||
loop.close()
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def test_engine():
|
||||
"""Create a test database engine."""
|
||||
engine = create_engine(TEST_DB_URL)
|
||||
Base.metadata.create_all(engine)
|
||||
yield engine
|
||||
Base.metadata.drop_all(engine)
|
||||
os.remove("test.db")
|
||||
|
||||
@pytest.fixture
|
||||
def db_session(test_engine):
|
||||
"""Create a new database session for a test."""
|
||||
connection = test_engine.connect()
|
||||
transaction = connection.begin()
|
||||
session = Session(bind=connection)
|
||||
|
||||
yield session
|
||||
|
||||
session.close()
|
||||
transaction.rollback()
|
||||
connection.close()
|
||||
|
||||
@pytest.fixture
|
||||
async def redis_client():
|
||||
"""Create a test Redis client."""
|
||||
await redis.connect()
|
||||
yield redis
|
||||
await redis.disconnect()
|
||||
|
||||
@pytest.fixture
|
||||
def test_client():
|
||||
"""Create a TestClient instance."""
|
||||
return TestClient(app)
|
95
tests/test_drafts.py
Normal file
95
tests/test_drafts.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import pytest
|
||||
from orm.shout import Shout
|
||||
from orm.author import Author
|
||||
|
||||
@pytest.fixture
|
||||
def test_author(db_session):
|
||||
"""Create a test author."""
|
||||
author = Author(
|
||||
name="Test Author",
|
||||
slug="test-author",
|
||||
user="test-user-id"
|
||||
)
|
||||
db_session.add(author)
|
||||
db_session.commit()
|
||||
return author
|
||||
|
||||
@pytest.fixture
|
||||
def test_shout(db_session):
|
||||
"""Create test shout with required fields."""
|
||||
author = Author(name="Test Author", slug="test-author", user="test-user-id")
|
||||
db_session.add(author)
|
||||
db_session.flush()
|
||||
|
||||
shout = Shout(
|
||||
title="Test Shout",
|
||||
slug="test-shout",
|
||||
created_by=author.id, # Обязательное поле
|
||||
body="Test body",
|
||||
layout="article",
|
||||
lang="ru"
|
||||
)
|
||||
db_session.add(shout)
|
||||
db_session.commit()
|
||||
return shout
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_shout(test_client, db_session, test_author):
|
||||
"""Test creating a new shout."""
|
||||
response = test_client.post(
|
||||
"/",
|
||||
json={
|
||||
"query": """
|
||||
mutation CreateDraft($input: DraftInput!) {
|
||||
create_draft(input: $input) {
|
||||
error
|
||||
draft {
|
||||
id
|
||||
title
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
"variables": {
|
||||
"input": {
|
||||
"title": "Test Shout",
|
||||
"body": "This is a test shout",
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "errors" not in data
|
||||
assert data["data"]["create_draft"]["draft"]["title"] == "Test Shout"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_drafts(test_client, db_session):
|
||||
"""Test retrieving a shout."""
|
||||
response = test_client.post(
|
||||
"/",
|
||||
json={
|
||||
"query": """
|
||||
query {
|
||||
load_drafts {
|
||||
error
|
||||
drafts {
|
||||
id
|
||||
title
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
"variables": {
|
||||
"slug": "test-shout"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "errors" not in data
|
||||
assert data["data"]["load_drafts"]["drafts"] == []
|
64
tests/test_reactions.py
Normal file
64
tests/test_reactions.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import pytest
|
||||
from orm.reaction import Reaction, ReactionKind
|
||||
from orm.shout import Shout
|
||||
from orm.author import Author
|
||||
from datetime import datetime
|
||||
|
||||
@pytest.fixture
|
||||
def test_setup(db_session):
|
||||
"""Set up test data."""
|
||||
now = int(datetime.now().timestamp())
|
||||
author = Author(name="Test Author", slug="test-author", user="test-user-id")
|
||||
db_session.add(author)
|
||||
db_session.flush()
|
||||
|
||||
shout = Shout(
|
||||
title="Test Shout",
|
||||
slug="test-shout",
|
||||
created_by=author.id,
|
||||
body="This is a test shout",
|
||||
layout="article",
|
||||
lang="ru",
|
||||
community=1,
|
||||
created_at=now,
|
||||
updated_at=now
|
||||
)
|
||||
db_session.add_all([author, shout])
|
||||
db_session.commit()
|
||||
return {"author": author, "shout": shout}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_reaction(test_client, db_session, test_setup):
|
||||
"""Test creating a reaction on a shout."""
|
||||
response = test_client.post(
|
||||
"/",
|
||||
json={
|
||||
"query": """
|
||||
mutation CreateReaction($reaction: ReactionInput!) {
|
||||
create_reaction(reaction: $reaction) {
|
||||
error
|
||||
reaction {
|
||||
id
|
||||
kind
|
||||
body
|
||||
created_by {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
"variables": {
|
||||
"reaction": {
|
||||
"shout": test_setup["shout"].id,
|
||||
"kind": ReactionKind.LIKE.value,
|
||||
"body": "Great post!"
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "error" not in data
|
||||
assert data["data"]["create_reaction"]["reaction"]["kind"] == ReactionKind.LIKE.value
|
83
tests/test_shouts.py
Normal file
83
tests/test_shouts.py
Normal file
@@ -0,0 +1,83 @@
|
||||
import pytest
|
||||
from orm.author import Author
|
||||
from orm.shout import Shout
|
||||
from datetime import datetime
|
||||
|
||||
@pytest.fixture
|
||||
def test_shout(db_session):
|
||||
"""Create test shout with required fields."""
|
||||
now = int(datetime.now().timestamp())
|
||||
author = Author(name="Test Author", slug="test-author", user="test-user-id")
|
||||
db_session.add(author)
|
||||
db_session.flush()
|
||||
|
||||
now = int(datetime.now().timestamp())
|
||||
|
||||
shout = Shout(
|
||||
title="Test Shout",
|
||||
slug="test-shout",
|
||||
created_by=author.id,
|
||||
body="Test body",
|
||||
layout="article",
|
||||
lang="ru",
|
||||
community=1,
|
||||
created_at=now,
|
||||
updated_at=now
|
||||
)
|
||||
db_session.add(shout)
|
||||
db_session.commit()
|
||||
return shout
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_shout(test_client, db_session):
|
||||
"""Test retrieving a shout."""
|
||||
# Создаем автора
|
||||
author = Author(name="Test Author", slug="test-author", user="test-user-id")
|
||||
db_session.add(author)
|
||||
db_session.flush()
|
||||
now = int(datetime.now().timestamp())
|
||||
|
||||
# Создаем публикацию со всеми обязательными полями
|
||||
shout = Shout(
|
||||
title="Test Shout",
|
||||
body="This is a test shout",
|
||||
slug="test-shout",
|
||||
created_by=author.id,
|
||||
layout="article",
|
||||
lang="ru",
|
||||
community=1,
|
||||
created_at=now,
|
||||
updated_at=now
|
||||
)
|
||||
db_session.add(shout)
|
||||
db_session.commit()
|
||||
|
||||
response = test_client.post(
|
||||
"/",
|
||||
json={
|
||||
"query": """
|
||||
query GetShout($slug: String!) {
|
||||
get_shout(slug: $slug) {
|
||||
id
|
||||
title
|
||||
body
|
||||
created_at
|
||||
updated_at
|
||||
created_by {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
"variables": {
|
||||
"slug": "test-shout"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
assert response.status_code == 200
|
||||
assert "errors" not in data
|
||||
assert data["data"]["get_shout"]["title"] == "Test Shout"
|
101
tests/test_validations.py
Normal file
101
tests/test_validations.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import pytest
|
||||
from datetime import datetime, timedelta
|
||||
from pydantic import ValidationError
|
||||
|
||||
from auth.validations import (
|
||||
AuthInput,
|
||||
UserRegistrationInput,
|
||||
UserLoginInput,
|
||||
TokenPayload,
|
||||
OAuthInput,
|
||||
AuthResponse
|
||||
)
|
||||
|
||||
class TestAuthValidations:
|
||||
def test_auth_input(self):
|
||||
"""Test basic auth input validation"""
|
||||
# Valid case
|
||||
auth = AuthInput(
|
||||
user_id="123",
|
||||
username="testuser",
|
||||
token="1234567890abcdef1234567890abcdef"
|
||||
)
|
||||
assert auth.user_id == "123"
|
||||
assert auth.username == "testuser"
|
||||
|
||||
# Invalid cases
|
||||
with pytest.raises(ValidationError):
|
||||
AuthInput(user_id="", username="test", token="x" * 32)
|
||||
|
||||
with pytest.raises(ValidationError):
|
||||
AuthInput(user_id="123", username="t", token="x" * 32)
|
||||
|
||||
def test_user_registration(self):
|
||||
"""Test user registration validation"""
|
||||
# Valid case
|
||||
user = UserRegistrationInput(
|
||||
email="test@example.com",
|
||||
password="SecurePass123!",
|
||||
name="Test User"
|
||||
)
|
||||
assert user.email == "test@example.com"
|
||||
assert user.name == "Test User"
|
||||
|
||||
# Test email validation
|
||||
with pytest.raises(ValidationError) as exc:
|
||||
UserRegistrationInput(
|
||||
email="invalid-email",
|
||||
password="SecurePass123!",
|
||||
name="Test"
|
||||
)
|
||||
assert "Invalid email format" in str(exc.value)
|
||||
|
||||
# Test password validation
|
||||
with pytest.raises(ValidationError) as exc:
|
||||
UserRegistrationInput(
|
||||
email="test@example.com",
|
||||
password="weak",
|
||||
name="Test"
|
||||
)
|
||||
assert "String should have at least 8 characters" in str(exc.value)
|
||||
|
||||
def test_token_payload(self):
|
||||
"""Test token payload validation"""
|
||||
now = datetime.utcnow()
|
||||
exp = now + timedelta(hours=1)
|
||||
|
||||
payload = TokenPayload(
|
||||
user_id="123",
|
||||
username="testuser",
|
||||
exp=exp,
|
||||
iat=now
|
||||
)
|
||||
assert payload.user_id == "123"
|
||||
assert payload.username == "testuser"
|
||||
assert payload.scopes == [] # Default empty list
|
||||
|
||||
def test_auth_response(self):
|
||||
"""Test auth response validation"""
|
||||
# Success case
|
||||
success_resp = AuthResponse(
|
||||
success=True,
|
||||
token="valid_token",
|
||||
user={"id": "123", "name": "Test"}
|
||||
)
|
||||
assert success_resp.success is True
|
||||
assert success_resp.token == "valid_token"
|
||||
|
||||
# Error case
|
||||
error_resp = AuthResponse(
|
||||
success=False,
|
||||
error="Invalid credentials"
|
||||
)
|
||||
assert error_resp.success is False
|
||||
assert error_resp.error == "Invalid credentials"
|
||||
|
||||
# Invalid case - отсутствует обязательное поле token при success=True
|
||||
with pytest.raises(ValidationError):
|
||||
AuthResponse(
|
||||
success=True,
|
||||
user={"id": "123", "name": "Test"}
|
||||
)
|
Reference in New Issue
Block a user