7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
560 lines
20 KiB
Python
560 lines
20 KiB
Python
"""
|
|
Comprehensive tests for the Google Programmable Search Engine.
|
|
Tests initialization, search functionality, error handling, and retry logic.
|
|
|
|
Note: These tests mock HTTP requests to avoid requiring an API key.
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock
|
|
|
|
|
|
class TestGooglePSESearchEngineInit:
|
|
"""Tests for Google PSE search engine initialization."""
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_validation(self, monkeypatch):
|
|
"""Mock validation to avoid HTTP requests during init."""
|
|
# Mock safe_get to return a valid test response
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
def test_init_with_credentials(self):
|
|
"""Test initialization with API key and search engine ID."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_api_key", search_engine_id="test_engine_id"
|
|
)
|
|
|
|
assert engine.api_key == "test_api_key"
|
|
assert engine.search_engine_id == "test_engine_id"
|
|
assert engine.max_results >= 10
|
|
assert engine.is_public is True
|
|
assert engine.is_generic is True
|
|
|
|
def test_init_custom_max_results(self):
|
|
"""Test initialization with custom max results."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
max_results=25,
|
|
)
|
|
assert engine.max_results >= 25
|
|
|
|
def test_init_with_region(self):
|
|
"""Test initialization with specific region."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
region="de",
|
|
)
|
|
assert engine.region == "de"
|
|
|
|
def test_init_with_safe_search(self):
|
|
"""Test initialization with safe search options."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
safe_search=True,
|
|
)
|
|
assert engine.safe == "active"
|
|
|
|
engine_off = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
safe_search=False,
|
|
)
|
|
assert engine_off.safe == "off"
|
|
|
|
def test_init_without_api_key_raises(self, monkeypatch):
|
|
"""Test that initialization without API key raises ValueError."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
# Mock get_setting_from_snapshot to return None
|
|
monkeypatch.setattr(
|
|
"local_deep_research.config.thread_settings.get_setting_from_snapshot",
|
|
lambda *args, **kwargs: None,
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="Google API key is required"):
|
|
GooglePSESearchEngine(search_engine_id="test_id")
|
|
|
|
def test_init_without_engine_id_raises(self, monkeypatch):
|
|
"""Test that initialization without engine ID raises ValueError."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
# Mock get_setting_from_snapshot to return None for engine_id
|
|
def mock_get_setting(key, **kwargs):
|
|
if "api_key" in key:
|
|
return "test_key"
|
|
return None
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.config.thread_settings.get_setting_from_snapshot",
|
|
mock_get_setting,
|
|
)
|
|
|
|
with pytest.raises(
|
|
ValueError, match="Google Search Engine ID is required"
|
|
):
|
|
GooglePSESearchEngine()
|
|
|
|
def test_init_with_language(self):
|
|
"""Test initialization with different languages."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
search_language="German",
|
|
)
|
|
assert engine.language == "de"
|
|
|
|
engine_jp = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
search_language="Japanese",
|
|
)
|
|
assert engine_jp.language == "ja"
|
|
|
|
|
|
class TestGooglePSEEngineType:
|
|
"""Tests for Google PSE engine type identification."""
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_validation(self, monkeypatch):
|
|
"""Mock validation to avoid HTTP requests during init."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
def test_engine_type_set(self):
|
|
"""Test that engine type is properly set."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
assert "google" in engine.engine_type.lower()
|
|
|
|
def test_engine_is_public(self):
|
|
"""Test that engine is marked as public."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
assert engine.is_public is True
|
|
|
|
def test_engine_is_generic(self):
|
|
"""Test that engine is marked as generic."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
assert engine.is_generic is True
|
|
|
|
|
|
class TestGooglePSERetryConfig:
|
|
"""Tests for Google PSE retry configuration."""
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_validation(self, monkeypatch):
|
|
"""Mock validation to avoid HTTP requests during init."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
def test_default_retry_config(self):
|
|
"""Test default retry configuration."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
assert engine.max_retries == 3
|
|
assert engine.retry_delay == 2.0
|
|
|
|
def test_custom_retry_config(self):
|
|
"""Test custom retry configuration."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
max_retries=5,
|
|
retry_delay=1.0,
|
|
)
|
|
assert engine.max_retries == 5
|
|
assert engine.retry_delay == 1.0
|
|
|
|
|
|
class TestGooglePSERateLimiting:
|
|
"""Tests for Google PSE rate limiting."""
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_validation(self, monkeypatch):
|
|
"""Mock validation to avoid HTTP requests during init."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
def test_min_request_interval_set(self):
|
|
"""Test that minimum request interval is set."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
assert hasattr(engine, "min_request_interval")
|
|
assert engine.min_request_interval == 0.5
|
|
|
|
def test_last_request_time_initialized(self):
|
|
"""Test that last request time is initialized."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
assert hasattr(engine, "last_request_time")
|
|
assert engine.last_request_time == 0
|
|
|
|
|
|
class TestGooglePSESearchExecution:
|
|
"""Tests for Google PSE search execution."""
|
|
|
|
@pytest.fixture
|
|
def engine(self, monkeypatch):
|
|
"""Create a Google PSE engine with mocked validation."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
return GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id"
|
|
)
|
|
|
|
def test_get_previews_success(self, monkeypatch):
|
|
"""Test successful preview retrieval."""
|
|
# First, mock validation to allow engine creation
|
|
validation_response = Mock()
|
|
validation_response.status_code = 200
|
|
validation_response.raise_for_status = Mock()
|
|
validation_response.json = Mock(return_value={"items": []})
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=validation_response),
|
|
)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
# Create engine with max_results=2 to match expected results
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id", max_results=2
|
|
)
|
|
|
|
# Now mock the search response
|
|
search_response = Mock()
|
|
search_response.status_code = 200
|
|
search_response.raise_for_status = Mock()
|
|
search_response.json = Mock(
|
|
return_value={
|
|
"items": [
|
|
{
|
|
"title": "Test Result 1",
|
|
"link": "https://example1.com",
|
|
"snippet": "This is a test snippet 1",
|
|
},
|
|
{
|
|
"title": "Test Result 2",
|
|
"link": "https://example2.com",
|
|
"snippet": "This is a test snippet 2",
|
|
},
|
|
]
|
|
}
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=search_response),
|
|
)
|
|
|
|
previews = engine._get_previews("test query")
|
|
|
|
assert len(previews) == 2
|
|
assert previews[0]["title"] == "Test Result 1"
|
|
assert previews[1]["link"] == "https://example2.com"
|
|
|
|
def test_get_previews_empty_results(self, engine, monkeypatch):
|
|
"""Test preview retrieval with no results."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={})
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
previews = engine._get_previews("test query")
|
|
|
|
assert previews == []
|
|
|
|
def test_get_previews_skips_results_without_url(self, monkeypatch):
|
|
"""Test that results without URLs are skipped."""
|
|
# First, mock validation to allow engine creation
|
|
validation_response = Mock()
|
|
validation_response.status_code = 200
|
|
validation_response.raise_for_status = Mock()
|
|
validation_response.json = Mock(return_value={"items": []})
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=validation_response),
|
|
)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
# Create engine with max_results=1 to match expected valid results
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id", max_results=1
|
|
)
|
|
|
|
# Now mock the search response
|
|
search_response = Mock()
|
|
search_response.status_code = 200
|
|
search_response.raise_for_status = Mock()
|
|
search_response.json = Mock(
|
|
return_value={
|
|
"items": [
|
|
{
|
|
"title": "Test Without URL",
|
|
"snippet": "No link here",
|
|
},
|
|
{
|
|
"title": "Test With URL",
|
|
"link": "https://example.com",
|
|
"snippet": "Has a link",
|
|
},
|
|
]
|
|
}
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=search_response),
|
|
)
|
|
|
|
previews = engine._get_previews("test query")
|
|
|
|
assert len(previews) == 1
|
|
assert previews[0]["title"] == "Test With URL"
|
|
|
|
|
|
class TestGooglePSEErrorHandling:
|
|
"""Tests for Google PSE error handling."""
|
|
|
|
@pytest.fixture
|
|
def engine(self, monkeypatch):
|
|
"""Create a Google PSE engine with mocked validation."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
return GooglePSESearchEngine(
|
|
api_key="test_key", search_engine_id="test_id", max_retries=1
|
|
)
|
|
|
|
def test_rate_limit_429_raises_error(self, engine, monkeypatch):
|
|
"""Test that 429 errors raise RateLimitError."""
|
|
from requests.exceptions import RequestException
|
|
|
|
from local_deep_research.web_search_engines.rate_limiting import (
|
|
RateLimitError,
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(side_effect=RequestException("429 Too Many Requests")),
|
|
)
|
|
|
|
with pytest.raises(RateLimitError):
|
|
engine._make_request("test query")
|
|
|
|
def test_quota_exceeded_raises_rate_limit_error(self, engine, monkeypatch):
|
|
"""Test that quota exceeded errors raise RateLimitError."""
|
|
from requests.exceptions import RequestException
|
|
|
|
from local_deep_research.web_search_engines.rate_limiting import (
|
|
RateLimitError,
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(side_effect=RequestException("quotaExceeded")),
|
|
)
|
|
|
|
with pytest.raises(RateLimitError):
|
|
engine._make_request("test query")
|
|
|
|
def test_general_error_raises_request_exception(self, engine, monkeypatch):
|
|
"""Test that general errors raise RequestException after retries."""
|
|
from requests.exceptions import RequestException
|
|
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(side_effect=RequestException("Network error")),
|
|
)
|
|
|
|
with pytest.raises(RequestException):
|
|
engine._make_request("test query")
|
|
|
|
|
|
class TestGooglePSELanguageMapping:
|
|
"""Tests for Google PSE language code mapping."""
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_validation(self, monkeypatch):
|
|
"""Mock validation to avoid HTTP requests during init."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.raise_for_status = Mock()
|
|
mock_response.json = Mock(return_value={"items": []})
|
|
monkeypatch.setattr(
|
|
"local_deep_research.web_search_engines.engines.search_engine_google_pse.safe_get",
|
|
Mock(return_value=mock_response),
|
|
)
|
|
|
|
def test_english_language(self):
|
|
"""Test English language mapping."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
search_language="English",
|
|
)
|
|
assert engine.language == "en"
|
|
|
|
def test_spanish_language(self):
|
|
"""Test Spanish language mapping."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
search_language="Spanish",
|
|
)
|
|
assert engine.language == "es"
|
|
|
|
def test_chinese_language(self):
|
|
"""Test Chinese language mapping."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
search_language="Chinese",
|
|
)
|
|
assert engine.language == "zh-CN"
|
|
|
|
def test_unknown_language_defaults_to_english(self):
|
|
"""Test that unknown language defaults to English."""
|
|
from local_deep_research.web_search_engines.engines.search_engine_google_pse import (
|
|
GooglePSESearchEngine,
|
|
)
|
|
|
|
engine = GooglePSESearchEngine(
|
|
api_key="test_key",
|
|
search_engine_id="test_id",
|
|
search_language="UnknownLanguage",
|
|
)
|
|
assert engine.language == "en"
|