Skip to content

Commit a00990d

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

File tree

3 files changed

+136
-3
lines changed

3 files changed

+136
-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

+132
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,29 @@ 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+
async_call(pipeline_simple())
346+
347+
spans = self.memory_exporter.get_finished_spans()
348+
self.assertEqual(len(spans), 1)
349+
span = spans[0]
350+
self.assertTrue(span.start_time > coro_created_time)
351+
self.assertTrue(span.end_time < finish_time)
352+
329353
def test_pipeline_traced(self):
330354
async def pipeline_simple():
331355
async with self.redis_client.pipeline(
@@ -348,6 +372,35 @@ async def pipeline_simple():
348372
)
349373
self.assertEqual(span.attributes.get("db.redis.pipeline_length"), 3)
350374

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

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

499+
def test_execute_command_traced_full_time(self):
500+
"""Command should be traced for coroutine execution time, not creation time."""
501+
coro_created_time = None
502+
finish_time = None
503+
504+
async def pipeline_simple():
505+
nonlocal coro_created_time
506+
nonlocal finish_time
507+
508+
# delay coroutine creation from coroutine execution
509+
coro = self.redis_client.get("foo")
510+
coro_created_time = time_ns()
511+
await coro
512+
finish_time = time_ns()
513+
514+
async_call(pipeline_simple())
515+
516+
spans = self.memory_exporter.get_finished_spans()
517+
self.assertEqual(len(spans), 1)
518+
span = spans[0]
519+
self.assertTrue(span.start_time > coro_created_time)
520+
self.assertTrue(span.end_time < finish_time)
521+
419522
def test_pipeline_traced(self):
420523
async def pipeline_simple():
421524
async with self.redis_client.pipeline(
@@ -438,6 +541,35 @@ async def pipeline_simple():
438541
)
439542
self.assertEqual(span.attributes.get("db.redis.pipeline_length"), 3)
440543

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

0 commit comments

Comments
 (0)