Skip to content
This repository has been archived by the owner on Mar 19, 2024. It is now read-only.

Commit

Permalink
Lesson1 updates
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexKupreev committed Sep 17, 2023
1 parent be3f28d commit a010229
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 95 deletions.
198 changes: 106 additions & 92 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ dennis = "^1.1"
dump-env = "^1.3"
ipython = "^8.15"
import-linter = "^1.11"
mimesis = "^11.1.0"

[tool.poetry.group.docs]
optional = true
Expand Down
4 changes: 1 addition & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
"""

pytest_plugins = [
# Should be the first custom one:
'plugins.django_settings',

# TODO: add your own plugins here!
'plugins.identity.user',
]
File renamed without changes.
10 changes: 10 additions & 0 deletions tests/plugins/django_settings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from random import SystemRandom

import pytest
from django.conf import LazySettings
from django.core.cache import BaseCache, caches

MAX_RANDOM_INT = 999999


@pytest.fixture(autouse=True)
def _media_root(
Expand Down Expand Up @@ -36,6 +40,12 @@ def _debug(settings: LazySettings) -> None:
template['OPTIONS']['debug'] = True


@pytest.fixture(scope='session', autouse=True)
def faker_seed() -> int:
"""Create a random seed for the Faker library."""
return SystemRandom().randint(0, MAX_RANDOM_INT)


@pytest.fixture(autouse=True)
def cache(settings: LazySettings) -> BaseCache:
"""Modifies how cache is used in Django tests."""
Expand Down
Empty file.
87 changes: 87 additions & 0 deletions tests/plugins/identity/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""Identity data related plugins."""
from datetime import datetime
from typing import Callable, Protocol, TypeAlias, TypedDict, Unpack, final

import pytest
from django.contrib.auth import get_user_model
from mimesis.locales import Locale
from mimesis.schema import Field, Schema


@final
class ProfileData(TypedDict, total=False):
"""Represent the simplified profile data."""

first_name: str
last_name: str
date_of_birth: datetime
address: str
job_title: str
phone: str


ProfileAssertion: TypeAlias = Callable[[str, ProfileData], None]


class ProfileDataFactory(Protocol):
"""Factory for representation of the simplified profile data."""

def __call__(self, **fields: Unpack[ProfileData]) -> ProfileData:
"""User data factory protocol."""


@pytest.fixture()
def profile_data_factory(
faker_seed: int,
) -> ProfileDataFactory:
"""Returns factory for fake random profile data."""

def factory(**fields: Unpack[ProfileData]) -> ProfileData:
mf = Field(locale=Locale.EN, seed=faker_seed)
schema = Schema(
schema=lambda: {
'first_name': mf('person.first_name'),
'last_name': mf('person.last_name'),
'date_of_birth': mf('datetime.date'),
'address': mf('address.city'),
'job_title': mf('person.occupation'),
'phone': mf('person.telephone'),
},
iterations=1,
)
return {
**schema.create()[0], # type: ignore[typeddict-item]
**fields,
}

return factory


@pytest.fixture(scope='session')
def assert_correct_profile() -> ProfileAssertion:
"""All profile fields are equal to reference."""

def factory(email: str, expected: ProfileData) -> None:
user = get_user_model().objects.get(email=email)
assert user.id
assert user.is_active
for field_name, data_value in expected.items():
assert getattr(user, field_name) == data_value
return factory


@pytest.fixture(scope='session')
def assert_incorrect_profile() -> ProfileAssertion:
"""At least one field does not match."""

def factory(email: str, expected: ProfileData) -> None:
user = get_user_model().objects.get(email=email)
assert user.id
assert user.is_active
matches = []
for field_name, data_value in expected.items():
matches.append(getattr(user, field_name) == data_value)

assert not all(matches)

return factory
61 changes: 61 additions & 0 deletions tests/test_server/test_urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from http import HTTPStatus

import pytest
from django.contrib.auth.models import User
from django.test import Client
from plugins.identity.user import ProfileAssertion, ProfileDataFactory


@pytest.mark.django_db()()
Expand Down Expand Up @@ -43,6 +45,65 @@ def test_admin_docs_authorized(admin_client: Client) -> None:
assert b'docutils' not in response.content


def test_picture_pages_unauthorized(client: Client) -> None:
"""This test ensures that picture management pages require auth."""
response = client.get('/pictures/dashboard')
assert response.status_code == HTTPStatus.FOUND

response = client.get('/pictures/favourites')
assert response.status_code == HTTPStatus.FOUND


@pytest.mark.django_db()
def test_picture_pages_authorized(
client: Client,
django_user_model: User,
) -> None:
"""Ensures picture management pages are accessible for authorized user."""
password, email = 'password', '[email protected]'
user = django_user_model.objects.create_user(
email,
password,
)
client.force_login(user)

response = client.get('/pictures/dashboard')
assert response.status_code == HTTPStatus.OK

response = client.get('/pictures/favourites')
assert response.status_code == HTTPStatus.OK


@pytest.mark.django_db()
def test_profile_update_authorized(
client: Client,
django_user_model: User,
profile_data_factory: 'ProfileDataFactory',
assert_correct_profile: 'ProfileAssertion',
assert_incorrect_profile: 'ProfileAssertion',
) -> None:
"""This test ensures profile updating for an authorized user."""
user_data = profile_data_factory()

password, email = 'password', '[email protected]'
user = django_user_model.objects.create_user(
email,
password,
)
client.force_login(user)

# there might be a probability of accidental match, but disregard it for now
assert_incorrect_profile(email, user_data)

response = client.post(
'/identity/update',
data=user_data,
)
assert response.status_code == HTTPStatus.FOUND
assert response.get('Location') == '/identity/update'
assert_correct_profile(email, user_data)


@pytest.mark.parametrize('page', [
'/robots.txt',
'/humans.txt',
Expand Down

0 comments on commit a010229

Please sign in to comment.