Merge branch 'master' of github.com:mongodb/mongo-python-driver

This commit is contained in:
Steven Silvester 2024-10-14 19:35:46 -05:00
commit 7ad62152ba
No known key found for this signature in database
GPG Key ID: B1BF5EC3A8B32F91
8 changed files with 347 additions and 61 deletions

View File

@ -2826,42 +2826,150 @@ buildvariants:
- "test-6.0-standalone"
- "test-5.0-standalone"
- matrix_name: "ocsp-test"
matrix_spec:
platform: rhel8
python-version: ["3.9", "3.10", "pypy3.9", "pypy3.10"]
mongodb-version: ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"]
auth: "noauth"
ssl: "ssl"
display_name: "OCSP test ${platform} ${python-version} ${mongodb-version}"
batchtime: 20160 # 14 days
# OCSP test matrix.
- name: ocsp-test-rhel8-v4.4-py3.9
tasks:
- name: ".ocsp"
- matrix_name: "ocsp-test-windows"
matrix_spec:
platform: windows
python-version-windows: ["3.9", "3.10"]
mongodb-version: ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"]
auth: "noauth"
ssl: "ssl"
display_name: "OCSP test ${platform} ${python-version-windows} ${mongodb-version}"
batchtime: 20160 # 14 days
- name: .ocsp
display_name: OCSP test RHEL8 v4.4 py3.9
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "4.4"
PYTHON_BINARY: /opt/python/3.9/bin/python3
- name: ocsp-test-rhel8-v5.0-py3.10
tasks:
# Windows MongoDB servers do not staple OCSP responses and only support RSA.
- name: ".ocsp-rsa !.ocsp-staple"
- matrix_name: "ocsp-test-macos"
matrix_spec:
platform: macos
mongodb-version: ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"]
auth: "noauth"
ssl: "ssl"
display_name: "OCSP test ${platform} ${mongodb-version}"
batchtime: 20160 # 14 days
- name: .ocsp
display_name: OCSP test RHEL8 v5.0 py3.10
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "5.0"
PYTHON_BINARY: /opt/python/3.10/bin/python3
- name: ocsp-test-rhel8-v6.0-py3.11
tasks:
# macOS MongoDB servers do not staple OCSP responses and only support RSA.
- name: ".ocsp-rsa !.ocsp-staple"
- name: .ocsp
display_name: OCSP test RHEL8 v6.0 py3.11
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "6.0"
PYTHON_BINARY: /opt/python/3.11/bin/python3
- name: ocsp-test-rhel8-v7.0-py3.12
tasks:
- name: .ocsp
display_name: OCSP test RHEL8 v7.0 py3.12
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "7.0"
PYTHON_BINARY: /opt/python/3.12/bin/python3
- name: ocsp-test-rhel8-v8.0-py3.13
tasks:
- name: .ocsp
display_name: OCSP test RHEL8 v8.0 py3.13
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "8.0"
PYTHON_BINARY: /opt/python/3.13/bin/python3
- name: ocsp-test-rhel8-rapid-pypy3.9
tasks:
- name: .ocsp
display_name: OCSP test RHEL8 rapid pypy3.9
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: rapid
PYTHON_BINARY: /opt/python/pypy3.9/bin/python3
- name: ocsp-test-rhel8-latest-pypy3.10
tasks:
- name: .ocsp
display_name: OCSP test RHEL8 latest pypy3.10
run_on:
- rhel87-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: latest
PYTHON_BINARY: /opt/python/pypy3.10/bin/python3
- name: ocsp-test-win64-v4.4-py3.9
tasks:
- name: .ocsp-rsa !.ocsp-staple
display_name: OCSP test Win64 v4.4 py3.9
run_on:
- windows-64-vsMulti-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "4.4"
PYTHON_BINARY: C:/python/Python39/python.exe
- name: ocsp-test-win64-v8.0-py3.13
tasks:
- name: .ocsp-rsa !.ocsp-staple
display_name: OCSP test Win64 v8.0 py3.13
run_on:
- windows-64-vsMulti-small
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "8.0"
PYTHON_BINARY: C:/python/Python313/python.exe
- name: ocsp-test-macos-v4.4-py3.9
tasks:
- name: .ocsp-rsa !.ocsp-staple
display_name: OCSP test macOS v4.4 py3.9
run_on:
- macos-14
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "4.4"
PYTHON_BINARY: /Library/Frameworks/Python.Framework/Versions/3.9/bin/python3
- name: ocsp-test-macos-v8.0-py3.13
tasks:
- name: .ocsp-rsa !.ocsp-staple
display_name: OCSP test macOS v8.0 py3.13
run_on:
- macos-14
batchtime: 20160
expansions:
AUTH: noauth
SSL: ssl
TOPOLOGY: server
VERSION: "8.0"
PYTHON_BINARY: /Library/Frameworks/Python.Framework/Versions/3.13/bin/python3
- matrix_name: "oidc-auth-test"
matrix_spec:

View File

@ -18,17 +18,25 @@ if [ -n "$SKIP_HATCH" ]; then
run_hatch() {
bash ./.evergreen/run-tests.sh
}
elif $PYTHON_BINARY -m hatch --version; then
run_hatch() {
$PYTHON_BINARY -m hatch run "$@"
}
else # No toolchain hatch present, set up virtualenv before installing hatch
else # Set up virtualenv before installing hatch
# Use a random venv name because the encryption tasks run this script multiple times in the same run.
ENV_NAME=hatchenv-$RANDOM
createvirtualenv "$PYTHON_BINARY" $ENV_NAME
# shellcheck disable=SC2064
trap "deactivate; rm -rf $ENV_NAME" EXIT HUP
python -m pip install -q hatch
# Ensure hatch does not write to user or global locations.
touch hatch_config.toml
HATCH_CONFIG=$(pwd)/hatch_config.toml
if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin
HATCH_CONFIG=$(cygpath -m "$HATCH_CONFIG")
fi
export HATCH_CONFIG
hatch config restore
hatch config set dirs.data ".hatch/data"
hatch config set dirs.cache ".hatch/cache"
run_hatch() {
python -m hatch run "$@"
}

View File

@ -0,0 +1,167 @@
# /// script
# requires-python = ">=3.9"
# dependencies = [
# "shrub.py>=3.2.0",
# "pyyaml>=6.0.2"
# ]
# ///
# Note: Run this file with `hatch run`, `pipx run`, or `uv run`.
from __future__ import annotations
from dataclasses import dataclass
from itertools import cycle, product, zip_longest
from typing import Any
from shrub.v3.evg_build_variant import BuildVariant
from shrub.v3.evg_project import EvgProject
from shrub.v3.evg_task import EvgTaskRef
from shrub.v3.shrub_service import ShrubService
##############
# Globals
##############
ALL_VERSIONS = ["4.0", "4.4", "5.0", "6.0", "7.0", "8.0", "rapid", "latest"]
CPYTHONS = ["3.9", "3.10", "3.11", "3.12", "3.13"]
PYPYS = ["pypy3.9", "pypy3.10"]
ALL_PYTHONS = CPYTHONS + PYPYS
BATCHTIME_WEEK = 10080
HOSTS = dict()
@dataclass
class Host:
name: str
run_on: str
display_name: str
HOSTS["rhel8"] = Host("rhel8", "rhel87-small", "RHEL8")
HOSTS["win64"] = Host("win64", "windows-64-vsMulti-small", "Win64")
HOSTS["macos"] = Host("macos", "macos-14", "macOS")
##############
# Helpers
##############
def create_variant(
task_names: list[str],
display_name: str,
*,
python: str | None = None,
version: str | None = None,
host: str | None = None,
**kwargs: Any,
) -> BuildVariant:
"""Create a build variant for the given inputs."""
task_refs = [EvgTaskRef(name=n) for n in task_names]
kwargs.setdefault("expansions", dict())
expansions = kwargs.pop("expansions", dict()).copy()
host = host or "rhel8"
run_on = [HOSTS[host].run_on]
name = display_name.replace(" ", "-").lower()
if python:
expansions["PYTHON_BINARY"] = get_python_binary(python, host)
if version:
expansions["VERSION"] = version
expansions = expansions or None
return BuildVariant(
name=name,
display_name=display_name,
tasks=task_refs,
expansions=expansions,
run_on=run_on,
**kwargs,
)
def get_python_binary(python: str, host: str) -> str:
"""Get the appropriate python binary given a python version and host."""
if host == "win64":
is_32 = python.startswith("32-bit")
if is_32:
_, python = python.split()
base = "C:/python/32"
else:
base = "C:/python"
python = python.replace(".", "")
return f"{base}/Python{python}/python.exe"
if host == "rhel8":
return f"/opt/python/{python}/bin/python3"
if host == "macos":
return f"/Library/Frameworks/Python.Framework/Versions/{python}/bin/python3"
raise ValueError(f"no match found for python {python} on {host}")
def get_display_name(base: str, host: str, version: str, python: str) -> str:
"""Get the display name of a variant."""
if version not in ["rapid", "latest"]:
version = f"v{version}"
if not python.startswith("pypy"):
python = f"py{python}"
return f"{base} {HOSTS[host].display_name} {version} {python}"
def zip_cycle(*iterables, empty_default=None):
"""Get all combinations of the inputs, cycling over the shorter list(s)."""
cycles = [cycle(i) for i in iterables]
for _ in zip_longest(*iterables):
yield tuple(next(i, empty_default) for i in cycles)
##############
# Variants
##############
def create_ocsp_variants() -> list[BuildVariant]:
variants = []
batchtime = BATCHTIME_WEEK * 2
expansions = dict(AUTH="noauth", SSL="ssl", TOPOLOGY="server")
base_display = "OCSP test"
# OCSP tests on rhel8 with all servers v4.4+ and all python versions.
versions = [v for v in ALL_VERSIONS if v != "4.0"]
for version, python in zip_cycle(versions, ALL_PYTHONS):
host = "rhel8"
variant = create_variant(
[".ocsp"],
get_display_name(base_display, host, version, python),
python=python,
version=version,
host=host,
expansions=expansions,
batchtime=batchtime,
)
variants.append(variant)
# OCSP tests on Windows and MacOS.
# MongoDB servers on these hosts do not staple OCSP responses and only support RSA.
for host, version in product(["win64", "macos"], ["4.4", "8.0"]):
python = CPYTHONS[0] if version == "4.4" else CPYTHONS[-1]
variant = create_variant(
[".ocsp-rsa !.ocsp-staple"],
get_display_name(base_display, host, version, python),
python=python,
version=version,
host=host,
expansions=expansions,
batchtime=batchtime,
)
variants.append(variant)
return variants
##################
# Generate Config
##################
project = EvgProject(tasks=None, buildvariants=create_ocsp_variants())
print(ShrubService.generate_yaml(project)) # noqa: T201

View File

@ -1412,12 +1412,11 @@ class TestCursor(AsyncIntegrationTest):
self.assertEqual(len(docs), 2)
async def test_to_list_csot_applied(self):
client = await self.async_single_client(timeoutMS=500)
client = await self.async_single_client(timeoutMS=500, w=1)
coll = client.pymongo.test
# Initialize the client with a larger timeout to help make test less flakey
with pymongo.timeout(10):
await client.admin.command("ping")
coll = client.pymongo.test
await coll.insert_many([{} for _ in range(5)])
await coll.insert_many([{} for _ in range(5)])
cursor = coll.find({"$where": delay(1)})
with self.assertRaises(PyMongoError) as ctx:
await cursor.to_list()
@ -1454,12 +1453,11 @@ class TestCursor(AsyncIntegrationTest):
@async_client_context.require_failCommand_blockConnection
async def test_command_cursor_to_list_csot_applied(self):
client = await self.async_single_client(timeoutMS=500)
client = await self.async_single_client(timeoutMS=500, w=1)
coll = client.pymongo.test
# Initialize the client with a larger timeout to help make test less flakey
with pymongo.timeout(10):
await client.admin.command("ping")
coll = client.pymongo.test
await coll.insert_many([{} for _ in range(5)])
await coll.insert_many([{} for _ in range(5)])
fail_command = {
"configureFailPoint": "failCommand",
"mode": {"times": 5},

View File

@ -36,7 +36,6 @@ from test.asynchronous import (
unittest,
)
from test.unified_format_shared import (
IS_INTERRUPTED,
KMS_TLS_OPTS,
PLACEHOLDER_MAP,
SKIP_CSOT_TESTS,
@ -104,6 +103,13 @@ from pymongo.write_concern import WriteConcern
_IS_SYNC = False
IS_INTERRUPTED = False
def interrupt_loop():
global IS_INTERRUPTED
IS_INTERRUPTED = True
async def is_run_on_requirement_satisfied(requirement):
topology_satisfied = True

View File

@ -1403,12 +1403,11 @@ class TestCursor(IntegrationTest):
self.assertEqual(len(docs), 2)
def test_to_list_csot_applied(self):
client = self.single_client(timeoutMS=500)
client = self.single_client(timeoutMS=500, w=1)
coll = client.pymongo.test
# Initialize the client with a larger timeout to help make test less flakey
with pymongo.timeout(10):
client.admin.command("ping")
coll = client.pymongo.test
coll.insert_many([{} for _ in range(5)])
coll.insert_many([{} for _ in range(5)])
cursor = coll.find({"$where": delay(1)})
with self.assertRaises(PyMongoError) as ctx:
cursor.to_list()
@ -1445,12 +1444,11 @@ class TestCursor(IntegrationTest):
@client_context.require_failCommand_blockConnection
def test_command_cursor_to_list_csot_applied(self):
client = self.single_client(timeoutMS=500)
client = self.single_client(timeoutMS=500, w=1)
coll = client.pymongo.test
# Initialize the client with a larger timeout to help make test less flakey
with pymongo.timeout(10):
client.admin.command("ping")
coll = client.pymongo.test
coll.insert_many([{} for _ in range(5)])
coll.insert_many([{} for _ in range(5)])
fail_command = {
"configureFailPoint": "failCommand",
"mode": {"times": 5},

View File

@ -36,7 +36,6 @@ from test import (
unittest,
)
from test.unified_format_shared import (
IS_INTERRUPTED,
KMS_TLS_OPTS,
PLACEHOLDER_MAP,
SKIP_CSOT_TESTS,
@ -104,6 +103,13 @@ from pymongo.write_concern import WriteConcern
_IS_SYNC = True
IS_INTERRUPTED = False
def interrupt_loop():
global IS_INTERRUPTED
IS_INTERRUPTED = True
def is_run_on_requirement_satisfied(requirement):
topology_satisfied = True

View File

@ -139,11 +139,6 @@ elif OIDC_ENV == "gcp":
}
def interrupt_loop():
global IS_INTERRUPTED
IS_INTERRUPTED = True
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass.