Skip to content

Commit 13ee90d

Browse files
committed
Add tests for the tool call wrapper utility.
1 parent a38b798 commit 13ee90d

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/common/otel_mocker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ def assert_has_span_named(self, name):
170170
span is not None
171171
), f'Could not find span named "{name}"; finished spans: {finished_spans}'
172172

173+
def assert_does_not_have_span_named(self, name):
174+
span = self.get_span_named(name)
175+
assert span is None, f'Found unexpected span named {name}'
176+
173177
def get_event_named(self, event_name):
174178
for event in self.get_finished_logs():
175179
event_name_attr = event.attributes.get("event.name")

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/utils/__init__.py

Whitespace-only changes.

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/utils/test_tool_call_wrapper.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,113 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import asyncio
16+
import unittest
17+
18+
from google.genai import types as genai_types
19+
20+
from opentelemetry._events import get_event_logger_provider
21+
from opentelemetry.metrics import get_meter_provider
22+
from opentelemetry.trace import get_tracer_provider
23+
24+
from opentelemetry.instrumentation.google_genai import tool_call_wrapper
25+
from opentelemetry.instrumentation.google_genai import otel_wrapper
26+
from ..common import otel_mocker
27+
28+
29+
class TestCase(unittest.TestCase):
30+
31+
def setUp(self):
32+
self._otel = otel_mocker.OTelMocker()
33+
self._otel.install()
34+
self._otel_wrapper = otel_wrapper.OTelWrapper.from_providers(
35+
get_tracer_provider(),
36+
get_event_logger_provider(),
37+
get_meter_provider())
38+
39+
@property
40+
def otel(self):
41+
return self._otel
42+
43+
@property
44+
def otel_wrapper(self):
45+
return self._otel_wrapper
46+
47+
def wrap(self, tool_or_tools, **kwargs):
48+
return tool_call_wrapper.wrapped(
49+
tool_or_tools,
50+
self.otel_wrapper,
51+
**kwargs)
52+
53+
def test_wraps_none(self):
54+
result = self.wrap(None)
55+
self.assertIsNone(result)
56+
57+
def test_wraps_single_tool_function(self):
58+
def foo():
59+
pass
60+
wrapped_foo = self.wrap(foo)
61+
self.otel.assert_does_not_have_span_named("tool_call foo")
62+
foo()
63+
self.otel.assert_does_not_have_span_named("tool_call foo")
64+
wrapped_foo()
65+
self.otel.assert_has_span_named("tool_call foo")
66+
67+
def test_wraps_multiple_tool_functions_as_list(self):
68+
def foo():
69+
pass
70+
def bar():
71+
pass
72+
wrapped_functions = self.wrap([foo, bar])
73+
wrapped_foo = wrapped_functions[0]
74+
wrapped_bar = wrapped_functions[1]
75+
self.otel.assert_does_not_have_span_named("tool_call foo")
76+
self.otel.assert_does_not_have_span_named("tool_call bar")
77+
foo()
78+
bar()
79+
self.otel.assert_does_not_have_span_named("tool_call foo")
80+
self.otel.assert_does_not_have_span_named("tool_call bar")
81+
wrapped_foo()
82+
self.otel.assert_has_span_named("tool_call foo")
83+
self.otel.assert_does_not_have_span_named("tool_call bar")
84+
wrapped_bar()
85+
self.otel.assert_has_span_named("tool_call bar")
86+
87+
88+
def test_wraps_multiple_tool_functions_as_dict(self):
89+
def foo():
90+
pass
91+
def bar():
92+
pass
93+
wrapped_functions = self.wrap({
94+
"foo": foo,
95+
"bar": bar
96+
})
97+
wrapped_foo = wrapped_functions["foo"]
98+
wrapped_bar = wrapped_functions["bar"]
99+
self.otel.assert_does_not_have_span_named("tool_call foo")
100+
self.otel.assert_does_not_have_span_named("tool_call bar")
101+
foo()
102+
bar()
103+
self.otel.assert_does_not_have_span_named("tool_call foo")
104+
self.otel.assert_does_not_have_span_named("tool_call bar")
105+
wrapped_foo()
106+
self.otel.assert_has_span_named("tool_call foo")
107+
self.otel.assert_does_not_have_span_named("tool_call bar")
108+
wrapped_bar()
109+
self.otel.assert_has_span_named("tool_call bar")
110+
111+
def test_wraps_async_tool_function(self):
112+
async def foo():
113+
pass
114+
wrapped_foo = self.wrap(foo)
115+
self.otel.assert_does_not_have_span_named("tool_call foo")
116+
asyncio.run(foo())
117+
self.otel.assert_does_not_have_span_named("tool_call foo")
118+
asyncio.run(wrapped_foo())
119+
self.otel.assert_has_span_named("tool_call foo")
120+
121+
def test_preserves_tool_dict(self):
122+
tool_dict = genai_types.ToolDict()
123+
wrapped_tool_dict = self.wrap(tool_dict)
124+
self.assertEqual(tool_dict, wrapped_tool_dict)

0 commit comments

Comments
 (0)