Skip to content

Commit 5a7bdb0

Browse files
committed
add tests
1 parent e96704c commit 5a7bdb0

9 files changed

Lines changed: 1590 additions & 252 deletions
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import warnings
17+
from unittest.mock import patch
18+
19+
import pytest
20+
21+
from nemoguardrails.llm.providers.providers import (
22+
_discover_langchain_community_llm_providers,
23+
discover_langchain_providers,
24+
)
25+
26+
27+
class MockBaseLLM:
28+
def _call(self, *args, **kwargs):
29+
return "Mock response"
30+
31+
32+
@pytest.fixture
33+
def mock_discover_function():
34+
with patch(
35+
"nemoguardrails.llm.providers.providers._discover_langchain_community_llm_providers"
36+
) as mock_func:
37+
mock_providers = {"mock_provider": MockBaseLLM}
38+
mock_func.return_value = mock_providers
39+
with patch(
40+
"nemoguardrails.llm.providers.providers._patch_acall_method_to"
41+
) as mock_patch:
42+
with patch(
43+
"nemoguardrails.llm.providers.providers._llm_providers"
44+
) as mock_llm_providers:
45+
mock_llm_providers.update(mock_providers)
46+
yield mock_func
47+
48+
49+
def test_discover_langchain_providers_deprecation(mock_discover_function):
50+
with warnings.catch_warnings(record=True) as w:
51+
warnings.simplefilter("always")
52+
discover_langchain_providers()
53+
assert len(w) == 1
54+
assert issubclass(w[0].category, DeprecationWarning)
55+
assert "deprecated" in str(w[0].message).lower()
56+
assert "v0.15.0" in str(w[0].message)
57+
58+
59+
def test_discover_langchain_providers_functionality(mock_discover_function):
60+
# ensure the function still works as expected
61+
discover_langchain_providers()
62+
# as the function is deprecated, we verify that it calls the underlying function
63+
mock_discover_function.assert_called_once()
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
"""
17+
Tests for the initialization methods for different model types.
18+
19+
This module contains tests for the initialization methods that are used to initialize
20+
different types of models (chat completion, community chat, text completion).
21+
"""
22+
23+
from unittest.mock import MagicMock, patch
24+
25+
import pytest
26+
27+
from nemoguardrails.llm.models.langchain_initializer import (
28+
_init_chat_completion_model,
29+
_init_community_chat_models,
30+
_init_text_completion_model,
31+
_update_model_kwargs,
32+
)
33+
34+
35+
class TestChatCompletionInitializer:
36+
"""Tests for the chat completion initializer."""
37+
38+
def test_init_chat_completion_model_success(self):
39+
with patch(
40+
"nemoguardrails.llm.models.langchain_initializer.init_chat_model"
41+
) as mock_init:
42+
mock_init.return_value = "chat_model"
43+
with patch(
44+
"nemoguardrails.llm.models.langchain_initializer.version"
45+
) as mock_version:
46+
mock_version.return_value = "0.2.7"
47+
result = _init_chat_completion_model("gpt-3.5-turbo", "openai", {})
48+
assert result == "chat_model"
49+
mock_init.assert_called_once_with(
50+
model="gpt-3.5-turbo",
51+
model_provider="openai",
52+
)
53+
54+
def test_init_chat_completion_model_old_version(self):
55+
with patch(
56+
"nemoguardrails.llm.models.langchain_initializer.version"
57+
) as mock_version:
58+
mock_version.return_value = "0.2.6"
59+
with pytest.raises(
60+
RuntimeError,
61+
match="this feature is supported from v0.2.7 of langchain-core",
62+
):
63+
_init_chat_completion_model("gpt-3.5-turbo", "openai", {})
64+
65+
def test_init_chat_completion_model_error(self):
66+
with patch(
67+
"nemoguardrails.llm.models.langchain_initializer.init_chat_model"
68+
) as mock_init:
69+
mock_init.side_effect = ValueError("Chat model failed")
70+
with patch(
71+
"nemoguardrails.llm.models.langchain_initializer.version"
72+
) as mock_version:
73+
mock_version.return_value = "0.2.7"
74+
with pytest.raises(ValueError, match="Chat model failed"):
75+
_init_chat_completion_model("gpt-3.5-turbo", "openai", {})
76+
77+
78+
class TestCommunityChatInitializer:
79+
"""Tests for the community chat initializer."""
80+
81+
def test_init_community_chat_models_success(self):
82+
with patch(
83+
"nemoguardrails.llm.models.langchain_initializer._get_chat_completion_provider"
84+
) as mock_get_provider:
85+
mock_provider_cls = MagicMock()
86+
mock_provider_cls.model_fields = {"model": None}
87+
mock_provider_cls.return_value = "community_model"
88+
mock_get_provider.return_value = mock_provider_cls
89+
result = _init_community_chat_models("community-model", "provider", {})
90+
assert result == "community_model"
91+
mock_get_provider.assert_called_once_with("provider")
92+
mock_provider_cls.assert_called_once_with(model="community-model")
93+
94+
def test_init_community_chat_models_no_provider(self):
95+
with patch(
96+
"nemoguardrails.llm.models.langchain_initializer._get_chat_completion_provider"
97+
) as mock_get_provider:
98+
mock_get_provider.return_value = None
99+
with pytest.raises(ValueError):
100+
_init_community_chat_models("community-model", "provider", {})
101+
102+
103+
class TestTextCompletionInitializer:
104+
"""Tests for the text completion initializer."""
105+
106+
def test_init_text_completion_model_success(self):
107+
with patch(
108+
"nemoguardrails.llm.models.langchain_initializer._get_text_completion_provider"
109+
) as mock_get_provider:
110+
mock_provider_cls = MagicMock()
111+
mock_provider_cls.model_fields = {"model": None}
112+
mock_provider_cls.return_value = "text_model"
113+
mock_get_provider.return_value = mock_provider_cls
114+
result = _init_text_completion_model("text-model", "provider", {})
115+
assert result == "text_model"
116+
mock_get_provider.assert_called_once_with("provider")
117+
mock_provider_cls.assert_called_once_with(model="text-model")
118+
119+
def test_init_text_completion_model_no_provider(self):
120+
with patch(
121+
"nemoguardrails.llm.models.langchain_initializer._get_text_completion_provider"
122+
) as mock_get_provider:
123+
mock_get_provider.return_value = None
124+
with pytest.raises(ValueError):
125+
_init_text_completion_model("text-model", "provider", {})
126+
127+
128+
class TestUpdateModelKwargs:
129+
"""Tests for the _update_model_kwargs function."""
130+
131+
def test_update_model_kwargs_with_model_field(self):
132+
mock_provider_cls = MagicMock()
133+
mock_provider_cls.model_fields = {"model": {}}
134+
kwargs = {}
135+
updated_kwargs = _update_model_kwargs(mock_provider_cls, "test-model", kwargs)
136+
assert updated_kwargs == {"model": "test-model"}
137+
138+
def test_update_model_kwargs_with_model_name_field(self):
139+
"""Test that _update_model_kwargs updates kwargs with model name when provider has model_name field."""
140+
mock_provider_cls = MagicMock()
141+
mock_provider_cls.model_fields = {"model_name": {}}
142+
kwargs = {}
143+
updated_kwargs = _update_model_kwargs(mock_provider_cls, "test-model", kwargs)
144+
assert updated_kwargs == {"model_name": "test-model"}
145+
146+
def test_update_model_kwargs_with_both_fields(self):
147+
"""Test _update_model_kwargs updates kwargs with model name when provider has both model and model_name fields."""
148+
149+
mock_provider_cls = MagicMock()
150+
mock_provider_cls.model_fields = {"model": {}, "model_name": {}}
151+
kwargs = {}
152+
updated_kwargs = _update_model_kwargs(mock_provider_cls, "test-model", kwargs)
153+
assert updated_kwargs == {"model": "test-model", "model_name": "test-model"}
154+
155+
def test_update_model_kwargs_with_existing_kwargs(self):
156+
"""Test _update_model_kwargs preserves existing kwargs."""
157+
158+
mock_provider_cls = MagicMock()
159+
mock_provider_cls.model_fields = {"model": {}}
160+
kwargs = {"temperature": 0.7}
161+
updated_kwargs = _update_model_kwargs(mock_provider_cls, "test-model", kwargs)
162+
assert updated_kwargs == {"model": "test-model", "temperature": 0.7}

0 commit comments

Comments
 (0)