mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-03 06:40:31 +00:00
* Fix: redirect SHARE_LINK_BUNDLE_DIR to the test temp layout instead of the real media directory * Fix: include f_to in test_filters subTest labels so each of the 8 cases reports distinctly * Fix: run the post_consume error-log assertion after the raising call and match the actual paperless_mail logger name * Fix: rename the blank-password workflow test to match its behavior and add a real wrong-password-fails test * Fix: use the created social account's actual pk and remove an accidental tuple wrapping the mock provider * Fix: assert against the created documents' actual pks instead of hardcoded 1 and 2 * Fix: assert test_compression actually produces a valid LZMA-compressed zip * Fix: clear os.environ when patching PAPERLESS_ADMIN_* vars so a host-set value can't leak into the no-user test * Fix: restore MIDDLEWARE, AUTHENTICATION_BACKENDS and REST_FRAMEWORK auth classes after each remote-user settings test instead of leaking the mutation into later tests * Fix: use a guaranteed-nonexistent temp path instead of hardcoded /tmp/foo/bar in test_export_target_not_exists
151 lines
4.2 KiB
Python
151 lines
4.2 KiB
Python
"""The Paperless-ngx temp directory layout, stated once.
|
|
|
|
``build_paperless_dirs`` owns where things go and creates them.
|
|
``dirs_settings`` owns the mapping onto Django setting names and is pure.
|
|
Everything else in the test suite is a caller of these two.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from contextlib import contextmanager
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
from typing import TYPE_CHECKING
|
|
from typing import TypedDict
|
|
|
|
import pytest
|
|
from django.test import override_settings
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterator
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class PaperlessDirs:
|
|
"""Standard Paperless-ngx directory layout for tests."""
|
|
|
|
data_dir: Path
|
|
scratch_dir: Path
|
|
media_dir: Path
|
|
consumption_dir: Path
|
|
static_dir: Path
|
|
index_dir: Path
|
|
originals_dir: Path
|
|
thumbnail_dir: Path
|
|
archive_dir: Path
|
|
logging_dir: Path
|
|
model_file: Path
|
|
media_lock: Path
|
|
share_link_bundle_dir: Path
|
|
|
|
|
|
class DirSettings(TypedDict):
|
|
"""The Django settings the layout above maps onto."""
|
|
|
|
DATA_DIR: Path
|
|
SCRATCH_DIR: Path
|
|
MEDIA_ROOT: Path
|
|
ORIGINALS_DIR: Path
|
|
THUMBNAIL_DIR: Path
|
|
ARCHIVE_DIR: Path
|
|
CONSUMPTION_DIR: Path
|
|
LOGGING_DIR: Path
|
|
INDEX_DIR: Path
|
|
STATIC_ROOT: Path
|
|
MODEL_FILE: Path
|
|
MEDIA_LOCK: Path
|
|
SHARE_LINK_BUNDLE_DIR: Path
|
|
|
|
|
|
def build_paperless_dirs(root: Path) -> PaperlessDirs:
|
|
"""Compute the layout under root and create the directories."""
|
|
data_dir = root / "data"
|
|
media_dir = root / "media"
|
|
documents_dir = media_dir / "documents"
|
|
|
|
dirs = PaperlessDirs(
|
|
data_dir=data_dir,
|
|
scratch_dir=root / "scratch",
|
|
media_dir=media_dir,
|
|
consumption_dir=root / "consume",
|
|
static_dir=root / "static",
|
|
index_dir=data_dir / "index",
|
|
originals_dir=documents_dir / "originals",
|
|
thumbnail_dir=documents_dir / "thumbnails",
|
|
archive_dir=documents_dir / "archive",
|
|
logging_dir=data_dir / "log",
|
|
model_file=data_dir / "classification_model.pickle",
|
|
media_lock=media_dir / "media.lock",
|
|
share_link_bundle_dir=documents_dir / "share_link_bundles",
|
|
)
|
|
|
|
for directory in (
|
|
dirs.data_dir,
|
|
dirs.scratch_dir,
|
|
dirs.media_dir,
|
|
dirs.consumption_dir,
|
|
dirs.static_dir,
|
|
dirs.index_dir,
|
|
dirs.originals_dir,
|
|
dirs.thumbnail_dir,
|
|
dirs.archive_dir,
|
|
dirs.logging_dir,
|
|
):
|
|
directory.mkdir(parents=True, exist_ok=True)
|
|
|
|
return dirs
|
|
|
|
|
|
def dirs_settings(dirs: PaperlessDirs) -> DirSettings:
|
|
"""Map the layout onto Django setting names."""
|
|
return DirSettings(
|
|
DATA_DIR=dirs.data_dir,
|
|
SCRATCH_DIR=dirs.scratch_dir,
|
|
MEDIA_ROOT=dirs.media_dir,
|
|
ORIGINALS_DIR=dirs.originals_dir,
|
|
THUMBNAIL_DIR=dirs.thumbnail_dir,
|
|
ARCHIVE_DIR=dirs.archive_dir,
|
|
CONSUMPTION_DIR=dirs.consumption_dir,
|
|
LOGGING_DIR=dirs.logging_dir,
|
|
INDEX_DIR=dirs.index_dir,
|
|
STATIC_ROOT=dirs.static_dir,
|
|
MODEL_FILE=dirs.model_file,
|
|
MEDIA_LOCK=dirs.media_lock,
|
|
SHARE_LINK_BUNDLE_DIR=dirs.share_link_bundle_dir,
|
|
)
|
|
|
|
|
|
@contextmanager
|
|
def paperless_environment() -> Iterator[PaperlessDirs]:
|
|
"""A second, isolated environment for the duration of the block.
|
|
|
|
Only for tests needing a fresh environment part way through a test body,
|
|
which a fixture cannot provide. Everything else uses the paperless_dirs
|
|
fixture.
|
|
"""
|
|
from documents.search import reset_backend
|
|
|
|
with TemporaryDirectory(ignore_cleanup_errors=True) as tmp:
|
|
dirs = build_paperless_dirs(Path(tmp))
|
|
with override_settings(**dirs_settings(dirs)):
|
|
reset_backend()
|
|
try:
|
|
yield dirs
|
|
finally:
|
|
reset_backend()
|
|
|
|
|
|
class DirectoriesMixin:
|
|
"""Bridges the directory fixture to unittest TestCase subclasses and to
|
|
plain pytest test classes that want `self.dirs`.
|
|
|
|
Delete once no class depends on it.
|
|
"""
|
|
|
|
dirs: PaperlessDirs
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _paperless_dirs(self, paperless_dirs: PaperlessDirs) -> None:
|
|
self.dirs = paperless_dirs
|