"""Where the application puts its files, and who agrees about it. OBS-006. Three roots were built as `os.path.join(os.getcwd(), …)`: the document store, the log directory and the backup directory. Each therefore moved with whatever directory the process was started from — and the processes that start this application are Waitress under Pterodactyl, a task scheduler, pytest, and a person in a shell. Only one of the four is reliably in the project directory. The document store was fixed in wave G. The other two were not, and the gap that opened between them is the reason this file exists: `backup.py` kept archiving `./documents` while the application wrote to `DOCUMENTS_ROOT`. The script now resolves the shared root and fails the run when it is absent. """ import os import pytest from app.storage import backups_root, documents_root, logs_root, project_root class TestTheProjectAnchor: def test_it_is_the_directory_holding_the_app_package(self): assert os.path.isdir(os.path.join(project_root(), 'app')) def test_it_does_not_follow_the_working_directory(self, tmp_path, monkeypatch): """The whole point. Every root below inherits this.""" before = project_root() monkeypatch.chdir(tmp_path) assert project_root() == before @pytest.mark.parametrize( ('root', 'env_name', 'default_name'), [ (documents_root, 'DOCUMENTS_ROOT', 'documents'), (logs_root, 'LOG_DIR', 'logs'), (backups_root, 'BACKUP_DIR', 'backups'), ], ) class TestEachRoot: def test_it_defaults_beside_the_project(self, root, env_name, default_name, monkeypatch): monkeypatch.delenv(env_name, raising=False) assert root() == os.path.join(project_root(), default_name) def test_it_ignores_the_working_directory( self, root, env_name, default_name, tmp_path, monkeypatch ): monkeypatch.delenv(env_name, raising=False) monkeypatch.chdir(tmp_path) assert root() == os.path.join(project_root(), default_name) assert not root().startswith(str(tmp_path)) def test_the_environment_wins(self, root, env_name, default_name, tmp_path, monkeypatch): monkeypatch.setenv(env_name, str(tmp_path / 'elsewhere')) assert root() == os.path.abspath(str(tmp_path / 'elsewhere')) class TestTheBackupScriptAgreesWithTheApplication: """The regression this file was written for. `backup.py` held its own `os.getcwd()`-based constant, so the two answers to "where are the contracts" could differ — and did, for anyone who set DOCUMENTS_ROOT because docs/deployment.md said to. """ def test_it_archives_the_directory_the_application_writes_to(self, tmp_path, monkeypatch): from app.supporting_scripts import backup store = tmp_path / 'somewhere-else' / 'documents' (store / 'contrats signés').mkdir(parents=True) (store / 'contrats signés' / 'a.pdf').write_bytes(b'%PDF-1.4 test') monkeypatch.setenv('DOCUMENTS_ROOT', str(store)) monkeypatch.setattr(backup, 'BACKUP_DIR', str(tmp_path / 'backups')) (tmp_path / 'backups').mkdir() archive = backup.backup_documents() assert archive is not None, ( 'the script skipped, which is what it did on production while reporting success' ) assert os.path.getsize(archive) > 0 def test_the_archive_actually_contains_the_contract(self, tmp_path, monkeypatch): """An empty zip is still a file of non-zero size. This is the assertion that would have caught the original defect.""" import zipfile from app.supporting_scripts import backup store = tmp_path / 'documents' (store / 'contrats signés').mkdir(parents=True) (store / 'contrats signés' / 'contrat.pdf').write_bytes(b'%PDF-1.4 test') monkeypatch.setenv('DOCUMENTS_ROOT', str(store)) monkeypatch.setattr(backup, 'BACKUP_DIR', str(tmp_path / 'backups')) (tmp_path / 'backups').mkdir() archive = backup.backup_documents() with zipfile.ZipFile(archive) as zf: assert any(name.endswith('contrat.pdf') for name in zf.namelist()) def test_a_missing_store_names_the_path_it_looked_in(self, tmp_path, monkeypatch): """A missing configured store is an actionable failure, not a skip.""" from app.supporting_scripts import backup missing = tmp_path / 'not-here' monkeypatch.setenv('DOCUMENTS_ROOT', str(missing)) with pytest.raises(backup.BackupError, match=str(missing).replace('\\', '\\\\')): backup.backup_documents() class TestLogsFollowTheSameRule: def test_configure_logging_writes_where_logs_root_says(self, tmp_path, monkeypatch): from app.app import create_app target = tmp_path / 'var' / 'log' monkeypatch.setenv('LOG_DIR', str(target)) create_app( { 'SECRET_KEY': 'test-secret-not-used-anywhere-real', 'SQLALCHEMY_DATABASE_URI': f'sqlite:///{tmp_path / "t.sqlite"}', 'TESTING': True, 'WTF_CSRF_ENABLED': False, 'FORCE_HTTPS': False, 'SESSION_COOKIE_SECURE': False, 'ENABLE_DISCORD_BOT': False, 'AUTO_CREATE_TABLES': True, 'CORS_ALLOWED_ORIGINS': '', 'RATELIMIT_ENABLED': False, } ) assert target.is_dir(), 'the log directory is created where LOG_DIR points' assert (target / 'app.log').exists()