Skip to content

Commit

Permalink
Chore(): Add Django test, simplify Django async test app
Browse files Browse the repository at this point in the history
  • Loading branch information
alithethird committed Nov 27, 2024
1 parent 37333e2 commit b132e1a
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,9 @@

from django.contrib import admin
from django.urls import path
from testing.views import environ, get_settings, login, sleep, user_count
from testing.views import sleep

urlpatterns = [
path("admin/", admin.site.urls),
path("settings/<str:name>", get_settings, name="get_settings"),
path("len/users", user_count, name="user_count"),
path("environ", environ, name="environ"),
path("sleep", sleep, name="sleep"),
path("login", login, name="login"),
]
Original file line number Diff line number Diff line change
@@ -1,39 +1,12 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.

import os
import time

from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.http import HttpResponse, JsonResponse


def environ(request):
return JsonResponse(dict(os.environ))


def user_count(request):
return JsonResponse(User.objects.count(), safe=False)


def get_settings(request, name):
if hasattr(settings, name):
return JsonResponse(getattr(settings, name), safe=False)
else:
return JsonResponse({"error": f"settings {name!r} not found"}, status=404)
from django.http import HttpResponse


def sleep(request):
duration = request.GET.get("duration")
time.sleep(int(duration))
return HttpResponse()


def login(request):
user = authenticate(username=request.GET.get("username"), password=request.GET.get("password"))
if user is not None:
return HttpResponse(status=200)
else:
return HttpResponse(status=403)
64 changes: 22 additions & 42 deletions tests/integration/django/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import logging
import time
import typing
from datetime import datetime

import aiohttp
import pytest
import requests
from juju.application import Application
Expand All @@ -18,55 +20,33 @@
logger = logging.getLogger(__name__)


@pytest.mark.parametrize(
"worker_class, expected_result",
[
("eventlet", "blocked"),
("gevent", "active"),
("sync", "active"),
],
)
@pytest.mark.usefixtures("django_async_app")
async def test_async_workers_config(
async def test_async_workers(
ops_test: OpsTest,
model: Model,
django_async_app: Application,
get_unit_ips,
worker_class: str,
expected_result: bool,
):
"""
arrange: Django is deployed with async enabled rock.
act: Change gunicorn worker class.
assert: Charm should only let the class to be 'sync' or 'gevent'.
If it is something other than these, then the unit should be blocked.
arrange: Django is deployed with async enabled rock. Change gunicorn worker class.
act: Do 15 requests that would take 2 seconds each.
assert: All 15 requests should be served in under 3 seconds.
"""
await django_async_app.set_config({"webserver-worker-class": worker_class})
await model.wait_for_idle(apps=[django_async_app.name], status=expected_result, timeout=60)
await django_async_app.set_config({"webserver-worker-class": "gevent"})
await model.wait_for_idle(apps=[django_async_app.name], status="active", timeout=60)

# the django unit is not important. Take the first one
django_unit_ip = (await get_unit_ips(django_async_app.name))[0]

@pytest.mark.parametrize(
"worker_class, expected_result",
[
("gevent", "blocked"),
("eventlet", "blocked"),
("sync", "active"),
],
)
@pytest.mark.usefixtures("django_app")
async def test_async_workers_config_fail(
ops_test: OpsTest,
model: Model,
django_app: Application,
get_unit_ips,
worker_class: str,
expected_result: str,
):
"""
arrange: Django is deployed with async not enabled rock.
act: Change gunicorn worker class.
assert: Charm should only let the class to be 'sync'.
If it is 'gevent' or something else, then the unit should be blocked.
"""
await django_app.set_config({"webserver-worker-class": worker_class})
await model.wait_for_idle(apps=[django_app.name], status=expected_result, timeout=60)
async def _fetch_page(session):
params = {"duration": 2}
async with session.get(f"http://{django_unit_ip}:8000/sleep", params=params) as response:
return await response.text()

start_time = datetime.now()
async with aiohttp.ClientSession() as session:
pages = [_fetch_page(session) for _ in range(15)]
await asyncio.gather(*pages)
assert (
datetime.now() - start_time
).seconds < 3, "Async workers for Django are not working!"
3 changes: 1 addition & 2 deletions tests/integration/flask/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ async def _fetch_page(session):
async with aiohttp.ClientSession() as session:
pages = [_fetch_page(session) for _ in range(15)]
await asyncio.gather(*pages)
print(f"TIMME: {(datetime.now() - start_time).seconds}")
assert (
datetime.now() - start_time
).seconds < 3, "The page took more than 2 seconds to load"
).seconds < 3, "Async workers for Flask are not working!"

0 comments on commit b132e1a

Please sign in to comment.