45 lines
2.4 KiB
Python
45 lines
2.4 KiB
Python
import os
|
|||
|
|
import unittest
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
from app.search_provider import ProviderConfigError, provider_status, search
|
||
|
|
|
||
|
|
|
||
|
|
class SearchProviderTests(unittest.TestCase):
|
||
|
|
def tearDown(self):
|
||
|
|
for key in ("SEARCH_PROVIDER_URL", "SEARCH_PROVIDER_ALLOWED_HOSTS", "SEARCH_PROVIDER_API_KEY"):
|
||
|
|
os.environ.pop(key, None)
|
||
|
|
|
||
|
|
def test_not_configured_is_fail_closed(self):
|
||
|
|
self.assertEqual(provider_status()["status"], "not_configured")
|
||
|
|
with self.assertRaisesRegex(ProviderConfigError, "not_configured"):
|
||
|
|
search({"keywords": ["solar"]}, 5)
|
||
|
|
|
||
|
|
def test_unsafe_provider_is_rejected(self):
|
||
|
|
os.environ["SEARCH_PROVIDER_URL"] = "http://search.example.test/query"
|
||
|
|
os.environ["SEARCH_PROVIDER_ALLOWED_HOSTS"] = "search.example.test"
|
||
|
|
self.assertEqual(provider_status()["status"], "unsafe_configured")
|
||
|
|
with self.assertRaisesRegex(ProviderConfigError, "unsafe_provider"):
|
||
|
|
search({}, 5)
|
||
|
|
|
||
|
|
def test_successful_mocked_search_returns_bounded_https_urls(self):
|
||
|
|
os.environ["SEARCH_PROVIDER_URL"] = "https://search.example.test/query"
|
||
|
|
os.environ["SEARCH_PROVIDER_ALLOWED_HOSTS"] = "search.example.test"
|
||
|
|
response = type("Response", (), {"__enter__": lambda self: self, "__exit__": lambda self, *args: None, "read": lambda self, *_: b'{"results":[{"url":"https://acme.test"},{"url":"http://bad.test"},{"url":"https://acme.test"}]}'})()
|
||
|
|
with patch("app.search_provider.urlopen", return_value=response), patch("app.search_provider.validate_url", side_effect=lambda url, **_: url):
|
||
|
|
self.assertEqual(search({"keywords": ["solar"]}, 5), ["https://acme.test"])
|
||
|
|
|
||
|
|
def test_limit_is_bounded_and_sent_to_provider(self):
|
||
|
|
os.environ["SEARCH_PROVIDER_URL"] = "https://search.example.test/query"
|
||
|
|
os.environ["SEARCH_PROVIDER_ALLOWED_HOSTS"] = "search.example.test"
|
||
|
|
response = type("Response", (), {"__enter__": lambda self: self, "__exit__": lambda self, *args: None, "read": lambda self, *_: b'{"results":[]}'})()
|
||
|
|
with patch("app.search_provider.urlopen", return_value=response) as opened:
|
||
|
|
self.assertEqual(search({}, 500), [])
|
||
|
|
self.assertEqual(opened.call_args.kwargs["timeout"], 8)
|
||
|
|
request = opened.call_args.args[0]
|
||
|
|
self.assertIn(b'"limit":50', request.data)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|