Skip to content

Commit

Permalink
Chore(test): Improve tests and gevent module check
Browse files Browse the repository at this point in the history
  • Loading branch information
alithethird committed Nov 29, 2024
1 parent b132e1a commit 128461a
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get("DJANGO_DEBUG", "true") == "true"

ALLOWED_HOSTS = json.loads(os.environ.get("DJANGO_ALLOWED_HOSTS", '["*"]'))
ALLOWED_HOSTS = json.loads(os.environ["DJANGO_ALLOWED_HOSTS"])


INSTALLED_APPS = [
Expand Down
5 changes: 0 additions & 5 deletions examples/django/django_async_app/django_async_app/migrate.sh

This file was deleted.

32 changes: 19 additions & 13 deletions src/paas_charm/_gunicorn/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import logging

from ops.pebble import ExecError, ExecProcess

from paas_charm._gunicorn.webserver import GunicornWebserver, WebserverConfig, WorkerClassEnum
from paas_charm._gunicorn.workload_config import create_workload_config
from paas_charm._gunicorn.wsgi_app import WsgiApp
Expand All @@ -25,18 +27,6 @@ def _workload_config(self) -> WorkloadConfig:
framework_name=self._framework_name, unit_name=self.unit.name
)

def check_gevent_package(self) -> bool:
"""Check that gevent is installed.
Returns:
True if gevent is installed.
"""
pip_list_command = self._container.exec(
["python3", "-c", "'import gevent;print(gevent.__version__)'"]
)
list_output = pip_list_command.wait_output()[0]
return "ModuleNotFoundError" not in list_output

def create_webserver_config(self) -> WebserverConfig:
"""Validate worker_class and create a WebserverConfig instance from the charm config.
Expand Down Expand Up @@ -68,7 +58,7 @@ def create_webserver_config(self) -> WebserverConfig:
if worker_class is WorkerClassEnum.SYNC:
return webserver_config

if not self.check_gevent_package():
if not self._check_gevent_package():
logger.error(
"gunicorn[gevent] must be installed in the rock. %s",
doc_link,
Expand Down Expand Up @@ -100,3 +90,19 @@ def _create_app(self) -> App:
webserver=webserver,
database_migration=self._database_migration,
)

def _check_gevent_package(self) -> bool:
"""Check that gevent is installed.
Returns:
True if gevent is installed.
"""
try:
check_gevent_process: ExecProcess = self._container.exec(
["python3", "-c", "import gevent"]
)
check_gevent_process.wait_output()
return True
except ExecError as cmd_error:
logger.warning("gunicorn[gevent] install check failed: %s", cmd_error)
return False
31 changes: 19 additions & 12 deletions tests/unit/django/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,27 @@

import ops
import pytest
from ops.testing import Harness
from ops.testing import ExecResult, Harness

from .constants import DEFAULT_LAYER


@pytest.mark.parametrize(
"worker_class, expected_status, expected_message",
"worker_class, expected_status, expected_message, exec_res",
[
(
"eventlet",
"blocked",
"Only 'gevent' and 'sync' are allowed. https://bit.ly/django-async-doc",
1,
),
("gevent", "active", ""),
("sync", "active", ""),
("gevent", "active", "", 0),
("sync", "active", "", 0),
],
)
def test_async_workers_config(harness: Harness, worker_class, expected_status, expected_message):
def test_async_workers_config(
harness: Harness, worker_class, expected_status, expected_message, exec_res
):
"""
arrange: Prepare a unit and run initial hooks.
act: Set the `webserver-worker-class` config.
Expand All @@ -38,11 +41,13 @@ def test_async_workers_config(harness: Harness, worker_class, expected_status, e
harness.add_relation("postgresql", "postgresql-k8s", app_data=postgresql_relation_data)
container = harness.model.unit.get_container("django-app")
container.add_layer("a_layer", DEFAULT_LAYER)

harness.handle_exec(
container.name,
["python3", "-c", "'import gevent;print(gevent.__version__)'"],
result="Gevent",
["python3", "-c", "import gevent"],
result=ExecResult(exit_code=exec_res),
)

harness.begin_with_initial_hooks()
harness.update_config({"webserver-worker-class": worker_class})
assert harness.model.unit.status == ops.StatusBase.from_name(
Expand All @@ -51,23 +56,25 @@ def test_async_workers_config(harness: Harness, worker_class, expected_status, e


@pytest.mark.parametrize(
"worker_class, expected_status, expected_message",
"worker_class, expected_status, expected_message, exec_res",
[
(
"eventlet",
"blocked",
"Only 'gevent' and 'sync' are allowed. https://bit.ly/django-async-doc",
1,
),
(
"gevent",
"blocked",
"gunicorn[gevent] must be installed in the rock. https://bit.ly/django-async-doc",
1,
),
("sync", "active", ""),
("sync", "active", "", 0),
],
)
def test_async_workers_config_fail(
harness: Harness, worker_class, expected_status, expected_message
harness: Harness, worker_class, expected_status, expected_message, exec_res
):
"""
arrange: Prepare a unit and run initial hooks.
Expand All @@ -86,8 +93,8 @@ def test_async_workers_config_fail(
container.add_layer("a_layer", DEFAULT_LAYER)
harness.handle_exec(
container.name,
["python3", "-c", "'import gevent;print(gevent.__version__)'"],
result="ModuleNotFoundError",
["python3", "-c", "import gevent"],
result=ExecResult(exit_code=exec_res),
)
harness.begin_with_initial_hooks()
harness.update_config({"webserver-worker-class": worker_class})
Expand Down
30 changes: 18 additions & 12 deletions tests/unit/flask/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import ops
import pytest
from ops.testing import Harness
from ops.testing import ExecResult, Harness

from .constants import DEFAULT_LAYER, FLASK_CONTAINER_NAME, LAYER_WITH_WORKER

Expand Down Expand Up @@ -40,18 +40,21 @@ def test_worker(harness: Harness):


@pytest.mark.parametrize(
"worker_class, expected_status, expected_message",
"worker_class, expected_status, expected_message, exec_res",
[
(
"eventlet",
"blocked",
"Only 'gevent' and 'sync' are allowed. https://bit.ly/flask-async-doc",
1,
),
("gevent", "active", ""),
("sync", "active", ""),
("gevent", "active", "", 0),
("sync", "active", "", 0),
],
)
def test_async_workers_config(harness: Harness, worker_class, expected_status, expected_message):
def test_async_workers_config(
harness: Harness, worker_class, expected_status, expected_message, exec_res
):
"""
arrange: Prepare a unit and run initial hooks.
act: Set the `webserver-worker-class` config.
Expand All @@ -63,9 +66,10 @@ def test_async_workers_config(harness: Harness, worker_class, expected_status, e

harness.handle_exec(
container.name,
["python3", "-c", "'import gevent;print(gevent.__version__)'"],
result="Gevent",
["python3", "-c", "import gevent"],
result=ExecResult(exit_code=exec_res),
)

harness.begin_with_initial_hooks()
harness.update_config({"webserver-worker-class": worker_class})
assert harness.model.unit.status == ops.StatusBase.from_name(
Expand All @@ -74,23 +78,25 @@ def test_async_workers_config(harness: Harness, worker_class, expected_status, e


@pytest.mark.parametrize(
"worker_class, expected_status, expected_message",
"worker_class, expected_status, expected_message, exec_res",
[
(
"eventlet",
"blocked",
"Only 'gevent' and 'sync' are allowed. https://bit.ly/flask-async-doc",
1,
),
(
"gevent",
"blocked",
"gunicorn[gevent] must be installed in the rock. https://bit.ly/flask-async-doc",
1,
),
("sync", "active", ""),
("sync", "active", "", 0),
],
)
def test_async_workers_config_fail(
harness: Harness, worker_class, expected_status, expected_message
harness: Harness, worker_class, expected_status, expected_message, exec_res
):
"""
arrange: Prepare a unit and run initial hooks.
Expand All @@ -103,8 +109,8 @@ def test_async_workers_config_fail(

harness.handle_exec(
container.name,
["python3", "-c", "'import gevent;print(gevent.__version__)'"],
result="ModuleNotFoundError",
["python3", "-c", "import gevent"],
result=ExecResult(exit_code=exec_res),
)
harness.begin_with_initial_hooks()
harness.update_config({"webserver-worker-class": worker_class})
Expand Down

0 comments on commit 128461a

Please sign in to comment.