test suite
This commit is contained in:
149
tests/conftest.py
Normal file
149
tests/conftest.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import pytest
|
||||
import requests
|
||||
import time
|
||||
import os
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables from .env file in the project root
|
||||
load_dotenv()
|
||||
|
||||
# --- Environment-based secrets for testing ---
|
||||
SPOTIFY_API_CLIENT_ID = os.environ.get("SPOTIFY_API_CLIENT_ID", "your_spotify_client_id")
|
||||
SPOTIFY_API_CLIENT_SECRET = os.environ.get("SPOTIFY_API_CLIENT_SECRET", "your_spotify_client_secret")
|
||||
SPOTIFY_BLOB_CONTENT_STR = os.environ.get("SPOTIFY_BLOB_CONTENT_STR", '{}')
|
||||
try:
|
||||
SPOTIFY_BLOB_CONTENT = json.loads(SPOTIFY_BLOB_CONTENT_STR)
|
||||
except json.JSONDecodeError:
|
||||
SPOTIFY_BLOB_CONTENT = {}
|
||||
|
||||
DEEZER_ARL = os.environ.get("DEEZER_ARL", "your_deezer_arl")
|
||||
|
||||
# --- Standard names for test accounts ---
|
||||
SPOTIFY_ACCOUNT_NAME = "test-spotify-account"
|
||||
DEEZER_ACCOUNT_NAME = "test-deezer-account"
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def base_url():
|
||||
"""Provides the base URL for the API tests."""
|
||||
return "http://localhost:7171/api"
|
||||
|
||||
|
||||
def wait_for_task(base_url, task_id, timeout=600):
|
||||
"""
|
||||
Waits for a Celery task to reach a terminal state (complete, error, etc.).
|
||||
Polls the progress endpoint and prints status updates.
|
||||
"""
|
||||
print(f"\n--- Waiting for task {task_id} (timeout: {timeout}s) ---")
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
response = requests.get(f"{base_url}/prgs/{task_id}")
|
||||
if response.status_code == 404:
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
response.raise_for_status() # Raise an exception for bad status codes
|
||||
|
||||
statuses = response.json()
|
||||
if not statuses:
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
last_status = statuses[-1]
|
||||
status = last_status.get("status")
|
||||
|
||||
# More verbose logging for debugging during tests
|
||||
message = last_status.get('message', '')
|
||||
track = last_status.get('track', '')
|
||||
progress = last_status.get('overall_progress', '')
|
||||
print(f"Task {task_id} | Status: {status:<12} | Progress: {progress or 'N/A':>3}% | Track: {track:<30} | Message: {message}")
|
||||
|
||||
if status in ["complete", "ERROR", "cancelled", "ERROR_RETRIED", "ERROR_AUTO_CLEANED"]:
|
||||
print(f"--- Task {task_id} finished with status: {status} ---")
|
||||
return last_status
|
||||
|
||||
time.sleep(2)
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Warning: Request to fetch task status for {task_id} failed: {e}. Retrying...")
|
||||
time.sleep(5)
|
||||
|
||||
raise TimeoutError(f"Task {task_id} did not complete within {timeout} seconds.")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def task_waiter(base_url):
|
||||
"""Provides a fixture that returns the wait_for_task helper function."""
|
||||
def _waiter(task_id, timeout=600):
|
||||
return wait_for_task(base_url, task_id, timeout)
|
||||
return _waiter
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def setup_credentials_for_tests(base_url):
|
||||
"""
|
||||
A session-wide, automatic fixture to set up all necessary credentials.
|
||||
It runs once before any tests, and tears down the credentials after all tests are complete.
|
||||
"""
|
||||
print("\n--- Setting up credentials for test session ---")
|
||||
|
||||
print("\n--- DEBUGGING CREDENTIALS ---")
|
||||
print(f"SPOTIFY_API_CLIENT_ID: {SPOTIFY_API_CLIENT_ID}")
|
||||
print(f"SPOTIFY_API_CLIENT_SECRET: {SPOTIFY_API_CLIENT_SECRET}")
|
||||
print(f"DEEZER_ARL: {DEEZER_ARL}")
|
||||
print(f"SPOTIFY_BLOB_CONTENT {SPOTIFY_BLOB_CONTENT}")
|
||||
print("--- END DEBUGGING ---\n")
|
||||
|
||||
# Skip all tests if secrets are not provided in the environment
|
||||
if SPOTIFY_API_CLIENT_ID == "your_spotify_client_id" or \
|
||||
SPOTIFY_API_CLIENT_SECRET == "your_spotify_client_secret" or \
|
||||
not SPOTIFY_BLOB_CONTENT or \
|
||||
DEEZER_ARL == "your_deezer_arl":
|
||||
pytest.skip("Required credentials not provided in .env file or environment. Skipping credential-dependent tests.")
|
||||
|
||||
# 1. Set global Spotify API creds
|
||||
data = {"client_id": SPOTIFY_API_CLIENT_ID, "client_secret": SPOTIFY_API_CLIENT_SECRET}
|
||||
response = requests.put(f"{base_url}/credentials/spotify_api_config", json=data)
|
||||
if response.status_code != 200:
|
||||
pytest.fail(f"Failed to set global Spotify API creds: {response.text}")
|
||||
print("Global Spotify API credentials set.")
|
||||
|
||||
# 2. Delete any pre-existing test credentials to ensure a clean state
|
||||
requests.delete(f"{base_url}/credentials/spotify/{SPOTIFY_ACCOUNT_NAME}")
|
||||
requests.delete(f"{base_url}/credentials/deezer/{DEEZER_ACCOUNT_NAME}")
|
||||
print("Cleaned up any old test credentials.")
|
||||
|
||||
# 3. Create Deezer credential
|
||||
data = {"name": DEEZER_ACCOUNT_NAME, "arl": DEEZER_ARL, "region": "US"}
|
||||
response = requests.post(f"{base_url}/credentials/deezer/{DEEZER_ACCOUNT_NAME}", json=data)
|
||||
if response.status_code != 201:
|
||||
pytest.fail(f"Failed to create Deezer credential: {response.text}")
|
||||
print("Deezer test credential created.")
|
||||
|
||||
# 4. Create Spotify credential
|
||||
data = {"name": SPOTIFY_ACCOUNT_NAME, "blob_content": SPOTIFY_BLOB_CONTENT, "region": "US"}
|
||||
response = requests.post(f"{base_url}/credentials/spotify/{SPOTIFY_ACCOUNT_NAME}", json=data)
|
||||
if response.status_code != 201:
|
||||
pytest.fail(f"Failed to create Spotify credential: {response.text}")
|
||||
print("Spotify test credential created.")
|
||||
|
||||
# 5. Set main config to use these accounts for downloads
|
||||
config_payload = {
|
||||
"spotify": SPOTIFY_ACCOUNT_NAME,
|
||||
"deezer": DEEZER_ACCOUNT_NAME,
|
||||
}
|
||||
response = requests.post(f"{base_url}/config", json=config_payload)
|
||||
if response.status_code != 200:
|
||||
pytest.fail(f"Failed to set main config for tests: {response.text}")
|
||||
print("Main config set to use test credentials.")
|
||||
|
||||
yield # This is where the tests will run
|
||||
|
||||
# --- Teardown ---
|
||||
print("\n--- Tearing down test credentials ---")
|
||||
response = requests.delete(f"{base_url}/credentials/spotify/{SPOTIFY_ACCOUNT_NAME}")
|
||||
assert response.status_code in [200, 404]
|
||||
response = requests.delete(f"{base_url}/credentials/deezer/{DEEZER_ACCOUNT_NAME}")
|
||||
assert response.status_code in [200, 404]
|
||||
print("Test credentials deleted.")
|
||||
Reference in New Issue
Block a user