From 19987d68a0c080e705f0f68222aca33bca3291ea Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Mon, 11 May 2026 21:37:55 +0200 Subject: [PATCH] refactor(tests): use client fixture for test isolation Replace all AsyncClient instantiations in test_sources.py and test_jobs.py with the shared fixture from conftest.py. This ensures proper test database isolation via dependency overrides. - Remove imports of httpx AsyncClient, ASGITransport, and app - Add client fixture parameter to all test functions - Remove async with blocks around HTTP requests - test_engine.py already uses db fixture correctly, no changes needed --- backend/app/main.py | 1 + .../test_jobs.cpython-314-pytest-9.0.3.pyc | Bin 27210 -> 23109 bytes .../test_sources.cpython-314-pytest-9.0.3.pyc | Bin 17562 -> 14411 bytes backend/tests/test_jobs.py | 320 +++++++++--------- backend/tests/test_sources.py | 113 +++---- 5 files changed, 205 insertions(+), 229 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index 2db80ae..2f0753c 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -3,6 +3,7 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager from app.database import engine, Base +from app import models # noqa: F401 - registers models with Base.metadata from app.routers import sources, jobs, executions, backups, settings, dashboard @asynccontextmanager diff --git a/backend/tests/__pycache__/test_jobs.cpython-314-pytest-9.0.3.pyc b/backend/tests/__pycache__/test_jobs.cpython-314-pytest-9.0.3.pyc index d87740a9370d4b2805451fa13f6f7cd02c18eaad..65978cf1e5c7f494bd3ed6b2b8857d7c79d32b7f 100644 GIT binary patch literal 23109 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 OcJ;0W;z?6bzyAjYJ$^X= literal 27210 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 YYcq6#gQHcswOU*5eHP@T= 1 @pytest.mark.asyncio -async def test_get_job(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - source_resp = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = source_resp.json()["id"] - - job_resp = await ac.post("/api/jobs/", json={ - "name": "Test Job", - "source_id": source_id, - "strategy": "full", - "destination_path": "/tmp/backups", - "exclude_patterns": [], - "enabled": True - }) - job_id = job_resp.json()["id"] - - response = await ac.get(f"/api/jobs/{job_id}") +async def test_get_job(client): + source_resp = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = source_resp.json()["id"] + + job_resp = await client.post("/api/jobs/", json={ + "name": "Test Job", + "source_id": source_id, + "strategy": "full", + "destination_path": "/tmp/backups", + "exclude_patterns": [], + "enabled": True + }) + job_id = job_resp.json()["id"] + + response = await client.get(f"/api/jobs/{job_id}") assert response.status_code == 200 assert response.json()["id"] == job_id @pytest.mark.asyncio -async def test_delete_job(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - source_resp = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = source_resp.json()["id"] - - job_resp = await ac.post("/api/jobs/", json={ - "name": "Delete Me", - "source_id": source_id, - "strategy": "full", - "destination_path": "/tmp/backups", - "exclude_patterns": [], - "enabled": True - }) - job_id = job_resp.json()["id"] - - response = await ac.delete(f"/api/jobs/{job_id}") +async def test_delete_job(client): + source_resp = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = source_resp.json()["id"] + + job_resp = await client.post("/api/jobs/", json={ + "name": "Delete Me", + "source_id": source_id, + "strategy": "full", + "destination_path": "/tmp/backups", + "exclude_patterns": [], + "enabled": True + }) + job_id = job_resp.json()["id"] + + response = await client.delete(f"/api/jobs/{job_id}") assert response.status_code == 200 # Verify deletion - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - get_resp = await ac.get(f"/api/jobs/{job_id}") + get_resp = await client.get(f"/api/jobs/{job_id}") assert get_resp.status_code == 404 @pytest.mark.asyncio -async def test_run_job(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - # Create source - source_resp = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = source_resp.json()["id"] - - # Create job - job_resp = await ac.post("/api/jobs/", json={ - "name": "Test Job", - "source_id": source_id, - "strategy": "full", - "destination_path": "/tmp/backups", - "exclude_patterns": [], - "enabled": True - }) - job_id = job_resp.json()["id"] - - response = await ac.post(f"/api/jobs/{job_id}/run") +async def test_run_job(client): + # Create source + source_resp = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = source_resp.json()["id"] + + # Create job + job_resp = await client.post("/api/jobs/", json={ + "name": "Test Job", + "source_id": source_id, + "strategy": "full", + "destination_path": "/tmp/backups", + "exclude_patterns": [], + "enabled": True + }) + job_id = job_resp.json()["id"] + + response = await client.post(f"/api/jobs/{job_id}/run") assert response.status_code == 200 assert response.json()["message"] == "Job execution started" @pytest.mark.asyncio -async def test_run_job_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.post("/api/jobs/999/run") +async def test_run_job_not_found(client): + response = await client.post("/api/jobs/999/run") assert response.status_code == 404 @pytest.mark.asyncio -async def test_update_job(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - # Create source - source_resp = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = source_resp.json()["id"] - - # Create job - job_resp = await ac.post("/api/jobs/", json={ - "name": "Original Name", - "source_id": source_id, - "strategy": "full", - "destination_path": "/tmp/backups", - "exclude_patterns": [], - "enabled": True - }) - job_id = job_resp.json()["id"] - - response = await ac.put(f"/api/jobs/{job_id}", json={ - "name": "Updated Name" - }) +async def test_update_job(client): + # Create source + source_resp = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = source_resp.json()["id"] + + # Create job + job_resp = await client.post("/api/jobs/", json={ + "name": "Original Name", + "source_id": source_id, + "strategy": "full", + "destination_path": "/tmp/backups", + "exclude_patterns": [], + "enabled": True + }) + job_id = job_resp.json()["id"] + + response = await client.put(f"/api/jobs/{job_id}", json={ + "name": "Updated Name" + }) assert response.status_code == 200 assert response.json()["name"] == "Updated Name" assert response.json()["strategy"] == "full" # Unchanged @pytest.mark.asyncio -async def test_create_schedule(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - # Create source - source_resp = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = source_resp.json()["id"] - - # Create job - job_resp = await ac.post("/api/jobs/", json={ - "name": "Test Job", - "source_id": source_id, - "strategy": "full", - "destination_path": "/tmp/backups", - "exclude_patterns": [], - "enabled": True - }) - job_id = job_resp.json()["id"] - - response = await ac.post(f"/api/jobs/{job_id}/schedule", json={ - "job_id": job_id, - "cron_expression": "0 0 * * *", - "enabled": True - }) +async def test_create_schedule(client): + # Create source + source_resp = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = source_resp.json()["id"] + + # Create job + job_resp = await client.post("/api/jobs/", json={ + "name": "Test Job", + "source_id": source_id, + "strategy": "full", + "destination_path": "/tmp/backups", + "exclude_patterns": [], + "enabled": True + }) + job_id = job_resp.json()["id"] + + response = await client.post(f"/api/jobs/{job_id}/schedule", json={ + "job_id": job_id, + "cron_expression": "0 0 * * *", + "enabled": True + }) assert response.status_code == 200 data = response.json() assert data["job_id"] == job_id @@ -201,19 +190,16 @@ async def test_create_schedule(): assert "id" in data @pytest.mark.asyncio -async def test_get_job_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.get("/api/jobs/99999") +async def test_get_job_not_found(client): + response = await client.get("/api/jobs/99999") assert response.status_code == 404 @pytest.mark.asyncio -async def test_update_job_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/api/jobs/99999", json={"name": "Test"}) +async def test_update_job_not_found(client): + response = await client.put("/api/jobs/99999", json={"name": "Test"}) assert response.status_code == 404 @pytest.mark.asyncio -async def test_delete_job_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.delete("/api/jobs/99999") +async def test_delete_job_not_found(client): + response = await client.delete("/api/jobs/99999") assert response.status_code == 404 diff --git a/backend/tests/test_sources.py b/backend/tests/test_sources.py index d8f08ee..14ff2ae 100644 --- a/backend/tests/test_sources.py +++ b/backend/tests/test_sources.py @@ -1,15 +1,12 @@ import pytest -from httpx import AsyncClient, ASGITransport -from app.main import app @pytest.mark.asyncio -async def test_create_source(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) +async def test_create_source(client): + response = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) assert response.status_code == 200 data = response.json() assert data["name"] == "Test Source" @@ -17,83 +14,75 @@ async def test_create_source(): assert "id" in data @pytest.mark.asyncio -async def test_list_sources(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - # Create source first - await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - - response = await ac.get("/api/sources/") +async def test_list_sources(client): + # Create source first + await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + + response = await client.get("/api/sources/") assert response.status_code == 200 data = response.json() assert len(data) >= 1 @pytest.mark.asyncio -async def test_get_source(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - create_resp = await ac.post("/api/sources/", json={ - "name": "Test Source", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = create_resp.json()["id"] - - response = await ac.get(f"/api/sources/{source_id}") +async def test_get_source(client): + create_resp = await client.post("/api/sources/", json={ + "name": "Test Source", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = create_resp.json()["id"] + + response = await client.get(f"/api/sources/{source_id}") assert response.status_code == 200 assert response.json()["id"] == source_id @pytest.mark.asyncio -async def test_delete_source(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - create_resp = await ac.post("/api/sources/", json={ - "name": "Delete Me", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = create_resp.json()["id"] - - response = await ac.delete(f"/api/sources/{source_id}") +async def test_delete_source(client): + create_resp = await client.post("/api/sources/", json={ + "name": "Delete Me", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = create_resp.json()["id"] + + response = await client.delete(f"/api/sources/{source_id}") assert response.status_code == 200 # Verify deletion - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - get_resp = await ac.get(f"/api/sources/{source_id}") + get_resp = await client.get(f"/api/sources/{source_id}") assert get_resp.status_code == 404 @pytest.mark.asyncio -async def test_update_source(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - create_resp = await ac.post("/api/sources/", json={ - "name": "Original Name", - "type": "local", - "config": {"path": "/tmp/test"} - }) - source_id = create_resp.json()["id"] - - response = await ac.put(f"/api/sources/{source_id}", json={ - "name": "Updated Name" - }) +async def test_update_source(client): + create_resp = await client.post("/api/sources/", json={ + "name": "Original Name", + "type": "local", + "config": {"path": "/tmp/test"} + }) + source_id = create_resp.json()["id"] + + response = await client.put(f"/api/sources/{source_id}", json={ + "name": "Updated Name" + }) assert response.status_code == 200 assert response.json()["name"] == "Updated Name" assert response.json()["type"] == "local" # Unchanged @pytest.mark.asyncio -async def test_get_source_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.get("/api/sources/99999") +async def test_get_source_not_found(client): + response = await client.get("/api/sources/99999") assert response.status_code == 404 @pytest.mark.asyncio -async def test_update_source_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/api/sources/99999", json={"name": "Test"}) +async def test_update_source_not_found(client): + response = await client.put("/api/sources/99999", json={"name": "Test"}) assert response.status_code == 404 @pytest.mark.asyncio -async def test_delete_source_not_found(): - async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.delete("/api/sources/99999") +async def test_delete_source_not_found(client): + response = await client.delete("/api/sources/99999") assert response.status_code == 404