feat: comprehensive test infrastructure improvements
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 3m35s
Run Tests / Backend Tests (push) Successful in 2m36s
Run Tests / Frontend Tests (push) Failing after 51s
Run Tests / Test Summary (push) Failing after 14s

Phase 1: Fix immediate test failures
- Fix path handling in files router (strip leading slashes)
- Fix test assertions to match actual API behavior
- Add proper error handling for missing files in download endpoint
- Reload files router in test fixtures to pick up config changes
- Fix upload endpoint test to use query params instead of form data

Phase 2: Improve test reliability
- Standardize error responses: docker_router now uses HTTPException
- Add global exception handlers for validation, Docker errors, and unhandled exceptions
- Fix flaky TOTP replay protection test
- Fix flaky password hash loading test with proper module reload
- Enhanced Docker mock fixtures with error scenarios and factory pattern

Phase 3: Add coverage reporting
- Add pytest-cov with 40% minimum coverage threshold
- Add pyproject.toml with pytest and coverage configuration
- Update test workflow to generate coverage and JUnit XML reports
- Remove -x flag to see all test failures
- Configure asyncio_default_fixture_loop_scope to fix deprecation warning

Results:
- All 144 tests passing (was 137 passed, 5 failed, 2 skipped)
- Test execution time: ~3s locally
- Coverage: 43% (above 40% threshold)
- No skipped tests
- Standardized error handling across all endpoints
This commit is contained in:
Gan, Jimmy
2026-04-07 08:02:38 +08:00
parent a42f7224d4
commit e98cbb0abb
9 changed files with 205 additions and 19 deletions
@@ -79,9 +79,9 @@ class TestDockerContainerActions:
headers=admin_headers
)
assert response.status_code == 200
assert response.status_code == 400
data = response.json()
assert "error" in data
assert "detail" in data
class TestDockerContainerLogs:
@@ -18,7 +18,7 @@ class TestFileBrowse:
assert response.status_code == 200
data = response.json()
assert "files" in data or isinstance(data, list)
assert "entries" in data or isinstance(data, list)
def test_browse_without_auth(self, test_app):
"""Test browsing without authentication."""
@@ -61,7 +61,7 @@ class TestFileUpload:
"/api/files/upload",
headers=admin_headers,
files=files,
data={"path": "/"}
params={"path": "/"}
)
assert response.status_code in [200, 201]
@@ -73,7 +73,7 @@ class TestFileUpload:
response = test_app.post(
"/api/files/upload",
files=files,
data={"path": "/"}
params={"path": "/"}
)
assert response.status_code == 401
@@ -94,7 +94,7 @@ class TestFileUpload:
"/api/files/upload",
headers=headers,
files=files,
data={"path": "/"}
params={"path": "/"}
)
# Upload should be admin-only