insightfy-bloom-ms-mpms / test_location_api.py
MukeshKapoor25's picture
feat: Implement location management API with CRUD operations and validation
59649fd
"""
Test script for the location API endpoints.
This script demonstrates how to use the location API and tests basic functionality.
"""
import asyncio
import json
import logging
from typing import Dict, Any
import httpx
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# API Base URL - adjust as needed
BASE_URL = "http://localhost:8000/api"
class LocationAPITester:
def __init__(self, base_url: str = BASE_URL):
self.base_url = base_url
self.client = httpx.AsyncClient()
async def close(self):
"""Close the HTTP client."""
await self.client.aclose()
async def test_health_check(self) -> bool:
"""Test the health check endpoint."""
try:
logger.info("Testing health check...")
response = await self.client.get(f"{self.base_url}/locations/health")
if response.status_code == 200:
logger.info("βœ… Health check passed")
return True
else:
logger.error(f"❌ Health check failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Health check error: {e}")
return False
async def test_list_locations(self) -> bool:
"""Test listing all locations."""
try:
logger.info("Testing list locations...")
response = await self.client.get(f"{self.base_url}/locations")
if response.status_code == 200:
data = response.json()
logger.info(f"βœ… List locations passed - Found {data.get('total', 0)} locations")
return True
else:
logger.error(f"❌ List locations failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ List locations error: {e}")
return False
async def test_get_countries(self) -> bool:
"""Test getting all countries."""
try:
logger.info("Testing get countries...")
response = await self.client.get(f"{self.base_url}/countries")
if response.status_code == 200:
countries = response.json()
logger.info(f"βœ… Get countries passed - Found {len(countries)} countries")
# Print country details
for country in countries[:3]: # Show first 3
logger.info(f" πŸ“ {country['name']} ({country['iso2']}) - {country['currency']['symbol']}")
return True
else:
logger.error(f"❌ Get countries failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Get countries error: {e}")
return False
async def test_get_location_by_id(self, location_id: str = "country:US") -> bool:
"""Test getting a specific location by ID."""
try:
logger.info(f"Testing get location by ID: {location_id}")
response = await self.client.get(f"{self.base_url}/locations/{location_id}")
if response.status_code == 200:
location = response.json()
logger.info(f"βœ… Get location by ID passed - Found: {location['name']}")
return True
elif response.status_code == 404:
logger.warning(f"⚠️ Location {location_id} not found (expected if not seeded)")
return True
else:
logger.error(f"❌ Get location by ID failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Get location by ID error: {e}")
return False
async def test_search_locations(self, query: str = "States") -> bool:
"""Test searching locations."""
try:
logger.info(f"Testing search locations with query: {query}")
search_data = {
"query": query,
"limit": 10
}
response = await self.client.post(
f"{self.base_url}/locations/search",
json=search_data
)
if response.status_code == 200:
results = response.json()
logger.info(f"βœ… Search locations passed - Found {len(results)} results")
# Show search results
for result in results[:3]: # Show first 3
logger.info(f" πŸ” {result['name']} ({result['level']})")
return True
else:
logger.error(f"❌ Search locations failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Search locations error: {e}")
return False
async def test_get_hierarchy_tree(self) -> bool:
"""Test getting location hierarchy tree."""
try:
logger.info("Testing get hierarchy tree...")
response = await self.client.get(f"{self.base_url}/locations/hierarchy/tree")
if response.status_code == 200:
tree = response.json()
logger.info(f"βœ… Get hierarchy tree passed - Found {len(tree)} root nodes")
# Show tree structure (first level only)
for node in tree[:3]: # Show first 3
children_count = len(node.get('children', []))
logger.info(f" 🌳 {node['name']} ({children_count} children)")
return True
else:
logger.error(f"❌ Get hierarchy tree failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Get hierarchy tree error: {e}")
return False
async def test_get_statistics(self) -> bool:
"""Test getting location statistics."""
try:
logger.info("Testing get statistics...")
response = await self.client.get(f"{self.base_url}/locations/statistics")
if response.status_code == 200:
stats = response.json()
logger.info("βœ… Get statistics passed")
# Show key statistics
logger.info(f" πŸ“Š Total locations: {stats.get('total_locations', 0)}")
logger.info(f" πŸ“Š Active locations: {stats.get('active_locations', 0)}")
logger.info(f" πŸ“Š Countries: {stats.get('country_active', 0)}")
logger.info(f" πŸ“Š States: {stats.get('state_active', 0)}")
logger.info(f" πŸ“Š Cities: {stats.get('city_active', 0)}")
return True
else:
logger.error(f"❌ Get statistics failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Get statistics error: {e}")
return False
async def test_create_location(self) -> bool:
"""Test creating a new location."""
try:
logger.info("Testing create location...")
# Test location data
test_location = {
"id": "country:TEST",
"level": "country",
"name": "Test Country",
"iso2": "TC",
"iso3": "TCY",
"code": "country:TEST",
"parent_code": None,
"hierarchy": ["country:TEST"],
"currency": {"code": "TST", "symbol": "T$", "decimals": 2},
"phone_country_code": "+999",
"timezone": "UTC",
"flag": "https://example.com/flag.png",
"has_states": False,
"is_active": True
}
response = await self.client.post(
f"{self.base_url}/locations",
json=test_location
)
if response.status_code == 201:
result = response.json()
logger.info(f"βœ… Create location passed - Created: {result.get('location_id')}")
# Clean up - try to delete the test location
await self.test_deactivate_location("country:TEST")
return True
elif response.status_code == 409:
logger.warning("⚠️ Test location already exists (expected if run multiple times)")
return True
else:
logger.error(f"❌ Create location failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Create location error: {e}")
return False
async def test_deactivate_location(self, location_id: str) -> bool:
"""Test deactivating a location."""
try:
logger.info(f"Testing deactivate location: {location_id}")
response = await self.client.patch(
f"{self.base_url}/locations/{location_id}/deactivate"
)
if response.status_code == 200:
logger.info("βœ… Deactivate location passed")
return True
elif response.status_code == 404:
logger.warning(f"⚠️ Location {location_id} not found")
return True
else:
logger.error(f"❌ Deactivate location failed: {response.status_code} - {response.text}")
return False
except Exception as e:
logger.error(f"❌ Deactivate location error: {e}")
return False
async def run_all_tests(self) -> Dict[str, bool]:
"""Run all tests and return results."""
logger.info("πŸš€ Starting Location API Tests")
logger.info("=" * 60)
tests = [
("Health Check", self.test_health_check()),
("List Locations", self.test_list_locations()),
("Get Countries", self.test_get_countries()),
("Get Location by ID", self.test_get_location_by_id()),
("Search Locations", self.test_search_locations()),
("Get Hierarchy Tree", self.test_get_hierarchy_tree()),
("Get Statistics", self.test_get_statistics()),
("Create Location", self.test_create_location()),
]
results = {}
for test_name, test_coro in tests:
logger.info(f"\nπŸ§ͺ Running: {test_name}")
try:
result = await test_coro
results[test_name] = result
except Exception as e:
logger.error(f"❌ {test_name} threw exception: {e}")
results[test_name] = False
await asyncio.sleep(0.5) # Brief pause between tests
return results
async def main():
"""Main function to run the tests."""
tester = LocationAPITester()
try:
# Run all tests
results = await tester.run_all_tests()
# Summary
logger.info("\n" + "=" * 60)
logger.info("πŸ“‹ TEST SUMMARY")
logger.info("=" * 60)
passed = 0
total = len(results)
for test_name, passed_test in results.items():
status = "βœ… PASS" if passed_test else "❌ FAIL"
logger.info(f"{status} - {test_name}")
if passed_test:
passed += 1
logger.info(f"\n🎯 Results: {passed}/{total} tests passed")
if passed == total:
logger.info("πŸŽ‰ All tests passed! Location API is working correctly.")
else:
logger.warning(f"⚠️ {total - passed} tests failed. Check the logs above for details.")
finally:
await tester.close()
if __name__ == "__main__":
# Run the tests
asyncio.run(main())