""" Coverage tests for local_deep_research/utilities/llm_utils.py. Focuses on paths not exercised by existing test files: - _close_base_llm: close() delegation, Ollama httpx client closing, non-Ollama _client skip, missing _client attr, missing httpx client - fetch_ollama_models: verifies safe_get (not requests.get) is used """ from unittest.mock import Mock, patch from local_deep_research.utilities.llm_utils import ( _close_base_llm, fetch_ollama_models, ) # --------------------------------------------------------------------------- # _close_base_llm # --------------------------------------------------------------------------- class TestCloseBaseLlmDelegation: """When the LLM object has its own close() method defined on the type.""" def test_delegates_to_close_method(self): """Should call llm.close() when the type defines close.""" class ClosableLLM: def close(self): pass llm = ClosableLLM() llm.close = Mock() _close_base_llm(llm) llm.close.assert_called_once() def test_does_not_inspect_client_after_close(self): """After calling close(), should return immediately without inspecting _client.""" class ClosableLLM: def close(self): pass llm = ClosableLLM() llm.close = Mock() llm._client = Mock() _close_base_llm(llm) llm.close.assert_called_once() llm._client.close.assert_not_called() class TestCloseBaseLlmOllamaClient: """When the LLM has an Ollama-module _client with an httpx _client.""" def test_closes_httpx_client_on_ollama(self): """Should close the nested httpx client on an Ollama _client.""" httpx_client = Mock() httpx_client.close = Mock() ollama_client = Mock() ollama_client._client = httpx_client type(ollama_client).__module__ = "ollama._client" llm = Mock(spec=[]) llm._client = ollama_client _close_base_llm(llm) httpx_client.close.assert_called_once() def test_skips_non_ollama_client_module(self): """Should NOT close _client._client when module is not ollama.""" httpx_client = Mock() httpx_client.close = Mock() non_ollama_client = Mock() non_ollama_client._client = httpx_client type(non_ollama_client).__module__ = "openai._http_client" llm = Mock(spec=[]) llm._client = non_ollama_client _close_base_llm(llm) httpx_client.close.assert_not_called() def test_no_client_attr_is_noop(self): """Should do nothing when llm has no _client attribute.""" llm = Mock(spec=[]) assert ( not hasattr(llm, "_client") or getattr(llm, "_client", None) is None ) _close_base_llm(llm) def test_ollama_client_without_httpx_client(self): """Should handle Ollama _client that has no nested _client (httpx).""" ollama_client = Mock(spec=[]) type(ollama_client).__module__ = "ollama._client" llm = Mock(spec=[]) llm._client = ollama_client _close_base_llm(llm) def test_ollama_httpx_client_without_close(self): """Should handle Ollama httpx _client that lacks close().""" httpx_client = Mock(spec=[]) ollama_client = Mock() ollama_client._client = httpx_client type(ollama_client).__module__ = "ollama.core" llm = Mock(spec=[]) llm._client = ollama_client _close_base_llm(llm) # --------------------------------------------------------------------------- # fetch_ollama_models - verifies safe_get usage # --------------------------------------------------------------------------- class TestFetchOllamaModelsUsesSafeGet: """Verify that fetch_ollama_models calls safe_get, not requests.get.""" def test_calls_safe_get_not_requests_get(self): """safe_get should be called; requests.get should NOT.""" mock_safe_get = Mock() mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"models": [{"name": "llama3"}]} mock_safe_get.return_value = mock_response with patch( "local_deep_research.utilities.llm_utils.safe_get", mock_safe_get, create=True, ): with patch("local_deep_research.security.safe_get", mock_safe_get): result = fetch_ollama_models("http://localhost:11434") mock_safe_get.assert_called() call_args = mock_safe_get.call_args assert "localhost:11434/api/tags" in call_args.args[0] assert call_args.kwargs["allow_localhost"] is True assert call_args.kwargs["allow_private_ips"] is True assert len(result) == 1 assert result[0]["value"] == "llama3" def test_safe_get_exception_returns_empty_list(self): """When safe_get raises, should return [] gracefully.""" with patch( "local_deep_research.security.safe_get", side_effect=RuntimeError("SSRF blocked"), ): result = fetch_ollama_models("http://evil.com:11434") assert result == [] def test_safe_get_non_200_returns_empty(self): """Non-200 response from safe_get should yield empty list.""" mock_response = Mock() mock_response.status_code = 503 with patch( "local_deep_research.security.safe_get", return_value=mock_response, ): result = fetch_ollama_models("http://localhost:11434") assert result == []