Spaces:
Paused
Paused
Download 4_AstroDynamics/tests/test_api.py from ESCP/LC-11-AstroDynamics: direct link, hf CLI and curl.
- Browser
- Download file 3.56 kB
-
https://huggingface.co/spaces/ESCP/LC-11-AstroDynamics/resolve/main/4_AstroDynamics/tests/test_api.py
- Command line
-
hf download hf://spaces/ESCP/LC-11-AstroDynamics/4_AstroDynamics/tests/test_api.py
-
curl -L -o test_api.py https://huggingface.co/spaces/ESCP/LC-11-AstroDynamics/resolve/main/4_AstroDynamics/tests/test_api.py
3.56 kB
| """Tests d'intégration de l'API AstroDynamics.""" | |
| import pytest | |
| def test_health_returns_loaded_model(client) -> None: | |
| response = client.get("/health") | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["status"] == "ok" | |
| assert payload["environment"] == "LunarLander-v3" | |
| assert payload["algorithm"] == "DQN" | |
| assert payload["model"] == "dqn_lunarlander_final.zip" | |
| def test_prediction_returns_valid_action(client, endpoint: str) -> None: | |
| response = client.post( | |
| endpoint, | |
| json={ | |
| "observation": [ | |
| 0.0, # position x | |
| 1.0, # position y | |
| 0.0, # vitesse x | |
| -0.2, # vitesse y | |
| 0.0, # angle | |
| 0.0, # vitesse angulaire | |
| 0.0, # contact jambe gauche | |
| 0.0, # contact jambe droite | |
| ] | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["action"] in {0, 1, 2, 3} | |
| assert isinstance(payload["action_label"], str) | |
| assert len(payload["q_values"]) == 4 | |
| assert all(isinstance(value, float) for value in payload["q_values"]) | |
| assert isinstance(payload["circumstance"], str) | |
| def test_prediction_rejects_invalid_observation_length( | |
| client, | |
| observation: list[float], | |
| ) -> None: | |
| response = client.post( | |
| "/predict", | |
| json={"observation": observation}, | |
| ) | |
| assert response.status_code == 422 | |
| def test_metrics_are_initially_empty(client) -> None: | |
| response = client.get("/metrics") | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["summary"]["number_of_episodes"] == 0 | |
| assert payload["summary"]["mean_reward"] is None | |
| assert payload["summary"]["std_reward"] is None | |
| assert payload["episodes"] == [] | |
| assert payload["action_distribution"] == {} | |
| assert payload["decisions_by_circumstance"] == {} | |
| def test_episode_is_played_and_persisted(client) -> None: | |
| """ | |
| Joue un véritable épisode avec le modèle sauvegardé. | |
| L'animation est désactivée pour accélérer la CI et limiter la RAM. | |
| """ | |
| response = client.post( | |
| "/episodes", | |
| json={ | |
| "seed": 42, | |
| "capture_animation": False, | |
| "frame_stride": 5, | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| episode = response.json() | |
| assert len(episode["episode_id"]) == 32 | |
| assert episode["seed"] == 42 | |
| assert episode["steps"] > 0 | |
| assert isinstance(episode["reward"], float) | |
| assert isinstance(episode["success"], bool) | |
| assert episode["animation_url"] is None | |
| assert sum(episode["action_counts"].values()) == episode["steps"] | |
| metrics_response = client.get("/metrics") | |
| assert metrics_response.status_code == 200 | |
| metrics = metrics_response.json() | |
| assert metrics["summary"]["number_of_episodes"] == 1 | |
| assert metrics["episodes"][0]["episode_id"] == episode["episode_id"] | |
| assert metrics["episodes"][0]["seed"] == 42 | |
| assert metrics["episodes"][0]["reward"] == pytest.approx( | |
| episode["reward"] | |
| ) | |
| def test_unknown_animation_returns_404(client) -> None: | |
| unknown_id = "0" * 32 | |
| response = client.get( | |
| f"/episodes/{unknown_id}/animation" | |
| ) | |
| assert response.status_code == 404 |