-
Notifications
You must be signed in to change notification settings - Fork 1
test: Add integration test for Serper scrape functionality #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,179 @@ | ||||||||||||||||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||||||||||||||||
| # Copyright (c) 2024 Travis Frisinger | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # This source code is licensed under the MIT license found in the | ||||||||||||||||||||||||||||||
| # LICENSE file in the root directory of this source tree. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| """Integration test for Serper scrape API functionality.""" | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Add docker directory to path | ||||||||||||||||||||||||||||||
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| from clients.serper_client import scrape_webpage # noqa: E402 | ||||||||||||||||||||||||||||||
| from models.domain.search_result import SearchResult # noqa: E402 | ||||||||||||||||||||||||||||||
| from services.content_scraper import scrape_search_result # noqa: E402 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def test_serper_scrape_client(): | ||||||||||||||||||||||||||||||
| """Test the Serper scrape client directly.""" | ||||||||||||||||||||||||||||||
| api_key = os.environ.get("SERPER_API_KEY", "") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if not api_key: | ||||||||||||||||||||||||||||||
| print("β οΈ SERPER_API_KEY not set - skipping Serper scrape test") | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| print("π§ͺ Testing Serper scrape client...") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Test with a simple, reliable URL | ||||||||||||||||||||||||||||||
| test_url = "https://example.com" | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||
| result = scrape_webpage(test_url, api_key) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if result is None: | ||||||||||||||||||||||||||||||
| print(f"β Serper scrape returned None for {test_url}") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if len(result) < 10: | ||||||||||||||||||||||||||||||
| print( | ||||||||||||||||||||||||||||||
| f"β Serper scrape returned suspiciously short content: {len(result)} chars" | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| print(f"β Serper scrape client working! Returned {len(result)} chars") | ||||||||||||||||||||||||||||||
| print(f"π Preview: {result[:200]}...") | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||
| print(f"β Serper scrape client failed: {str(e)}") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def test_content_scraper_with_serper(): | ||||||||||||||||||||||||||||||
| """Test the content scraper service with Serper integration.""" | ||||||||||||||||||||||||||||||
|
Comment on lines
+55
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add missing return type hint. The coding guidelines require type hints for all function signatures. Add As per coding guidelines. Apply this diff: -def test_content_scraper_with_serper():
+def test_content_scraper_with_serper() -> bool:
"""Test the content scraper service with Serper integration."""
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||
| api_key = os.environ.get("SERPER_API_KEY", "") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if not api_key: | ||||||||||||||||||||||||||||||
| print("β οΈ SERPER_API_KEY not set - skipping content scraper test") | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| print("\nπ§ͺ Testing content scraper with Serper integration...") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Create a test search result | ||||||||||||||||||||||||||||||
| test_result = SearchResult( | ||||||||||||||||||||||||||||||
| title="Example Domain", | ||||||||||||||||||||||||||||||
| url="https://example.com", | ||||||||||||||||||||||||||||||
| snippet="This domain is for use in illustrative examples", | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||
| scraped = scrape_search_result(test_result) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if not scraped.content: | ||||||||||||||||||||||||||||||
| print("β Content scraper returned empty content") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if "Error:" in scraped.content: | ||||||||||||||||||||||||||||||
| print(f"β Content scraper returned error: {scraped.content}") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Check that it includes our formatting | ||||||||||||||||||||||||||||||
| if "# Example Domain" not in scraped.content: | ||||||||||||||||||||||||||||||
| print("β Content missing expected title formatting") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if "*Source: https://example.com*" not in scraped.content: | ||||||||||||||||||||||||||||||
| print("β Content missing expected source attribution") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| print(f"β Content scraper working! Returned {len(scraped.content)} chars") | ||||||||||||||||||||||||||||||
| print(f"π Preview:\n{scraped.content[:300]}...") | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||
| print(f"β Content scraper failed: {str(e)}") | ||||||||||||||||||||||||||||||
| import traceback | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| traceback.print_exc() | ||||||||||||||||||||||||||||||
|
Comment on lines
+98
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion | π Major Move traceback import to module level. The coding guidelines prefer absolute imports at the module level. Move the As per coding guidelines. Add this import at the module level (after line 10): import os
import sys
+import tracebackThen remove the import from inside the function: except Exception as e:
print(f"β Content scraper failed: {str(e)}")
- import traceback
-
traceback.print_exc()π Committable suggestion
Suggested change
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def test_fallback_to_trafilatura(): | ||||||||||||||||||||||||||||||
| """Test that Trafilatura fallback works when Serper is not available.""" | ||||||||||||||||||||||||||||||
|
Comment on lines
+104
to
+105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add missing return type hint. The coding guidelines require type hints for all function signatures. Add As per coding guidelines. Apply this diff: -def test_fallback_to_trafilatura():
+def test_fallback_to_trafilatura() -> bool:
"""Test that Trafilatura fallback works when Serper is not available."""
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||
| print("\nπ§ͺ Testing Trafilatura fallback (without Serper key)...") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Temporarily remove API key | ||||||||||||||||||||||||||||||
| original_key = os.environ.get("SERPER_API_KEY") | ||||||||||||||||||||||||||||||
| if original_key: | ||||||||||||||||||||||||||||||
| os.environ["SERPER_API_KEY"] = "" | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||
| test_result = SearchResult( | ||||||||||||||||||||||||||||||
| title="Example Domain", | ||||||||||||||||||||||||||||||
| url="https://example.com", | ||||||||||||||||||||||||||||||
| snippet="This domain is for use in illustrative examples", | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| scraped = scrape_search_result(test_result) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if not scraped.content: | ||||||||||||||||||||||||||||||
| print("β Trafilatura fallback returned empty content") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if "Error:" in scraped.content: | ||||||||||||||||||||||||||||||
| print(f"β Trafilatura fallback returned error: {scraped.content}") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| print(f"β Trafilatura fallback working! Returned {len(scraped.content)} chars") | ||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||
| print(f"β Trafilatura fallback failed: {str(e)}") | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
| finally: | ||||||||||||||||||||||||||||||
| # Restore API key | ||||||||||||||||||||||||||||||
| if original_key: | ||||||||||||||||||||||||||||||
| os.environ["SERPER_API_KEY"] = original_key | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def main(): | ||||||||||||||||||||||||||||||
| """Run all integration tests.""" | ||||||||||||||||||||||||||||||
|
Comment on lines
+142
to
+143
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add missing return type hint. The coding guidelines require type hints for all function signatures. Add As per coding guidelines. Apply this diff: -def main():
+def main() -> int:
"""Run all integration tests."""π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||
| print("=" * 60) | ||||||||||||||||||||||||||||||
| print("π Serper Scrape Integration Tests") | ||||||||||||||||||||||||||||||
| print("=" * 60) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| results = [] | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Test 1: Serper scrape client | ||||||||||||||||||||||||||||||
| results.append(("Serper scrape client", test_serper_scrape_client())) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Test 2: Content scraper with Serper | ||||||||||||||||||||||||||||||
| results.append(("Content scraper with Serper", test_content_scraper_with_serper())) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Test 3: Trafilatura fallback | ||||||||||||||||||||||||||||||
| results.append(("Trafilatura fallback", test_fallback_to_trafilatura())) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Summary | ||||||||||||||||||||||||||||||
| print("\n" + "=" * 60) | ||||||||||||||||||||||||||||||
| print("π Test Summary") | ||||||||||||||||||||||||||||||
| print("=" * 60) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| passed = sum(1 for _, result in results if result) | ||||||||||||||||||||||||||||||
| total = len(results) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| for test_name, result in results: | ||||||||||||||||||||||||||||||
| status = "β PASS" if result else "β FAIL" | ||||||||||||||||||||||||||||||
| print(f"{status}: {test_name}") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| print("=" * 60) | ||||||||||||||||||||||||||||||
| print(f"Results: {passed}/{total} tests passed") | ||||||||||||||||||||||||||||||
| print("=" * 60) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return 0 if passed == total else 1 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||||||||||||||
| sys.exit(main()) | ||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add missing return type hint.
The coding guidelines require type hints for all function signatures. Add
-> boolto the function signature.As per coding guidelines.
Apply this diff:
π Committable suggestion
π€ Prompt for AI Agents