Fix: resolve_offer_to_hub call in resolve_route_to_coordinate (same graphene self=None bug)
All checks were successful
Build Docker Image / build (push) Successful in 1m27s

This commit is contained in:
Ruslan Bakiev
2026-01-26 16:28:39 +07:00
parent 0c19135c49
commit 17081e13e4
3 changed files with 172 additions and 1 deletions

View File

@@ -1677,7 +1677,8 @@ class Query(graphene.ObjectType):
logger.info("Found nearest hub %s to coordinates (%.3f, %.3f)", hub_uuid, lat, lon)
# Use existing offer_to_hub logic
return self.resolve_offer_to_hub(info, offer_uuid, hub_uuid)
# Note: in graphene, self is None (root value), so we call as class method
return Query.resolve_offer_to_hub(Query, info, offer_uuid, hub_uuid)
except Exception as e:
logger.error("Error finding route to coordinates: %s", e)
return None

View File

@@ -454,6 +454,176 @@ class TestNearestEndpoints:
suppliers = data['data']['nearestSuppliers']
print(f"✓ nearestSuppliers with product: {len(suppliers)} suppliers for product {product_uuid[:8]}")
def test_nearest_offers_with_hub_uuid(self):
"""Test nearestOffers with hubUuid - should return offers with calculated routes.
This tests the fix for the bug where resolve_offer_to_hub was called incorrectly
(self was None in graphene resolvers).
"""
# First, get a hub UUID from the database
hubs_query = """
query {
nearestHubs(lat: 0, lon: 0, radius: 20000, limit: 5) {
uuid
name
latitude
longitude
}
}
"""
hubs_response = requests.post(GEO_URL, json={'query': hubs_query})
hubs_data = hubs_response.json()
if not hubs_data.get('data', {}).get('nearestHubs'):
pytest.skip("No hubs found in database")
hub = hubs_data['data']['nearestHubs'][0]
hub_uuid = hub['uuid']
hub_lat = hub['latitude']
hub_lon = hub['longitude']
# Now test nearestOffers with this hub UUID
query = """
query NearestOffers($lat: Float!, $lon: Float!, $radius: Float, $hubUuid: String, $limit: Int) {
nearestOffers(lat: $lat, lon: $lon, radius: $radius, hubUuid: $hubUuid, limit: $limit) {
uuid
productUuid
productName
supplierUuid
supplierName
latitude
longitude
pricePerUnit
currency
distanceKm
routes {
totalDistanceKm
totalTimeSeconds
stages {
fromUuid
fromName
fromLat
fromLon
toUuid
toName
toLat
toLon
distanceKm
travelTimeSeconds
transportType
}
}
}
}
"""
# Search around the hub location with large radius
variables = {
'lat': float(hub_lat) if hub_lat else 0.0,
'lon': float(hub_lon) if hub_lon else 0.0,
'radius': 5000, # 5000km radius to find offers
'hubUuid': hub_uuid,
'limit': 10
}
response = requests.post(GEO_URL, json={'query': query, 'variables': variables})
assert response.status_code == 200, f"Status: {response.status_code}, Body: {response.text}"
data = response.json()
assert 'errors' not in data, f"GraphQL errors: {data.get('errors')}"
offers = data['data']['nearestOffers']
assert isinstance(offers, list), "nearestOffers should return a list"
# The key assertion: with hubUuid, we should get offers with routes calculated
# (This was the bug - resolve_offer_to_hub was failing silently)
print(f"✓ nearestOffers with hubUuid: {len(offers)} offers for hub '{hub['name']}'")
if len(offers) > 0:
# Check first offer structure
offer = offers[0]
assert 'uuid' in offer
assert 'productUuid' in offer
assert 'routes' in offer, "Offer should have routes field when hubUuid is provided"
# If routes exist, verify structure
if offer['routes'] and len(offer['routes']) > 0:
route = offer['routes'][0]
assert 'totalDistanceKm' in route
assert 'totalTimeSeconds' in route
assert 'stages' in route
if route['stages'] and len(route['stages']) > 0:
stage = route['stages'][0]
assert 'fromUuid' in stage
assert 'toUuid' in stage
assert 'transportType' in stage
assert 'distanceKm' in stage
print(f" Route has {len(route['stages'])} stages, total {route['totalDistanceKm']:.1f}km")
def test_nearest_offers_with_hub_and_product(self):
"""Test nearestOffers with both hubUuid and productUuid filters."""
# Get a product and hub
products_query = "query { products { uuid name } }"
prod_response = requests.post(GEO_URL, json={'query': products_query})
products = prod_response.json().get('data', {}).get('products', [])
hubs_query = """
query {
nearestHubs(lat: 0, lon: 0, radius: 20000, limit: 1) {
uuid
name
latitude
longitude
}
}
"""
hubs_response = requests.post(GEO_URL, json={'query': hubs_query})
hubs = hubs_response.json().get('data', {}).get('nearestHubs', [])
if not products or not hubs:
pytest.skip("No products or hubs in database")
product = products[0]
hub = hubs[0]
query = """
query NearestOffers($lat: Float!, $lon: Float!, $radius: Float, $productUuid: String, $hubUuid: String) {
nearestOffers(lat: $lat, lon: $lon, radius: $radius, productUuid: $productUuid, hubUuid: $hubUuid) {
uuid
productUuid
productName
routes {
totalDistanceKm
stages {
transportType
}
}
}
}
"""
variables = {
'lat': float(hub['latitude']) if hub['latitude'] else 0.0,
'lon': float(hub['longitude']) if hub['longitude'] else 0.0,
'radius': 10000,
'productUuid': product['uuid'],
'hubUuid': hub['uuid']
}
response = requests.post(GEO_URL, json={'query': query, 'variables': variables})
assert response.status_code == 200
data = response.json()
assert 'errors' not in data, f"GraphQL errors: {data.get('errors')}"
offers = data['data']['nearestOffers']
# All offers should be for the requested product
for offer in offers:
assert offer['productUuid'] == product['uuid'], \
f"Offer has wrong productUuid: {offer['productUuid']} != {product['uuid']}"
print(f"✓ nearestOffers with hub+product: {len(offers)} offers for '{product['name']}' via hub '{hub['name']}'")
class TestRoutingEndpoints:
"""Test routing and pathfinding endpoints."""