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

PYTHON-5149 Convert run-tests.sh to a Python script #2155

Merged
merged 15 commits into from
Feb 24, 2025
2 changes: 1 addition & 1 deletion .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ functions:
params:
include_expansions_in_env: [AUTH, SSL, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
AWS_SESSION_TOKEN, COVERAGE, PYTHON_BINARY, LIBMONGOCRYPT_URL, MONGODB_URI,
DISABLE_TEST_COMMANDS, GREEN_FRAMEWORK, NO_EXT, COMPRESSORS]
DISABLE_TEST_COMMANDS, GREEN_FRAMEWORK, NO_EXT, COMPRESSORS, MONGODB_API_VERSION]
binary: bash
working_dir: "src"
args: [.evergreen/just.sh, setup-test, "${TEST_NAME}", "${SUB_TEST_NAME}"]
Expand Down
70 changes: 5 additions & 65 deletions .evergreen/run-tests.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
#!/bin/bash
set -eux
set -eu

SCRIPT_DIR=$(dirname ${BASH_SOURCE:-$0})
SCRIPT_DIR="$( cd -- "$SCRIPT_DIR" > /dev/null 2>&1 && pwd )"
ROOT_DIR="$(dirname $SCRIPT_DIR)"

pushd $ROOT_DIR

export PIP_QUIET=1 # Quiet by default
export PIP_PREFER_BINARY=1 # Prefer binary dists by default
export UV_FROZEN=1 # Do not modify lock files

# Try to source the env file.
if [ -f $SCRIPT_DIR/scripts/env.sh ]; then
echo "Sourcing env inputs"
Expand All @@ -25,74 +21,18 @@ if [ -f $SCRIPT_DIR/scripts/test-env.sh ]; then
. $SCRIPT_DIR/scripts/test-env.sh
else
echo "Missing test inputs, please run 'just setup-test'"
exit 1
fi


# Source the local secrets export file if available.
if [ -f "./secrets-export.sh" ]; then
. "./secrets-export.sh"
fi

PYTHON_IMPL=$(uv run python -c "import platform; print(platform.python_implementation())")

# Ensure C extensions if applicable.
if [ -z "${NO_EXT:-}" ] && [ "$PYTHON_IMPL" = "CPython" ]; then
uv run --frozen tools/fail_if_no_c.py
fi

if [ -n "${PYMONGOCRYPT_LIB:-}" ]; then
# Ensure pymongocrypt is working properly.
# shellcheck disable=SC2048
uv run ${UV_ARGS} python -c "import pymongocrypt; print('pymongocrypt version: '+pymongocrypt.__version__)"
# shellcheck disable=SC2048
uv run ${UV_ARGS} python -c "import pymongocrypt; print('libmongocrypt version: '+pymongocrypt.libmongocrypt_version())"
# PATH is updated by configure-env.sh for access to mongocryptd.
fi

PYTHON_IMPL=$(uv run python -c "import platform; print(platform.python_implementation())")
echo "Running ${AUTH:-noauth} tests over ${SSL:-nossl} with python $(uv python find)"
uv run python -c 'import sys; print(sys.version)'

# Show the installed packages
# shellcheck disable=SC2048
# List the packages.
PIP_QUIET=0 uv run ${UV_ARGS} --with pip pip list

# Record the start time for a perf test.
if [ -n "${TEST_PERF:-}" ]; then
start_time=$(date +%s)
fi

# Run the tests, and store the results in Evergreen compatible XUnit XML
# files in the xunit-results/ directory.
TEST_ARGS=${TEST_ARGS}
if [ "$#" -ne 0 ]; then
TEST_ARGS="$*"
fi
echo "Running tests with $TEST_ARGS and uv args $UV_ARGS..."
if [ -z "${GREEN_FRAMEWORK:-}" ]; then
# shellcheck disable=SC2048
uv run ${UV_ARGS} pytest $TEST_ARGS
else
# shellcheck disable=SC2048
uv run ${UV_ARGS} green_framework_test.py $GREEN_FRAMEWORK -v $TEST_ARGS
fi
echo "Running tests with $TEST_ARGS... done."

# Handle perf test post actions.
if [ -n "${TEST_PERF:-}" ]; then
end_time=$(date +%s)
elapsed_secs=$((end_time-start_time))

cat results.json

echo "{\"failures\": 0, \"results\": [{\"status\": \"pass\", \"exit_code\": 0, \"test_file\": \"BenchMarkTests\", \"start\": $start_time, \"end\": $end_time, \"elapsed\": $elapsed_secs}]}" > report.json

cat report.json
fi

# Handle coverage post actions.
if [ -n "${COVERAGE:-}" ]; then
rm -rf .pytest_cache
fi
# Start the test runner.
uv run ${UV_ARGS} .evergreen/scripts/run_tests.py

popd
119 changes: 119 additions & 0 deletions .evergreen/scripts/run_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
from __future__ import annotations

import json
import logging
import os
import platform
import shutil
import sys
from datetime import datetime
from pathlib import Path

import pytest

HERE = Path(__file__).absolute().parent
ROOT = HERE.parent.parent
AUTH = os.environ.get("AUTH", "noauth")
SSL = os.environ.get("SSL", "nossl")
UV_ARGS = os.environ.get("UV_ARGS", "")
TEST_PERF = os.environ.get("TEST_PERF")
GREEN_FRAMEWORK = os.environ.get("GREEN_FRAMEWORK")
TEST_ARGS = os.environ.get("TEST_ARGS", "").split()

LOGGER = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")


def handle_perf(start_time: datetime):
end_time = datetime.now()
elapsed_secs = (end_time - start_time).total_seconds()
with open("results.json") as fid:
results = json.load(fid)
LOGGER.info("results.json:\n%s", json.dumps(results, indent=2))

results = dict(
status="PASS",
exit_code=0,
test_file="BenchMarkTests",
start=int(start_time.timestamp()),
end=int(end_time.timestamp()),
elapsed=elapsed_secs,
)
report = dict(failures=0, results=[results])
LOGGER.info("report.json\n%s", json.dumps(report, indent=2))

with open("report.json", "w", newline="\n") as fid:
json.dump(report, fid)


def handle_green_framework() -> None:
if GREEN_FRAMEWORK == "eventlet":
import eventlet

# https://github.com/eventlet/eventlet/issues/401
eventlet.sleep()
eventlet.monkey_patch()
elif GREEN_FRAMEWORK == "gevent":
from gevent import monkey

monkey.patch_all()

# Never run async tests with a framework.
if len(TEST_ARGS) <= 1:
TEST_ARGS.extend(["-m", "not default_async and default"])
else:
for i in range(len(TEST_ARGS) - 1):
if "-m" in TEST_ARGS[i]:
TEST_ARGS[i + 1] = f"not default_async and {TEST_ARGS[i + 1]}"

LOGGER.info(f"Running tests with {GREEN_FRAMEWORK}...")


def handle_c_ext() -> None:
if platform.python_implementation() != "CPython":
return
sys.path.insert(0, str(ROOT / "tools"))
from fail_if_no_c import main as fail_if_no_c

fail_if_no_c()


def handle_pymongocrypt() -> None:
import pymongocrypt

LOGGER.info(f"pymongocrypt version: {pymongocrypt.__version__})")
LOGGER.info(f"libmongocrypt version: {pymongocrypt.libmongocrypt_version()})")


def run() -> None:
# Handle green framework first so they can patch modules.
if GREEN_FRAMEWORK:
handle_green_framework()

# Ensure C extensions if applicable.
if not os.environ.get("NO_EXT"):
handle_c_ext()

if os.environ.get("PYMONGOCRYPT_LIB"):
handle_pymongocrypt()

LOGGER.info(f"Test setup:\n{AUTH=}\n{SSL=}\n{UV_ARGS=}\n{TEST_ARGS=}")

# Record the start time for a perf test.
if TEST_PERF:
start_time = datetime.now()

# Run the tests.
pytest.main(TEST_ARGS)

# Handle perf test post actions.
if TEST_PERF:
handle_perf(start_time)

# Handle coverage post actions.
if os.environ.get("COVERAGE"):
shutil.rmtree(".pytest_cache", ignore_errors=True)


if __name__ == "__main__":
run()
3 changes: 3 additions & 0 deletions .evergreen/scripts/setup_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ def handle_test_env() -> None:

write_env("AUTH", AUTH)
write_env("SSL", SSL)
write_env("PIP_QUIET") # Quiet by default.
write_env("PIP_PREFER_BINARY") # Prefer binary dists by default.
write_env("UV_FROZEN") # Do not modify lock files.

# Skip CSOT tests on non-linux platforms.
if PLATFORM != "linux":
Expand Down
2 changes: 1 addition & 1 deletion .evergreen/scripts/teardown-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ if [ -n "${TEST_ENCRYPTION:-}" ]; then
fi

# Shut down load balancer if applicable.
if [ -n "${TEST_LOADBALANCER:-}" ]; then
if [ -n "${TEST_LOAD_BALANCER:-}" ]; then
bash "${DRIVERS_TOOLS}"/.evergreen/run-load-balancer.sh stop
fi
117 changes: 0 additions & 117 deletions green_framework_test.py

This file was deleted.

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?)|dummy.*)$"
"RET", "ARG", "F405", "B028", "PGH001", "B018", "F403", "RUF015", "E731", "B007",
"UP031", "F401", "B023", "F811"]
"tools/*.py" = ["T201"]
"green_framework_test.py" = ["T201"]
"hatch_build.py" = ["S"]
"_setup.py" = ["SIM112"]

Expand Down
2 changes: 1 addition & 1 deletion test/asynchronous/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

COMPRESSORS = os.environ.get("COMPRESSORS")
MONGODB_API_VERSION = os.environ.get("MONGODB_API_VERSION")
TEST_LOADBALANCER = bool(os.environ.get("TEST_LOADBALANCER"))
TEST_LOADBALANCER = bool(os.environ.get("TEST_LOAD_BALANCER"))
TEST_SERVERLESS = bool(os.environ.get("TEST_SERVERLESS"))
SINGLE_MONGOS_LB_URI = os.environ.get("SINGLE_MONGOS_LB_URI")
MULTI_MONGOS_LB_URI = os.environ.get("MULTI_MONGOS_LB_URI")
Expand Down
2 changes: 1 addition & 1 deletion test/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

COMPRESSORS = os.environ.get("COMPRESSORS")
MONGODB_API_VERSION = os.environ.get("MONGODB_API_VERSION")
TEST_LOADBALANCER = bool(os.environ.get("TEST_LOADBALANCER"))
TEST_LOADBALANCER = bool(os.environ.get("TEST_LOAD_BALANCER"))
TEST_SERVERLESS = bool(os.environ.get("TEST_SERVERLESS"))
SINGLE_MONGOS_LB_URI = os.environ.get("SINGLE_MONGOS_LB_URI")
MULTI_MONGOS_LB_URI = os.environ.get("MULTI_MONGOS_LB_URI")
Expand Down
Loading
Loading