diff --git a/.github/workflows/test_1.yml b/.github/workflows/test_1.yml index f40cd6e738..bbbbf9b645 100644 --- a/.github/workflows/test_1.yml +++ b/.github/workflows/test_1.yml @@ -1168,6 +1168,24 @@ jobs: - name: Run tests run: tox -e py38-test-instrumentation-sqlalchemy-1 -- -ra + py38-test-instrumentation-sqlalchemy-2_ubuntu-latest: + name: instrumentation-sqlalchemy-2 3.8 Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.8 + uses: actions/setup-python@v5 + with: + python-version: "3.8" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e py38-test-instrumentation-sqlalchemy-2 -- -ra + py39-test-instrumentation-sqlalchemy-1_ubuntu-latest: name: instrumentation-sqlalchemy-1 3.9 Ubuntu runs-on: ubuntu-latest @@ -1186,6 +1204,24 @@ jobs: - name: Run tests run: tox -e py39-test-instrumentation-sqlalchemy-1 -- -ra + py39-test-instrumentation-sqlalchemy-2_ubuntu-latest: + name: instrumentation-sqlalchemy-2 3.9 Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: "3.9" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e py39-test-instrumentation-sqlalchemy-2 -- -ra + py310-test-instrumentation-sqlalchemy-1_ubuntu-latest: name: instrumentation-sqlalchemy-1 3.10 Ubuntu runs-on: ubuntu-latest @@ -1204,6 +1240,24 @@ jobs: - name: Run tests run: tox -e py310-test-instrumentation-sqlalchemy-1 -- -ra + py310-test-instrumentation-sqlalchemy-2_ubuntu-latest: + name: instrumentation-sqlalchemy-2 3.10 Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e py310-test-instrumentation-sqlalchemy-2 -- -ra + py311-test-instrumentation-sqlalchemy-1_ubuntu-latest: name: instrumentation-sqlalchemy-1 3.11 Ubuntu runs-on: ubuntu-latest @@ -1222,6 +1276,24 @@ jobs: - name: Run tests run: tox -e py311-test-instrumentation-sqlalchemy-1 -- -ra + py311-test-instrumentation-sqlalchemy-2_ubuntu-latest: + name: instrumentation-sqlalchemy-2 3.11 Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e py311-test-instrumentation-sqlalchemy-2 -- -ra + py312-test-instrumentation-sqlalchemy-1_ubuntu-latest: name: instrumentation-sqlalchemy-1 3.12 Ubuntu runs-on: ubuntu-latest @@ -1240,6 +1312,24 @@ jobs: - name: Run tests run: tox -e py312-test-instrumentation-sqlalchemy-1 -- -ra + py312-test-instrumentation-sqlalchemy-2_ubuntu-latest: + name: instrumentation-sqlalchemy-2 3.12 Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e py312-test-instrumentation-sqlalchemy-2 -- -ra + pypy3-test-instrumentation-sqlalchemy-0_ubuntu-latest: name: instrumentation-sqlalchemy-0 pypy-3.8 Ubuntu runs-on: ubuntu-latest @@ -1276,6 +1366,24 @@ jobs: - name: Run tests run: tox -e pypy3-test-instrumentation-sqlalchemy-1 -- -ra + pypy3-test-instrumentation-sqlalchemy-2_ubuntu-latest: + name: instrumentation-sqlalchemy-2 pypy-3.8 Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python pypy-3.8 + uses: actions/setup-python@v5 + with: + python-version: "pypy-3.8" + + - name: Install tox + run: pip install tox + + - name: Run tests + run: tox -e pypy3-test-instrumentation-sqlalchemy-2 -- -ra + py38-test-instrumentation-redis_ubuntu-latest: name: instrumentation-redis 3.8 Ubuntu runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index e1378d7ad9..c9718639d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `opentelemetry-instrumentation-sqlalchemy` Update unit tests to run with SQLALchemy 2 + ([#2976](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2976)) + ### Fixed ### Breaking changes diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-2.txt new file mode 100644 index 0000000000..757224a25b --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-2.txt @@ -0,0 +1,13 @@ +aiosqlite==0.20.0 +asgiref==3.8.1 +Deprecated==1.2.14 +greenlet==3.1.1 +iniconfig==2.0.0 +packaging==24.1 +pluggy==1.5.0 +pytest==7.4.4 +SQLAlchemy==2.0.36 +typing_extensions==4.12.2 +wrapt==1.16.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-sqlalchemy diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py index f729fa6d80..957ae16237 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py @@ -17,7 +17,10 @@ import pytest import sqlalchemy -from sqlalchemy import create_engine +from sqlalchemy import ( + create_engine, + text, +) from opentelemetry import trace from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor @@ -43,12 +46,14 @@ def test_trace_integration(self): tracer_provider=self.tracer_provider, ) cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() - cnx.execute("/* leading comment */ SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() + cnx.execute(text("/* leading comment */ SELECT 1 + 1;")).fetchall() cnx.execute( - "/* leading comment */ SELECT 1 + 1; /* trailing comment */" + text( + "/* leading comment */ SELECT 1 + 1; /* trailing comment */" + ) ).fetchall() - cnx.execute("SELECT 1 + 1; /* trailing comment */").fetchall() + cnx.execute(text("SELECT 1 + 1; /* trailing comment */")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 5) @@ -76,9 +81,9 @@ def test_instrument_two_engines(self): ) cnx_1 = engine_1.connect() - cnx_1.execute("SELECT 1 + 1;").fetchall() + cnx_1.execute(text("SELECT 1 + 1;")).fetchall() cnx_2 = engine_2.connect() - cnx_2.execute("SELECT 1 + 1;").fetchall() + cnx_2.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() # 2 queries + 2 engine connect @@ -111,7 +116,7 @@ async def run(): engine=engine.sync_engine, tracer_provider=self.tracer_provider ) async with engine.connect() as cnx: - await cnx.execute(sqlalchemy.text("SELECT 1 + 1;")) + await cnx.execute(text("SELECT 1 + 1;")) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) # first span - the connection to the db @@ -144,7 +149,7 @@ def test_not_recording(self): tracer_provider=self.tracer_provider, ) cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() self.assertFalse(mock_span.is_recording()) self.assertTrue(mock_span.is_recording.called) self.assertFalse(mock_span.set_attribute.called) @@ -156,7 +161,7 @@ def test_create_engine_wrapper(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) @@ -187,7 +192,7 @@ def test_create_engine_wrapper_enable_commenter(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() # sqlcommenter self.assertRegex( self.caplog.records[-2].getMessage(), @@ -207,7 +212,7 @@ def test_create_engine_wrapper_enable_commenter_otel_values_false(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() # sqlcommenter self.assertRegex( self.caplog.records[-2].getMessage(), @@ -233,7 +238,7 @@ def test_custom_tracer_provider(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) @@ -258,7 +263,7 @@ async def run(): engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with engine.connect() as cnx: - await cnx.execute(sqlalchemy.text("SELECT 1 + 1;")) + await cnx.execute(text("SELECT 1 + 1;")) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) # first span - the connection to the db @@ -299,7 +304,7 @@ async def run(): engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with engine.connect() as cnx: - await cnx.execute(sqlalchemy.text("SELECT 1;")) + await cnx.execute(text("SELECT 1;")) # sqlcommenter self.assertRegex( self.caplog.records[1].getMessage(), @@ -330,7 +335,7 @@ async def run(): engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with engine.connect() as cnx: - await cnx.execute(sqlalchemy.text("SELECT 1;")) + await cnx.execute(text("SELECT 1;")) # sqlcommenter self.assertRegex( self.caplog.records[1].getMessage(), @@ -346,7 +351,7 @@ def test_uninstrument(self): tracer_provider=self.tracer_provider, ) cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) @@ -359,10 +364,10 @@ def test_uninstrument(self): self.memory_exporter.clear() SQLAlchemyInstrumentor().uninstrument() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() engine2 = create_engine("sqlite:///:memory:") cnx2 = engine2.connect() - cnx2.execute("SELECT 2 + 2;").fetchall() + cnx2.execute(text("SELECT 2 + 2;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 0) @@ -371,7 +376,7 @@ def test_uninstrument(self): tracer_provider=self.tracer_provider, ) cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) @@ -384,13 +389,13 @@ def test_uninstrument_without_engine(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) self.memory_exporter.clear() SQLAlchemyInstrumentor().uninstrument() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 0) @@ -401,7 +406,7 @@ def test_no_op_tracer_provider(self): tracer_provider=trace.NoOpTracerProvider(), ) cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() + cnx.execute(text("SELECT 1 + 1;")).fetchall() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 0) @@ -420,7 +425,7 @@ def make_shortlived_engine(): # collection weakref.finalize(engine, callback) with engine.connect() as conn: - conn.execute("SELECT 1 + 1;").fetchall() + conn.execute(text("SELECT 1 + 1;")).fetchall() for _ in range(0, 5): make_shortlived_engine() diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py index f13c552bf4..ec2fc51e5b 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py @@ -14,7 +14,10 @@ import logging import pytest -from sqlalchemy import create_engine +from sqlalchemy import ( + create_engine, + text, +) from opentelemetry import context from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor @@ -37,7 +40,7 @@ def test_sqlcommenter_disabled(self): engine=engine, tracer_provider=self.tracer_provider ) cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() self.assertEqual(self.caplog.records[-2].getMessage(), "SELECT 1;") @@ -50,7 +53,7 @@ def test_sqlcommenter_enabled(self): commenter_options={"db_framework": False}, ) cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), r"SELECT 1 /\*db_driver='(.*)',traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", @@ -68,7 +71,7 @@ def test_sqlcommenter_enabled_otel_values_false(self): }, ) cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), r"SELECT 1 /\*db_driver='(.*)'\*/;", @@ -90,7 +93,7 @@ def test_sqlcommenter_flask_integration(self): ) context.attach(sqlcommenter_context) - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), r"SELECT 1 /\*db_driver='(.*)',flask=1,traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", @@ -105,7 +108,7 @@ def test_sqlcommenter_enabled_create_engine_after_instrumentation(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), r"SELECT 1 /\*db_driver='(.*)',traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", @@ -120,5 +123,5 @@ def test_sqlcommenter_disabled_create_engine_after_instrumentation(self): engine = create_engine("sqlite:///:memory:") cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() + cnx.execute(text("SELECT 1;")).fetchall() self.assertEqual(self.caplog.records[-2].getMessage(), "SELECT 1;") diff --git a/tox.ini b/tox.ini index 62eeb03be2..5137fe4c3c 100644 --- a/tox.ini +++ b/tox.ini @@ -263,8 +263,9 @@ envlist = ; below mean these dependencies are being used: ; 0: sqlalchemy>=1.1,<1.2 ; 1: sqlalchemy~=1.4 aiosqlite - py3{8,9,10,11,12}-test-instrumentation-sqlalchemy-{1} - pypy3-test-instrumentation-sqlalchemy-{0,1} + ; 2: sqlalchemy~=2.0.0 + py3{8,9,10,11,12}-test-instrumentation-sqlalchemy-{1,2} + pypy3-test-instrumentation-sqlalchemy-{0,1,2} lint-instrumentation-sqlalchemy ; opentelemetry-instrumentation-redis @@ -746,6 +747,7 @@ commands_pre = sqlalchemy: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sqlalchemy-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt sqlalchemy-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt + sqlalchemy-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-2.txt lint-instrumentation-sqlalchemy: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt elasticsearch: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api