Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional tests for the Concordia app #2668

Merged
merged 16 commits into from
Jan 10, 2025
Merged
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 .coveragerc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[run]
dynamic_context = test_function
branch = true
include =
concordia/*
Expand All @@ -8,6 +9,7 @@ omit =
*/migrations/*
*/tests/*
*/settings*.py
*/urls.py
*/static/*

[report]
Expand Down
7 changes: 0 additions & 7 deletions concordia/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,3 @@
from concordia.celery import app as celery_app

__all__ = ["celery_app"]


VERSION = (0, 0, 1)


def get_version():
return ".".join(map(str, VERSION))
5 changes: 0 additions & 5 deletions concordia/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,3 @@

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()


@app.task(bind=True)
def debug_task(self):
print("Request: {0!r}".format(self.request))
11 changes: 11 additions & 0 deletions concordia/tests/test_account_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ def test_AccountProfileView_post(self):

self.login_user()

with self.settings(REQUIRE_EMAIL_RECONFIRMATION=False):
# First, test trying to 'update' to the already used email
response = self.client.post(
reverse("user-profile"),
{"email": self.user.email, "username": "tester"},
)

self.assertEqual(response.status_code, 200)
self.assertIn("form", response.context)
self.assertFalse(response.context["form"].is_valid())

with self.settings(REQUIRE_EMAIL_RECONFIRMATION=False):
response = self.client.post(
reverse("user-profile"), {"email": test_email, "username": "tester"}
Expand Down
68 changes: 67 additions & 1 deletion concordia/tests/test_api_views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from datetime import date
from unittest import mock
from urllib.parse import urlparse

from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils.timezone import now

from concordia import api_views
from concordia.models import (
Asset,
Campaign,
Expand All @@ -23,6 +26,57 @@
)


class URLAwareEncoderTest(TestCase):
def test_default(self):
encoder = api_views.URLAwareEncoder()
self.assertEqual(encoder.default(None), None)

obj = mock.Mock(spec=["url"])
self.assertEqual(encoder.default(obj), obj.url)

obj = mock.Mock(spec=["get_absolute_url"])
self.assertEqual(encoder.default(obj), obj.get_absolute_url())

# Test non-model object
obj = date.today()
self.assertEqual(encoder.default(obj), date.today().isoformat())


class APIViewMixinTest(TestCase):
def setUp(self):
self.mixin = api_views.APIViewMixin()

def test_serialize_conctext(self):
context = {"test-key": "test-value"}
self.assertEqual(self.mixin.serialize_context(context), context)

@mock.patch("concordia.api_views.model_to_dict")
def test_serialize_object(self, mtd_mock):
return_data = {"test-key": "test-value"}
mtd_mock.return_value = return_data

obj = mock.Mock(spec=["get_absolute_url"])
data = self.mixin.serialize_object(obj)

self.assertEqual(data, return_data | {"url": obj.get_absolute_url()})

obj = mock.Mock(spec=[])
data = self.mixin.serialize_object(obj)

self.assertEqual(data, return_data)


@mock.patch("concordia.api_views.time")
class APIListViewTest(TestCase):
def test_serialize_context(self, time_mock):
time_mock.return_value = "test-time"
view = api_views.APIListView()
context = {"object_list": []}

data = view.serialize_context(context)
self.assertEqual(data, {"objects": [], "sent": "test-time"})


@override_settings(RATELIMIT_ENABLE=False)
class ConcordiaViewTests(JSONAssertMixin, TestCase):
@classmethod
Expand Down Expand Up @@ -50,6 +104,16 @@ def setUpTestData(cls):

cls.assets = []
for item in cls.items:
cls.assets.append(
create_asset(
title=f"Thumbnail URL test for {item.id}",
item=item,
download_url="http://tile.loc.gov/image-services/iiif/"
"service:music:mussuffrage:mussuffrage-100183:mussuffrage-100183.0001/"
"full/pct:100/0/default.jpg",
do_save=False,
)
)
for i in range(0, 15):
cls.assets.append(
create_asset(title=f"{item.id} — {i}", item=item, do_save=False)
Expand Down Expand Up @@ -92,7 +156,7 @@ def get_api_response(self, url, **request_args):
data = self.assertValidJSON(resp)
return resp, data

def get_api_list_response(self, url, page_size=23, **request_args):
def get_api_list_response(self, url, page_size=10, **request_args):
"""
This issues a call to one of our API views and confirms that the
response follows our basic conventions of returning a top level object
Expand Down Expand Up @@ -347,3 +411,5 @@ def test_item_detail(self):
self.assertIn("slug", obj)
self.assertIn("url", obj)
self.assertIn("year", obj)
if "Thumbnail test" in obj["title"]:
self.assertIn("https", obj["thumbnail_url"])
69 changes: 69 additions & 0 deletions concordia/tests/test_authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from django.test import RequestFactory, TestCase

from concordia.authentication_backends import EmailOrUsernameModelBackend

from .utils import CreateTestUsers


class AuthenticationBackendTests(TestCase, CreateTestUsers):
def test_EmailOrUsernameModelBackend(self):
backend = EmailOrUsernameModelBackend()
request_factory = RequestFactory()
test_user = self.create_user("tester")
request = request_factory.get("/")

# Fail to authenticate with no information
user = backend.authenticate(request)
self.assertEqual(user, None)

# Fail to authenticate with no password, using username
user = backend.authenticate(request, test_user.username)
self.assertEqual(user, None)

# Authenticate with correct password, using username
user = backend.authenticate(request, test_user.username, test_user._password)
self.assertEqual(user, test_user)

# Fail to authenticate with no password, using email
user = backend.authenticate(request, test_user.email)
self.assertEqual(user, None)

# Authenticate with correct password, using email
user = backend.authenticate(request, test_user.email, test_user._password)
self.assertEqual(user, test_user)

# Fail to authenticate with incorrect password, using username
user = backend.authenticate(request, test_user.username, "bad-password")
self.assertEqual(user, None)

# Fail to authenticate with incorrect password, using email
user = backend.authenticate(request, test_user.email, "bad-password")
self.assertEqual(user, None)

# Same tests, with user with a username
# the same as the first user's email address
test_user2 = self.create_user(test_user.email)

# Fail to authenticate with no password, using username
user = backend.authenticate(request, test_user2.username)
self.assertEqual(user, None)

# Authenticate with correct password, using username
user = backend.authenticate(request, test_user2.username, test_user2._password)
self.assertEqual(user, test_user2)

# Fail to authenticate with no password, using email
user = backend.authenticate(request, test_user2.email)
self.assertEqual(user, None)

# Authenticate with correct password, using email
user = backend.authenticate(request, test_user2.email, test_user2._password)
self.assertEqual(user, test_user2)

# Fail to authenticate with incorrect password, using username
user = backend.authenticate(request, test_user2.username, "bad-password")
self.assertEqual(user, None)

# Fail to authenticate with incorrect password, using email
user = backend.authenticate(request, test_user2.email, "bad-password")
self.assertEqual(user, None)
70 changes: 70 additions & 0 deletions concordia/tests/test_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from unittest import mock
from urllib.error import HTTPError

from django.forms import ValidationError
from django.test import TestCase, override_settings

from concordia.turnstile.fields import TurnstileField


class TestFields(TestCase):
@override_settings(
TURNSTILE_PROXIES={},
TURNSTILE_SECRET="test-secret",
TURNSTILE_VERIFY_URL="http://example.com",
TURNSTILE_TIMEOUT=0,
)
def test_TurnstileField(self):
with (
override_settings(
TURNSTILE_DEFAULT_CONFIG={"appearance": "interaction-only"}
),
mock.patch("concordia.turnstile.fields.Request"),
mock.patch("concordia.turnstile.fields.build_opener") as opener_mock,
):
open_mock = opener_mock.return_value.open
read_mock = open_mock.return_value.read

field = TurnstileField(required=False)

self.assertEqual(
field.widget_attrs(field.widget),
{"data-appearance": "interaction-only"},
)

# Successful validation from Turnstile
read_mock.return_value = '{"success" : true}'.encode()
self.assertEqual(field.validate("test-value"), None)

# Unsuccessful validation from Turnstile
read_mock.return_value = '{"test-key" : "test-value"}'.encode()
self.assertRaises(ValidationError, field.validate, "test-value")

# Error trying to contact Turnstile
open_mock.side_effect = HTTPError(
"http://example.com", 404, "Test message%", "", mock.MagicMock()
)
self.assertRaises(ValidationError, field.validate, "test-value")

# Testing special parameters on the widget
field = TurnstileField(
onload="testOnload()",
render="test-render",
hl="test-hl",
test_parameter="test-data",
)
self.assertEqual(
field.widget_attrs(field.widget),
{
"data-appearance": "interaction-only",
"data-test_parameter": "test-data",
},
)
self.assertEqual(
field.widget.extra_url,
{
"onload": "testOnload()",
"render": "test-render",
"hl": "test-hl",
},
)
53 changes: 53 additions & 0 deletions concordia/tests/test_maintenance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from django.core.cache import cache
from django.test import RequestFactory, TestCase
from maintenance_mode.core import set_maintenance_mode

from concordia.maintenance import need_maintenance_response

from .utils import CreateTestUsers


class TestMaintenance(TestCase, CreateTestUsers):
def setUp(self):
self.request_factory = RequestFactory()
cache.clear()

def tearDown(self):
cache.clear()

def test_need_maintenance_response_maintenance_default(self):
request = self.request_factory.get("/")
self.assertFalse(need_maintenance_response(request))

def test_need_maintenance_response_maintenance_off(self):
set_maintenance_mode(False)
request = self.request_factory.get("/")
self.assertFalse(need_maintenance_response(request))

def test_need_maintenance_response_maintenance_on(self):
set_maintenance_mode(True)
request = self.request_factory.get("/")
self.assertTrue(need_maintenance_response(request))

request.user = self.create_test_user()
request.user.is_staff = True

# User is set and is staff, but frontend is off
# (the default) so they should still get a maintenance
# mode response
self.assertTrue(need_maintenance_response(request))

def test_need_maintenance_response_maintenance_frontend(self):
set_maintenance_mode(True)
request = self.request_factory.get("/")
request.user = self.create_test_user()
cache.set("maintenance_mode_frontend_available", True)

# User is set but isn't super user, so they should get
# a maintenance mode response
self.assertTrue(need_maintenance_response(request))

request.user.is_staff = True
# User is staff, so they shouldn't get a maintenance
# mode response
self.assertFalse(need_maintenance_response(request))
Loading
Loading