""" Download API integration tests. """ import pytest class TestDownloadJobs: """Tests for download job management.""" def test_list_jobs_requires_auth(self, client): """List jobs should require authentication.""" response = client.get("/api/downloads/jobs") assert response.status_code in [401, 423] # Unauthorized or setup incomplete def test_create_job_requires_auth(self, client): """Create job should require authentication.""" response = client.post("/api/downloads/jobs", json={ "source_url": "https://open.spotify.com/track/123", "source": "spotify", "quality": "high", }) assert response.status_code in [401, 423] def test_get_queue_requires_auth(self, client): """Get queue should require authentication.""" response = client.get("/api/downloads/queue") assert response.status_code in [401, 423] def test_get_status_requires_auth(self, client): """Get status should require authentication.""" response = client.get("/api/downloads/status") assert response.status_code in [401, 423] class TestDownloadJobsWithAuth: """Tests for download jobs with authentication.""" def test_list_jobs_returns_empty_initially(self, client, auth_headers): """List jobs should return empty list for new user.""" response = client.get("/api/downloads/jobs", headers=auth_headers) assert response.status_code == 200 data = response.get_json() assert "jobs" in data assert "total" in data assert isinstance(data["jobs"], list) def test_create_job_validates_source(self, client, auth_headers): """Create job should accept valid source.""" response = client.post( "/api/downloads/jobs", headers=auth_headers, json={ "source_url": "https://open.spotify.com/track/test123", "source": "spotify", "quality": "high", "item_type": "track", }, ) # Should create job (201) or fail gracefully assert response.status_code in [200, 201, 400, 503] if response.status_code in [200, 201]: data = response.get_json() assert "job_id" in data or "job" in data def test_get_queue_returns_structure(self, client, auth_headers): """Get queue should return expected structure.""" response = client.get("/api/downloads/queue", headers=auth_headers) assert response.status_code == 200 data = response.get_json() assert "queue" in data assert "pending" in data assert "active" in data assert "history" in data assert "queue_length" in data assert "active_downloads" in data def test_get_status_returns_counts(self, client, auth_headers): """Get status should return job counts by state.""" response = client.get("/api/downloads/status", headers=auth_headers) assert response.status_code == 200 data = response.get_json() assert "counts" in data assert "total" in data counts = data["counts"] assert "queued" in counts assert "downloading" in counts assert "completed" in counts assert "failed" in counts assert "cancelled" in counts def test_get_history_returns_structure(self, client, auth_headers): """Get history should return paginated results.""" response = client.get("/api/downloads/history", headers=auth_headers) assert response.status_code == 200 data = response.get_json() assert "history" in data assert "total" in data assert "limit" in data assert "offset" in data class TestDownloadJobOperations: """Tests for individual job operations.""" def test_get_nonexistent_job(self, client, auth_headers): """Get nonexistent job should return 404.""" response = client.get("/api/downloads/jobs/999999", headers=auth_headers) assert response.status_code == 404 def test_cancel_nonexistent_job(self, client, auth_headers): """Cancel nonexistent job should fail.""" response = client.post("/api/downloads/jobs/999999/cancel", headers=auth_headers) assert response.status_code in [400, 404] def test_retry_nonexistent_job(self, client, auth_headers): """Retry nonexistent job should fail.""" response = client.post("/api/downloads/jobs/999999/retry", headers=auth_headers) assert response.status_code in [400, 404] class TestImportWorkflow: """Tests for the import workflow.""" def test_get_import_candidates_requires_auth(self, client): """Get import candidates should require authentication.""" response = client.post("/api/downloads/imports/candidates", json={ "trackhash": "testhash123", }) assert response.status_code in [401, 423] def test_confirm_import_requires_auth(self, client): """Confirm import should require authentication.""" response = client.post("/api/downloads/imports/confirm", json={ "trackhash": "testhash123", }) assert response.status_code in [401, 423] def test_get_import_candidates_returns_structure(self, client, auth_headers): """Get import candidates should return expected structure.""" response = client.post( "/api/downloads/imports/candidates", headers=auth_headers, json={"trackhash": "nonexistent_hash_12345"}, ) assert response.status_code == 200 data = response.get_json() assert "trackhash" in data assert "availability" in data assert "candidates" in data class TestStorageRoots: """Tests for storage roots management.""" def test_get_storage_roots_requires_auth(self, client): """Get storage roots should require authentication.""" response = client.get("/api/downloads/storage/roots") assert response.status_code in [401, 423] def test_set_storage_roots_requires_auth(self, client): """Set storage roots should require authentication.""" response = client.post("/api/downloads/storage/roots", json={ "root_dirs": ["/home/user/music"], }) assert response.status_code in [401, 423] def test_get_storage_roots_returns_structure(self, client, auth_headers): """Get storage roots should return expected structure.""" response = client.get("/api/downloads/storage/roots", headers=auth_headers) assert response.status_code == 200 data = response.get_json() # Should have root_dirs or similar assert isinstance(data, dict) class TestDownloadContract: """Contract tests for download API.""" def test_job_response_schema(self, client, auth_headers): """Job response should match expected schema.""" # Create a job create_response = client.post( "/api/downloads/jobs", headers=auth_headers, json={ "source_url": "https://open.spotify.com/track/contracttest", "source": "spotify", "quality": "high", "item_type": "track", "title": "Contract Test Track", "artist": "Contract Test Artist", }, ) if create_response.status_code in [200, 201]: data = create_response.get_json() # If job was created, verify structure if "job" in data: job = data["job"] assert "id" in job or "job_id" in job assert "state" in job def test_queue_response_schema(self, client, auth_headers): """Queue response should match expected schema.""" response = client.get("/api/downloads/queue", headers=auth_headers) assert response.status_code == 200 data = response.get_json() # Verify all required fields required_fields = ["queue", "pending", "active", "history", "queue_length", "active_downloads"] for field in required_fields: assert field in data, f"Missing field: {field}"