authentik.admin.files.tests.test_manager

Test file service layer

  1"""Test file service layer"""
  2
  3from unittest import skipUnless
  4from urllib.parse import urlparse
  5
  6from django.http import HttpRequest
  7from django.test import TestCase
  8
  9from authentik.admin.files.manager import FileManager
 10from authentik.admin.files.tests.utils import (
 11    FileTestFileBackendMixin,
 12    FileTestS3BackendMixin,
 13    s3_test_server_available,
 14)
 15from authentik.admin.files.usage import FileUsage
 16from authentik.lib.config import CONFIG
 17
 18
 19class TestResolveFileUrlBasic(TestCase):
 20    def test_resolve_empty_path(self):
 21        """Test resolving empty file path"""
 22        manager = FileManager(FileUsage.MEDIA)
 23        result = manager.file_url("")
 24        self.assertEqual(result, "")
 25
 26    def test_resolve_none_path(self):
 27        """Test resolving None file path"""
 28        manager = FileManager(FileUsage.MEDIA)
 29        result = manager.file_url(None)
 30        self.assertEqual(result, "")
 31
 32    def test_resolve_font_awesome(self):
 33        """Test resolving Font Awesome icon"""
 34        manager = FileManager(FileUsage.MEDIA)
 35        result = manager.file_url("fa://fa-check")
 36        self.assertEqual(result, "fa://fa-check")
 37
 38    def test_resolve_http_url(self):
 39        """Test resolving HTTP URL"""
 40        manager = FileManager(FileUsage.MEDIA)
 41        result = manager.file_url("http://example.com/icon.png")
 42        self.assertEqual(result, "http://example.com/icon.png")
 43
 44    def test_resolve_https_url(self):
 45        """Test resolving HTTPS URL"""
 46        manager = FileManager(FileUsage.MEDIA)
 47        result = manager.file_url("https://example.com/icon.png")
 48        self.assertEqual(result, "https://example.com/icon.png")
 49
 50    def test_resolve_static_path(self):
 51        """Test resolving static file path"""
 52        manager = FileManager(FileUsage.MEDIA)
 53        result = manager.file_url("/static/authentik/sources/icon.svg")
 54        self.assertEqual(result, "/static/authentik/sources/icon.svg")
 55
 56
 57class TestResolveFileUrlFileBackend(FileTestFileBackendMixin, TestCase):
 58    def test_resolve_storage_file(self):
 59        """Test resolving uploaded storage file"""
 60        manager = FileManager(FileUsage.MEDIA)
 61        result = manager.file_url("test.png").split("?")[0]
 62        self.assertEqual(result, "/files/media/public/test.png")
 63
 64    def test_resolve_full_static_with_request(self):
 65        """Test resolving static file with request builds absolute URI"""
 66        mock_request = HttpRequest()
 67        mock_request.META = {
 68            "HTTP_HOST": "example.com",
 69            "SERVER_NAME": "example.com",
 70        }
 71
 72        manager = FileManager(FileUsage.MEDIA)
 73        result = manager.file_url("/static/icon.svg", mock_request)
 74
 75        self.assertEqual(result, "http://example.com/static/icon.svg")
 76
 77    def test_resolve_full_file_backend_with_request(self):
 78        """Test resolving FileBackend file with request"""
 79        mock_request = HttpRequest()
 80        mock_request.META = {
 81            "HTTP_HOST": "example.com",
 82            "SERVER_NAME": "example.com",
 83        }
 84
 85        manager = FileManager(FileUsage.MEDIA)
 86        result = manager.file_url("test.png", mock_request).split("?")[0]
 87
 88        self.assertEqual(result, "http://example.com/files/media/public/test.png")
 89
 90
 91@skipUnless(s3_test_server_available(), "S3 test server not available")
 92class TestResolveFileUrlS3Backend(FileTestS3BackendMixin, TestCase):
 93    @CONFIG.patch("storage.media.s3.custom_domain", "s3.test:8080/test")
 94    @CONFIG.patch("storage.media.s3.secure_urls", False)
 95    def test_resolve_full_s3_backend(self):
 96        """Test resolving S3Backend returns presigned URL as-is"""
 97        mock_request = HttpRequest()
 98        mock_request.META = {
 99            "HTTP_HOST": "example.com",
100            "SERVER_NAME": "example.com",
101        }
102
103        manager = FileManager(FileUsage.MEDIA)
104        result = manager.file_url("test.png", mock_request)
105
106        # S3 URLs should be returned as-is (already absolute)
107        self.assertTrue(result.startswith("http://s3.test:8080/test"))
108
109
110class TestThemedUrls(FileTestFileBackendMixin, TestCase):
111    """Test FileManager.themed_urls method"""
112
113    def test_themed_urls_none_path(self):
114        """Test themed_urls returns None for None path"""
115        manager = FileManager(FileUsage.MEDIA)
116        result = manager.themed_urls(None)
117        self.assertIsNone(result)
118
119    def test_themed_urls_empty_path(self):
120        """Test themed_urls returns None for empty path"""
121        manager = FileManager(FileUsage.MEDIA)
122        result = manager.themed_urls("")
123        self.assertIsNone(result)
124
125    def test_themed_urls_no_theme_variable(self):
126        """Test themed_urls returns None when no %(theme)s in path"""
127        manager = FileManager(FileUsage.MEDIA)
128        result = manager.themed_urls("logo.png")
129        self.assertIsNone(result)
130
131    def test_themed_urls_with_theme_variable(self):
132        """Test themed_urls returns dict of URLs for each theme"""
133        manager = FileManager(FileUsage.MEDIA)
134        result = manager.themed_urls("logo-%(theme)s.png")
135
136        self.assertIsInstance(result, dict)
137        self.assertIn("light", result)
138        self.assertIn("dark", result)
139        self.assertIn("logo-light.png", result["light"])
140        self.assertIn("logo-dark.png", result["dark"])
141
142    def test_themed_urls_with_request(self):
143        """Test themed_urls builds absolute URLs with request"""
144        mock_request = HttpRequest()
145        mock_request.META = {
146            "HTTP_HOST": "example.com",
147            "SERVER_NAME": "example.com",
148        }
149
150        manager = FileManager(FileUsage.MEDIA)
151        result = manager.themed_urls("logo-%(theme)s.svg", mock_request)
152
153        self.assertIsInstance(result, dict)
154        light_url = urlparse(result["light"])
155        dark_url = urlparse(result["dark"])
156        self.assertEqual(light_url.scheme, "http")
157        self.assertEqual(light_url.netloc, "example.com")
158        self.assertEqual(dark_url.scheme, "http")
159        self.assertEqual(dark_url.netloc, "example.com")
160
161    def test_themed_urls_passthrough_with_theme_variable(self):
162        """Test themed_urls returns dict for passthrough URLs with %(theme)s"""
163        manager = FileManager(FileUsage.MEDIA)
164        # External URLs with %(theme)s should return themed URLs
165        result = manager.themed_urls("https://example.com/logo-%(theme)s.png")
166        self.assertIsInstance(result, dict)
167        self.assertEqual(result["light"], "https://example.com/logo-light.png")
168        self.assertEqual(result["dark"], "https://example.com/logo-dark.png")
169
170    def test_themed_urls_passthrough_without_theme_variable(self):
171        """Test themed_urls returns None for passthrough URLs without %(theme)s"""
172        manager = FileManager(FileUsage.MEDIA)
173        # External URLs without %(theme)s should return None
174        result = manager.themed_urls("https://example.com/logo.png")
175        self.assertIsNone(result)
class TestResolveFileUrlBasic(django.test.testcases.TestCase):
20class TestResolveFileUrlBasic(TestCase):
21    def test_resolve_empty_path(self):
22        """Test resolving empty file path"""
23        manager = FileManager(FileUsage.MEDIA)
24        result = manager.file_url("")
25        self.assertEqual(result, "")
26
27    def test_resolve_none_path(self):
28        """Test resolving None file path"""
29        manager = FileManager(FileUsage.MEDIA)
30        result = manager.file_url(None)
31        self.assertEqual(result, "")
32
33    def test_resolve_font_awesome(self):
34        """Test resolving Font Awesome icon"""
35        manager = FileManager(FileUsage.MEDIA)
36        result = manager.file_url("fa://fa-check")
37        self.assertEqual(result, "fa://fa-check")
38
39    def test_resolve_http_url(self):
40        """Test resolving HTTP URL"""
41        manager = FileManager(FileUsage.MEDIA)
42        result = manager.file_url("http://example.com/icon.png")
43        self.assertEqual(result, "http://example.com/icon.png")
44
45    def test_resolve_https_url(self):
46        """Test resolving HTTPS URL"""
47        manager = FileManager(FileUsage.MEDIA)
48        result = manager.file_url("https://example.com/icon.png")
49        self.assertEqual(result, "https://example.com/icon.png")
50
51    def test_resolve_static_path(self):
52        """Test resolving static file path"""
53        manager = FileManager(FileUsage.MEDIA)
54        result = manager.file_url("/static/authentik/sources/icon.svg")
55        self.assertEqual(result, "/static/authentik/sources/icon.svg")

Similar to TransactionTestCase, but use transaction.atomic() to achieve test isolation.

In most situations, TestCase should be preferred to TransactionTestCase as it allows faster execution. However, there are some situations where using TransactionTestCase might be necessary (e.g. testing some transactional behavior).

On database backends with no transaction support, TestCase behaves as TransactionTestCase.

def test_resolve_empty_path(self):
21    def test_resolve_empty_path(self):
22        """Test resolving empty file path"""
23        manager = FileManager(FileUsage.MEDIA)
24        result = manager.file_url("")
25        self.assertEqual(result, "")

Test resolving empty file path

def test_resolve_none_path(self):
27    def test_resolve_none_path(self):
28        """Test resolving None file path"""
29        manager = FileManager(FileUsage.MEDIA)
30        result = manager.file_url(None)
31        self.assertEqual(result, "")

Test resolving None file path

def test_resolve_font_awesome(self):
33    def test_resolve_font_awesome(self):
34        """Test resolving Font Awesome icon"""
35        manager = FileManager(FileUsage.MEDIA)
36        result = manager.file_url("fa://fa-check")
37        self.assertEqual(result, "fa://fa-check")

Test resolving Font Awesome icon

def test_resolve_http_url(self):
39    def test_resolve_http_url(self):
40        """Test resolving HTTP URL"""
41        manager = FileManager(FileUsage.MEDIA)
42        result = manager.file_url("http://example.com/icon.png")
43        self.assertEqual(result, "http://example.com/icon.png")

Test resolving HTTP URL

def test_resolve_https_url(self):
45    def test_resolve_https_url(self):
46        """Test resolving HTTPS URL"""
47        manager = FileManager(FileUsage.MEDIA)
48        result = manager.file_url("https://example.com/icon.png")
49        self.assertEqual(result, "https://example.com/icon.png")

Test resolving HTTPS URL

def test_resolve_static_path(self):
51    def test_resolve_static_path(self):
52        """Test resolving static file path"""
53        manager = FileManager(FileUsage.MEDIA)
54        result = manager.file_url("/static/authentik/sources/icon.svg")
55        self.assertEqual(result, "/static/authentik/sources/icon.svg")

Test resolving static file path

class TestResolveFileUrlFileBackend(authentik.admin.files.tests.utils.FileTestFileBackendMixin, django.test.testcases.TestCase):
58class TestResolveFileUrlFileBackend(FileTestFileBackendMixin, TestCase):
59    def test_resolve_storage_file(self):
60        """Test resolving uploaded storage file"""
61        manager = FileManager(FileUsage.MEDIA)
62        result = manager.file_url("test.png").split("?")[0]
63        self.assertEqual(result, "/files/media/public/test.png")
64
65    def test_resolve_full_static_with_request(self):
66        """Test resolving static file with request builds absolute URI"""
67        mock_request = HttpRequest()
68        mock_request.META = {
69            "HTTP_HOST": "example.com",
70            "SERVER_NAME": "example.com",
71        }
72
73        manager = FileManager(FileUsage.MEDIA)
74        result = manager.file_url("/static/icon.svg", mock_request)
75
76        self.assertEqual(result, "http://example.com/static/icon.svg")
77
78    def test_resolve_full_file_backend_with_request(self):
79        """Test resolving FileBackend file with request"""
80        mock_request = HttpRequest()
81        mock_request.META = {
82            "HTTP_HOST": "example.com",
83            "SERVER_NAME": "example.com",
84        }
85
86        manager = FileManager(FileUsage.MEDIA)
87        result = manager.file_url("test.png", mock_request).split("?")[0]
88
89        self.assertEqual(result, "http://example.com/files/media/public/test.png")

Similar to TransactionTestCase, but use transaction.atomic() to achieve test isolation.

In most situations, TestCase should be preferred to TransactionTestCase as it allows faster execution. However, there are some situations where using TransactionTestCase might be necessary (e.g. testing some transactional behavior).

On database backends with no transaction support, TestCase behaves as TransactionTestCase.

def test_resolve_storage_file(self):
59    def test_resolve_storage_file(self):
60        """Test resolving uploaded storage file"""
61        manager = FileManager(FileUsage.MEDIA)
62        result = manager.file_url("test.png").split("?")[0]
63        self.assertEqual(result, "/files/media/public/test.png")

Test resolving uploaded storage file

def test_resolve_full_static_with_request(self):
65    def test_resolve_full_static_with_request(self):
66        """Test resolving static file with request builds absolute URI"""
67        mock_request = HttpRequest()
68        mock_request.META = {
69            "HTTP_HOST": "example.com",
70            "SERVER_NAME": "example.com",
71        }
72
73        manager = FileManager(FileUsage.MEDIA)
74        result = manager.file_url("/static/icon.svg", mock_request)
75
76        self.assertEqual(result, "http://example.com/static/icon.svg")

Test resolving static file with request builds absolute URI

def test_resolve_full_file_backend_with_request(self):
78    def test_resolve_full_file_backend_with_request(self):
79        """Test resolving FileBackend file with request"""
80        mock_request = HttpRequest()
81        mock_request.META = {
82            "HTTP_HOST": "example.com",
83            "SERVER_NAME": "example.com",
84        }
85
86        manager = FileManager(FileUsage.MEDIA)
87        result = manager.file_url("test.png", mock_request).split("?")[0]
88
89        self.assertEqual(result, "http://example.com/files/media/public/test.png")

Test resolving FileBackend file with request

@skipUnless(s3_test_server_available(), 'S3 test server not available')
class TestResolveFileUrlS3Backend(authentik.admin.files.tests.utils.FileTestS3BackendMixin, django.test.testcases.TestCase):
 92@skipUnless(s3_test_server_available(), "S3 test server not available")
 93class TestResolveFileUrlS3Backend(FileTestS3BackendMixin, TestCase):
 94    @CONFIG.patch("storage.media.s3.custom_domain", "s3.test:8080/test")
 95    @CONFIG.patch("storage.media.s3.secure_urls", False)
 96    def test_resolve_full_s3_backend(self):
 97        """Test resolving S3Backend returns presigned URL as-is"""
 98        mock_request = HttpRequest()
 99        mock_request.META = {
100            "HTTP_HOST": "example.com",
101            "SERVER_NAME": "example.com",
102        }
103
104        manager = FileManager(FileUsage.MEDIA)
105        result = manager.file_url("test.png", mock_request)
106
107        # S3 URLs should be returned as-is (already absolute)
108        self.assertTrue(result.startswith("http://s3.test:8080/test"))

Similar to TransactionTestCase, but use transaction.atomic() to achieve test isolation.

In most situations, TestCase should be preferred to TransactionTestCase as it allows faster execution. However, there are some situations where using TransactionTestCase might be necessary (e.g. testing some transactional behavior).

On database backends with no transaction support, TestCase behaves as TransactionTestCase.

@CONFIG.patch('storage.media.s3.custom_domain', 's3.test:8080/test')
@CONFIG.patch('storage.media.s3.secure_urls', False)
def test_resolve_full_s3_backend(self):
 94    @CONFIG.patch("storage.media.s3.custom_domain", "s3.test:8080/test")
 95    @CONFIG.patch("storage.media.s3.secure_urls", False)
 96    def test_resolve_full_s3_backend(self):
 97        """Test resolving S3Backend returns presigned URL as-is"""
 98        mock_request = HttpRequest()
 99        mock_request.META = {
100            "HTTP_HOST": "example.com",
101            "SERVER_NAME": "example.com",
102        }
103
104        manager = FileManager(FileUsage.MEDIA)
105        result = manager.file_url("test.png", mock_request)
106
107        # S3 URLs should be returned as-is (already absolute)
108        self.assertTrue(result.startswith("http://s3.test:8080/test"))

Test resolving S3Backend returns presigned URL as-is

class TestThemedUrls(authentik.admin.files.tests.utils.FileTestFileBackendMixin, django.test.testcases.TestCase):
111class TestThemedUrls(FileTestFileBackendMixin, TestCase):
112    """Test FileManager.themed_urls method"""
113
114    def test_themed_urls_none_path(self):
115        """Test themed_urls returns None for None path"""
116        manager = FileManager(FileUsage.MEDIA)
117        result = manager.themed_urls(None)
118        self.assertIsNone(result)
119
120    def test_themed_urls_empty_path(self):
121        """Test themed_urls returns None for empty path"""
122        manager = FileManager(FileUsage.MEDIA)
123        result = manager.themed_urls("")
124        self.assertIsNone(result)
125
126    def test_themed_urls_no_theme_variable(self):
127        """Test themed_urls returns None when no %(theme)s in path"""
128        manager = FileManager(FileUsage.MEDIA)
129        result = manager.themed_urls("logo.png")
130        self.assertIsNone(result)
131
132    def test_themed_urls_with_theme_variable(self):
133        """Test themed_urls returns dict of URLs for each theme"""
134        manager = FileManager(FileUsage.MEDIA)
135        result = manager.themed_urls("logo-%(theme)s.png")
136
137        self.assertIsInstance(result, dict)
138        self.assertIn("light", result)
139        self.assertIn("dark", result)
140        self.assertIn("logo-light.png", result["light"])
141        self.assertIn("logo-dark.png", result["dark"])
142
143    def test_themed_urls_with_request(self):
144        """Test themed_urls builds absolute URLs with request"""
145        mock_request = HttpRequest()
146        mock_request.META = {
147            "HTTP_HOST": "example.com",
148            "SERVER_NAME": "example.com",
149        }
150
151        manager = FileManager(FileUsage.MEDIA)
152        result = manager.themed_urls("logo-%(theme)s.svg", mock_request)
153
154        self.assertIsInstance(result, dict)
155        light_url = urlparse(result["light"])
156        dark_url = urlparse(result["dark"])
157        self.assertEqual(light_url.scheme, "http")
158        self.assertEqual(light_url.netloc, "example.com")
159        self.assertEqual(dark_url.scheme, "http")
160        self.assertEqual(dark_url.netloc, "example.com")
161
162    def test_themed_urls_passthrough_with_theme_variable(self):
163        """Test themed_urls returns dict for passthrough URLs with %(theme)s"""
164        manager = FileManager(FileUsage.MEDIA)
165        # External URLs with %(theme)s should return themed URLs
166        result = manager.themed_urls("https://example.com/logo-%(theme)s.png")
167        self.assertIsInstance(result, dict)
168        self.assertEqual(result["light"], "https://example.com/logo-light.png")
169        self.assertEqual(result["dark"], "https://example.com/logo-dark.png")
170
171    def test_themed_urls_passthrough_without_theme_variable(self):
172        """Test themed_urls returns None for passthrough URLs without %(theme)s"""
173        manager = FileManager(FileUsage.MEDIA)
174        # External URLs without %(theme)s should return None
175        result = manager.themed_urls("https://example.com/logo.png")
176        self.assertIsNone(result)

Test FileManager.themed_urls method

def test_themed_urls_none_path(self):
114    def test_themed_urls_none_path(self):
115        """Test themed_urls returns None for None path"""
116        manager = FileManager(FileUsage.MEDIA)
117        result = manager.themed_urls(None)
118        self.assertIsNone(result)

Test themed_urls returns None for None path

def test_themed_urls_empty_path(self):
120    def test_themed_urls_empty_path(self):
121        """Test themed_urls returns None for empty path"""
122        manager = FileManager(FileUsage.MEDIA)
123        result = manager.themed_urls("")
124        self.assertIsNone(result)

Test themed_urls returns None for empty path

def test_themed_urls_no_theme_variable(self):
126    def test_themed_urls_no_theme_variable(self):
127        """Test themed_urls returns None when no %(theme)s in path"""
128        manager = FileManager(FileUsage.MEDIA)
129        result = manager.themed_urls("logo.png")
130        self.assertIsNone(result)

Test themed_urls returns None when no %(theme)s in path

def test_themed_urls_with_theme_variable(self):
132    def test_themed_urls_with_theme_variable(self):
133        """Test themed_urls returns dict of URLs for each theme"""
134        manager = FileManager(FileUsage.MEDIA)
135        result = manager.themed_urls("logo-%(theme)s.png")
136
137        self.assertIsInstance(result, dict)
138        self.assertIn("light", result)
139        self.assertIn("dark", result)
140        self.assertIn("logo-light.png", result["light"])
141        self.assertIn("logo-dark.png", result["dark"])

Test themed_urls returns dict of URLs for each theme

def test_themed_urls_with_request(self):
143    def test_themed_urls_with_request(self):
144        """Test themed_urls builds absolute URLs with request"""
145        mock_request = HttpRequest()
146        mock_request.META = {
147            "HTTP_HOST": "example.com",
148            "SERVER_NAME": "example.com",
149        }
150
151        manager = FileManager(FileUsage.MEDIA)
152        result = manager.themed_urls("logo-%(theme)s.svg", mock_request)
153
154        self.assertIsInstance(result, dict)
155        light_url = urlparse(result["light"])
156        dark_url = urlparse(result["dark"])
157        self.assertEqual(light_url.scheme, "http")
158        self.assertEqual(light_url.netloc, "example.com")
159        self.assertEqual(dark_url.scheme, "http")
160        self.assertEqual(dark_url.netloc, "example.com")

Test themed_urls builds absolute URLs with request

def test_themed_urls_passthrough_with_theme_variable(self):
162    def test_themed_urls_passthrough_with_theme_variable(self):
163        """Test themed_urls returns dict for passthrough URLs with %(theme)s"""
164        manager = FileManager(FileUsage.MEDIA)
165        # External URLs with %(theme)s should return themed URLs
166        result = manager.themed_urls("https://example.com/logo-%(theme)s.png")
167        self.assertIsInstance(result, dict)
168        self.assertEqual(result["light"], "https://example.com/logo-light.png")
169        self.assertEqual(result["dark"], "https://example.com/logo-dark.png")

Test themed_urls returns dict for passthrough URLs with %(theme)s

def test_themed_urls_passthrough_without_theme_variable(self):
171    def test_themed_urls_passthrough_without_theme_variable(self):
172        """Test themed_urls returns None for passthrough URLs without %(theme)s"""
173        manager = FileManager(FileUsage.MEDIA)
174        # External URLs without %(theme)s should return None
175        result = manager.themed_urls("https://example.com/logo.png")
176        self.assertIsNone(result)

Test themed_urls returns None for passthrough URLs without %(theme)s