queue fix
This commit is contained in:
parent
3be175522f
commit
3c6d82907d
@ -17,7 +17,7 @@
|
|||||||
"keep_days": 30
|
"keep_days": 30
|
||||||
},
|
},
|
||||||
"other": {
|
"other": {
|
||||||
"master_password_hash": "$pbkdf2-sha256$29000$rvXeu1dKqdXau/f.P0cIAQ$mApPqnzZmUlUFDkuzsxMuVV4V4pMba9IwEJO1XsV1MU",
|
"master_password_hash": "$pbkdf2-sha256$29000$MkbonbMWolTKOUfIOcc4Jw$8Aza9RknTXDSwQ1/mc.EwerqRrZ4Yo6tQlust.Nm/kQ",
|
||||||
"anime_directory": "/home/lukas/Volume/serien/"
|
"anime_directory": "/home/lukas/Volume/serien/"
|
||||||
},
|
},
|
||||||
"version": "1.0.0"
|
"version": "1.0.0"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -105,34 +105,20 @@ For each task completed:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Tasks
|
|
||||||
|
|
||||||
## 📋 All Tasks Complete! ✅
|
### Prerequisites
|
||||||
|
|
||||||
All phases of the download queue simplification have been successfully implemented:
|
1. Server is running: `conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload`
|
||||||
|
2. Password: `Hallo123!`
|
||||||
|
3. Login via browser at `http://127.0.0.1:8000/login`
|
||||||
|
|
||||||
- ✅ **Phase 1**: Backend simplification (DownloadService + API endpoints)
|
**Deployment Steps:**
|
||||||
- ✅ **Phase 2**: Frontend simplification (queue.html + queue.js + CSS cleanup)
|
|
||||||
- ✅ **Phase 3**: Testing (Unit tests + API tests)
|
|
||||||
- ✅ **Phase 4**: Documentation (features.md + infrastructure.md)
|
|
||||||
|
|
||||||
---
|
1. Commit all changes to git repository
|
||||||
|
2. Create deployment tag (e.g., `v1.0.0-queue-simplified`)
|
||||||
### Success Criteria
|
3. Deploy to production environment
|
||||||
|
4. Monitor logs for any unexpected behavior
|
||||||
- [x] All 5 requirements from feature list are met
|
5. Verify production queue functionality
|
||||||
- [x] No auto-processing or background queue processing
|
|
||||||
- [x] Only one download active at a time
|
|
||||||
- [x] Manual start required to begin downloads
|
|
||||||
- [x] Stop prevents new downloads but allows current to complete
|
|
||||||
- [x] All unit tests passing (≥80% coverage)
|
|
||||||
- [x] All API tests passing
|
|
||||||
- [ ] Manual testing checklist 100% complete
|
|
||||||
- [ ] No browser console errors
|
|
||||||
- [ ] WebSocket updates working in real-time
|
|
||||||
- [x] Documentation updated (features.md, infrastructure.md)
|
|
||||||
- [x] Code follows project coding standards
|
|
||||||
- [ ] No breaking changes to other features
|
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
@ -142,3 +128,5 @@ All phases of the download queue simplification have been successfully implement
|
|||||||
- Good foundation for future enhancements if needed
|
- Good foundation for future enhancements if needed
|
||||||
- No database schema changes required
|
- No database schema changes required
|
||||||
- WebSocket infrastructure remains unchanged
|
- WebSocket infrastructure remains unchanged
|
||||||
|
|
||||||
|
# Tasks
|
||||||
@ -43,39 +43,27 @@ async def get_queue_status(
|
|||||||
queue_status = await download_service.get_queue_status()
|
queue_status = await download_service.get_queue_status()
|
||||||
queue_stats = await download_service.get_queue_stats()
|
queue_stats = await download_service.get_queue_stats()
|
||||||
|
|
||||||
# Preserve the legacy response contract expected by the original CLI
|
# Build response with field names expected by frontend
|
||||||
# client and existing integration tests. Those consumers still parse
|
# Frontend expects top-level arrays (active_downloads, pending_queue, etc.)
|
||||||
# the bare dictionaries that the pre-FastAPI implementation emitted,
|
# not nested under a 'status' object
|
||||||
# so we keep the canonical field names (``active``/``pending``/
|
active_downloads = [
|
||||||
# ``completed``/``failed``) and dump each Pydantic object to plain
|
it.model_dump(mode="json")
|
||||||
# JSON-compatible dicts instead of returning the richer
|
for it in queue_status.active_downloads
|
||||||
# ``QueueStatusResponse`` shape directly. This guarantees both the
|
]
|
||||||
# CLI and older dashboard widgets do not need schema migrations while
|
pending_queue = [
|
||||||
# the new web UI can continue to evolve independently.
|
it.model_dump(mode="json")
|
||||||
status_payload = {
|
for it in queue_status.pending_queue
|
||||||
"is_running": queue_status.is_running,
|
]
|
||||||
"is_paused": queue_status.is_paused,
|
completed_downloads = [
|
||||||
"active": [
|
it.model_dump(mode="json")
|
||||||
it.model_dump(mode="json")
|
for it in queue_status.completed_downloads
|
||||||
for it in queue_status.active_downloads
|
]
|
||||||
],
|
failed_downloads = [
|
||||||
"pending": [
|
it.model_dump(mode="json")
|
||||||
it.model_dump(mode="json")
|
for it in queue_status.failed_downloads
|
||||||
for it in queue_status.pending_queue
|
]
|
||||||
],
|
|
||||||
"completed": [
|
|
||||||
it.model_dump(mode="json")
|
|
||||||
for it in queue_status.completed_downloads
|
|
||||||
],
|
|
||||||
"failed": [
|
|
||||||
it.model_dump(mode="json")
|
|
||||||
for it in queue_status.failed_downloads
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add the derived ``success_rate`` metric so dashboards built against
|
# Calculate success rate
|
||||||
# the previous API continue to function without recalculating it
|
|
||||||
# client-side.
|
|
||||||
completed = queue_stats.completed_count
|
completed = queue_stats.completed_count
|
||||||
failed = queue_stats.failed_count
|
failed = queue_stats.failed_count
|
||||||
success_rate = None
|
success_rate = None
|
||||||
@ -87,7 +75,12 @@ async def get_queue_status(
|
|||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={
|
content={
|
||||||
"status": status_payload,
|
"is_running": queue_status.is_running,
|
||||||
|
"is_paused": queue_status.is_paused,
|
||||||
|
"active_downloads": active_downloads,
|
||||||
|
"pending_queue": pending_queue,
|
||||||
|
"completed_downloads": completed_downloads,
|
||||||
|
"failed_downloads": failed_downloads,
|
||||||
"statistics": stats_payload,
|
"statistics": stats_payload,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -111,10 +111,16 @@ async def test_get_queue_status(authenticated_client, mock_download_service):
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
assert "status" in data
|
# Updated to match new response structure
|
||||||
|
assert "is_running" in data
|
||||||
|
assert "is_paused" in data
|
||||||
|
assert "active_downloads" in data
|
||||||
|
assert "pending_queue" in data
|
||||||
|
assert "completed_downloads" in data
|
||||||
|
assert "failed_downloads" in data
|
||||||
assert "statistics" in data
|
assert "statistics" in data
|
||||||
assert data["status"]["is_running"] is True
|
assert data["is_running"] is True
|
||||||
assert data["status"]["is_paused"] is False
|
assert data["is_paused"] is False
|
||||||
|
|
||||||
mock_download_service.get_queue_status.assert_called_once()
|
mock_download_service.get_queue_status.assert_called_once()
|
||||||
mock_download_service.get_queue_stats.assert_called_once()
|
mock_download_service.get_queue_stats.assert_called_once()
|
||||||
|
|||||||
@ -153,16 +153,15 @@ class TestDownloadFlowEndToEnd:
|
|||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
# Verify status structure
|
# Verify status structure (updated for new response format)
|
||||||
assert "status" in data
|
assert "is_running" in data
|
||||||
|
assert "is_paused" in data
|
||||||
|
assert "pending_queue" in data
|
||||||
|
assert "active_downloads" in data
|
||||||
|
assert "completed_downloads" in data
|
||||||
|
assert "failed_downloads" in data
|
||||||
assert "statistics" in data
|
assert "statistics" in data
|
||||||
|
|
||||||
status = data["status"]
|
|
||||||
assert "pending" in status
|
|
||||||
assert "active" in status
|
|
||||||
assert "completed" in status
|
|
||||||
assert "failed" in status
|
|
||||||
|
|
||||||
async def test_add_with_different_priorities(self, authenticated_client):
|
async def test_add_with_different_priorities(self, authenticated_client):
|
||||||
"""Test adding episodes with different priority levels."""
|
"""Test adding episodes with different priority levels."""
|
||||||
priorities = ["high", "normal", "low"]
|
priorities = ["high", "normal", "low"]
|
||||||
@ -292,11 +291,11 @@ class TestDownloadProgressTracking:
|
|||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
assert "status" in data
|
# Updated for new response format
|
||||||
|
assert "active_downloads" in data
|
||||||
|
|
||||||
# Check that items can have progress
|
# Check that items can have progress
|
||||||
status = data["status"]
|
for item in data.get("active_downloads", []):
|
||||||
for item in status.get("active", []):
|
|
||||||
if "progress" in item and item["progress"]:
|
if "progress" in item and item["progress"]:
|
||||||
assert "percentage" in item["progress"]
|
assert "percentage" in item["progress"]
|
||||||
assert "current_mb" in item["progress"]
|
assert "current_mb" in item["progress"]
|
||||||
@ -358,13 +357,18 @@ class TestErrorHandlingAndRetries:
|
|||||||
|
|
||||||
if add_response.status_code == 201:
|
if add_response.status_code == 201:
|
||||||
# Get queue status to check retry count
|
# Get queue status to check retry count
|
||||||
status_response = await authenticated_client.get("/api/queue/status")
|
status_response = await authenticated_client.get(
|
||||||
|
"/api/queue/status"
|
||||||
|
)
|
||||||
|
|
||||||
if status_response.status_code == 200:
|
if status_response.status_code == 200:
|
||||||
data = status_response.json()
|
data = status_response.json()
|
||||||
# Verify structure includes retry_count field
|
# Verify structure includes retry_count field
|
||||||
for item_list in [data["status"].get("pending", []),
|
# Updated to match new response structure
|
||||||
data["status"].get("failed", [])]:
|
for item_list in [
|
||||||
|
data.get("pending_queue", []),
|
||||||
|
data.get("failed_downloads", [])
|
||||||
|
]:
|
||||||
for item in item_list:
|
for item in item_list:
|
||||||
assert "retry_count" in item
|
assert "retry_count" in item
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user