Skip to content

Commit 3f621c2

Browse files
committed
Add module to test end to end with a real client.
1 parent 82ea24a commit 3f621c2

File tree

1 file changed

+186
-0
lines changed
  • instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/generate_content

1 file changed

+186
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
import google.genai
17+
from google.genai import types as genai_types
18+
import os
19+
import vcr
20+
from vcr.record_mode import RecordMode
21+
import logging
22+
import asyncio
23+
import pytest
24+
25+
from ..common.auth import FakeCredentials
26+
27+
from opentelemetry.instrumentation.google_genai import (
28+
GoogleGenAiSdkInstrumentor,
29+
)
30+
31+
32+
@pytest.fixture
33+
def instrumentor():
34+
return GoogleGenAiSdkInstrumentor()
35+
36+
37+
@pytest.fixture(autouse=True)
38+
def setup_instrumentation(instrumentor):
39+
instrumentor.instrument()
40+
yield
41+
instrumentor.uninstrument()
42+
43+
44+
@pytest.fixture(autouse=True, params=[True, False])
45+
def setup_content_recording(request):
46+
os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = str(request.param)
47+
48+
49+
@pytest.fixture
50+
def vcr_record_mode(vcr):
51+
return vcr.record_mode
52+
53+
54+
@pytest.fixture
55+
def in_replay_mode(vcr_record_mode):
56+
return vcr_record_mode == RecordMode.NONE
57+
58+
59+
@pytest.fixture
60+
def gcloud_project(in_replay_mode):
61+
if in_replay_mode:
62+
return "test-project"
63+
_, from_creds = google.auth.default()
64+
return from_creds
65+
66+
67+
@pytest.fixture
68+
def gcloud_location(in_replay_mode):
69+
if in_replay_mode:
70+
return "test-location"
71+
return os.getenv("GCLOUD_LOCATION")
72+
73+
74+
@pytest.fixture
75+
def gcloud_credentials(in_replay_mode):
76+
if in_replay_mode:
77+
return FakeCredentials()
78+
creds, _ = google.auth.default()
79+
return creds
80+
81+
82+
@pytest.fixture(autouse=True)
83+
def gcloud_api_key(in_replay_mode):
84+
if in_replay_mode:
85+
os.environ["GOOGLE_API_KEY"] = "test-api-key"
86+
return "test-api-key"
87+
return os.getenv("GOOGLE_API_KEY")
88+
89+
90+
@pytest.fixture
91+
def nonvertex_client_factory(gcloud_api_key):
92+
def _factory():
93+
return google.genai.Client(api_key=gcloud_api_key)
94+
return _factory
95+
96+
97+
@pytest.fixture
98+
def vertex_client_factory(in_replay_mode):
99+
def _factory():
100+
return google.genai.Client(
101+
vertexai=True,
102+
project=gcloud_project,
103+
location=gcloud_location,
104+
credentials=gcloud_credentials)
105+
return _factory
106+
107+
108+
@pytest.fixture(params=[True, False])
109+
def use_vertex(request):
110+
return request.param
111+
112+
113+
@pytest.fixture
114+
def client(vertex_client_factory, nonvertex_client_factory, use_vertex):
115+
if use_vertex:
116+
return vertex_client_factory()
117+
return nonvertex_client_factory()
118+
119+
120+
@pytest.fixture(params=[True, False])
121+
def is_async(request):
122+
return request.param
123+
124+
125+
@pytest.fixture(params=["gemini-1.0-flash", "gemini-2.0-flash"])
126+
def model(request):
127+
return request.param
128+
129+
130+
@pytest.fixture
131+
def generate_content(client, is_async):
132+
def _sync_impl(*args, **kwargs):
133+
return client.models.generate_content(*args, **kwargs)
134+
135+
def _async_impl(*args, **kwargs):
136+
return asyncio.run(client.aio.models.generate_content(*args, **kwargs))
137+
138+
if is_async:
139+
return _async_impl
140+
return _sync_impl
141+
142+
143+
@pytest.fixture
144+
def generate_content_stream(client, is_async):
145+
def _sync_impl(*args, **kwargs):
146+
results = []
147+
for result in client.models.generate_content_stream(*args, **kwargs):
148+
results.append(result)
149+
return results
150+
151+
def _async_impl(*args, **kwargs):
152+
async def _gather_all():
153+
results = []
154+
async for result in await client.aio.models.generate_content_stream(*args, **kwargs):
155+
results.append(result)
156+
return results
157+
return asyncio.run(_gather_all())
158+
159+
if is_async:
160+
return _async_impl
161+
return _sync_impl
162+
163+
164+
@pytest.mark.vcr
165+
def test_single_response(generate_content, model):
166+
response = generate_content(
167+
model=model,
168+
contents="Create a poem about Open Telemetry.")
169+
assert response is not None
170+
assert response.text is not None
171+
assert len(response.text) > 0
172+
173+
174+
@pytest.mark.vcr
175+
def test_multiple_responses(generate_content_stream, model):
176+
count = 0
177+
for response in generate_content_stream(
178+
model=model,
179+
contents="Create a poem about Open Telemetry.",
180+
config=genai_types.GenerateContentConfig(candidate_count=2)):
181+
assert response is not None
182+
assert response.text is not None
183+
assert len(response.text) > 0
184+
count += 1
185+
assert count == 2
186+

0 commit comments

Comments
 (0)