"""High-value tests for OpenAI-Compatible endpoint provider edge cases. Focuses on the unique is_available logic (URL-based availability), create_llm URL passthrough, and backward compatibility functions. """ from unittest.mock import Mock, patch from local_deep_research.llm.providers.implementations.custom_openai_endpoint import ( CustomOpenAIEndpointProvider, ) from local_deep_research.llm.providers.openai_base import ( OpenAICompatibleProvider, ) CUSTOM_MOD = ( "local_deep_research.llm.providers.implementations.custom_openai_endpoint" ) GET_SETTING = f"{CUSTOM_MOD}.get_setting_from_snapshot" PARENT_CREATE = "local_deep_research.llm.providers.openai_base.OpenAICompatibleProvider.create_llm" class TestCustomOpenAIIsAvailable: """Tests for the unique is_available logic (api_key OR custom URL).""" def test_available_with_api_key_only(self): """Provider is available when only API key is set.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.api_key": return "my-key" return default with patch(GET_SETTING, side_effect=side_effect): assert CustomOpenAIEndpointProvider.is_available() is True def test_available_with_custom_url_only(self): """Provider is available when custom URL differs from default.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.api_key": return None if key == "llm.openai_endpoint.url": return "http://localhost:8080/v1" return default with patch(GET_SETTING, side_effect=side_effect): assert CustomOpenAIEndpointProvider.is_available() is True def test_not_available_with_default_url_and_no_key(self): """Provider is NOT available when URL equals default and no API key.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.api_key": return None if key == "llm.openai_endpoint.url": return "https://api.openai.com/v1" return default with patch(GET_SETTING, side_effect=side_effect): assert CustomOpenAIEndpointProvider.is_available() is False def test_not_available_with_none_url_and_no_key(self): """Provider is NOT available when both URL and key are None.""" with patch(GET_SETTING, return_value=None): assert CustomOpenAIEndpointProvider.is_available() is False def test_whitespace_api_key_not_available(self): """Whitespace-only API key does not make provider available.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.api_key": return " " if key == "llm.openai_endpoint.url": return None return default with patch(GET_SETTING, side_effect=side_effect): assert CustomOpenAIEndpointProvider.is_available() is False def test_whitespace_url_not_available(self): """Whitespace-only URL does not make provider available.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.api_key": return None if key == "llm.openai_endpoint.url": return " " return default with patch(GET_SETTING, side_effect=side_effect): assert CustomOpenAIEndpointProvider.is_available() is False def test_exception_in_api_key_check_falls_through_to_url(self): """Exception reading API key falls through to URL check.""" call_count = 0 def side_effect(key, default=None, **kwargs): nonlocal call_count call_count += 1 if key == "llm.openai_endpoint.api_key": raise RuntimeError("settings error") if key == "llm.openai_endpoint.url": return "http://myserver:5000/v1" return default with patch(GET_SETTING, side_effect=side_effect): assert CustomOpenAIEndpointProvider.is_available() is True def test_both_exceptions_return_false(self): """Exceptions in both api_key and url checks return False.""" with patch(GET_SETTING, side_effect=RuntimeError("boom")): assert CustomOpenAIEndpointProvider.is_available() is False class TestCustomOpenAICreateLlm: """Tests for create_llm URL passthrough.""" def test_custom_url_passed_to_parent(self): """Custom URL from settings is passed as base_url to parent.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.url": return "http://myserver:9000/v1" if key == "llm.openai_endpoint.api_key": return "test-key" return default with patch(GET_SETTING, side_effect=side_effect): with patch(PARENT_CREATE) as mock_parent: mock_parent.return_value = Mock() CustomOpenAIEndpointProvider.create_llm() _, kwargs = mock_parent.call_args assert "base_url" in kwargs def test_none_url_uses_default(self): """None URL falls back to default_base_url.""" def side_effect(key, default=None, **kwargs): if key == "llm.openai_endpoint.url": return None if key == "llm.openai_endpoint.api_key": return "test-key" return default with patch(GET_SETTING, side_effect=side_effect): with patch(PARENT_CREATE) as mock_parent: mock_parent.return_value = Mock() CustomOpenAIEndpointProvider.create_llm() _, kwargs = mock_parent.call_args assert ( kwargs["base_url"] == CustomOpenAIEndpointProvider.default_base_url ) class TestCustomOpenAIClassAttributes: """Tests for class-level metadata.""" def test_inherits_from_openai_compatible(self): """Inherits from OpenAICompatibleProvider.""" assert issubclass( CustomOpenAIEndpointProvider, OpenAICompatibleProvider ) def test_provider_key(self): """Provider key is OPENAI_ENDPOINT.""" assert CustomOpenAIEndpointProvider.provider_key == "OPENAI_ENDPOINT" def test_is_cloud_is_none(self): """is_cloud is None (could be local or cloud).""" assert CustomOpenAIEndpointProvider.is_cloud is None def test_requires_auth_for_models_returns_false(self): """Custom endpoints don't require auth for model listing.""" assert CustomOpenAIEndpointProvider.requires_auth_for_models() is False