Skip to content

Commit 8b3d2f0

Browse files
committed
Add tests for pyodbc
1 parent 11c1cda commit 8b3d2f0

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

tests/datastore_pyodbc/conftest.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2010 New Relic, Inc.
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+
import pytest
16+
from testing_support.fixtures import ( # noqa: F401; pylint: disable=W0611
17+
collector_agent_registration_fixture,
18+
collector_available_fixture,
19+
)
20+
21+
_default_settings = {
22+
"transaction_tracer.explain_threshold": 0.0,
23+
"transaction_tracer.transaction_threshold": 0.0,
24+
"transaction_tracer.stack_trace_threshold": 0.0,
25+
"debug.log_data_collector_payloads": True,
26+
"debug.record_transaction_failure": True,
27+
"debug.log_explain_plan_queries": True,
28+
}
29+
30+
collector_agent_registration = collector_agent_registration_fixture(
31+
app_name="Python Agent Test (datastore_pyodbc)",
32+
default_settings=_default_settings,
33+
linked_applications=["Python Agent Test (datastore)"],
34+
)

tests/datastore_pyodbc/test_pyodbc.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Copyright 2010 New Relic, Inc.
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+
import pyodbc
16+
from testing_support.db_settings import postgresql_settings
17+
from testing_support.validators.validate_database_trace_inputs import (
18+
validate_database_trace_inputs,
19+
)
20+
from testing_support.validators.validate_transaction_metrics import (
21+
validate_transaction_metrics,
22+
)
23+
24+
from newrelic.api.background_task import background_task
25+
26+
DB_SETTINGS = postgresql_settings()[0]
27+
28+
_test_execute_via_cursor_scoped_metrics = [
29+
("Function/postgresql.driver.dbapi20:connect", 1),
30+
("Function/postgresql.driver.dbapi20:Connection.__enter__", 1),
31+
("Function/postgresql.driver.dbapi20:Connection.__exit__", 1),
32+
("Datastore/statement/Postgres/%s/select" % DB_SETTINGS["table_name"], 1),
33+
("Datastore/statement/Postgres/%s/insert" % DB_SETTINGS["table_name"], 1),
34+
("Datastore/statement/Postgres/%s/update" % DB_SETTINGS["table_name"], 1),
35+
("Datastore/statement/Postgres/%s/delete" % DB_SETTINGS["table_name"], 1),
36+
("Datastore/statement/Postgres/now/call", 1),
37+
("Datastore/statement/Postgres/pg_sleep/call", 1),
38+
("Datastore/operation/Postgres/drop", 1),
39+
("Datastore/operation/Postgres/create", 1),
40+
("Datastore/operation/Postgres/commit", 3),
41+
("Datastore/operation/Postgres/rollback", 1),
42+
]
43+
44+
_test_execute_via_cursor_rollup_metrics = [
45+
("Datastore/all", 13),
46+
("Datastore/allOther", 13),
47+
("Datastore/Postgres/all", 13),
48+
("Datastore/Postgres/allOther", 13),
49+
("Datastore/operation/Postgres/select", 1),
50+
("Datastore/statement/Postgres/%s/select" % DB_SETTINGS["table_name"], 1),
51+
("Datastore/operation/Postgres/insert", 1),
52+
("Datastore/statement/Postgres/%s/insert" % DB_SETTINGS["table_name"], 1),
53+
("Datastore/operation/Postgres/update", 1),
54+
("Datastore/statement/Postgres/%s/update" % DB_SETTINGS["table_name"], 1),
55+
("Datastore/operation/Postgres/delete", 1),
56+
("Datastore/statement/Postgres/%s/delete" % DB_SETTINGS["table_name"], 1),
57+
("Datastore/operation/Postgres/drop", 1),
58+
("Datastore/operation/Postgres/create", 1),
59+
("Datastore/statement/Postgres/now/call", 1),
60+
("Datastore/statement/Postgres/pg_sleep/call", 1),
61+
("Datastore/operation/Postgres/call", 2),
62+
("Datastore/operation/Postgres/commit", 3),
63+
("Datastore/operation/Postgres/rollback", 1),
64+
]
65+
66+
67+
@validate_transaction_metrics(
68+
"test_database:test_execute_via_cursor",
69+
scoped_metrics=_test_execute_via_cursor_scoped_metrics,
70+
rollup_metrics=_test_execute_via_cursor_rollup_metrics,
71+
background_task=True,
72+
)
73+
@validate_database_trace_inputs(sql_parameters_type=tuple)
74+
@background_task()
75+
def test_execute_via_cursor():
76+
with pyodbc.connect(
77+
"DRIVER={Devart ODBC Driver for PostgreSQL};SERVER=%s;Port=%s;DATABASE=%s;UID=%s;PWD=%s"
78+
% (
79+
DB_SETTINGS["host"],
80+
DB_SETTINGS["port"],
81+
DB_SETTINGS["name"],
82+
DB_SETTINGS["user"],
83+
DB_SETTINGS["password"],
84+
)
85+
) as connection:
86+
cursor = connection.cursor()
87+
cursor.execute("""drop table if exists %s""" % DB_SETTINGS["table_name"])
88+
cursor.execute("""create table %s """ % DB_SETTINGS["table_name"] + """(a integer, b real, c text)""")
89+
cursor.executemany(
90+
"""insert into %s """ % DB_SETTINGS["table_name"] + """values (%s, %s, %s)""",
91+
[(1, 1.0, "1.0"), (2, 2.2, "2.2"), (3, 3.3, "3.3")],
92+
)
93+
cursor.execute("""select * from %s""" % DB_SETTINGS["table_name"])
94+
for row in cursor:
95+
pass
96+
cursor.execute(
97+
"""update %s """ % DB_SETTINGS["table_name"] + """set a=%s, b=%s, c=%s where a=%s""",
98+
(4, 4.0, "4.0", 1),
99+
)
100+
cursor.execute("""delete from %s where a=2""" % DB_SETTINGS["table_name"])
101+
connection.commit()
102+
103+
cursor.callproc("now", ())
104+
cursor.callproc("pg_sleep", (0.25,))
105+
106+
connection.rollback()
107+
connection.commit()
108+
109+
110+
_test_rollback_on_exception_scoped_metrics = [
111+
("Function/postgresql.driver.dbapi20:connect", 1),
112+
("Function/postgresql.driver.dbapi20:Connection.__enter__", 1),
113+
("Function/postgresql.driver.dbapi20:Connection.__exit__", 1),
114+
("Datastore/operation/Postgres/rollback", 1),
115+
]
116+
117+
_test_rollback_on_exception_rollup_metrics = [
118+
("Datastore/all", 2),
119+
("Datastore/allOther", 2),
120+
("Datastore/Postgres/all", 2),
121+
("Datastore/Postgres/allOther", 2),
122+
]
123+
124+
125+
@validate_transaction_metrics(
126+
"test_database:test_rollback_on_exception",
127+
scoped_metrics=_test_rollback_on_exception_scoped_metrics,
128+
rollup_metrics=_test_rollback_on_exception_rollup_metrics,
129+
background_task=True,
130+
)
131+
@validate_database_trace_inputs(sql_parameters_type=tuple)
132+
@background_task()
133+
def test_rollback_on_exception():
134+
try:
135+
with pyodbc.connect(
136+
"DRIVER={Devart ODBC Driver for PostgreSQL};SERVER=%s;Port=%s;DATABASE=%s;UID=%s;PWD=%s"
137+
% (
138+
DB_SETTINGS["host"],
139+
DB_SETTINGS["port"],
140+
DB_SETTINGS["name"],
141+
DB_SETTINGS["user"],
142+
DB_SETTINGS["password"],
143+
)
144+
) as connection:
145+
raise RuntimeError("error")
146+
except RuntimeError:
147+
pass

tox.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ envlist =
8080
postgres-datastore_postgresql-{py37,py38,py39},
8181
postgres-datastore_psycopg2-{py27,py37,py38,py39,py310,py311}-psycopg2latest
8282
postgres-datastore_psycopg2cffi-{py27,pypy,py37,py38,py39,py310,py311}-psycopg2cffilatest,
83+
postgres-datastore_pyodbc-{py27,py37,py38,py39,py310,py311}-pyobdclatest
8384
memcached-datastore_pylibmc-{py27,py37},
8485
memcached-datastore_pymemcache-{py27,py37,py38,py39,py310,py311,pypy,pypy37},
8586
mongodb-datastore_pymongo-{py27,py37,py38,py39,py310,py311,pypy}-pymongo{03},
@@ -233,6 +234,7 @@ deps =
233234
datastore_postgresql: py-postgresql<1.3
234235
datastore_psycopg2-psycopg2latest: psycopg2-binary
235236
datastore_psycopg2cffi-psycopg2cffilatest: psycopg2cffi
237+
datastore_pyodbc-pyodbclatest: pyodbc
236238
datastore_pyelasticsearch: pyelasticsearch<2.0
237239
datastore_pylibmc: pylibmc
238240
datastore_pymemcache: pymemcache
@@ -439,6 +441,7 @@ changedir =
439441
datastore_mysql: tests/datastore_mysql
440442
datastore_postgresql: tests/datastore_postgresql
441443
datastore_psycopg2: tests/datastore_psycopg2
444+
datastore_pyodbc: tests/datastore_pyodbc
442445
datastore_psycopg2cffi: tests/datastore_psycopg2cffi
443446
datastore_pyelasticsearch: tests/datastore_pyelasticsearch
444447
datastore_pylibmc: tests/datastore_pylibmc

0 commit comments

Comments
 (0)