From d4aee282479b6c7aea9333c5044969029caaa459 Mon Sep 17 00:00:00 2001 From: retoor Date: Fri, 3 Oct 2025 02:33:26 +0200 Subject: [PATCH] Working tests. --- .gitignore | 4 +++ Dockerfile | 2 +- conftest.py | 26 +++++++++++++++++ main.py | 14 +++++---- nginx.conf => nginx/nginx.conf | 10 +++---- pytest.ini | 52 ++++++++++++++++++++++++++++++++++ test_webdav.py | 9 +++--- 7 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 .gitignore create mode 100644 conftest.py rename nginx.conf => nginx/nginx.conf (100%) create mode 100644 pytest.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4341520 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.coverage +.env +__pycache__/ +logs/ diff --git a/Dockerfile b/Dockerfile index c618310..904f3f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,7 +52,7 @@ COPY --from=builder /install /usr/local # Copy application files COPY main.py . -COPY config.py . +COPY gunicorn_config.py . COPY .env.example .env # Create necessary directories diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..7c742cc --- /dev/null +++ b/conftest.py @@ -0,0 +1,26 @@ +""" +Pytest configuration for WebDAV server tests +""" + +import pytest +import asyncio + + +# Configure pytest-asyncio +def pytest_configure(config): + """Configure pytest with custom settings""" + config.addinivalue_line( + "markers", "asyncio: mark test as an asyncio test" + ) + + +@pytest.fixture(scope="session") +def event_loop(): + """Create an instance of the default event loop for the test session.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + +# Set asyncio mode +pytest_plugins = ('pytest_asyncio',) diff --git a/main.py b/main.py index 81629d9..0e9b17d 100644 --- a/main.py +++ b/main.py @@ -679,7 +679,8 @@ class WebDAVHandler: return web.Response( status=207, - content_type='application/xml; charset=utf-8', + content_type='application/xml', + charset='utf-8', text='\n' + xml_response, headers={ 'DAV': '1, 2, 3', @@ -786,7 +787,8 @@ class WebDAVHandler: return web.Response( status=207, - content_type='application/xml; charset=utf-8', + content_type='application/xml', + charset='utf-8', text='\n' + xml_response ) @@ -923,7 +925,8 @@ class WebDAVHandler: return web.Response( status=200, - content_type='application/xml; charset=utf-8', + content_type='application/xml', + charset='utf-8', text=response_xml, headers={ 'Lock-Token': f'<{lock_token}>', @@ -1007,9 +1010,10 @@ async def webdav_middleware(app, handler): """Middleware to handle authentication and routing""" async def middleware_handler(request: web.Request): - # Skip authentication for OPTIONS preflight + # Handle OPTIONS without authentication if request.method == 'OPTIONS': - return await handler(request) + webdav = app['webdav'] + return await webdav.handle_options(request, {}) # Authenticate user user = await app['auth'].authenticate(request) diff --git a/nginx.conf b/nginx/nginx.conf similarity index 100% rename from nginx.conf rename to nginx/nginx.conf index 901b005..0eefe86 100644 --- a/nginx.conf +++ b/nginx/nginx.conf @@ -4,10 +4,7 @@ # ============================================================================ # Upstream backend -upstream webdav_backend { - server webdav:8080 max_fails=3 fail_timeout=30s; - keepalive 32; -} + # HTTP Server - Redirect to HTTPS server { @@ -19,7 +16,10 @@ server { location /.well-known/acme-challenge/ { root /var/www/certbot; } - +upstream webdav_backend { + server webdav:8080 max_fails=3 fail_timeout=30s; + keepalive 32; +} # Redirect all other traffic to HTTPS location / { return 301 https://$server_name$request_uri; diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..9f20ed8 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,52 @@ +[pytest] +# Pytest configuration for WebDAV server tests + +# Asyncio configuration +asyncio_mode = auto +asyncio_default_fixture_loop_scope = function + +# Test discovery patterns +python_files = test_*.py *_test.py +python_classes = Test* +python_functions = test_* + +# Minimum version +minversion = 7.0 + +# Add current directory to Python path +pythonpath = . + +# Test output options +addopts = + -v + --strict-markers + --tb=short + --disable-warnings + -p no:warnings + +# Markers +markers = + asyncio: mark test as an asyncio test + slow: mark test as slow running + integration: mark test as integration test + unit: mark test as unit test + +# Logging +log_cli = false +log_cli_level = INFO +log_cli_format = %(asctime)s [%(levelname)8s] %(message)s +log_cli_date_format = %Y-%m-%d %H:%M:%S + +# Coverage options (if using pytest-cov) +[coverage:run] +source = . +omit = + */tests/* + */test_*.py + */.venv/* + */venv/* + +[coverage:report] +precision = 2 +show_missing = True +skip_covered = False diff --git a/test_webdav.py b/test_webdav.py index 41964dd..028cab3 100644 --- a/test_webdav.py +++ b/test_webdav.py @@ -4,6 +4,7 @@ Tests all WebDAV methods, authentication, and edge cases """ import pytest +import pytest_asyncio import asyncio import tempfile import shutil @@ -22,7 +23,7 @@ from main import Database, AuthHandler, WebDAVHandler, init_app, Config # Fixtures # ============================================================================ -@pytest.fixture +@pytest_asyncio.fixture async def temp_dir(): """Create temporary directory for tests""" temp_path = Path(tempfile.mkdtemp()) @@ -30,7 +31,7 @@ async def temp_dir(): shutil.rmtree(temp_path, ignore_errors=True) -@pytest.fixture +@pytest_asyncio.fixture async def test_db(temp_dir): """Create test database""" db_path = temp_dir / 'test.db' @@ -43,7 +44,7 @@ async def test_db(temp_dir): yield db -@pytest.fixture +@pytest_asyncio.fixture async def test_app(test_db, temp_dir, monkeypatch): """Create test application""" # Override config for testing @@ -60,7 +61,7 @@ async def test_app(test_db, temp_dir, monkeypatch): yield app -@pytest.fixture +@pytest_asyncio.fixture async def client(test_app): """Create test client""" server = TestServer(test_app)