Skip to content

Commit

Permalink
✅ [#1] a create testapp and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
annashamray committed Feb 21, 2024
1 parent 2cc9bae commit 6c047d7
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 0 deletions.
47 changes: 47 additions & 0 deletions testapp/configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.models import User

from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import SelfTestFailed


class UserConfigurationStep(BaseConfigurationStep):
"""
Set up an initial user
The configuration set up a particular user only once in the regular mode.
If you want to change password or permissions use 'overwrite' mode
"""

verbose_name = "User Configuration"
required_settings = ["USER_CONFIGURATION_USERNAME", "USER_CONFIGURATION_PASSWORD"]
enable_setting = "USER_CONFIGURATION_ENABLED"

def is_configured(self) -> bool:
return User.objects.filter(
username=settings.USER_CONFIGURATION_USERNAME
).exists()

def configure(self) -> None:
user_qs = User.objects.filter(username=settings.USER_CONFIGURATION_USERNAME)
if user_qs.exists():
user = user_qs.get()
if not user.check_password(settings.USER_CONFIGURATION_PASSWORD):
user.set_password(settings.USER_CONFIGURATION_PASSWORD)
user.save()

else:
User.objects.create_user(
username=settings.USER_CONFIGURATION_USERNAME,
password=settings.USER_CONFIGURATION_PASSWORD,
is_superuser=True,
)

def test_configuration(self) -> None:
user = authenticate(
username=settings.USER_CONFIGURATION_USERNAME,
password=settings.USER_CONFIGURATION_PASSWORD,
)
if not user:
raise SelfTestFailed("No user with provided credentials is found")
14 changes: 14 additions & 0 deletions testapp/settings.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve(strict=True).parent
Expand Down Expand Up @@ -50,3 +51,16 @@
]

ROOT_URLCONF = "testapp.urls"

#
# django-setup-configuration settings
#
SETUP_CONFIGURATION_STEPS = ["testapp.configuration.UserConfigurationStep"]


#
# testapp settings
#
USER_CONFIGURATION_ENABLED = os.getenv("USER_CONFIGURATION_ENABLED", True)
USER_CONFIGURATION_USERNAME = os.getenv("USER_CONFIGURATION_USERNAME", "demo")
USER_CONFIGURATION_PASSWORD = os.getenv("USER_CONFIGURATION_PASSWORD", "secret")
145 changes: 145 additions & 0 deletions tests/test_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
from io import StringIO

from django.conf import settings
from django.contrib.auth.models import User
from django.core.management import CommandError, call_command

import pytest

from testapp.configuration import UserConfigurationStep

pytestmark = pytest.mark.django_db


def test_command_success():
"""
test happy flow
"""
assert User.objects.count() == 0

stdout = StringIO()
call_command("setup_configuration", stdout=stdout)

output = stdout.getvalue().splitlines()
step = UserConfigurationStep()
expected_output = [
f"Configuration would be set up with following steps: [{step}]",
f"Configuring {step}...",
f"{step} is successfully configured",
"Instance configuration completed.",
]
assert output == expected_output

assert User.objects.count() == 1
user = User.objects.get()
assert user.username == settings.USER_CONFIGURATION_USERNAME
assert user.check_password(settings.USER_CONFIGURATION_PASSWORD) is True


def test_command_called_twice(settings):
"""
test that the second run doesn't change configuration
"""
# 1st call
settings.USER_CONFIGURATION_PASSWORD = "secret1"
call_command("setup_configuration")
user = User.objects.get(username=settings.USER_CONFIGURATION_USERNAME)
assert user.check_password("secret1") is True

# 2nd call
settings.USER_CONFIGURATION_PASSWORD = "secret2"
stdout = StringIO()
call_command("setup_configuration", stdout=stdout)

output = stdout.getvalue().splitlines()
step = UserConfigurationStep()
expected_output = [
f"Configuration would be set up with following steps: [{step}]",
f"Step {step} is skipped, because the configuration already exists.",
"Instance configuration completed.",
]
assert output == expected_output

user = User.objects.get(username=settings.USER_CONFIGURATION_USERNAME)
assert user.check_password("secret1") is True


def test_command_called_twice_with_overwrite():
"""
test that the second run change configuration in overwrite mode
"""
# 1st call
settings.USER_CONFIGURATION_PASSWORD = "secret1"
call_command("setup_configuration")
user = User.objects.get(username=settings.USER_CONFIGURATION_USERNAME)
assert user.check_password("secret1") is True

# 2nd call
settings.USER_CONFIGURATION_PASSWORD = "secret2"
stdout = StringIO()
call_command("setup_configuration", overwrite=True, stdout=stdout)

output = stdout.getvalue().splitlines()
step = UserConfigurationStep()
expected_output = [
f"Configuration would be set up with following steps: [{step}]",
f"Configuring {step}...",
f"{step} is successfully configured",
"Instance configuration completed.",
]
assert output == expected_output

user = User.objects.get(username=settings.USER_CONFIGURATION_USERNAME)
assert user.check_password("secret2") is True


def test_command_no_config_steps(settings):
"""
test that the command quits in the beginning with appropriate stdout
"""
settings.SETUP_CONFIGURATION_STEPS = []

stdout = StringIO()
call_command("setup_configuration", stdout=stdout)

output = stdout.getvalue().splitlines()
expected_output = [
"There are no enabled configuration steps. Configuration can't be set up",
]
assert output == expected_output
assert User.objects.count() == 0


def test_command_disabled(settings):
"""
test that the command doesn't run the disabled configuration step
"""
settings.USER_CONFIGURATION_ENABLED = False

stdout = StringIO()
call_command("setup_configuration", stdout=stdout)

output = stdout.getvalue().splitlines()
expected_output = [
"There are no enabled configuration steps. Configuration can't be set up",
]
assert output == expected_output
assert User.objects.count() == 0


def test_command_failed_selftest(mocker):
"""
test that if configuration.test_configuration fails with SelfTestFailed
CommandError is raised and no db change is done
"""
mocker.patch("testapp.configuration.authenticate", return_value=None)

with pytest.raises(CommandError) as exc:
call_command("setup_configuration")

exc_description = (
f"Configuration test failed with errors: "
f"{UserConfigurationStep()}: No user with provided credentials is found"
)
assert exc.value.args[0] == exc_description
assert User.objects.count() == 0
38 changes: 38 additions & 0 deletions tests/test_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

from django_setup_configuration.exceptions import PrerequisiteFailed
from testapp.configuration import UserConfigurationStep


def test_configuration_enabled():
"""
test that configuration is enabled when the related setting is set to True
"""
assert UserConfigurationStep().is_enabled() is True


def test_configuration_disabled(settings):
"""
test that configuration is enabled when the related setting is set to False
"""
settings.USER_CONFIGURATION_ENABLED = False

assert UserConfigurationStep().is_enabled() is False


def test_prerequisites_valid():
"""
test that no error is raised when necessary settings are provided
"""
UserConfigurationStep().validate_requirements()


def test_prerequisites_invalid(settings):
"""
test that PrerequisiteFailed is raised when necessary settings are missing
"""
settings.USER_CONFIGURATION_USERNAME = ""
settings.USER_CONFIGURATION_PASSWORD = ""

with pytest.raises(PrerequisiteFailed):
UserConfigurationStep().validate_requirements()

0 comments on commit 6c047d7

Please sign in to comment.