Skip to main content
Glama
test_health.py14.9 kB
"""Tests for FastAPI health endpoint.""" from unittest.mock import patch import pytest class TestHealthEndpoint: """Tests for the /health endpoint.""" @pytest.mark.unit def test_health_endpoint_with_openap(self, client): """Test health endpoint when OpenAP is available.""" with patch("main.OPENAP_AVAILABLE", True): with patch( "main._AIRPORTS_IATA", {"SJC": {"iata": "SJC"}, "NRT": {"iata": "NRT"}} ): response = client.get("/health") assert response.status_code == 200 data = response.json() assert "status" in data assert "openap" in data assert "airports_count" in data assert data["status"] == "ok" assert data["openap"] is True assert data["airports_count"] == 2 @pytest.mark.unit def test_health_endpoint_without_openap(self, client): """Test health endpoint when OpenAP is not available.""" with patch("main.OPENAP_AVAILABLE", False): with patch("main._AIRPORTS_IATA", {"SJC": {"iata": "SJC"}}): response = client.get("/health") assert response.status_code == 200 data = response.json() assert data["status"] == "ok" assert data["openap"] is False assert data["airports_count"] == 1 @pytest.mark.unit def test_health_endpoint_empty_airports(self, client): """Test health endpoint with no airports loaded.""" with patch("main.OPENAP_AVAILABLE", True): with patch("main._AIRPORTS_IATA", {}): response = client.get("/health") assert response.status_code == 200 data = response.json() assert data["status"] == "ok" assert data["openap"] is True assert data["airports_count"] == 0 @pytest.mark.unit def test_health_endpoint_response_format(self, client): """Test that health endpoint returns correct JSON format.""" response = client.get("/health") assert response.status_code == 200 assert response.headers["content-type"] == "application/json" data = response.json() # Check required fields exist required_fields = ["status", "openap", "airports_count"] for field in required_fields: assert field in data, f"Missing required field: {field}" # Check field types assert isinstance(data["status"], str) assert isinstance(data["openap"], bool) assert isinstance(data["airports_count"], int) # Check status value assert data["status"] == "ok" # Check airports_count is non-negative assert data["airports_count"] >= 0 @pytest.mark.integration def test_health_endpoint_real_data(self, client): """Test health endpoint with real airport data.""" response = client.get("/health") assert response.status_code == 200 data = response.json() assert data["status"] == "ok" # Real airport data should have many airports assert data["airports_count"] > 1000 # OpenAP availability depends on installation assert isinstance(data["openap"], bool) class TestAirportsByCity: """Tests for the /airports/by_city endpoint.""" @pytest.mark.unit def test_airports_by_city_san_jose(self, client, mock_airports_iata): """Test finding airports for San Jose.""" response = client.get("/airports/by_city?city=San Jose&country=US") assert response.status_code == 200 data = response.json() assert isinstance(data, list) assert len(data) == 1 airport = data[0] assert airport["iata"] == "SJC" assert airport["city"] == "San Jose" assert airport["country"] == "US" assert airport["name"] == "San Jose International Airport" @pytest.mark.unit def test_airports_by_city_without_country(self, client, mock_airports_iata): """Test finding airports without specifying country.""" response = client.get("/airports/by_city?city=San Jose") assert response.status_code == 200 data = response.json() assert isinstance(data, list) assert len(data) >= 1 # Should find at least SJC iatas = [airport["iata"] for airport in data] assert "SJC" in iatas @pytest.mark.unit def test_airports_by_city_nonexistent(self, client, mock_airports_iata): """Test finding airports for non-existent city.""" response = client.get("/airports/by_city?city=NonexistentCity&country=US") assert response.status_code == 200 data = response.json() assert isinstance(data, list) assert len(data) == 0 @pytest.mark.unit def test_airports_by_city_missing_parameter(self, client): """Test airports endpoint with missing city parameter.""" response = client.get("/airports/by_city") # Should return 422 for missing required parameter assert response.status_code == 422 @pytest.mark.unit def test_airports_by_city_case_insensitive(self, client, mock_airports_iata): """Test that city search is case insensitive.""" responses = [ client.get("/airports/by_city?city=san jose&country=US"), client.get("/airports/by_city?city=SAN JOSE&country=US"), client.get("/airports/by_city?city=San Jose&country=US"), ] # All responses should be successful and identical for response in responses: assert response.status_code == 200 data_sets = [response.json() for response in responses] # All should return the same results assert all(data == data_sets[0] for data in data_sets) assert len(data_sets[0]) == 1 assert data_sets[0][0]["iata"] == "SJC" class TestPlanEndpoint: """Tests for the /plan endpoint.""" @pytest.mark.unit def test_plan_endpoint_success( self, client, mock_airports_iata, mock_openap_flight_generator, mock_openap_fuel_flow, mock_openap_props, ): """Test successful flight planning.""" with patch("main.OPENAP_AVAILABLE", True): with patch( "main.FlightGenerator", return_value=mock_openap_flight_generator ): with patch("main.FuelFlow", return_value=mock_openap_fuel_flow): with patch("main.prop.aircraft", return_value=mock_openap_props): request_data = { "depart_city": "San Jose", "arrive_city": "Tokyo", "depart_country": "US", "arrive_country": "JP", "ac_type": "A359", "cruise_alt_ft": 35000, "route_step_km": 50.0, } response = client.post("/plan", json=request_data) assert response.status_code == 200 data = response.json() # Check response structure required_fields = [ "engine", "depart", "arrive", "distance_km", "distance_nm", "polyline", "estimates", ] for field in required_fields: assert field in data # Check airport data assert data["depart"]["iata"] == "SJC" assert data["arrive"]["iata"] == "NRT" # Check distance reasonableness assert 8200 < data["distance_km"] < 8400 assert 4400 < data["distance_nm"] < 4550 # km * NM_PER_KM # Check polyline assert isinstance(data["polyline"], list) assert len(data["polyline"]) > 100 # Should have many points # Check estimates structure estimates = data["estimates"] assert "block" in estimates assert "climb" in estimates assert "cruise" in estimates assert "descent" in estimates @pytest.mark.unit def test_plan_endpoint_same_city_error(self, client, mock_airports_iata): """Test error when departure and arrival are the same city.""" request_data = { "depart_city": "San Jose", "arrive_city": "San Jose", "ac_type": "A320", } response = client.post("/plan", json=request_data) assert response.status_code == 400 data = response.json() assert "identical" in data["detail"].lower() @pytest.mark.unit def test_plan_endpoint_invalid_airport(self, client, mock_airports_iata): """Test error with invalid airport.""" request_data = { "depart_city": "NonexistentCity", "arrive_city": "Tokyo", "ac_type": "A320", } response = client.post("/plan", json=request_data) assert response.status_code == 404 data = response.json() assert "no airport" in data["detail"].lower() @pytest.mark.unit def test_plan_endpoint_preferred_iata( self, client, mock_airports_iata, mock_openap_flight_generator, mock_openap_fuel_flow, mock_openap_props, ): """Test planning with preferred IATA codes.""" with patch("main.OPENAP_AVAILABLE", True): with patch( "main.FlightGenerator", return_value=mock_openap_flight_generator ): with patch("main.FuelFlow", return_value=mock_openap_fuel_flow): with patch("main.prop.aircraft", return_value=mock_openap_props): request_data = { "depart_city": "Any City", # This would normally fail "arrive_city": "Any City", "prefer_depart_iata": "SJC", "prefer_arrive_iata": "NRT", "ac_type": "A359", } response = client.post("/plan", json=request_data) assert response.status_code == 200 data = response.json() assert data["depart"]["iata"] == "SJC" assert data["arrive"]["iata"] == "NRT" @pytest.mark.unit def test_plan_endpoint_invalid_preferred_iata(self, client, mock_airports_iata): """Test error with invalid preferred IATA.""" request_data = { "depart_city": "San Jose", "arrive_city": "Tokyo", "prefer_depart_iata": "INVALID", "ac_type": "A320", } response = client.post("/plan", json=request_data) assert response.status_code == 400 data = response.json() assert "not found" in data["detail"].lower() @pytest.mark.unit def test_plan_endpoint_openap_unavailable(self, client, mock_airports_iata): """Test error when OpenAP is unavailable.""" with patch("main.OPENAP_AVAILABLE", False): request_data = { "depart_city": "San Jose", "arrive_city": "Tokyo", "ac_type": "A320", } response = client.post("/plan", json=request_data) assert response.status_code == 501 data = response.json() assert "unavailable" in data["detail"].lower() @pytest.mark.unit def test_plan_endpoint_validation_errors(self, client): """Test various validation errors.""" # Missing required field response = client.post( "/plan", json={ "depart_city": "San Jose", # Missing arrive_city and ac_type }, ) assert response.status_code == 422 # Invalid altitude response = client.post( "/plan", json={ "depart_city": "San Jose", "arrive_city": "Tokyo", "ac_type": "A320", "cruise_alt_ft": 100000, # Too high }, ) assert response.status_code == 422 # Invalid route step response = client.post( "/plan", json={ "depart_city": "San Jose", "arrive_city": "Tokyo", "ac_type": "A320", "route_step_km": -10.0, # Negative }, ) assert response.status_code == 422 @pytest.mark.unit def test_plan_endpoint_custom_parameters( self, client, mock_airports_iata, mock_openap_flight_generator, mock_openap_fuel_flow, mock_openap_props, ): """Test planning with custom parameters.""" with patch("main.OPENAP_AVAILABLE", True): with patch( "main.FlightGenerator", return_value=mock_openap_flight_generator ): with patch("main.FuelFlow", return_value=mock_openap_fuel_flow): with patch("main.prop.aircraft", return_value=mock_openap_props): request_data = { "depart_city": "San Jose", "arrive_city": "Tokyo", "ac_type": "A320", "cruise_alt_ft": 41000, "mass_kg": 70000.0, "route_step_km": 100.0, } response = client.post("/plan", json=request_data) assert response.status_code == 200 data = response.json() # Check that custom parameters were used assert ( data["estimates"]["assumptions"]["cruise_alt_ft"] == 41000 ) assert data["estimates"]["assumptions"]["mass_kg"] == 70000.0 # Polyline should have fewer points due to larger step size assert ( len(data["polyline"]) < 200 ) # Fewer than default 25km step

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cheesejaguar/aerospace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server