Skip to content

Commit

Permalink
MSSQL Testing (#852)
Browse files Browse the repository at this point in the history
* For mysql tests into mssql

* Add tox envs for mssql

* Add mssql DB settings

* Add correct MSSQL tests

* Add mssql to GHA

* Add MSSQL libs to CI image

* Pin to dev CI image sha

* Swap SQLServer container image

* Fix healthcheck

* Put MSSQL image back

* Drop pypy37 tests

* Unpin dev image sha
  • Loading branch information
TimPansino committed Jun 27, 2023
1 parent e707cc0 commit ab590a2
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 14 deletions.
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:latest
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:latest
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:latest
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:latest
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:latest
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:latest
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:latest
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:latest
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:latest
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:latest
# 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:latest
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:latest
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:latest
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:latest
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

0 comments on commit ab590a2

Please sign in to comment.