Skip to content
This repository was archived by the owner on Jul 18, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ norecursedirs = *.egg .eggs dist build docs .tox .git __pycache__
# Strict `@xfail` by default:
xfail_strict = true

DJANGO_SETTINGS_MODULE = autodonate.settings

# Extra options:
addopts =
--strict-markers
Expand Down
1 change: 1 addition & 0 deletions tests/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Package for the tests which test API app."""
16 changes: 16 additions & 0 deletions tests/api/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Shared fixtures for tests in ``api/`` folder."""
from django.core.management import call_command
from pytest import fixture

from autodonate.models import Config
from tests import api


@fixture(scope="session", autouse=True)
def django_db_setup(django_db_setup, django_db_blocker):
"""Additional setup DB steps."""
with django_db_blocker.unblock():
api.test_config.set_up()
api.test_product.set_up()
api.test_player.set_up()
api.test_donation.set_up()
86 changes: 86 additions & 0 deletions tests/api/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Tests for ``/api/config/`` path."""
from json import loads

from pytest import fixture, mark
from rest_framework.response import Response
from rest_framework.test import APIClient
from structlog import get_logger

from autodonate.models import Config

log = get_logger()

response: Response = None


def set_up() -> None:
"""Set up some variables for config testing.

This called once only in ``conftest.py``, do not touch.

Raises:
NameError: When ``test_config.response`` variable already set,
so this function called second time.
"""
Config.set("something1", "1", True)
Config.set("something2", "2", True)
Config.set("something3", "3", False)

global response
if response is not None:
raise NameError("This function must be called once!")
response = APIClient().get("/api/config/")


class TestConfig:
"""Tests for ``/api/config/`` path."""

@fixture(scope="session")
def data(self):
"""Parse and return dict with answer."""
return loads(response.content)

def test_status_code(self) -> None:
"""``status_code`` must be 200 - okay."""
assert 200 == response.status_code

@mark.parametrize(
"key,value",
[
("something1", '"1"'),
("something2", '"2"'),
],
)
def test_exist_object(self, data, key: str, value: str) -> None:
"""Is object in response data."""
assert {"key": key, "value": value, "read_only": False} in data

@mark.parametrize(
"key,value",
[("something3", '"3"')],
)
def test_object_not_exist(self, data, key: str, value: str) -> None:
"""Is object not in response data."""
assert {"key": key, "value": value, "read_only": False} not in data

def test_no_public_field_in_api_response(self, data) -> None:
"""User shouldn't see ``public`` field in API response, because it is always True."""
for row in data:
assert "public" not in row.keys()


@mark.skip("Feature for this test didn't implemented.")
class TestConfigNotImplemented:
"""Tests for features that was planned, but didn't implemented.

Todo:
Implement features and move this tests to ``TestConfig``.
"""

def test_value_returning_string(self, data) -> None:
"""Check that we returning string, not string in string.

Example:
Return ``'abc'`` instead of ``"'abc'"``.
"""
assert {"key": "something1", "value": "1", "read_only": False} in data
98 changes: 98 additions & 0 deletions tests/api/test_donation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Tests for ``/api/donation/`` path."""
from json import loads

from pytest import fixture, mark
from rest_framework.response import Response
from rest_framework.test import APIClient
from structlog import get_logger

from autodonate.models import Config, Donation, Player, Product

log = get_logger()

response: Response = None


def set_up() -> None:
"""Set up some variables for donation testing.

This called once only in ``conftest.py``, do not touch.

Raises:
NameError: When ``test_donation.response`` variable already set,
so this function called second time.
"""
products, players = [], []
for num in range(1, 7):
product = Product(name=str(num), price=num)
player = Player(nickname="Steve" + str(num))

product.save()
player.save()

products.append(product)
players.append(player)

Donation(product=product, player=player).save()

global response
if response is not None:
raise NameError("This function must be called once!")
response = APIClient().get("/api/donation/")

for product in products:
product.delete()
for player in players:
player.delete()


class TestDonation:
"""Tests for ``/api/donation/`` path."""

@fixture(scope="session")
def data(self):
"""Parse and return dict with answer."""
return loads(response.content)

def test_status_code(self) -> None:
"""``status_code`` must be 200 - okay."""
assert 200 == response.status_code

def test_response_len_6(self, data) -> None:
"""API must return only first 6 records."""
assert len(data) == 6

def test_correct_order(self, data) -> None:
"""Suring about correct order in response."""
for i, record in enumerate(data):
i += 1 # start with 1, not 0
assert record["product"]["name"] == str(i)
assert record["product"]["price"] == i
assert record["player"]["nickname"] == "Steve" + str(i)

@mark.skip("This is a bug")
@mark.django_db
def test_do_not_show_not_enabled_products(self) -> None:
"""If ``product`` is not enabled, it should be hidden."""
Donation.objects.all().delete()

products, players = [], []
for num in range(3):
product = Product(name=str(num), price=num)
player = Player(nickname="Steve" + str(num))

product.save()
player.save()

products.append(product)
players.append(player)

Donation(product=product, player=player).save()

response = APIClient().get("/api/donation/")
assert loads(response.content) == []

for product in products:
product.delete()
for player in players:
player.delete()
95 changes: 95 additions & 0 deletions tests/api/test_player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""Tests for ``/api/player/`` path."""
from json import loads
from typing import Any, Dict, List

from pytest import fixture, mark
from rest_framework.response import Response
from rest_framework.test import APIClient
from structlog import get_logger

from autodonate.models import Player

log = get_logger()

_response: List[Response] = []

parametrize_num: int


def set_up() -> None:
"""Set up some variables for player testing.

This called once only in ``conftest.py``, do not touch.

Raises:
NameError: When ``test_player._response`` variable already set,
so this function called second time.
"""
global _response
if _response != []:
raise NameError("This function must be called once!")

for player_nick in ["something1", "something2", "something3"]:
Player(nickname=player_nick).save()

_response.append(APIClient().get(f"/api/player/{player_nick}/"))

_response.append(APIClient().get(f"/api/player/"))


class TestPlayer:
"""Tests for ``/api/player/`` path."""

@fixture(scope="session", params=[0, 1, 2])
def response(self, request) -> Response:
"""Response object for parametrizing tests."""
global parametrize_num
parametrize_num = request.param
return _response[parametrize_num]

def test_status_code(self, response) -> None:
"""``status_code`` must be 200 - okay."""
assert 200 == response.status_code

def test_expected_output(self, response) -> None:
"""Is object in response data."""
assert {"nickname": "something" + str(parametrize_num + 1)} == response.data


class TestPlayerRootPath:
"""Actually, root path of ``/api/player/`` should return 404.

So in this way, pontential hacker can't get list with all players, he
will get some info, only if have players nickname, and setted it as
``/api/player/{nickname}/``.
"""

@fixture(scope="session")
def response(self) -> Response:
"""Actually just return fourth element from ``_response``.

Becouse fourth element in ``_response`` list is response to API
root. See ``set_up()`` method here.

Returns:
Cached ``Response`` element.
"""
return _response[3]

def test_status_code(self, response: Response) -> None:
"""Status code should be 404 here.

See description of the class.
"""
assert 404 == response.status_code

@mark.skip("Feature for this test didn't implemented.")
def test_status_code_unathorized(self, response: Response) -> None:
"""Status code should be 401 here.

We should return 401 (Unathorized) instead of just 404 (Not found).

Todo:
Implement this, and replace ``test_status_code`` with this test.
"""
assert 401 == response.status_code
Loading