Skip to main content
Glama
LOCAL_TESTING_GUIDE.md10.5 kB
# Local Testing Guide # Cursor-Based Pagination **Version**: 1.0 **Date**: October 15, 2025 ## Quick Start This guide walks through testing the cursor-based pagination feature locally before production deployment. ## Prerequisites - [ ] Python 3.12+ installed - [ ] Virtual environment activated (`.venv`) - [ ] Dependencies installed (`uv sync`) - [ ] Environment variables configured - [ ] Local database running (if using Supabase locally) ## Environment Setup ### 1. Configure Environment Variables Create `.env` file in project root: ```bash # Hostaway API Credentials HOSTAWAY_ACCOUNT_ID=your_account_id HOSTAWAY_SECRET_KEY=your_secret_key HOSTAWAY_API_BASE_URL=https://api.hostaway.com/v1 # Supabase Configuration (for API key auth) SUPABASE_URL=your_supabase_url SUPABASE_SERVICE_KEY=your_service_key # Rate Limiting RATE_LIMIT_IP=15 RATE_LIMIT_ACCOUNT=20 MAX_CONCURRENT_REQUESTS=50 # Logging LOG_LEVEL=INFO ``` ### 2. Start the Server ```bash # Activate virtual environment source .venv/bin/activate # Start the FastAPI server uvicorn src.api.main:app --reload --host 0.0.0.0 --port 8000 # Server should start on http://localhost:8000 ``` Expected output: ``` INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) INFO: Started reloader process INFO: Started server process INFO: Waiting for application startup. INFO: Application startup complete. ``` ## Test Scenarios ### Test 1: Health Endpoint Verify the server is running and context protection metrics are available. ```bash curl http://localhost:8000/health | jq . ``` **Expected Response:** ```json { "status": "healthy", "timestamp": "2025-10-15T...", "version": "0.1.0", "service": "hostaway-mcp", "context_protection": { "total_requests": 0, "pagination_adoption": 0, "summarization_adoption": 0, "avg_response_size_bytes": 0, "avg_latency_ms": 0, "oversized_events": 0, "uptime_seconds": 5 } } ``` ✅ **Pass Criteria**: HTTP 200, status = "healthy" ### Test 2: API Documentation Check that Swagger UI shows the updated pagination endpoints. ```bash # Open in browser open http://localhost:8000/docs ``` **Verify:** - [ ] `/api/listings` shows `PaginatedResponse[dict]` response - [ ] `cursor` parameter is documented - [ ] `limit` parameter has min=1, max=200 - [ ] Response schema shows `items`, `nextCursor`, `meta` ### Test 3: First Page Pagination (Listings) Fetch the first page of listings. ```bash # Set your API key export API_KEY="your_test_api_key" # Request first page curl -X GET "http://localhost:8000/api/listings?limit=10" \ -H "X-API-Key: $API_KEY" \ | jq . ``` **Expected Response:** ```json { "items": [ { "id": 12345, "name": "Property Name", ... } ], "nextCursor": "eyJvZmZzZXQiOjEwLCJ0cyI6MTY5NzQ1MjgwMC4wfQ==", "meta": { "totalCount": 150, "pageSize": 10, "hasMore": true } } ``` ✅ **Pass Criteria**: - HTTP 200 status - `items` is an array - `nextCursor` is a non-null string - `meta.hasMore` is true - `meta.pageSize` matches requested limit ### Test 4: Cursor Navigation Use the cursor from Test 3 to fetch the next page. ```bash # Save cursor from previous response export CURSOR="eyJvZmZzZXQiOjEwLCJ0cyI6MTY5NzQ1MjgwMC4wfQ==" # Request second page curl -X GET "http://localhost:8000/api/listings?cursor=$CURSOR" \ -H "X-API-Key: $API_KEY" \ | jq . ``` **Expected Response:** ```json { "items": [ { "id": 12355, "name": "Different Property", ... } ], "nextCursor": "eyJvZmZzZXQiOjIwLCJ0cyI6MTY5NzQ1MjgwMC4wfQ==", "meta": { "totalCount": 150, "pageSize": 10, "hasMore": true } } ``` ✅ **Pass Criteria**: - Items are different from first page - Cursor value has changed - No duplicate items across pages ### Test 5: Invalid Cursor Handling Test error handling for invalid cursors. ```bash # Test with completely invalid cursor curl -X GET "http://localhost:8000/api/listings?cursor=invalid-cursor" \ -H "X-API-Key: $API_KEY" \ -w "\nHTTP Status: %{http_code}\n" ``` **Expected Response:** ```json { "detail": "Invalid cursor: Signature verification failed" } HTTP Status: 400 ``` ✅ **Pass Criteria**: - HTTP 400 status - Clear error message - No server crash ### Test 6: Final Page (No More Results) Fetch a page with fewer items than requested (last page). ```bash # Request with high limit to potentially hit last page curl -X GET "http://localhost:8000/api/listings?limit=200" \ -H "X-API-Key: $API_KEY" \ | jq '.meta' ``` **Expected Response:** ```json { "totalCount": 25, "pageSize": 25, "hasMore": false } ``` If there's a `nextCursor`, navigate to the last page and verify: ✅ **Pass Criteria**: - `nextCursor` is null on last page - `meta.hasMore` is false - `meta.pageSize` < requested limit (if fewer items exist) ### Test 7: Bookings Pagination Test pagination on the reservations endpoint. ```bash # First page curl -X GET "http://localhost:8000/api/reservations?limit=20" \ -H "X-API-Key: $API_KEY" \ | jq '{itemCount: (.items | length), hasMore: .meta.hasMore, cursor: .nextCursor}' ``` **Expected Response:** ```json { "itemCount": 20, "hasMore": true, "cursor": "eyJvZmZzZXQiOjIwLCJ0cyI6MTY5NzQ1MjgwMC4wfQ==" } ``` ✅ **Pass Criteria**: - Same pagination structure as listings - Cursor navigation works - Filters still work with pagination ### Test 8: Pagination with Filters Test that filters work correctly with pagination. ```bash # Filter by status curl -X GET "http://localhost:8000/api/reservations?limit=10&status=confirmed" \ -H "X-API-Key: $API_KEY" \ | jq '{items: .items | length, status: .items[0].status}' ``` ✅ **Pass Criteria**: - Filters applied correctly - Pagination works with filters - Cursor preserves filter context ### Test 9: Performance Testing Measure cursor encode/decode performance. ```bash # Make 10 requests and measure average response time for i in {1..10}; do curl -X GET "http://localhost:8000/api/listings?limit=50" \ -H "X-API-Key: $API_KEY" \ -w "Time: %{time_total}s\n" \ -o /dev/null -s done ``` ✅ **Pass Criteria**: - Response time <500ms p95 - No degradation over time - Memory usage stable ### Test 10: Cursor Expiration (10 minute TTL) Test that cursors expire after 10 minutes. ```bash # Get a cursor CURSOR=$(curl -s -X GET "http://localhost:8000/api/listings?limit=10" \ -H "X-API-Key: $API_KEY" | jq -r '.nextCursor') echo "Cursor: $CURSOR" echo "Waiting 11 minutes for expiration..." # Wait 11 minutes (661 seconds) # sleep 661 # Try to use expired cursor # curl -X GET "http://localhost:8000/api/listings?cursor=$CURSOR" \ # -H "X-API-Key: $API_KEY" ``` **Expected Response (after 11 min):** ```json { "detail": "Invalid cursor: Cursor expired" } ``` ✅ **Pass Criteria**: HTTP 400 after TTL expiration ### Test 11: Backwards Compatibility Verify old clients can still access data. ```bash # Old client just reading items array curl -X GET "http://localhost:8000/api/listings?limit=10" \ -H "X-API-Key: $API_KEY" \ | jq '.items | length' ``` **Expected Output:** `10` (just the count) ✅ **Pass Criteria**: `items` field always present and accessible ### Test 12: Metrics Collection Verify metrics are being collected. ```bash # Make several requests for i in {1..5}; do curl -s -X GET "http://localhost:8000/api/listings?limit=10" \ -H "X-API-Key: $API_KEY" > /dev/null done # Check metrics curl -s http://localhost:8000/health | jq '.context_protection' ``` **Expected Response:** ```json { "total_requests": 5, "pagination_adoption": 1.0, "avg_response_size_bytes": 2400, ... } ``` ✅ **Pass Criteria**: - `total_requests` increasing - `pagination_adoption` > 0 - Metrics updating in real-time ## Integration Test Suite Run the automated integration tests: ```bash # Run pagination integration tests pytest tests/api/routes/test_pagination.py -v # Expected output: # 8 passed in 0.52s ``` ## Load Testing (Optional) ### Simple Load Test with Apache Bench ```bash # Install ab (Apache Bench) # macOS: already installed # Linux: sudo apt-get install apache2-utils # Run 1000 requests with 10 concurrent ab -n 1000 -c 10 \ -H "X-API-Key: $API_KEY" \ http://localhost:8000/api/listings?limit=50 ``` **Review:** - Requests per second - Time per request - Failed requests (should be 0) ### Load Test with Locust ```bash # Install locust pip install locust # Create locustfile (see MONITORING_OBSERVABILITY.md) # Run load test locust -f locustfile.py --host=http://localhost:8000 --users=50 --spawn-rate=5 ``` ## Troubleshooting ### Issue: Server won't start **Error:** `ModuleNotFoundError: No module named 'src'` **Solution:** ```bash # Make sure you're in the project root pwd # Should be: /Users/.../hostaway-mcp # Install dependencies uv sync # Try again uvicorn src.api.main:app --reload ``` ### Issue: 401 Unauthorized **Error:** `{"detail": "Missing API key. Provide X-API-Key header."}` **Solution:** ```bash # Make sure you're passing the API key header curl -H "X-API-Key: your-key-here" http://localhost:8000/api/listings ``` ### Issue: No listings returned **Error:** `{"items": [], "nextCursor": null, ...}` **Solution:** - Check Hostaway credentials in `.env` - Verify your account has listings - Check logs for API errors ### Issue: Cursor decode errors **Error:** `{"detail": "Invalid cursor: Invalid format"}` **Solution:** - Cursor may be URL-encoded incorrectly - Make sure to copy the full cursor string - Check cursor isn't being truncated ## Test Results Checklist Mark tests as you complete them: - [ ] Test 1: Health endpoint ✅ - [ ] Test 2: API documentation ✅ - [ ] Test 3: First page pagination ✅ - [ ] Test 4: Cursor navigation ✅ - [ ] Test 5: Invalid cursor handling ✅ - [ ] Test 6: Final page ✅ - [ ] Test 7: Bookings pagination ✅ - [ ] Test 8: Pagination with filters ✅ - [ ] Test 9: Performance testing ✅ - [ ] Test 10: Cursor expiration ⏱️ - [ ] Test 11: Backwards compatibility ✅ - [ ] Test 12: Metrics collection ✅ - [ ] Integration tests ✅ ## Next Steps After successful local testing: 1. [ ] Document any issues found 2. [ ] Fix any failing tests 3. [ ] Re-run full test suite 4. [ ] Deploy to staging environment 5. [ ] Run same tests on staging 6. [ ] Schedule production deployment --- **Last Updated**: October 15, 2025 **Tested By**: _____________ **Date Tested**: _____________

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/darrentmorgan/hostaway-mcp'

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