mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-29 13:12:39 +08:00
Fix running async psycopg tests (#2540)
This commit is contained in:

committed by
GitHub

parent
c06fd1dd53
commit
95fea2bfa7
@ -10,7 +10,6 @@ protobuf==3.20.3
|
|||||||
py==1.11.0
|
py==1.11.0
|
||||||
py-cpuinfo==9.0.0
|
py-cpuinfo==9.0.0
|
||||||
pytest==7.1.3
|
pytest==7.1.3
|
||||||
pytest-asyncio==0.23.5
|
|
||||||
pytest-benchmark==4.0.0
|
pytest-benchmark==4.0.0
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
typing_extensions==4.9.0
|
typing_extensions==4.9.0
|
||||||
|
@ -11,24 +11,9 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
try:
|
from unittest import IsolatedAsyncioTestCase
|
||||||
from unittest import IsolatedAsyncioTestCase
|
|
||||||
except ImportError:
|
|
||||||
# unittest.IsolatedAsyncioTestCase was introduced in Python 3.8. It's use
|
|
||||||
# simplifies the following tests. Without it, the amount of test code
|
|
||||||
# increases significantly, with most of the additional code handling
|
|
||||||
# the asyncio set up.
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
class IsolatedAsyncioTestCase(TestCase):
|
|
||||||
def run(self, result=None):
|
|
||||||
self.skipTest(
|
|
||||||
"This test requires Python 3.8 for unittest.IsolatedAsyncioTestCase"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
import pytest
|
|
||||||
|
|
||||||
import opentelemetry.instrumentation.grpc
|
import opentelemetry.instrumentation.grpc
|
||||||
from opentelemetry import trace
|
from opentelemetry import trace
|
||||||
@ -65,7 +50,6 @@ class RecordingInterceptor(grpc.aio.UnaryUnaryClientInterceptor):
|
|||||||
return await continuation(client_call_details, request)
|
return await continuation(client_call_details, request)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
class TestAioClientInterceptor(TestBase, IsolatedAsyncioTestCase):
|
class TestAioClientInterceptor(TestBase, IsolatedAsyncioTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
@ -11,27 +11,10 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
try:
|
|
||||||
from unittest import IsolatedAsyncioTestCase
|
|
||||||
except ImportError:
|
|
||||||
# unittest.IsolatedAsyncioTestCase was introduced in Python 3.8. It's use
|
|
||||||
# simplifies the following tests. Without it, the amount of test code
|
|
||||||
# increases significantly, with most of the additional code handling
|
|
||||||
# the asyncio set up.
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
class IsolatedAsyncioTestCase(TestCase):
|
|
||||||
def run(self, result=None):
|
|
||||||
self.skipTest(
|
|
||||||
"This test requires Python 3.8 for unittest.IsolatedAsyncioTestCase"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from unittest import mock
|
from unittest import IsolatedAsyncioTestCase, mock
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
import pytest
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.grpc import (
|
from opentelemetry.instrumentation.grpc import (
|
||||||
GrpcAioInstrumentorClient,
|
GrpcAioInstrumentorClient,
|
||||||
@ -50,7 +33,6 @@ from ._server import create_test_server
|
|||||||
from .protobuf import test_server_pb2_grpc # pylint: disable=no-name-in-module
|
from .protobuf import test_server_pb2_grpc # pylint: disable=no-name-in-module
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
class TestAioClientInterceptorFiltered(TestBase, IsolatedAsyncioTestCase):
|
class TestAioClientInterceptorFiltered(TestBase, IsolatedAsyncioTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
@ -11,24 +11,9 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
try:
|
from unittest import IsolatedAsyncioTestCase
|
||||||
from unittest import IsolatedAsyncioTestCase
|
|
||||||
except ImportError:
|
|
||||||
# unittest.IsolatedAsyncioTestCase was introduced in Python 3.8. It's use
|
|
||||||
# simplifies the following tests. Without it, the amount of test code
|
|
||||||
# increases significantly, with most of the additional code handling
|
|
||||||
# the asyncio set up.
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
class IsolatedAsyncioTestCase(TestCase):
|
|
||||||
def run(self, result=None):
|
|
||||||
self.skipTest(
|
|
||||||
"This test requires Python 3.8 for unittest.IsolatedAsyncioTestCase"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
import pytest
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.grpc import GrpcAioInstrumentorClient
|
from opentelemetry.instrumentation.grpc import GrpcAioInstrumentorClient
|
||||||
from opentelemetry.test.test_base import TestBase
|
from opentelemetry.test.test_base import TestBase
|
||||||
@ -54,7 +39,6 @@ def response_hook_with_exception(_span, _response):
|
|||||||
raise Exception() # pylint: disable=broad-exception-raised
|
raise Exception() # pylint: disable=broad-exception-raised
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
class TestAioClientInterceptorWithHooks(TestBase, IsolatedAsyncioTestCase):
|
class TestAioClientInterceptorWithHooks(TestBase, IsolatedAsyncioTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
@ -12,26 +12,10 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from unittest import IsolatedAsyncioTestCase
|
||||||
try:
|
|
||||||
from unittest import IsolatedAsyncioTestCase
|
|
||||||
except ImportError:
|
|
||||||
# unittest.IsolatedAsyncioTestCase was introduced in Python 3.8. It's use
|
|
||||||
# simplifies the following tests. Without it, the amount of test code
|
|
||||||
# increases significantly, with most of the additional code handling
|
|
||||||
# the asyncio set up.
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
class IsolatedAsyncioTestCase(TestCase):
|
|
||||||
def run(self, result=None):
|
|
||||||
self.skipTest(
|
|
||||||
"This test requires Python 3.8 for unittest.IsolatedAsyncioTestCase"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
import grpc.aio
|
import grpc.aio
|
||||||
import pytest
|
|
||||||
|
|
||||||
import opentelemetry.instrumentation.grpc
|
import opentelemetry.instrumentation.grpc
|
||||||
from opentelemetry import trace
|
from opentelemetry import trace
|
||||||
@ -97,7 +81,6 @@ async def run_with_test_server(
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
class TestOpenTelemetryAioServerInterceptor(TestBase, IsolatedAsyncioTestCase):
|
class TestOpenTelemetryAioServerInterceptor(TestBase, IsolatedAsyncioTestCase):
|
||||||
async def test_instrumentor(self):
|
async def test_instrumentor(self):
|
||||||
"""Check that automatic instrumentation configures the interceptor"""
|
"""Check that automatic instrumentation configures the interceptor"""
|
||||||
|
@ -11,25 +11,10 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
try:
|
from unittest import IsolatedAsyncioTestCase
|
||||||
from unittest import IsolatedAsyncioTestCase
|
|
||||||
except ImportError:
|
|
||||||
# unittest.IsolatedAsyncioTestCase was introduced in Python 3.8. It's use
|
|
||||||
# simplifies the following tests. Without it, the amount of test code
|
|
||||||
# increases significantly, with most of the additional code handling
|
|
||||||
# the asyncio set up.
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
class IsolatedAsyncioTestCase(TestCase):
|
|
||||||
def run(self, result=None):
|
|
||||||
self.skipTest(
|
|
||||||
"This test requires Python 3.8 for unittest.IsolatedAsyncioTestCase"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
import grpc.aio
|
import grpc.aio
|
||||||
import pytest
|
|
||||||
|
|
||||||
from opentelemetry import trace
|
from opentelemetry import trace
|
||||||
from opentelemetry.instrumentation.grpc import (
|
from opentelemetry.instrumentation.grpc import (
|
||||||
@ -68,7 +53,6 @@ async def run_with_test_server(
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
class TestOpenTelemetryAioServerInterceptor(TestBase, IsolatedAsyncioTestCase):
|
class TestOpenTelemetryAioServerInterceptor(TestBase, IsolatedAsyncioTestCase):
|
||||||
async def test_instrumentor(self):
|
async def test_instrumentor(self):
|
||||||
"""Check that automatic instrumentation configures the interceptor"""
|
"""Check that automatic instrumentation configures the interceptor"""
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import types
|
import types
|
||||||
from unittest import mock
|
from unittest import IsolatedAsyncioTestCase, mock
|
||||||
|
|
||||||
import psycopg
|
import psycopg
|
||||||
|
|
||||||
@ -114,6 +113,10 @@ class MockAsyncConnection:
|
|||||||
return cur
|
return cur
|
||||||
return MockAsyncCursor()
|
return MockAsyncCursor()
|
||||||
|
|
||||||
|
def execute(self, query, params=None, *, prepare=None, binary=False):
|
||||||
|
cur = self.cursor()
|
||||||
|
return cur.execute(query, params, prepare=prepare)
|
||||||
|
|
||||||
def get_dsn_parameters(self): # pylint: disable=no-self-use
|
def get_dsn_parameters(self): # pylint: disable=no-self-use
|
||||||
return {"dbname": "test"}
|
return {"dbname": "test"}
|
||||||
|
|
||||||
@ -124,7 +127,8 @@ class MockAsyncConnection:
|
|||||||
return mock.MagicMock(spec=types.MethodType)
|
return mock.MagicMock(spec=types.MethodType)
|
||||||
|
|
||||||
|
|
||||||
class TestPostgresqlIntegration(TestBase):
|
class PostgresqlIntegrationTestMixin:
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.cursor_mock = mock.patch(
|
self.cursor_mock = mock.patch(
|
||||||
@ -148,6 +152,7 @@ class TestPostgresqlIntegration(TestBase):
|
|||||||
self.connection_sync_mock.start()
|
self.connection_sync_mock.start()
|
||||||
self.connection_async_mock.start()
|
self.connection_async_mock.start()
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
self.memory_exporter.clear()
|
self.memory_exporter.clear()
|
||||||
@ -159,6 +164,8 @@ class TestPostgresqlIntegration(TestBase):
|
|||||||
with self.disable_logging():
|
with self.disable_logging():
|
||||||
PsycopgInstrumentor().uninstrument()
|
PsycopgInstrumentor().uninstrument()
|
||||||
|
|
||||||
|
|
||||||
|
class TestPostgresqlIntegration(PostgresqlIntegrationTestMixin, TestBase):
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def test_instrumentor(self):
|
def test_instrumentor(self):
|
||||||
PsycopgInstrumentor().instrument()
|
PsycopgInstrumentor().instrument()
|
||||||
@ -221,60 +228,6 @@ class TestPostgresqlIntegration(TestBase):
|
|||||||
spans_list = self.memory_exporter.get_finished_spans()
|
spans_list = self.memory_exporter.get_finished_spans()
|
||||||
self.assertEqual(len(spans_list), 1)
|
self.assertEqual(len(spans_list), 1)
|
||||||
|
|
||||||
async def test_wrap_async_connection_class_with_cursor(self):
|
|
||||||
PsycopgInstrumentor().instrument()
|
|
||||||
|
|
||||||
async def test_async_connection():
|
|
||||||
acnx = await psycopg.AsyncConnection.connect(database="test")
|
|
||||||
async with acnx as cnx:
|
|
||||||
async with cnx.cursor() as cursor:
|
|
||||||
await cursor.execute("SELECT * FROM test")
|
|
||||||
|
|
||||||
asyncio.run(test_async_connection())
|
|
||||||
spans_list = self.memory_exporter.get_finished_spans()
|
|
||||||
self.assertEqual(len(spans_list), 1)
|
|
||||||
span = spans_list[0]
|
|
||||||
|
|
||||||
# Check version and name in span's instrumentation info
|
|
||||||
self.assertEqualSpanInstrumentationInfo(
|
|
||||||
span, opentelemetry.instrumentation.psycopg
|
|
||||||
)
|
|
||||||
|
|
||||||
# check that no spans are generated after uninstrument
|
|
||||||
PsycopgInstrumentor().uninstrument()
|
|
||||||
|
|
||||||
asyncio.run(test_async_connection())
|
|
||||||
|
|
||||||
spans_list = self.memory_exporter.get_finished_spans()
|
|
||||||
self.assertEqual(len(spans_list), 1)
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
async def test_instrumentor_with_async_connection_class(self):
|
|
||||||
PsycopgInstrumentor().instrument()
|
|
||||||
|
|
||||||
async def test_async_connection():
|
|
||||||
acnx = await psycopg.AsyncConnection.connect(database="test")
|
|
||||||
async with acnx as cnx:
|
|
||||||
await cnx.execute("SELECT * FROM test")
|
|
||||||
|
|
||||||
asyncio.run(test_async_connection())
|
|
||||||
|
|
||||||
spans_list = self.memory_exporter.get_finished_spans()
|
|
||||||
self.assertEqual(len(spans_list), 1)
|
|
||||||
span = spans_list[0]
|
|
||||||
|
|
||||||
# Check version and name in span's instrumentation info
|
|
||||||
self.assertEqualSpanInstrumentationInfo(
|
|
||||||
span, opentelemetry.instrumentation.psycopg
|
|
||||||
)
|
|
||||||
|
|
||||||
# check that no spans are generated after uninstrument
|
|
||||||
PsycopgInstrumentor().uninstrument()
|
|
||||||
asyncio.run(test_async_connection())
|
|
||||||
|
|
||||||
spans_list = self.memory_exporter.get_finished_spans()
|
|
||||||
self.assertEqual(len(spans_list), 1)
|
|
||||||
|
|
||||||
def test_span_name(self):
|
def test_span_name(self):
|
||||||
PsycopgInstrumentor().instrument()
|
PsycopgInstrumentor().instrument()
|
||||||
|
|
||||||
@ -301,33 +254,6 @@ class TestPostgresqlIntegration(TestBase):
|
|||||||
self.assertEqual(spans_list[4].name, "query")
|
self.assertEqual(spans_list[4].name, "query")
|
||||||
self.assertEqual(spans_list[5].name, "query")
|
self.assertEqual(spans_list[5].name, "query")
|
||||||
|
|
||||||
async def test_span_name_async(self):
|
|
||||||
PsycopgInstrumentor().instrument()
|
|
||||||
|
|
||||||
cnx = psycopg.AsyncConnection.connect(database="test")
|
|
||||||
async with cnx.cursor() as cursor:
|
|
||||||
await cursor.execute("Test query", ("param1Value", False))
|
|
||||||
await cursor.execute(
|
|
||||||
"""multi
|
|
||||||
line
|
|
||||||
query"""
|
|
||||||
)
|
|
||||||
await cursor.execute("tab\tseparated query")
|
|
||||||
await cursor.execute("/* leading comment */ query")
|
|
||||||
await cursor.execute(
|
|
||||||
"/* leading comment */ query /* trailing comment */"
|
|
||||||
)
|
|
||||||
await cursor.execute("query /* trailing comment */")
|
|
||||||
|
|
||||||
spans_list = self.memory_exporter.get_finished_spans()
|
|
||||||
self.assertEqual(len(spans_list), 6)
|
|
||||||
self.assertEqual(spans_list[0].name, "Test")
|
|
||||||
self.assertEqual(spans_list[1].name, "multi")
|
|
||||||
self.assertEqual(spans_list[2].name, "tab")
|
|
||||||
self.assertEqual(spans_list[3].name, "query")
|
|
||||||
self.assertEqual(spans_list[4].name, "query")
|
|
||||||
self.assertEqual(spans_list[5].name, "query")
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def test_not_recording(self):
|
def test_not_recording(self):
|
||||||
mock_tracer = mock.Mock()
|
mock_tracer = mock.Mock()
|
||||||
@ -348,26 +274,6 @@ class TestPostgresqlIntegration(TestBase):
|
|||||||
|
|
||||||
PsycopgInstrumentor().uninstrument()
|
PsycopgInstrumentor().uninstrument()
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
async def test_not_recording_async(self):
|
|
||||||
mock_tracer = mock.Mock()
|
|
||||||
mock_span = mock.Mock()
|
|
||||||
mock_span.is_recording.return_value = False
|
|
||||||
mock_tracer.start_span.return_value = mock_span
|
|
||||||
PsycopgInstrumentor().instrument()
|
|
||||||
with mock.patch("opentelemetry.trace.get_tracer") as tracer:
|
|
||||||
tracer.return_value = mock_tracer
|
|
||||||
cnx = psycopg.AsyncConnection.connect(database="test")
|
|
||||||
async with cnx.cursor() as cursor:
|
|
||||||
query = "SELECT * FROM test"
|
|
||||||
cursor.execute(query)
|
|
||||||
self.assertFalse(mock_span.is_recording())
|
|
||||||
self.assertTrue(mock_span.is_recording.called)
|
|
||||||
self.assertFalse(mock_span.set_attribute.called)
|
|
||||||
self.assertFalse(mock_span.set_status.called)
|
|
||||||
|
|
||||||
PsycopgInstrumentor().uninstrument()
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def test_custom_tracer_provider(self):
|
def test_custom_tracer_provider(self):
|
||||||
resource = resources.Resource.create({})
|
resource = resources.Resource.create({})
|
||||||
@ -477,3 +383,108 @@ class TestPostgresqlIntegration(TestBase):
|
|||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
kwargs = event_mocked.call_args[1]
|
kwargs = event_mocked.call_args[1]
|
||||||
self.assertEqual(kwargs["enable_commenter"], False)
|
self.assertEqual(kwargs["enable_commenter"], False)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPostgresqlIntegrationAsync(
|
||||||
|
PostgresqlIntegrationTestMixin, TestBase, IsolatedAsyncioTestCase
|
||||||
|
):
|
||||||
|
async def test_wrap_async_connection_class_with_cursor(self):
|
||||||
|
PsycopgInstrumentor().instrument()
|
||||||
|
|
||||||
|
async def test_async_connection():
|
||||||
|
acnx = await psycopg.AsyncConnection.connect("test")
|
||||||
|
async with acnx as cnx:
|
||||||
|
async with cnx.cursor() as cursor:
|
||||||
|
await cursor.execute("SELECT * FROM test")
|
||||||
|
|
||||||
|
await test_async_connection()
|
||||||
|
spans_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(spans_list), 1)
|
||||||
|
span = spans_list[0]
|
||||||
|
|
||||||
|
# Check version and name in span's instrumentation info
|
||||||
|
self.assertEqualSpanInstrumentationInfo(
|
||||||
|
span, opentelemetry.instrumentation.psycopg
|
||||||
|
)
|
||||||
|
|
||||||
|
# check that no spans are generated after uninstrument
|
||||||
|
PsycopgInstrumentor().uninstrument()
|
||||||
|
|
||||||
|
await test_async_connection()
|
||||||
|
|
||||||
|
spans_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(spans_list), 1)
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
async def test_instrumentor_with_async_connection_class(self):
|
||||||
|
PsycopgInstrumentor().instrument()
|
||||||
|
|
||||||
|
async def test_async_connection():
|
||||||
|
acnx = await psycopg.AsyncConnection.connect("test")
|
||||||
|
async with acnx as cnx:
|
||||||
|
await cnx.execute("SELECT * FROM test")
|
||||||
|
|
||||||
|
await test_async_connection()
|
||||||
|
|
||||||
|
spans_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(spans_list), 1)
|
||||||
|
span = spans_list[0]
|
||||||
|
|
||||||
|
# Check version and name in span's instrumentation info
|
||||||
|
self.assertEqualSpanInstrumentationInfo(
|
||||||
|
span, opentelemetry.instrumentation.psycopg
|
||||||
|
)
|
||||||
|
|
||||||
|
# check that no spans are generated after uninstrument
|
||||||
|
PsycopgInstrumentor().uninstrument()
|
||||||
|
await test_async_connection()
|
||||||
|
|
||||||
|
spans_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(spans_list), 1)
|
||||||
|
|
||||||
|
async def test_span_name_async(self):
|
||||||
|
PsycopgInstrumentor().instrument()
|
||||||
|
|
||||||
|
cnx = await psycopg.AsyncConnection.connect("test")
|
||||||
|
async with cnx.cursor() as cursor:
|
||||||
|
await cursor.execute("Test query", ("param1Value", False))
|
||||||
|
await cursor.execute(
|
||||||
|
"""multi
|
||||||
|
line
|
||||||
|
query"""
|
||||||
|
)
|
||||||
|
await cursor.execute("tab\tseparated query")
|
||||||
|
await cursor.execute("/* leading comment */ query")
|
||||||
|
await cursor.execute(
|
||||||
|
"/* leading comment */ query /* trailing comment */"
|
||||||
|
)
|
||||||
|
await cursor.execute("query /* trailing comment */")
|
||||||
|
|
||||||
|
spans_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(spans_list), 6)
|
||||||
|
self.assertEqual(spans_list[0].name, "Test")
|
||||||
|
self.assertEqual(spans_list[1].name, "multi")
|
||||||
|
self.assertEqual(spans_list[2].name, "tab")
|
||||||
|
self.assertEqual(spans_list[3].name, "query")
|
||||||
|
self.assertEqual(spans_list[4].name, "query")
|
||||||
|
self.assertEqual(spans_list[5].name, "query")
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
async def test_not_recording_async(self):
|
||||||
|
mock_tracer = mock.Mock()
|
||||||
|
mock_span = mock.Mock()
|
||||||
|
mock_span.is_recording.return_value = False
|
||||||
|
mock_tracer.start_span.return_value = mock_span
|
||||||
|
PsycopgInstrumentor().instrument()
|
||||||
|
with mock.patch("opentelemetry.trace.get_tracer") as tracer:
|
||||||
|
tracer.return_value = mock_tracer
|
||||||
|
cnx = await psycopg.AsyncConnection.connect("test")
|
||||||
|
async with cnx.cursor() as cursor:
|
||||||
|
query = "SELECT * FROM test"
|
||||||
|
await cursor.execute(query)
|
||||||
|
self.assertFalse(mock_span.is_recording())
|
||||||
|
self.assertTrue(mock_span.is_recording.called)
|
||||||
|
self.assertFalse(mock_span.set_attribute.called)
|
||||||
|
self.assertFalse(mock_span.set_status.called)
|
||||||
|
|
||||||
|
PsycopgInstrumentor().uninstrument()
|
||||||
|
1
tox.ini
1
tox.ini
@ -373,7 +373,6 @@ deps =
|
|||||||
test: pytest-benchmark
|
test: pytest-benchmark
|
||||||
coverage: pytest
|
coverage: pytest
|
||||||
coverage: pytest-cov
|
coverage: pytest-cov
|
||||||
grpc: pytest-asyncio
|
|
||||||
|
|
||||||
; FIXME: add coverage testing
|
; FIXME: add coverage testing
|
||||||
; FIXME: add mypy testing
|
; FIXME: add mypy testing
|
||||||
|
Reference in New Issue
Block a user