|
| 1 | +"""Tests for RunnerFactory provider loading and error messages.""" |
| 2 | + |
| 3 | +from unittest.mock import patch |
| 4 | + |
| 5 | +import pytest |
| 6 | + |
| 7 | +from ldai.providers.runner_factory import RunnerFactory, _PYPI_PACKAGE_NAMES |
| 8 | + |
| 9 | + |
| 10 | +class TestPkgExists: |
| 11 | + """_pkg_exists raises ImportError with the PyPI package name when a module is missing.""" |
| 12 | + |
| 13 | + def test_raises_import_error_with_pypi_name_for_openai(self): |
| 14 | + with patch('ldai.providers.runner_factory.util') as mock_util: |
| 15 | + mock_util.find_spec.return_value = None |
| 16 | + with pytest.raises(ImportError) as exc_info: |
| 17 | + RunnerFactory._pkg_exists('ldai_openai') |
| 18 | + assert 'launchdarkly-server-sdk-ai-openai' in str(exc_info.value) |
| 19 | + assert 'pip install' not in str(exc_info.value) |
| 20 | + |
| 21 | + def test_raises_import_error_with_pypi_name_for_langchain(self): |
| 22 | + with patch('ldai.providers.runner_factory.util') as mock_util: |
| 23 | + mock_util.find_spec.return_value = None |
| 24 | + with pytest.raises(ImportError) as exc_info: |
| 25 | + RunnerFactory._pkg_exists('ldai_langchain') |
| 26 | + assert 'launchdarkly-server-sdk-ai-langchain' in str(exc_info.value) |
| 27 | + assert 'pip install' not in str(exc_info.value) |
| 28 | + |
| 29 | + def test_raises_import_error_with_module_name_when_no_mapping(self): |
| 30 | + """Unknown module names fall back to the module name itself.""" |
| 31 | + with patch('ldai.providers.runner_factory.util') as mock_util: |
| 32 | + mock_util.find_spec.return_value = None |
| 33 | + with pytest.raises(ImportError) as exc_info: |
| 34 | + RunnerFactory._pkg_exists('some_unknown_module') |
| 35 | + assert 'some_unknown_module' in str(exc_info.value) |
| 36 | + |
| 37 | + def test_does_not_raise_when_package_is_found(self): |
| 38 | + with patch('ldai.providers.runner_factory.util') as mock_util: |
| 39 | + mock_util.find_spec.return_value = object() # non-None means found |
| 40 | + # Should not raise |
| 41 | + RunnerFactory._pkg_exists('ldai_openai') |
| 42 | + |
| 43 | + |
| 44 | +class TestPypiPackageNameMapping: |
| 45 | + """The _PYPI_PACKAGE_NAMES mapping covers all supported providers.""" |
| 46 | + |
| 47 | + def test_openai_module_maps_to_pypi_name(self): |
| 48 | + assert _PYPI_PACKAGE_NAMES['ldai_openai'] == 'launchdarkly-server-sdk-ai-openai' |
| 49 | + |
| 50 | + def test_langchain_module_maps_to_pypi_name(self): |
| 51 | + assert _PYPI_PACKAGE_NAMES['ldai_langchain'] == 'launchdarkly-server-sdk-ai-langchain' |
| 52 | + |
| 53 | + |
| 54 | +class TestGetProviderFactory: |
| 55 | + """_get_provider_factory logs the PyPI package name in its warning when a package is missing.""" |
| 56 | + |
| 57 | + def test_warning_includes_pypi_name_for_openai(self): |
| 58 | + with patch('ldai.providers.runner_factory.util') as mock_util, \ |
| 59 | + patch('ldai.providers.runner_factory.log') as mock_log: |
| 60 | + mock_util.find_spec.return_value = None |
| 61 | + result = RunnerFactory._get_provider_factory('openai') |
| 62 | + assert result is None |
| 63 | + warning_text = mock_log.warning.call_args[0][0] |
| 64 | + assert 'launchdarkly-server-sdk-ai-openai' in warning_text |
| 65 | + assert 'ldai_openai' not in warning_text |
| 66 | + |
| 67 | + def test_warning_includes_pypi_name_for_langchain(self): |
| 68 | + with patch('ldai.providers.runner_factory.util') as mock_util, \ |
| 69 | + patch('ldai.providers.runner_factory.log') as mock_log: |
| 70 | + mock_util.find_spec.return_value = None |
| 71 | + result = RunnerFactory._get_provider_factory('langchain') |
| 72 | + assert result is None |
| 73 | + warning_text = mock_log.warning.call_args[0][0] |
| 74 | + assert 'launchdarkly-server-sdk-ai-langchain' in warning_text |
| 75 | + assert 'ldai_langchain' not in warning_text |
| 76 | + |
| 77 | + def test_warning_does_not_reference_pip(self): |
| 78 | + """Warning should be package-manager agnostic — no pip install command.""" |
| 79 | + with patch('ldai.providers.runner_factory.util') as mock_util, \ |
| 80 | + patch('ldai.providers.runner_factory.log') as mock_log: |
| 81 | + mock_util.find_spec.return_value = None |
| 82 | + RunnerFactory._get_provider_factory('openai') |
| 83 | + warning_text = mock_log.warning.call_args[0][0] |
| 84 | + assert 'pip install' not in warning_text |
0 commit comments