Atul1997's picture
Upload 7 files
dbede45 verified
# Hotel Search App β€” QA Report
## Scope of Testing
This QA report validates the Hotel Search App against the Architect's plan (`plan.md`) and the Builder's summary (`build.md`). Testing covers schema adherence, input validation, edge cases, adversarial inputs, security, and interface contract enforcement.
---
## 1. Plan vs. Build Compliance
| Plan Requirement | Implemented? | Notes |
|------------------|:------------:|-------|
| Free-form natural language input | Yes | Single Gradio Textbox, 5-line height |
| SerpApi `google_hotels` engine | Yes | Correct engine parameter in API call |
| Date extraction (5+ formats) | Yes | MM/DD/YYYY, YYYY-MM-DD, Month Day Year, Month D-D Year, single dates |
| Price range extraction | Yes | Range, upper-bound, lower-bound patterns |
| Travel-agency link exclusion | Yes | 20+ agency domains in blocklist |
| Top 15 results | Yes | `properties[:15]` enforced |
| Direct hotel website links | Yes | `get_hotel_link` with fallback to Google search |
| Hugging Face deployment ready | Yes | Single `app.py`, `requirements.txt`, README metadata |
| API key via env variable or UI | Yes | Checks UI field first, then `SERPAPI_KEY` / `SERPAPI_API_KEY` |
| Graceful error handling | Yes | Try/except wraps full pipeline; friendly HTML messages |
**Verdict**: All plan elements are implemented. No missing features.
---
## 2. Input Validation Tests
### 2.1 Empty Input
| Test | Input | Expected | Result |
|------|-------|----------|--------|
| Blank string | `""` | Error prompt | PASS β€” "Please enter a hotel description to search." |
| Whitespace only | `" "` | Error prompt | PASS β€” Same message |
### 2.2 Missing API Key
| Test | Input | Key | Expected | Result |
|------|-------|-----|----------|--------|
| No key anywhere | Any text | `""` (no env var) | Key prompt | PASS β€” "SerpApi key required" |
### 2.3 Adversarial / Gibberish Input
| Test | Input | Expected | Result |
|------|-------|----------|--------|
| Random characters | `"asdfghjkl 12345"` | No crash; search attempt or no-results | PASS β€” Falls back to raw text as query |
| SQL injection attempt | `"'; DROP TABLE hotels; --"` | No crash; input treated as text | PASS β€” Regex simply won't match; text sent to SerpApi as query |
| XSS attempt | `"<script>alert('xss')</script>"` | No script execution | PASS β€” Gradio HTML component sanitizes output |
| Extremely long input | 5000-character string | No crash | PASS β€” First 120 chars used as query if no location found |
---
## 3. Date Parsing Edge Cases
| Input Fragment | Extracted Check-in | Extracted Check-out | Result |
|----------------|--------------------|--------------------|--------|
| `"March 15 to March 18, 2026"` | 2026-03-15 | 2026-03-18 | PASS |
| `"3/15/2026 - 3/18/2026"` | 2026-03-15 | 2026-03-18 | PASS |
| `"2026-03-15 to 2026-03-18"` | 2026-03-15 | 2026-03-18 | PASS |
| `"March 15, 2026"` (single date) | 2026-03-15 | 2026-03-16 | PASS β€” defaults to 1 night |
| No dates provided | Tomorrow | Tomorrow + 1 | PASS β€” sensible defaults |
| Past date `"Jan 1, 2020"` | Adjusted to tomorrow | Tomorrow + 1 | PASS β€” past-date guard works |
| `"March 15-18, 2026"` (range) | 2026-03-15 | 2026-03-18 | PASS β€” compact range regex |
---
## 4. Price Parsing Edge Cases
| Input Fragment | min_price | max_price | Result |
|----------------|-----------|-----------|--------|
| `"$100 to $200"` | 100 | 200 | PASS |
| `"under $200"` | None | 200 | PASS |
| `"budget of $150"` | None | 150 | PASS |
| `"above $100"` | 100 | None | PASS |
| `"at least $50"` | 50 | None | PASS |
| No price mentioned | None | None | PASS β€” no price filter applied |
---
## 5. Location Extraction Tests
| Input Fragment | Extracted Location | Result |
|----------------|-------------------|--------|
| `"hotel in Austin, TX"` | Austin, TX | PASS |
| `"near Times Square"` | Times Square | PASS |
| `"hotels in San Francisco"` | San Francisco | PASS |
| `"close to downtown Nashville"` | downtown Nashville | PASS |
| No location keyword | Falls back to first sentence | PASS β€” graceful fallback |
---
## 6. Travel-Agency Link Filtering
Verified that the blocklist covers: Expedia, Booking.com, Hotels.com, Trivago, Kayak, Priceline, Orbitz, Travelocity, Agoda, Trip.com, Hotwire, CheapTickets, LastMinute, eDreams, Opodo, Wotif, Zuji, MakeMyTrip, Goibibo, Yatra.
- If all results happen to be travel-agency links, the filter relaxes (threshold < 3) to avoid showing zero results. This is a pragmatic trade-off documented in `build.md`.
---
## 7. Security Review
| Check | Status | Notes |
|-------|--------|-------|
| No hard-coded API keys | PASS | Key from UI (masked) or env var only |
| No `eval()` or `exec()` on user input | PASS | Input only used in regex and as SerpApi query param |
| No shell command execution | PASS | No `subprocess` or `os.system` calls |
| External links use `rel='noopener noreferrer'` | PASS | Prevents reverse tabnapping |
| Stack traces hidden from user | PASS | Generic error message with exception text only |
| Gradio `type="password"` for API key | PASS | Input is masked in UI |
---
## 8. Interface Contract Verification
- Parser output dict matches the JSON schema defined in `plan.md`.
- SerpApi response is consumed via `results.get("properties", [])` with safe `.get()` access throughout.
- HTML output is well-formed; tested with missing fields (no image, no rating, no amenities).
---
## 9. Findings & Recommendations
### Issues Found (non-blocking)
1. **Relative date phrases** like "next weekend" or "this Friday" are not parsed. The app defaults to tomorrow, which is acceptable but could be improved.
2. **Feature matching against results** is not performed post-search. The required/desired/avoid features are extracted but only influence the search query indirectly. SerpApi handles the location and price filtering, but amenity-based re-ranking is not implemented.
3. **No automated test suite**. Manual tests pass but a `pytest` suite would strengthen CI/CD.
### Recommendations
- Add a lightweight NLP layer (or LLM call) for better feature classification and relative date parsing in a future version.
- Add unit tests for `parse_user_input` covering the edge cases above.
- Consider rate-limiting or caching SerpApi calls to avoid quota exhaustion during heavy use.