Skip to content

Commit ad1ae10

Browse files
author
Viktor Ivanov
committed
Add functional integration tests and fix linting issues
1 parent a4e2f5e commit ad1ae10

File tree

3 files changed

+141
-3
lines changed

3 files changed

+141
-3
lines changed

instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def _build_span_meta_data_for_pipeline(instance, sanitize_query):
195195
return command_stack, resource, span_name
196196

197197

198+
# pylint: disable=R0915
198199
def _instrument(
199200
tracer,
200201
request_hook: _RequestHookT = None,

instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ def __init__(self):
3333
self.mock = mock.Mock()
3434

3535
async def __call__(self, *args, **kwargs):
36-
f = asyncio.Future()
37-
f.set_result("random")
38-
return f
36+
future = asyncio.Future()
37+
future.set_result("random")
38+
return future
3939

4040
def __getattr__(self, item):
4141
return AsyncMock()

tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py

+137
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import asyncio
16+
from time import time_ns
1617

1718
import redis
1819
import redis.asyncio
@@ -326,6 +327,30 @@ def test_basics(self):
326327
)
327328
self.assertEqual(span.attributes.get("db.redis.args_length"), 2)
328329

330+
def test_execute_command_traced_full_time(self):
331+
"""Command should be traced for coroutine execution time, not creation time."""
332+
coro_created_time = None
333+
finish_time = None
334+
335+
async def pipeline_simple():
336+
nonlocal coro_created_time
337+
nonlocal finish_time
338+
339+
# delay coroutine creation from coroutine execution
340+
coro = self.redis_client.get("foo")
341+
coro_created_time = time_ns()
342+
await coro
343+
finish_time = time_ns()
344+
345+
# create coroutine
346+
async_call(pipeline_simple())
347+
348+
spans = self.memory_exporter.get_finished_spans()
349+
self.assertEqual(len(spans), 1)
350+
span = spans[0]
351+
self.assertTrue(span.start_time > coro_created_time)
352+
self.assertTrue(span.end_time < finish_time)
353+
329354
def test_pipeline_traced(self):
330355
async def pipeline_simple():
331356
async with self.redis_client.pipeline(
@@ -348,6 +373,36 @@ async def pipeline_simple():
348373
)
349374
self.assertEqual(span.attributes.get("db.redis.pipeline_length"), 3)
350375

376+
def test_pipeline_traced_full_time(self):
377+
"""Command should be traced for coroutine execution time, not creation time."""
378+
coro_created_time = None
379+
finish_time = None
380+
381+
async def pipeline_simple():
382+
async with self.redis_client.pipeline(
383+
transaction=False
384+
) as pipeline:
385+
nonlocal coro_created_time
386+
nonlocal finish_time
387+
pipeline.set("blah", 32)
388+
pipeline.rpush("foo", "éé")
389+
pipeline.hgetall("xxx")
390+
391+
# delay coroutine creation from coroutine execution
392+
coro = pipeline.execute()
393+
coro_created_time = time_ns()
394+
await coro
395+
finish_time = time_ns()
396+
397+
# create coroutine
398+
async_call(pipeline_simple())
399+
400+
spans = self.memory_exporter.get_finished_spans()
401+
self.assertEqual(len(spans), 1)
402+
span = spans[0]
403+
self.assertTrue(span.start_time > coro_created_time)
404+
self.assertTrue(span.end_time < finish_time)
405+
351406
def test_pipeline_immediate(self):
352407
async def pipeline_immediate():
353408
async with self.redis_client.pipeline() as pipeline:
@@ -367,6 +422,34 @@ async def pipeline_immediate():
367422
span.attributes.get(SpanAttributes.DB_STATEMENT), "SET b 2"
368423
)
369424

425+
def test_pipeline_immediate_traced_full_time(self):
426+
"""Command should be traced for coroutine execution time, not creation time."""
427+
coro_created_time = None
428+
finish_time = None
429+
430+
async def pipeline_simple():
431+
async with self.redis_client.pipeline(
432+
transaction=False
433+
) as pipeline:
434+
nonlocal coro_created_time
435+
nonlocal finish_time
436+
pipeline.set("a", 1)
437+
438+
# delay coroutine creation from coroutine execution
439+
coro = pipeline.immediate_execute_command("SET", "b", 2)
440+
coro_created_time = time_ns()
441+
await coro
442+
finish_time = time_ns()
443+
444+
# create coroutine
445+
async_call(pipeline_simple())
446+
447+
spans = self.memory_exporter.get_finished_spans()
448+
self.assertEqual(len(spans), 1)
449+
span = spans[0]
450+
self.assertTrue(span.start_time > coro_created_time)
451+
self.assertTrue(span.end_time < finish_time)
452+
370453
def test_parent(self):
371454
"""Ensure OpenTelemetry works with redis."""
372455
ot_tracer = trace.get_tracer("redis_svc")
@@ -416,6 +499,30 @@ def test_basics(self):
416499
)
417500
self.assertEqual(span.attributes.get("db.redis.args_length"), 2)
418501

502+
def test_execute_command_traced_full_time(self):
503+
"""Command should be traced for coroutine execution time, not creation time."""
504+
coro_created_time = None
505+
finish_time = None
506+
507+
async def pipeline_simple():
508+
nonlocal coro_created_time
509+
nonlocal finish_time
510+
511+
# delay coroutine creation from coroutine execution
512+
coro = self.redis_client.get("foo")
513+
coro_created_time = time_ns()
514+
await coro
515+
finish_time = time_ns()
516+
517+
# create coroutine
518+
async_call(pipeline_simple())
519+
520+
spans = self.memory_exporter.get_finished_spans()
521+
self.assertEqual(len(spans), 1)
522+
span = spans[0]
523+
self.assertTrue(span.start_time > coro_created_time)
524+
self.assertTrue(span.end_time < finish_time)
525+
419526
def test_pipeline_traced(self):
420527
async def pipeline_simple():
421528
async with self.redis_client.pipeline(
@@ -438,6 +545,36 @@ async def pipeline_simple():
438545
)
439546
self.assertEqual(span.attributes.get("db.redis.pipeline_length"), 3)
440547

548+
def test_pipeline_traced_full_time(self):
549+
"""Command should be traced for coroutine execution time, not creation time."""
550+
coro_created_time = None
551+
finish_time = None
552+
553+
async def pipeline_simple():
554+
async with self.redis_client.pipeline(
555+
transaction=False
556+
) as pipeline:
557+
nonlocal coro_created_time
558+
nonlocal finish_time
559+
pipeline.set("blah", 32)
560+
pipeline.rpush("foo", "éé")
561+
pipeline.hgetall("xxx")
562+
563+
# delay coroutine creation from coroutine execution
564+
coro = pipeline.execute()
565+
coro_created_time = time_ns()
566+
await coro
567+
finish_time = time_ns()
568+
569+
# create coroutine
570+
async_call(pipeline_simple())
571+
572+
spans = self.memory_exporter.get_finished_spans()
573+
self.assertEqual(len(spans), 1)
574+
span = spans[0]
575+
self.assertTrue(span.start_time > coro_created_time)
576+
self.assertTrue(span.end_time < finish_time)
577+
441578
def test_parent(self):
442579
"""Ensure OpenTelemetry works with redis."""
443580
ot_tracer = trace.get_tracer("redis_svc")

0 commit comments

Comments
 (0)