authentik.admin.files.backends.tests.test_file_backend

  1from pathlib import Path
  2
  3from django.test import TestCase
  4
  5from authentik.admin.files.backends.file import FileBackend
  6from authentik.admin.files.tests.utils import FileTestFileBackendMixin
  7from authentik.admin.files.usage import FileUsage
  8from authentik.lib.config import CONFIG
  9
 10
 11class TestFileBackend(FileTestFileBackendMixin, TestCase):
 12    """Test FileBackend class"""
 13
 14    def setUp(self):
 15        """Set up test fixtures"""
 16        super().setUp()
 17        self.backend = FileBackend(FileUsage.MEDIA)
 18
 19    def test_allowed_usages(self):
 20        """Test that FileBackend supports all usage types"""
 21        self.assertEqual(self.backend.allowed_usages, list(FileUsage))
 22
 23    def test_base_path(self):
 24        """Test base_path property constructs correct path"""
 25        base_path = self.backend.base_path
 26
 27        expected = Path(self.media_backend_path) / "media" / "public"
 28        self.assertEqual(base_path, expected)
 29
 30    def test_base_path_reports_usage(self):
 31        """Test base_path with reports usage"""
 32        backend = FileBackend(FileUsage.REPORTS)
 33        base_path = backend.base_path
 34
 35        expected = Path(self.reports_backend_path) / "reports" / "public"
 36        self.assertEqual(base_path, expected)
 37
 38    def test_list_files_empty_directory(self):
 39        """Test list_files returns empty when directory is empty"""
 40        # Create the directory but keep it empty
 41        self.backend.base_path.mkdir(parents=True, exist_ok=True)
 42
 43        files = list(self.backend.list_files())
 44        self.assertEqual(files, [])
 45
 46    def test_list_files_with_files(self):
 47        """Test list_files returns all files in directory"""
 48        base_path = self.backend.base_path
 49        base_path.mkdir(parents=True, exist_ok=True)
 50
 51        # Create some test files
 52        (base_path / "file1.txt").write_text("content1")
 53        (base_path / "file2.png").write_text("content2")
 54        (base_path / "subdir").mkdir()
 55        (base_path / "subdir" / "file3.csv").write_text("content3")
 56
 57        files = sorted(list(self.backend.list_files()))
 58        expected = sorted(["file1.txt", "file2.png", "subdir/file3.csv"])
 59        self.assertEqual(files, expected)
 60
 61    def test_list_files_nonexistent_directory(self):
 62        """Test list_files returns empty when directory doesn't exist"""
 63        files = list(self.backend.list_files())
 64        self.assertEqual(files, [])
 65
 66    def test_save_file(self):
 67        content = b"test file content"
 68        file_name = "test.txt"
 69
 70        self.backend.save_file(file_name, content)
 71
 72        # Verify file was created
 73        file_path = self.backend.base_path / file_name
 74        self.assertTrue(file_path.exists())
 75        self.assertEqual(file_path.read_bytes(), content)
 76
 77    def test_save_file_creates_subdirectories(self):
 78        """Test save_file creates parent directories as needed"""
 79        content = b"nested file content"
 80        file_name = "subdir1/subdir2/nested.txt"
 81
 82        self.backend.save_file(file_name, content)
 83
 84        # Verify file and directories were created
 85        file_path = self.backend.base_path / file_name
 86        self.assertTrue(file_path.exists())
 87        self.assertEqual(file_path.read_bytes(), content)
 88
 89    def test_save_file_stream(self):
 90        """Test save_file_stream context manager writes file correctly"""
 91        content = b"streamed content"
 92        file_name = "stream_test.txt"
 93
 94        with self.backend.save_file_stream(file_name) as f:
 95            f.write(content)
 96
 97        # Verify file was created
 98        file_path = self.backend.base_path / file_name
 99        self.assertTrue(file_path.exists())
100        self.assertEqual(file_path.read_bytes(), content)
101
102    def test_save_file_stream_creates_subdirectories(self):
103        """Test save_file_stream creates parent directories as needed"""
104        content = b"nested stream content"
105        file_name = "dir1/dir2/stream.bin"
106
107        with self.backend.save_file_stream(file_name) as f:
108            f.write(content)
109
110        # Verify file and directories were created
111        file_path = self.backend.base_path / file_name
112        self.assertTrue(file_path.exists())
113        self.assertEqual(file_path.read_bytes(), content)
114
115    def test_delete_file(self):
116        """Test delete_file removes existing file"""
117        file_name = "to_delete.txt"
118
119        # Create file first
120        self.backend.save_file(file_name, b"content")
121        file_path = self.backend.base_path / file_name
122        self.assertTrue(file_path.exists())
123
124        # Delete it
125        self.backend.delete_file(file_name)
126        self.assertFalse(file_path.exists())
127
128    def test_delete_file_nonexistent(self):
129        """Test delete_file handles nonexistent file gracefully"""
130        file_name = "does_not_exist.txt"
131        self.backend.delete_file(file_name)
132
133    def test_file_url(self):
134        """Test file_url generates correct URL"""
135        file_name = "icon.png"
136
137        url = self.backend.file_url(file_name).split("?")[0]
138        expected = "/files/media/public/icon.png"
139        self.assertEqual(url, expected)
140
141    @CONFIG.patch("web.path", "/authentik/")
142    def test_file_url_with_prefix(self):
143        """Test file_url with web path prefix"""
144        file_name = "logo.svg"
145
146        url = self.backend.file_url(file_name).split("?")[0]
147        expected = "/authentik/files/media/public/logo.svg"
148        self.assertEqual(url, expected)
149
150    def test_file_url_nested_path(self):
151        """Test file_url with nested file path"""
152        file_name = "path/to/file.png"
153
154        url = self.backend.file_url(file_name).split("?")[0]
155        expected = "/files/media/public/path/to/file.png"
156        self.assertEqual(url, expected)
157
158    def test_file_exists_true(self):
159        """Test file_exists returns True for existing file"""
160        file_name = "exists.txt"
161        self.backend.base_path.mkdir(parents=True, exist_ok=True)
162        (self.backend.base_path / file_name).touch()
163        self.assertTrue(self.backend.file_exists(file_name))
164
165    def test_file_exists_false(self):
166        """Test file_exists returns False for nonexistent file"""
167        self.assertFalse(self.backend.file_exists("does_not_exist.txt"))
168
169    def test_themed_urls_without_theme_variable(self):
170        """Test themed_urls returns None when filename has no %(theme)s"""
171        file_name = "logo.png"
172        result = self.backend.themed_urls(file_name)
173        self.assertIsNone(result)
174
175    def test_themed_urls_with_theme_variable(self):
176        """Test themed_urls returns dict of URLs for each theme"""
177        file_name = "logo-%(theme)s.png"
178        result = self.backend.themed_urls(file_name)
179
180        self.assertIsInstance(result, dict)
181        self.assertIn("light", result)
182        self.assertIn("dark", result)
183
184        # Check URLs contain the substituted theme
185        self.assertIn("logo-light.png", result["light"])
186        self.assertIn("logo-dark.png", result["dark"])
187
188    def test_themed_urls_multiple_theme_variables(self):
189        """Test themed_urls with multiple %(theme)s in path"""
190        file_name = "%(theme)s/logo-%(theme)s.svg"
191        result = self.backend.themed_urls(file_name)
192
193        self.assertIsInstance(result, dict)
194        self.assertIn("light/logo-light.svg", result["light"])
195        self.assertIn("dark/logo-dark.svg", result["dark"])
class TestFileBackend(authentik.admin.files.tests.utils.FileTestFileBackendMixin, django.test.testcases.TestCase):
 12class TestFileBackend(FileTestFileBackendMixin, TestCase):
 13    """Test FileBackend class"""
 14
 15    def setUp(self):
 16        """Set up test fixtures"""
 17        super().setUp()
 18        self.backend = FileBackend(FileUsage.MEDIA)
 19
 20    def test_allowed_usages(self):
 21        """Test that FileBackend supports all usage types"""
 22        self.assertEqual(self.backend.allowed_usages, list(FileUsage))
 23
 24    def test_base_path(self):
 25        """Test base_path property constructs correct path"""
 26        base_path = self.backend.base_path
 27
 28        expected = Path(self.media_backend_path) / "media" / "public"
 29        self.assertEqual(base_path, expected)
 30
 31    def test_base_path_reports_usage(self):
 32        """Test base_path with reports usage"""
 33        backend = FileBackend(FileUsage.REPORTS)
 34        base_path = backend.base_path
 35
 36        expected = Path(self.reports_backend_path) / "reports" / "public"
 37        self.assertEqual(base_path, expected)
 38
 39    def test_list_files_empty_directory(self):
 40        """Test list_files returns empty when directory is empty"""
 41        # Create the directory but keep it empty
 42        self.backend.base_path.mkdir(parents=True, exist_ok=True)
 43
 44        files = list(self.backend.list_files())
 45        self.assertEqual(files, [])
 46
 47    def test_list_files_with_files(self):
 48        """Test list_files returns all files in directory"""
 49        base_path = self.backend.base_path
 50        base_path.mkdir(parents=True, exist_ok=True)
 51
 52        # Create some test files
 53        (base_path / "file1.txt").write_text("content1")
 54        (base_path / "file2.png").write_text("content2")
 55        (base_path / "subdir").mkdir()
 56        (base_path / "subdir" / "file3.csv").write_text("content3")
 57
 58        files = sorted(list(self.backend.list_files()))
 59        expected = sorted(["file1.txt", "file2.png", "subdir/file3.csv"])
 60        self.assertEqual(files, expected)
 61
 62    def test_list_files_nonexistent_directory(self):
 63        """Test list_files returns empty when directory doesn't exist"""
 64        files = list(self.backend.list_files())
 65        self.assertEqual(files, [])
 66
 67    def test_save_file(self):
 68        content = b"test file content"
 69        file_name = "test.txt"
 70
 71        self.backend.save_file(file_name, content)
 72
 73        # Verify file was created
 74        file_path = self.backend.base_path / file_name
 75        self.assertTrue(file_path.exists())
 76        self.assertEqual(file_path.read_bytes(), content)
 77
 78    def test_save_file_creates_subdirectories(self):
 79        """Test save_file creates parent directories as needed"""
 80        content = b"nested file content"
 81        file_name = "subdir1/subdir2/nested.txt"
 82
 83        self.backend.save_file(file_name, content)
 84
 85        # Verify file and directories were created
 86        file_path = self.backend.base_path / file_name
 87        self.assertTrue(file_path.exists())
 88        self.assertEqual(file_path.read_bytes(), content)
 89
 90    def test_save_file_stream(self):
 91        """Test save_file_stream context manager writes file correctly"""
 92        content = b"streamed content"
 93        file_name = "stream_test.txt"
 94
 95        with self.backend.save_file_stream(file_name) as f:
 96            f.write(content)
 97
 98        # Verify file was created
 99        file_path = self.backend.base_path / file_name
100        self.assertTrue(file_path.exists())
101        self.assertEqual(file_path.read_bytes(), content)
102
103    def test_save_file_stream_creates_subdirectories(self):
104        """Test save_file_stream creates parent directories as needed"""
105        content = b"nested stream content"
106        file_name = "dir1/dir2/stream.bin"
107
108        with self.backend.save_file_stream(file_name) as f:
109            f.write(content)
110
111        # Verify file and directories were created
112        file_path = self.backend.base_path / file_name
113        self.assertTrue(file_path.exists())
114        self.assertEqual(file_path.read_bytes(), content)
115
116    def test_delete_file(self):
117        """Test delete_file removes existing file"""
118        file_name = "to_delete.txt"
119
120        # Create file first
121        self.backend.save_file(file_name, b"content")
122        file_path = self.backend.base_path / file_name
123        self.assertTrue(file_path.exists())
124
125        # Delete it
126        self.backend.delete_file(file_name)
127        self.assertFalse(file_path.exists())
128
129    def test_delete_file_nonexistent(self):
130        """Test delete_file handles nonexistent file gracefully"""
131        file_name = "does_not_exist.txt"
132        self.backend.delete_file(file_name)
133
134    def test_file_url(self):
135        """Test file_url generates correct URL"""
136        file_name = "icon.png"
137
138        url = self.backend.file_url(file_name).split("?")[0]
139        expected = "/files/media/public/icon.png"
140        self.assertEqual(url, expected)
141
142    @CONFIG.patch("web.path", "/authentik/")
143    def test_file_url_with_prefix(self):
144        """Test file_url with web path prefix"""
145        file_name = "logo.svg"
146
147        url = self.backend.file_url(file_name).split("?")[0]
148        expected = "/authentik/files/media/public/logo.svg"
149        self.assertEqual(url, expected)
150
151    def test_file_url_nested_path(self):
152        """Test file_url with nested file path"""
153        file_name = "path/to/file.png"
154
155        url = self.backend.file_url(file_name).split("?")[0]
156        expected = "/files/media/public/path/to/file.png"
157        self.assertEqual(url, expected)
158
159    def test_file_exists_true(self):
160        """Test file_exists returns True for existing file"""
161        file_name = "exists.txt"
162        self.backend.base_path.mkdir(parents=True, exist_ok=True)
163        (self.backend.base_path / file_name).touch()
164        self.assertTrue(self.backend.file_exists(file_name))
165
166    def test_file_exists_false(self):
167        """Test file_exists returns False for nonexistent file"""
168        self.assertFalse(self.backend.file_exists("does_not_exist.txt"))
169
170    def test_themed_urls_without_theme_variable(self):
171        """Test themed_urls returns None when filename has no %(theme)s"""
172        file_name = "logo.png"
173        result = self.backend.themed_urls(file_name)
174        self.assertIsNone(result)
175
176    def test_themed_urls_with_theme_variable(self):
177        """Test themed_urls returns dict of URLs for each theme"""
178        file_name = "logo-%(theme)s.png"
179        result = self.backend.themed_urls(file_name)
180
181        self.assertIsInstance(result, dict)
182        self.assertIn("light", result)
183        self.assertIn("dark", result)
184
185        # Check URLs contain the substituted theme
186        self.assertIn("logo-light.png", result["light"])
187        self.assertIn("logo-dark.png", result["dark"])
188
189    def test_themed_urls_multiple_theme_variables(self):
190        """Test themed_urls with multiple %(theme)s in path"""
191        file_name = "%(theme)s/logo-%(theme)s.svg"
192        result = self.backend.themed_urls(file_name)
193
194        self.assertIsInstance(result, dict)
195        self.assertIn("light/logo-light.svg", result["light"])
196        self.assertIn("dark/logo-dark.svg", result["dark"])

Test FileBackend class

def setUp(self):
15    def setUp(self):
16        """Set up test fixtures"""
17        super().setUp()
18        self.backend = FileBackend(FileUsage.MEDIA)

Set up test fixtures

def test_allowed_usages(self):
20    def test_allowed_usages(self):
21        """Test that FileBackend supports all usage types"""
22        self.assertEqual(self.backend.allowed_usages, list(FileUsage))

Test that FileBackend supports all usage types

def test_base_path(self):
24    def test_base_path(self):
25        """Test base_path property constructs correct path"""
26        base_path = self.backend.base_path
27
28        expected = Path(self.media_backend_path) / "media" / "public"
29        self.assertEqual(base_path, expected)

Test base_path property constructs correct path

def test_base_path_reports_usage(self):
31    def test_base_path_reports_usage(self):
32        """Test base_path with reports usage"""
33        backend = FileBackend(FileUsage.REPORTS)
34        base_path = backend.base_path
35
36        expected = Path(self.reports_backend_path) / "reports" / "public"
37        self.assertEqual(base_path, expected)

Test base_path with reports usage

def test_list_files_empty_directory(self):
39    def test_list_files_empty_directory(self):
40        """Test list_files returns empty when directory is empty"""
41        # Create the directory but keep it empty
42        self.backend.base_path.mkdir(parents=True, exist_ok=True)
43
44        files = list(self.backend.list_files())
45        self.assertEqual(files, [])

Test list_files returns empty when directory is empty

def test_list_files_with_files(self):
47    def test_list_files_with_files(self):
48        """Test list_files returns all files in directory"""
49        base_path = self.backend.base_path
50        base_path.mkdir(parents=True, exist_ok=True)
51
52        # Create some test files
53        (base_path / "file1.txt").write_text("content1")
54        (base_path / "file2.png").write_text("content2")
55        (base_path / "subdir").mkdir()
56        (base_path / "subdir" / "file3.csv").write_text("content3")
57
58        files = sorted(list(self.backend.list_files()))
59        expected = sorted(["file1.txt", "file2.png", "subdir/file3.csv"])
60        self.assertEqual(files, expected)

Test list_files returns all files in directory

def test_list_files_nonexistent_directory(self):
62    def test_list_files_nonexistent_directory(self):
63        """Test list_files returns empty when directory doesn't exist"""
64        files = list(self.backend.list_files())
65        self.assertEqual(files, [])

Test list_files returns empty when directory doesn't exist

def test_save_file(self):
67    def test_save_file(self):
68        content = b"test file content"
69        file_name = "test.txt"
70
71        self.backend.save_file(file_name, content)
72
73        # Verify file was created
74        file_path = self.backend.base_path / file_name
75        self.assertTrue(file_path.exists())
76        self.assertEqual(file_path.read_bytes(), content)
def test_save_file_creates_subdirectories(self):
78    def test_save_file_creates_subdirectories(self):
79        """Test save_file creates parent directories as needed"""
80        content = b"nested file content"
81        file_name = "subdir1/subdir2/nested.txt"
82
83        self.backend.save_file(file_name, content)
84
85        # Verify file and directories were created
86        file_path = self.backend.base_path / file_name
87        self.assertTrue(file_path.exists())
88        self.assertEqual(file_path.read_bytes(), content)

Test save_file creates parent directories as needed

def test_save_file_stream(self):
 90    def test_save_file_stream(self):
 91        """Test save_file_stream context manager writes file correctly"""
 92        content = b"streamed content"
 93        file_name = "stream_test.txt"
 94
 95        with self.backend.save_file_stream(file_name) as f:
 96            f.write(content)
 97
 98        # Verify file was created
 99        file_path = self.backend.base_path / file_name
100        self.assertTrue(file_path.exists())
101        self.assertEqual(file_path.read_bytes(), content)

Test save_file_stream context manager writes file correctly

def test_save_file_stream_creates_subdirectories(self):
103    def test_save_file_stream_creates_subdirectories(self):
104        """Test save_file_stream creates parent directories as needed"""
105        content = b"nested stream content"
106        file_name = "dir1/dir2/stream.bin"
107
108        with self.backend.save_file_stream(file_name) as f:
109            f.write(content)
110
111        # Verify file and directories were created
112        file_path = self.backend.base_path / file_name
113        self.assertTrue(file_path.exists())
114        self.assertEqual(file_path.read_bytes(), content)

Test save_file_stream creates parent directories as needed

def test_delete_file(self):
116    def test_delete_file(self):
117        """Test delete_file removes existing file"""
118        file_name = "to_delete.txt"
119
120        # Create file first
121        self.backend.save_file(file_name, b"content")
122        file_path = self.backend.base_path / file_name
123        self.assertTrue(file_path.exists())
124
125        # Delete it
126        self.backend.delete_file(file_name)
127        self.assertFalse(file_path.exists())

Test delete_file removes existing file

def test_delete_file_nonexistent(self):
129    def test_delete_file_nonexistent(self):
130        """Test delete_file handles nonexistent file gracefully"""
131        file_name = "does_not_exist.txt"
132        self.backend.delete_file(file_name)

Test delete_file handles nonexistent file gracefully

def test_file_url(self):
134    def test_file_url(self):
135        """Test file_url generates correct URL"""
136        file_name = "icon.png"
137
138        url = self.backend.file_url(file_name).split("?")[0]
139        expected = "/files/media/public/icon.png"
140        self.assertEqual(url, expected)

Test file_url generates correct URL

@CONFIG.patch('web.path', '/authentik/')
def test_file_url_with_prefix(self):
142    @CONFIG.patch("web.path", "/authentik/")
143    def test_file_url_with_prefix(self):
144        """Test file_url with web path prefix"""
145        file_name = "logo.svg"
146
147        url = self.backend.file_url(file_name).split("?")[0]
148        expected = "/authentik/files/media/public/logo.svg"
149        self.assertEqual(url, expected)

Test file_url with web path prefix

def test_file_url_nested_path(self):
151    def test_file_url_nested_path(self):
152        """Test file_url with nested file path"""
153        file_name = "path/to/file.png"
154
155        url = self.backend.file_url(file_name).split("?")[0]
156        expected = "/files/media/public/path/to/file.png"
157        self.assertEqual(url, expected)

Test file_url with nested file path

def test_file_exists_true(self):
159    def test_file_exists_true(self):
160        """Test file_exists returns True for existing file"""
161        file_name = "exists.txt"
162        self.backend.base_path.mkdir(parents=True, exist_ok=True)
163        (self.backend.base_path / file_name).touch()
164        self.assertTrue(self.backend.file_exists(file_name))

Test file_exists returns True for existing file

def test_file_exists_false(self):
166    def test_file_exists_false(self):
167        """Test file_exists returns False for nonexistent file"""
168        self.assertFalse(self.backend.file_exists("does_not_exist.txt"))

Test file_exists returns False for nonexistent file

def test_themed_urls_without_theme_variable(self):
170    def test_themed_urls_without_theme_variable(self):
171        """Test themed_urls returns None when filename has no %(theme)s"""
172        file_name = "logo.png"
173        result = self.backend.themed_urls(file_name)
174        self.assertIsNone(result)

Test themed_urls returns None when filename has no %(theme)s

def test_themed_urls_with_theme_variable(self):
176    def test_themed_urls_with_theme_variable(self):
177        """Test themed_urls returns dict of URLs for each theme"""
178        file_name = "logo-%(theme)s.png"
179        result = self.backend.themed_urls(file_name)
180
181        self.assertIsInstance(result, dict)
182        self.assertIn("light", result)
183        self.assertIn("dark", result)
184
185        # Check URLs contain the substituted theme
186        self.assertIn("logo-light.png", result["light"])
187        self.assertIn("logo-dark.png", result["dark"])

Test themed_urls returns dict of URLs for each theme

def test_themed_urls_multiple_theme_variables(self):
189    def test_themed_urls_multiple_theme_variables(self):
190        """Test themed_urls with multiple %(theme)s in path"""
191        file_name = "%(theme)s/logo-%(theme)s.svg"
192        result = self.backend.themed_urls(file_name)
193
194        self.assertIsInstance(result, dict)
195        self.assertIn("light/logo-light.svg", result["light"])
196        self.assertIn("dark/logo-dark.svg", result["dark"])

Test themed_urls with multiple %(theme)s in path