Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSSQL Testing #852

Merged
merged 13 commits into from
Jun 27, 2023
3 changes: 3 additions & 0 deletions .github/containers/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
build-essential \
curl \
expat \
freetds-common \
freetds-dev \
gcc \
git \
libbz2-dev \
libcurl4-openssl-dev \
libffi-dev \
libgmp-dev \
libkrb5-dev \
liblzma-dev \
libmpfr-dev \
libncurses-dev \
Expand Down
90 changes: 77 additions & 13 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
#- kafka
- memcached
- mongodb
- mssql
- mysql
- postgres
- rabbitmq
Expand Down Expand Up @@ -118,7 +119,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
lrafeei marked this conversation as resolved.
Show resolved Hide resolved
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -163,7 +164,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -208,7 +209,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -257,6 +258,69 @@ jobs:
path: ./**/.coverage.*
retention-days: 1

mssql:
env:
TOTAL_GROUPS: 1

strategy:
fail-fast: false
matrix:
group-number: [1]

runs-on: ubuntu-20.04
container:
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30

services:
mssql:
image: mcr.microsoft.com/azure-sql-edge:latest
env:
MSSQL_USER: python_agent
MSSQL_PASSWORD: python_agent
MSSQL_SA_PASSWORD: "python_agent#1234"
ACCEPT_EULA: "Y"
ports:
- 8080:1433
- 8081:1433
# Set health checks to wait until mysql has started
options: >-
--health-cmd "/opt/mssql-tools/bin/sqlcmd -U SA -P $MSSQL_SA_PASSWORD -Q 'SELECT 1'"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v3

- name: Fetch git tags
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git fetch --tags origin

- name: Get Environments
id: get-envs
run: |
echo "envs=$(tox -l | grep '^${{ github.job }}\-' | ./.github/workflows/get-envs.py)" >> $GITHUB_OUTPUT
env:
GROUP_NUMBER: ${{ matrix.group-number }}

- name: Test
run: |
tox -vv -e ${{ steps.get-envs.outputs.envs }} -p auto
env:
TOX_PARALLEL_NO_SPINNER: 1
PY_COLORS: 0

- name: Upload Coverage Artifacts
uses: actions/upload-artifact@v3
with:
name: coverage-${{ github.job }}-${{ strategy.job-index }}
path: ./**/.coverage.*
retention-days: 1

mysql:
env:
TOTAL_GROUPS: 2
Expand All @@ -268,7 +332,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -331,7 +395,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -389,7 +453,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -449,7 +513,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -507,7 +571,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -566,7 +630,7 @@ jobs:

# runs-on: ubuntu-20.04
# container:
# image: ghcr.io/${{ github.repository }}-ci:latest
# image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
# options: >-
# --add-host=host.docker.internal:host-gateway
# timeout-minutes: 30
Expand Down Expand Up @@ -646,7 +710,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -704,7 +768,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -764,7 +828,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down Expand Up @@ -825,7 +889,7 @@ jobs:

runs-on: ubuntu-20.04
container:
image: ghcr.io/${{ github.repository }}-ci:latest
image: ghcr.io/newrelic/newrelic-python-agent-ci:sha-153311bd06d7b3db4d4ea8c04fa6031cba956e38
options: >-
--add-host=host.docker.internal:host-gateway
timeout-minutes: 30
Expand Down
36 changes: 36 additions & 0 deletions tests/datastore_pymssql/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2010 New Relic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest

from testing_support.fixtures import (
collector_agent_registration_fixture,
collector_available_fixture,
) # noqa: F401; pylint: disable=W0611


_default_settings = {
"transaction_tracer.explain_threshold": 0.0,
"transaction_tracer.transaction_threshold": 0.0,
"transaction_tracer.stack_trace_threshold": 0.0,
"debug.log_data_collector_payloads": True,
"debug.record_transaction_failure": True,
"debug.log_explain_plan_queries": True,
}

collector_agent_registration = collector_agent_registration_fixture(
app_name="Python Agent Test (datastore_pymssql)",
default_settings=_default_settings,
linked_applications=["Python Agent Test (datastore)"],
)
115 changes: 115 additions & 0 deletions tests/datastore_pymssql/test_database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright 2010 New Relic, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pymssql

from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics
from testing_support.validators.validate_database_trace_inputs import validate_database_trace_inputs

from testing_support.db_settings import mssql_settings

from newrelic.api.background_task import background_task

DB_SETTINGS = mssql_settings()[0]
TABLE_NAME = "datastore_pymssql_" + DB_SETTINGS["namespace"]
PROCEDURE_NAME = "hello_" + DB_SETTINGS["namespace"]


def execute_db_calls_with_cursor(cursor):
cursor.execute("""drop table if exists %s""" % TABLE_NAME)

cursor.execute("""create table %s """ % TABLE_NAME + """(a integer, b real, c text)""")

cursor.executemany(
"""insert into %s """ % TABLE_NAME + """values (%s, %s, %s)""",
[(1, 1.0, "1.0"), (2, 2.2, "2.2"), (3, 3.3, "3.3")],
)

cursor.execute("""select * from %s""" % TABLE_NAME)

for row in cursor:
pass

cursor.execute("""update %s""" % TABLE_NAME + """ set a=%s, b=%s, """ """c=%s where a=%s""", (4, 4.0, "4.0", 1))

cursor.execute("""delete from %s where a=2""" % TABLE_NAME)
cursor.execute("""drop procedure if exists %s""" % PROCEDURE_NAME)
cursor.execute(
"""CREATE PROCEDURE %s AS
BEGIN
SELECT 'Hello World!';
END"""
% PROCEDURE_NAME
)

cursor.callproc(PROCEDURE_NAME)


_test_scoped_metrics = [
("Function/pymssql._pymssql:connect", 1),
("Datastore/statement/MSSQL/%s/select" % TABLE_NAME, 1),
("Datastore/statement/MSSQL/%s/insert" % TABLE_NAME, 1),
("Datastore/statement/MSSQL/%s/update" % TABLE_NAME, 1),
("Datastore/statement/MSSQL/%s/delete" % TABLE_NAME, 1),
("Datastore/operation/MSSQL/drop", 2),
("Datastore/operation/MSSQL/create", 2),
("Datastore/statement/MSSQL/%s/call" % PROCEDURE_NAME, 1),
("Datastore/operation/MSSQL/commit", 2),
("Datastore/operation/MSSQL/rollback", 1),
]

_test_rollup_metrics = [
("Datastore/all", 13),
("Datastore/allOther", 13),
("Datastore/MSSQL/all", 13),
("Datastore/MSSQL/allOther", 13),
("Datastore/statement/MSSQL/%s/select" % TABLE_NAME, 1),
("Datastore/statement/MSSQL/%s/insert" % TABLE_NAME, 1),
("Datastore/statement/MSSQL/%s/update" % TABLE_NAME, 1),
("Datastore/statement/MSSQL/%s/delete" % TABLE_NAME, 1),
("Datastore/operation/MSSQL/select", 1),
("Datastore/operation/MSSQL/insert", 1),
("Datastore/operation/MSSQL/update", 1),
("Datastore/operation/MSSQL/delete", 1),
("Datastore/statement/MSSQL/%s/call" % PROCEDURE_NAME, 1),
("Datastore/operation/MSSQL/call", 1),
("Datastore/operation/MSSQL/drop", 2),
("Datastore/operation/MSSQL/create", 2),
("Datastore/operation/MSSQL/commit", 2),
("Datastore/operation/MSSQL/rollback", 1),
]


@validate_transaction_metrics(
"test_database:test_execute_via_cursor_context_manager",
scoped_metrics=_test_scoped_metrics,
rollup_metrics=_test_rollup_metrics,
background_task=True,
)
@validate_database_trace_inputs(sql_parameters_type=tuple)
@background_task()
def test_execute_via_cursor_context_manager():
connection = pymssql.connect(
user=DB_SETTINGS["user"], password=DB_SETTINGS["password"], host=DB_SETTINGS["host"], port=DB_SETTINGS["port"]
)

with connection:
cursor = connection.cursor()

with cursor:
execute_db_calls_with_cursor(cursor)

connection.commit()
connection.rollback()
connection.commit()
Loading