Merge branch 'master' of github.com:mongodb/mongo-python-driver
This commit is contained in:
commit
789a10f799
@ -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}"]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(dirname ${BASH_SOURCE:-$0})
|
||||
SCRIPT_DIR="$( cd -- "$SCRIPT_DIR" > /dev/null 2>&1 && pwd )"
|
||||
@ -7,10 +7,6 @@ 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"
|
||||
@ -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
.evergreen/scripts/run_tests.py
Normal file
119
.evergreen/scripts/run_tests.py
Normal file
@ -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()
|
||||
@ -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":
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
# Copyright 2015-present MongoDB, 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.
|
||||
|
||||
"""Test PyMongo with a variety of greenlet-based monkey-patching frameworks."""
|
||||
from __future__ import annotations
|
||||
|
||||
import getopt
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def run_gevent():
|
||||
"""Prepare to run tests with Gevent. Can raise ImportError."""
|
||||
from gevent import monkey
|
||||
|
||||
monkey.patch_all()
|
||||
|
||||
|
||||
def run_eventlet():
|
||||
"""Prepare to run tests with Eventlet. Can raise ImportError."""
|
||||
import eventlet
|
||||
|
||||
# https://github.com/eventlet/eventlet/issues/401
|
||||
eventlet.sleep()
|
||||
eventlet.monkey_patch()
|
||||
|
||||
|
||||
FRAMEWORKS = {
|
||||
"gevent": run_gevent,
|
||||
"eventlet": run_eventlet,
|
||||
}
|
||||
|
||||
|
||||
def list_frameworks():
|
||||
"""Tell the user what framework names are valid."""
|
||||
sys.stdout.write(
|
||||
"""Testable frameworks: %s
|
||||
|
||||
Note that membership in this list means the framework can be tested with
|
||||
PyMongo, not necessarily that it is officially supported.
|
||||
"""
|
||||
% ", ".join(sorted(FRAMEWORKS))
|
||||
)
|
||||
|
||||
|
||||
def run(framework_name, *args):
|
||||
"""Run tests with monkey-patching enabled. Can raise ImportError."""
|
||||
# Monkey-patch.
|
||||
FRAMEWORKS[framework_name]()
|
||||
|
||||
arg_list = list(args)
|
||||
|
||||
# Never run async tests with a framework
|
||||
if len(arg_list) <= 1:
|
||||
arg_list.extend(["-m", "not default_async and default"])
|
||||
else:
|
||||
for i in range(len(arg_list) - 1):
|
||||
if "-m" in arg_list[i]:
|
||||
arg_list[i + 1] = f"not default_async and {arg_list[i + 1]}"
|
||||
|
||||
# Run the tests.
|
||||
sys.exit(pytest.main(arg_list))
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse options and run tests."""
|
||||
usage = f"""python {sys.argv[0]} FRAMEWORK_NAME
|
||||
|
||||
Test PyMongo with a variety of greenlet-based monkey-patching frameworks. See
|
||||
python {sys.argv[0]} --help-frameworks."""
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "help-frameworks"])
|
||||
except getopt.GetoptError as err:
|
||||
print(str(err))
|
||||
print(usage)
|
||||
sys.exit(2)
|
||||
|
||||
for option_name, _ in opts:
|
||||
if option_name in ("-h", "--help"):
|
||||
print(usage)
|
||||
sys.exit()
|
||||
elif option_name == "--help-frameworks":
|
||||
list_frameworks()
|
||||
sys.exit()
|
||||
else:
|
||||
raise AssertionError("unhandled option")
|
||||
|
||||
if not args:
|
||||
print(usage)
|
||||
sys.exit(1)
|
||||
|
||||
if args[0] not in FRAMEWORKS:
|
||||
print("%r is not a testable framework.\n" % args[0])
|
||||
list_frameworks()
|
||||
sys.exit(1)
|
||||
|
||||
run(
|
||||
args[0],
|
||||
*args[1:], # Framework name.
|
||||
) # Command line args to pytest, like what test to run.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -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"]
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ if CA_PEM:
|
||||
|
||||
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")
|
||||
|
||||
@ -81,7 +81,7 @@ if CA_PEM:
|
||||
|
||||
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")
|
||||
|
||||
@ -18,34 +18,30 @@ Only really intended to be used by internal build scripts.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
|
||||
|
||||
sys.path[0:0] = [""]
|
||||
|
||||
import bson # noqa: E402
|
||||
import pymongo # noqa: E402
|
||||
|
||||
if not pymongo.has_c() or not bson.has_c():
|
||||
try:
|
||||
from pymongo import _cmessage # type:ignore[attr-defined] # noqa: F401
|
||||
except Exception as e:
|
||||
print(e)
|
||||
try:
|
||||
from bson import _cbson # type:ignore[attr-defined] # noqa: F401
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit("could not load C extensions")
|
||||
|
||||
if os.environ.get("ENSURE_UNIVERSAL2") == "1":
|
||||
parent_dir = Path(pymongo.__path__[0]).parent
|
||||
for pkg in ["pymongo", "bson", "grifs"]:
|
||||
for so_file in Path(f"{parent_dir}/{pkg}").glob("*.so"):
|
||||
print(f"Checking universal2 compatibility in {so_file}...")
|
||||
output = subprocess.check_output(["file", so_file]) # noqa: S603, S607
|
||||
if "arm64" not in output.decode("utf-8"):
|
||||
sys.exit("Universal wheel was not compiled with arm64 support")
|
||||
if "x86_64" not in output.decode("utf-8"):
|
||||
sys.exit("Universal wheel was not compiled with x86_64 support")
|
||||
def main() -> None:
|
||||
if not pymongo.has_c() or not bson.has_c():
|
||||
try:
|
||||
from pymongo import _cmessage # type:ignore[attr-defined] # noqa: F401
|
||||
except Exception as e:
|
||||
LOGGER.exception(e)
|
||||
try:
|
||||
from bson import _cbson # type:ignore[attr-defined] # noqa: F401
|
||||
except Exception as e:
|
||||
LOGGER.exception(e)
|
||||
sys.exit("could not load C extensions")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user