Merge branch 'devel' into 'master'

Pull latest fixed from devel

See merge request oliver/ivatar!266
This commit is contained in:
Oliver Falk
2025-10-17 12:56:16 +02:00

View File

@@ -575,14 +575,12 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
# rb => Read binary
with open(TEST_IMAGE_FILE, "rb") as photo_file:
photo_data = photo_file.read()
from django.core.files.uploadedfile import SimpleUploadedFile
uploaded_file = SimpleUploadedFile(
"deadbeef.png",
photo_data,
content_type="image/png"
"deadbeef.png", photo_data, content_type="image/png"
)
response = self.client.post(
url,
{
@@ -2028,3 +2026,319 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
"This mail address has been taken already and cannot be confirmed",
"This should return an error message!",
)
class OpenIDErrorHandlingTestCase(TestCase):
"""
Test cases for OpenID error handling and error.html template coverage
"""
def setUp(self):
"""Set up test user and client"""
self.username = random_string()
self.password = random_string()
self.user = User.objects.create_user(
username=self.username,
password=self.password,
)
self.client = Client()
def login(self):
"""Login as test user"""
self.client.login(username=self.username, password=self.password)
def test_openid_discovery_failure_renders_error_template(self):
"""
Test that OpenID discovery failure renders error.html template
"""
from unittest.mock import patch, MagicMock
from openid.consumer import consumer
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://invalid-openid-provider.example.com/",
)
# Mock the OpenID consumer to raise DiscoveryFailure
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a proper DiscoveryFailure with required http_response parameter
mock_response = MagicMock()
mock_response.status_code = 404
discovery_failure = consumer.DiscoveryFailure(
"Invalid provider", mock_response
)
mock_consumer.begin.side_effect = discovery_failure
# Make request to openid_redirection view
response = self.client.get(
reverse("openid_redirection", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(
any("OpenID discovery failed" in str(msg) for msg in messages)
)
def test_openid_confirmation_failure_renders_error_template(self):
"""
Test that OpenID confirmation failure renders error.html template
"""
from unittest.mock import patch, MagicMock
from openid.consumer import consumer
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://test-provider.example.com/",
)
# Mock the OpenID consumer to return FAILURE status
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a mock response with FAILURE status
mock_response = MagicMock()
mock_response.status = consumer.FAILURE
mock_response.message = "Authentication failed"
mock_consumer.complete.return_value = mock_response
# Make request to confirm_openid view
response = self.client.get(
reverse("confirm_openid", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(any("Confirmation failed" in str(msg) for msg in messages))
def test_openid_cancellation_renders_error_template(self):
"""
Test that OpenID cancellation renders error.html template
"""
from unittest.mock import patch, MagicMock
from openid.consumer import consumer
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://test-provider.example.com/",
)
# Mock the OpenID consumer to return CANCEL status
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a mock response with CANCEL status
mock_response = MagicMock()
mock_response.status = consumer.CANCEL
mock_consumer.complete.return_value = mock_response
# Make request to confirm_openid view
response = self.client.get(
reverse("confirm_openid", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(any("Cancelled by user" in str(msg) for msg in messages))
def test_openid_unknown_error_renders_error_template(self):
"""
Test that unknown OpenID verification error renders error.html template
"""
from unittest.mock import patch, MagicMock
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://test-provider.example.com/",
)
# Mock the OpenID consumer to return unknown status
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a mock response with unknown status
mock_response = MagicMock()
mock_response.status = "UNKNOWN_STATUS"
mock_consumer.complete.return_value = mock_response
# Make request to confirm_openid view
response = self.client.get(
reverse("confirm_openid", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(
any("Unknown verification error" in str(msg) for msg in messages)
)
def test_openid_nonexistent_id_error(self):
"""
Test that accessing non-existent OpenID ID shows error message
"""
self.login()
# Try to access a non-existent OpenID ID
response = self.client.get(
reverse("openid_redirection", args=[99999]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(any("ID does not exist" in str(msg) for msg in messages))
def test_django_openid_auth_failure_template_coverage(self):
"""
Test that django-openid-auth failure template uses error.html
This test verifies the OpenID login page renders correctly
"""
# Try to access the OpenID login page
response = self.client.get(reverse("openid-login"))
self.assertEqual(response.status_code, 200)
# The login page should render successfully
self.assertContains(response, "OpenID Login")
def test_error_template_direct_rendering(self):
"""
Test error.html template directly to ensure it renders correctly
"""
from django.test import RequestFactory
from django.template import Context, Template
from django.contrib.auth.models import AnonymousUser
# Test with authenticated user
factory = RequestFactory()
request = factory.get("/")
request.user = self.user
# Test template with error message
template_content = """
{% extends 'error.html' %}
{% load i18n %}
{% block errormessage %}
{% trans 'Test error message:' %} {{ errormessage }}
{% endblock errormessage %}
"""
template = Template(template_content)
context = Context(
{
"request": request,
"errormessage": "This is a test error",
"user": self.user,
}
)
rendered = template.render(context)
# Verify the template renders without errors
self.assertIn("Error!", rendered)
self.assertIn("This is a test error", rendered)
# Check for the profile link in the navbar (not in the backlink block)
self.assertIn("/accounts/profile/", rendered)
# Test with anonymous user
request.user = AnonymousUser()
context = Context(
{
"request": request,
"errormessage": "This is a test error",
"user": AnonymousUser(),
}
)
rendered = template.render(context)
# Verify the template renders without errors for anonymous users
self.assertIn("Error!", rendered)
self.assertIn("This is a test error", rendered)
# Should not contain profile link for anonymous users
self.assertNotIn("/accounts/profile/", rendered)
def test_openid_failure_template_inheritance(self):
"""
Test that openid/failure.html properly extends error.html
"""
from django.test import RequestFactory
from django.template import Context, Template
factory = RequestFactory()
request = factory.get("/")
request.user = self.user
# Test the openid/failure.html template
template_content = """
{% extends 'error.html' %}
{% load i18n %}
{% block errormessage %}
{% trans 'OpenID error:' %} {{ message }}
{% endblock errormessage %}
"""
template = Template(template_content)
context = Context(
{
"request": request,
"message": "Authentication failed",
"user": self.user,
}
)
rendered = template.render(context)
# Verify the template renders correctly
self.assertIn("Error!", rendered)
self.assertIn("OpenID error:", rendered)
self.assertIn("Authentication failed", rendered)
# Check for the profile link in the navbar (not in the backlink block)
self.assertIn("/accounts/profile/", rendered)