"""Tests for the Brave Search cron executor.""" import os from unittest.mock import AsyncMock, MagicMock, patch import pytest from cron.brave_search import execute_brave_search @pytest.fixture def job(): return { "id": "j1", "name": "BMW Search", "jobType": "brave_search", "config": {"query": "BMW X3 damaged Cyprus", "maxResults": 5}, "targetRoom": "!room:cars", "dedupKeys": ["https://old-result.com"], } class TestBraveSearchExecutor: @pytest.mark.asyncio async def test_returns_error_without_api_key(self, job): with patch.dict(os.environ, {"BRAVE_API_KEY": ""}, clear=False): # Need to reload module to pick up empty env import importlib import cron.brave_search as bs original_key = bs.BRAVE_API_KEY bs.BRAVE_API_KEY = "" try: result = await execute_brave_search(job=job, send_text=AsyncMock()) assert result["status"] == "error" assert "BRAVE_API_KEY" in result["error"] finally: bs.BRAVE_API_KEY = original_key @pytest.mark.asyncio async def test_returns_error_without_query(self): job = { "id": "j1", "name": "Empty", "jobType": "brave_search", "config": {}, "targetRoom": "!room:test", "dedupKeys": [], } import cron.brave_search as bs original_key = bs.BRAVE_API_KEY bs.BRAVE_API_KEY = "test-key" try: result = await execute_brave_search(job=job, send_text=AsyncMock()) assert result["status"] == "error" assert "query" in result["error"].lower() finally: bs.BRAVE_API_KEY = original_key @pytest.mark.asyncio async def test_deduplicates_results(self, job): """Results with URLs already in dedupKeys should be filtered out.""" import cron.brave_search as bs original_key = bs.BRAVE_API_KEY bs.BRAVE_API_KEY = "test-key" mock_response = MagicMock() mock_response.json.return_value = { "web": { "results": [ {"title": "Old Result", "url": "https://old-result.com", "description": "Already seen"}, {"title": "New BMW", "url": "https://new-result.com", "description": "Fresh listing"}, ] } } mock_response.raise_for_status = MagicMock() send_text = AsyncMock() with patch("httpx.AsyncClient") as mock_client_cls: mock_client = AsyncMock() mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client) mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False) mock_client.get = AsyncMock(return_value=mock_response) try: result = await execute_brave_search(job=job, send_text=send_text) finally: bs.BRAVE_API_KEY = original_key assert result["status"] == "success" assert result["newDedupKeys"] == ["https://new-result.com"] send_text.assert_called_once() # Message should contain only the new result msg = send_text.call_args[0][1] assert "New BMW" in msg assert "Old Result" not in msg @pytest.mark.asyncio async def test_no_results_status(self, job): """When API returns empty results, status should be no_results.""" import cron.brave_search as bs original_key = bs.BRAVE_API_KEY bs.BRAVE_API_KEY = "test-key" mock_response = MagicMock() mock_response.json.return_value = {"web": {"results": []}} mock_response.raise_for_status = MagicMock() with patch("httpx.AsyncClient") as mock_client_cls: mock_client = AsyncMock() mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client) mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False) mock_client.get = AsyncMock(return_value=mock_response) try: result = await execute_brave_search(job=job, send_text=AsyncMock()) finally: bs.BRAVE_API_KEY = original_key assert result["status"] == "no_results" @pytest.mark.asyncio async def test_all_results_already_seen(self, job): """When all results are already in dedupKeys, status should be no_results.""" import cron.brave_search as bs original_key = bs.BRAVE_API_KEY bs.BRAVE_API_KEY = "test-key" mock_response = MagicMock() mock_response.json.return_value = { "web": { "results": [ {"title": "Old", "url": "https://old-result.com", "description": "Seen"}, ] } } mock_response.raise_for_status = MagicMock() with patch("httpx.AsyncClient") as mock_client_cls: mock_client = AsyncMock() mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client) mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False) mock_client.get = AsyncMock(return_value=mock_response) try: result = await execute_brave_search(job=job, send_text=AsyncMock()) finally: bs.BRAVE_API_KEY = original_key assert result["status"] == "no_results"