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

This commit is contained in:
Steven Silvester 2025-03-12 07:36:52 -05:00
commit d870f6d460
No known key found for this signature in database
GPG Key ID: B1BF5EC3A8B32F91
24 changed files with 1379 additions and 741 deletions

View File

@ -201,7 +201,7 @@ functions:
params:
file: "src/xunit-results/TEST-*.xml"
"run-server":
"run server":
- command: subprocess.exec
params:
binary: bash
@ -255,7 +255,8 @@ 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, MONGODB_API_VERSION, DEBUG_LOG]
DISABLE_TEST_COMMANDS, GREEN_FRAMEWORK, NO_EXT, COMPRESSORS, MONGODB_API_VERSION, DEBUG_LOG,
ORCHESTRATION_FILE, OCSP_SERVER_TYPE]
binary: bash
working_dir: "src"
args: [.evergreen/just.sh, setup-tests, "${TEST_NAME}", "${SUB_TEST_NAME}"]
@ -320,12 +321,6 @@ functions:
- .evergreen/scripts/cleanup.sh
"teardown system":
- command: subprocess.exec
params:
binary: bash
working_dir: "src"
args:
- ${DRIVERS_TOOLS}/.evergreen/ocsp/teardown.sh
- command: subprocess.exec
params:
binary: bash
@ -357,26 +352,6 @@ functions:
params:
file: atlas-expansion.yml
"run-ocsp-test":
- command: subprocess.exec
type: test
params:
include_expansions_in_env: ["OCSP_ALGORITHM", "OCSP_TLS_SHOULD_SUCCEED", "PYTHON_BINARY"]
binary: bash
working_dir: "src"
args:
- .evergreen/scripts/run-with-env.sh
- .evergreen/scripts/run-ocsp-test.sh
"run-ocsp-server":
- command: subprocess.exec
params:
background: true
binary: bash
include_expansions_in_env: [SERVER_TYPE, OCSP_ALGORITHM]
args:
- ${DRIVERS_TOOLS}/.evergreen/ocsp/setup.sh
"teardown atlas":
- command: subprocess.exec
params:
@ -579,7 +554,7 @@ tasks:
- name: "doctests"
tags: ["doctests"]
commands:
- func: "run-server"
- func: "run server"
- func: "run doctests"
- name: "test-serverless"
@ -592,13 +567,13 @@ tasks:
- name: "test-enterprise-auth"
tags: ["enterprise-auth"]
commands:
- func: "run-server"
- func: "run server"
- func: "assume ec2 role"
- func: "run enterprise auth tests"
- name: "test-search-index-helpers"
commands:
- func: "run-server"
- func: "run server"
vars:
VERSION: "6.0"
TOPOLOGY: "replica_set"
@ -610,7 +585,7 @@ tasks:
- name: "mod-wsgi-standalone"
tags: ["mod_wsgi"]
commands:
- func: "run-server"
- func: "run server"
vars:
TOPOLOGY: "server"
- func: "run mod_wsgi tests"
@ -618,7 +593,7 @@ tasks:
- name: "mod-wsgi-replica-set"
tags: ["mod_wsgi"]
commands:
- func: "run-server"
- func: "run server"
vars:
TOPOLOGY: "replica_set"
- func: "run mod_wsgi tests"
@ -626,7 +601,7 @@ tasks:
- name: "mod-wsgi-embedded-mode-standalone"
tags: ["mod_wsgi"]
commands:
- func: "run-server"
- func: "run server"
- func: "run mod_wsgi tests"
vars:
MOD_WSGI_EMBEDDED: "1"
@ -634,7 +609,7 @@ tasks:
- name: "mod-wsgi-embedded-mode-replica-set"
tags: ["mod_wsgi"]
commands:
- func: "run-server"
- func: "run server"
vars:
TOPOLOGY: "replica_set"
- func: "run mod_wsgi tests"
@ -649,7 +624,7 @@ tasks:
- name: "free-threading"
tags: ["free-threading"]
commands:
- func: "run-server"
- func: "run server"
vars:
VERSION: "8.0"
TOPOLOGY: "replica_set"
@ -684,350 +659,6 @@ tasks:
env:
TEST_LAMBDA_DIRECTORY: ${PROJECT_DIRECTORY}/test/lambda
- name: test-ocsp-rsa-valid-cert-server-staples
tags: ["ocsp", "ocsp-rsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: "valid"
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-rsa-invalid-cert-server-staples
tags: ["ocsp", "ocsp-rsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: "revoked"
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-rsa-valid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: valid
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-rsa-invalid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: revoked
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-rsa-soft-fail
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-rsa-malicious-invalid-cert-mustStaple-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: revoked
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-rsa-malicious-no-responder-mustStaple-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-rsa-delegate-valid-cert-server-staples
tags: ["ocsp", "ocsp-rsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: valid-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-rsa-delegate-invalid-cert-server-staples
tags: ["ocsp", "ocsp-rsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: revoked-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-rsa-delegate-valid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: valid-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-rsa-delegate-invalid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: revoked-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-rsa-delegate-malicious-invalid-cert-mustStaple-server-does-not-staple
tags: ["ocsp", "ocsp-rsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "rsa"
SERVER_TYPE: revoked-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "rsa-basic-tls-ocsp-mustStaple-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "rsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-valid-cert-server-staples
tags: ["ocsp", "ocsp-ecdsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: valid
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-ecdsa-invalid-cert-server-staples
tags: ["ocsp", "ocsp-ecdsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: revoked
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-valid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: valid
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-ecdsa-invalid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: revoked
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-soft-fail
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-ecdsa-malicious-invalid-cert-mustStaple-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: revoked
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-malicious-no-responder-mustStaple-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-delegate-valid-cert-server-staples
tags: ["ocsp", "ocsp-ecdsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: valid-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-ecdsa-delegate-invalid-cert-server-staples
tags: ["ocsp", "ocsp-ecdsa", "ocsp-staple"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: revoked-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-delegate-valid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: valid-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "true"
- name: test-ocsp-ecdsa-delegate-invalid-cert-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: revoked-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: test-ocsp-ecdsa-delegate-malicious-invalid-cert-mustStaple-server-does-not-staple
tags: ["ocsp", "ocsp-ecdsa"]
commands:
- func: run-ocsp-server
vars:
OCSP_ALGORITHM: "ecdsa"
SERVER_TYPE: valid-delegate
- func: "run-server"
vars:
ORCHESTRATION_FILE: "ecdsa-basic-tls-ocsp-mustStaple-disableStapling.json"
- func: run-ocsp-test
vars:
OCSP_ALGORITHM: "ecdsa"
OCSP_TLS_SHOULD_SUCCEED: "false"
- name: "oidc-auth-test"
commands:
- func: "run oidc auth test with test credentials"
@ -1095,7 +726,7 @@ tasks:
- name: "perf-6.0-standalone"
tags: ["perf"]
commands:
- func: "run-server"
- func: "run server"
vars:
VERSION: "v6.0-perf"
- func: "run perf tests"
@ -1105,7 +736,7 @@ tasks:
- name: "perf-6.0-standalone-ssl"
tags: ["perf"]
commands:
- func: "run-server"
- func: "run server"
vars:
VERSION: "v6.0-perf"
SSL: "ssl"
@ -1116,7 +747,7 @@ tasks:
- name: "perf-8.0-standalone"
tags: ["perf"]
commands:
- func: "run-server"
- func: "run server"
vars:
VERSION: "8.0"
- func: "run perf tests"

File diff suppressed because it is too large Load Diff

View File

@ -801,7 +801,7 @@ def create_server_tasks():
AUTH=auth,
SSL=ssl,
)
server_func = FunctionCall(func="run-server", vars=server_vars)
server_func = FunctionCall(func="run server", vars=server_vars)
test_vars = dict(AUTH=auth, SSL=ssl, SYNC=sync)
if sync == "sync":
test_vars["TEST_NAME"] = "default_sync"
@ -820,7 +820,7 @@ def create_load_balancer_tasks():
server_vars = dict(
TOPOLOGY="sharded_cluster", AUTH=auth, SSL=ssl, TEST_NAME="load_balancer"
)
server_func = FunctionCall(func="run-server", vars=server_vars)
server_func = FunctionCall(func="run server", vars=server_vars)
test_vars = dict(AUTH=auth, SSL=ssl, TEST_NAME="load_balancer")
test_func = FunctionCall(func="run tests", vars=test_vars)
tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func]))
@ -839,7 +839,7 @@ def create_kms_tasks():
sub_test_name += "-fail"
commands = []
if not success:
commands.append(FunctionCall(func="run-server"))
commands.append(FunctionCall(func="run server"))
test_vars = dict(TEST_NAME="kms", SUB_TEST_NAME=sub_test_name)
test_func = FunctionCall(func="run tests", vars=test_vars)
commands.append(test_func)
@ -862,7 +862,7 @@ def create_aws_tasks():
base_name = f"test-auth-aws-{version}"
base_tags = ["auth-aws"]
server_vars = dict(AUTH_AWS="1", VERSION=version)
server_func = FunctionCall(func="run-server", vars=server_vars)
server_func = FunctionCall(func="run server", vars=server_vars)
assume_func = FunctionCall(func="assume ec2 role")
for test_type in aws_test_types:
tags = [*base_tags, f"auth-aws-{test_type}"]
@ -884,6 +884,60 @@ def create_aws_tasks():
return tasks
def _create_ocsp_task(algo, variant, server_type, base_task_name):
file_name = f"{algo}-basic-tls-ocsp-{variant}.json"
vars = dict(TEST_NAME="ocsp", ORCHESTRATION_FILE=file_name)
server_func = FunctionCall(func="run server", vars=vars)
vars = dict(ORCHESTRATION_FILE=file_name, OCSP_SERVER_TYPE=server_type, TEST_NAME="ocsp")
test_func = FunctionCall(func="run tests", vars=vars)
tags = ["ocsp", f"ocsp-{algo}"]
if "disableStapling" not in variant:
tags.append("ocsp-staple")
task_name = f"test-ocsp-{algo}-{base_task_name}"
commands = [server_func, test_func]
return EvgTask(name=task_name, tags=tags, commands=commands)
def create_ocsp_tasks():
tasks = []
tests = [
("disableStapling", "valid", "valid-cert-server-does-not-staple"),
("disableStapling", "revoked", "invalid-cert-server-does-not-staple"),
("disableStapling", "valid-delegate", "delegate-valid-cert-server-does-not-staple"),
("disableStapling", "revoked-delegate", "delegate-invalid-cert-server-does-not-staple"),
("disableStapling", "no-responder", "soft-fail"),
("mustStaple", "valid", "valid-cert-server-staples"),
("mustStaple", "revoked", "invalid-cert-server-staples"),
("mustStaple", "valid-delegate", "delegate-valid-cert-server-staples"),
("mustStaple", "revoked-delegate", "delegate-invalid-cert-server-staples"),
(
"mustStaple-disableStapling",
"revoked",
"malicious-invalid-cert-mustStaple-server-does-not-staple",
),
(
"mustStaple-disableStapling",
"revoked-delegate",
"delegate-malicious-invalid-cert-mustStaple-server-does-not-staple",
),
(
"mustStaple-disableStapling",
"no-responder",
"malicious-no-responder-mustStaple-server-does-not-staple",
),
]
for algo in ["ecdsa", "rsa"]:
for variant, server_type, base_task_name in tests:
task = _create_ocsp_task(algo, variant, server_type, base_task_name)
tasks.append(task)
return tasks
##################
# Generate Config
##################

View File

@ -1,12 +0,0 @@
#!/bin/bash
set -eu
pushd "${PROJECT_DIRECTORY}/.evergreen"
bash scripts/setup-dev-env.sh
CA_FILE="${DRIVERS_TOOLS}/.evergreen/ocsp/${OCSP_ALGORITHM}/ca.pem" \
OCSP_TLS_SHOULD_SUCCEED="${OCSP_TLS_SHOULD_SUCCEED}" \
bash scripts/setup-tests.sh ocsp
bash run-tests.sh
bash "${DRIVERS_TOOLS}"/.evergreen/ocsp/teardown.sh
popd

View File

@ -32,15 +32,26 @@ def start_server():
elif test_name == "load_balancer":
set_env("LOAD_BALANCER")
elif test_name == "ocsp":
opts.ssl = True
if "ORCHESTRATION_FILE" not in os.environ:
found = False
for opt in extra_opts:
if opt.startswith("--orchestration-file"):
found = True
if not found:
raise ValueError("Please provide an orchestration file")
if not os.environ.get("TEST_CRYPT_SHARED"):
set_env("SKIP_CRYPT_SHARED")
if opts.ssl:
extra_opts.append("--ssl")
certs = ROOT / "test/certificates"
set_env("TLS_CERT_KEY_FILE", certs / "client.pem")
set_env("TLS_PEM_KEY_FILE", certs / "server.pem")
set_env("TLS_CA_FILE", certs / "ca.pem")
if test_name != "ocsp":
certs = ROOT / "test/certificates"
set_env("TLS_CERT_KEY_FILE", certs / "client.pem")
set_env("TLS_PEM_KEY_FILE", certs / "server.pem")
set_env("TLS_CA_FILE", certs / "ca.pem")
cmd = ["bash", f"{DRIVERS_TOOLS}/.evergreen/run-orchestration.sh", *extra_opts]
run_command(cmd, cwd=DRIVERS_TOOLS)

View File

@ -239,6 +239,30 @@ def handle_test_env() -> None:
cmd = f'bash "{DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh" start'
run_command(cmd)
if test_name == "ocsp":
if sub_test_name:
os.environ["OCSP_SERVER_TYPE"] = sub_test_name
for name in ["OCSP_SERVER_TYPE", "ORCHESTRATION_FILE"]:
if name not in os.environ:
raise ValueError(f"Please set {name}")
server_type = os.environ["OCSP_SERVER_TYPE"]
orch_file = os.environ["ORCHESTRATION_FILE"]
ocsp_algo = orch_file.split("-")[0]
if server_type == "no-responder":
tls_should_succeed = "false" if "mustStaple-disableStapling" in orch_file else "true"
else:
tls_should_succeed = "true" if "valid" in server_type else "false"
write_env("OCSP_TLS_SHOULD_SUCCEED", tls_should_succeed)
write_env("CA_FILE", f"{DRIVERS_TOOLS}/.evergreen/ocsp/{ocsp_algo}/ca.pem")
if server_type != "no-responder":
env = os.environ.copy()
env["SERVER_TYPE"] = server_type
env["OCSP_ALGORITHM"] = ocsp_algo
run_command(f"bash {DRIVERS_TOOLS}/.evergreen/ocsp/setup.sh", env=env)
if SSL != "nossl":
if not DRIVERS_TOOLS:
raise RuntimeError("Missing DRIVERS_TOOLS")
@ -302,10 +326,6 @@ def handle_test_env() -> None:
setup_kms(sub_test_name)
if test_name == "ocsp":
write_env("CA_FILE", os.environ["CA_FILE"])
write_env("OCSP_TLS_SHOULD_SUCCEED", os.environ["OCSP_TLS_SHOULD_SUCCEED"])
if test_name == "auth_aws" and sub_test_name != "ecs-remote":
auth_aws_dir = f"{DRIVERS_TOOLS}/.evergreen/auth_aws"
if "AWS_ROLE_SESSION_NAME" in os.environ:

View File

@ -24,6 +24,10 @@ elif TEST_NAME == "kms" and SUB_TEST_NAME in ["azure", "gcp"]:
teardown_kms(SUB_TEST_NAME)
# Tear down ocsp if applicable.
elif TEST_NAME == "ocsp":
run_command(f"bash {DRIVERS_TOOLS}/.evergreen/teardown.sh")
# Tear down auth_aws if applicable.
# We do not run web-identity hosts on macos, because the hosts lack permissions,
# so there is no reason to run the teardown, which would error with a 401.

View File

@ -218,12 +218,12 @@ the pages will re-render and the browser will automatically refresh.
### Usage
- Run `just run-server` with optional args to set up the server.
All given flags will be passed to `run-orchestration.sh` in `DRIVERS_TOOLS`.
All given flags will be passed to `run-orchestration.sh` in `$DRIVERS_TOOLS`.
- Run `just setup-tests` with optional args to set up the test environment, secrets, etc.
- Run `just run-tests` to run the tests in an appropriate Python environment.
- When done, run `just teardown-tests` to clean up and `just stop-server` to stop the server.
## Encryption tests
### Encryption tests
- Run `just run-server` to start the server.
- Run `just setup-tests encryption`.
@ -236,13 +236,13 @@ the pages will re-render and the browser will automatically refresh.
- Set up the test with `just setup-tests load_balancer`.
- Run the tests with `just run-tests`.
## AWS tests
### AWS tests
- Run `just run-server auth_aws` to start the server.
- Run `just setup-tests auth_aws <aws-test-type>` to set up the AWS test.
- Run the tests with `just run-tests`.
## KMS tests
### KMS tests
For KMS tests that are run locally, and expected to fail, in this case using `azure`:
@ -255,6 +255,17 @@ For KMS tests that run remotely and are expected to pass, in this case using `gc
- Run `just setup-tests kms gcp`.
- Run `just run-tests`.
### OCSP tests
- Export the orchestration file, e.g. `export ORCHESTRATION_FILE=rsa-basic-tls-ocsp-disableStapling.json`.
This corresponds to a config file in `$DRIVERS_TOOLS/.evergreen/orchestration/configs/servers`.
MongoDB servers on MacOS and Windows do not staple OCSP responses and only support RSA.
- Run `just run-server ocsp`.
- Run `just setup-tests ocsp <sub test>` (options are "valid", "revoked", "valid-delegate", "revoked-delegate").
- Run `just run-tests`
If you are running one of the `no-responder` tests, omit the `run-server` step.
## Enable Debug Logs
- Use `-o log_cli_level="DEBUG" -o log_cli=1` with `just test` or `pytest`.
- Add `log_cli_level = "DEBUG` and `log_cli = 1` to the `tool.pytest.ini_options` section in `pyproject.toml` for Evergreen patches or to enable debug logs by default on your machine.

View File

@ -14,7 +14,6 @@
from __future__ import annotations
import struct
from dataclasses import dataclass
from enum import Enum
from typing import TYPE_CHECKING, Any, Optional, Sequence, Tuple, Type, Union, overload
from uuid import UUID
@ -227,7 +226,6 @@ class BinaryVectorDtype(Enum):
PACKED_BIT = b"\x10"
@dataclass
class BinaryVector:
"""Vector of numbers along with metadata for binary interoperability.
.. versionadded:: 4.10
@ -247,6 +245,16 @@ class BinaryVector:
self.dtype = dtype
self.padding = padding
def __repr__(self) -> str:
return f"BinaryVector(dtype={self.dtype}, padding={self.padding}, data={self.data})"
def __eq__(self, other: Any) -> bool:
if not isinstance(other, BinaryVector):
return False
return (
self.dtype == other.dtype and self.padding == other.padding and self.data == other.data
)
class Binary(bytes):
"""Representation of BSON binary data.

View File

@ -1,7 +1,23 @@
Changelog
=========
Changes in Version 4.11.2 (YYYY/MM/DD)
Changes in Version 4.12.0 (YYYY/MM/DD)
--------------------------------------
PyMongo 4.12 brings a number of changes including:
- Support for configuring DEK cache lifetime via the ``key_expiration_ms`` argument to
:class:`~pymongo.encryption_options.AutoEncryptionOpts`.
Issues Resolved
...............
See the `PyMongo 4.12 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _PyMongo 4.12 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=41916
Changes in Version 4.11.2 (2025/03/05)
--------------------------------------
Version 4.11.2 is a bug fix release.

View File

@ -445,6 +445,7 @@ class _Encrypter:
bypass_encryption=opts._bypass_auto_encryption,
encrypted_fields_map=encrypted_fields_map,
bypass_query_analysis=opts._bypass_query_analysis,
key_expiration_ms=opts._key_expiration_ms,
),
)
self._closed = False
@ -547,11 +548,10 @@ class QueryType(str, enum.Enum):
def _create_mongocrypt_options(**kwargs: Any) -> MongoCryptOptions:
opts = MongoCryptOptions(**kwargs)
# Opt into range V2 encryption.
if hasattr(opts, "enable_range_v2"):
opts.enable_range_v2 = True
return opts
# For compat with pymongocrypt <1.13, avoid setting the default key_expiration_ms.
if kwargs.get("key_expiration_ms") is None:
kwargs.pop("key_expiration_ms", None)
return MongoCryptOptions(**kwargs)
class AsyncClientEncryption(Generic[_DocumentType]):
@ -564,6 +564,7 @@ class AsyncClientEncryption(Generic[_DocumentType]):
key_vault_client: AsyncMongoClient[_DocumentTypeArg],
codec_options: CodecOptions[_DocumentTypeArg],
kms_tls_options: Optional[Mapping[str, Any]] = None,
key_expiration_ms: Optional[int] = None,
) -> None:
"""Explicit client-side field level encryption.
@ -630,7 +631,12 @@ class AsyncClientEncryption(Generic[_DocumentType]):
Or to supply a client certificate::
kms_tls_options={'kmip': {'tlsCertificateKeyFile': 'client.pem'}}
:param key_expiration_ms: The cache expiration time for data encryption keys.
Defaults to ``None`` which defers to libmongocrypt's default which is currently 60000.
Set to 0 to disable key expiration.
.. versionchanged:: 4.12
Added the `key_expiration_ms` parameter.
.. versionchanged:: 4.0
Added the `kms_tls_options` parameter and the "kmip" KMS provider.
@ -666,14 +672,19 @@ class AsyncClientEncryption(Generic[_DocumentType]):
key_vault_coll = key_vault_client[db][coll]
opts = AutoEncryptionOpts(
kms_providers, key_vault_namespace, kms_tls_options=kms_tls_options
kms_providers,
key_vault_namespace,
kms_tls_options=kms_tls_options,
key_expiration_ms=key_expiration_ms,
)
self._io_callbacks: Optional[_EncryptionIO] = _EncryptionIO(
None, key_vault_coll, None, opts
)
self._encryption = AsyncExplicitEncrypter(
self._io_callbacks,
_create_mongocrypt_options(kms_providers=kms_providers, schema_map=None),
_create_mongocrypt_options(
kms_providers=kms_providers, schema_map=None, key_expiration_ms=key_expiration_ms
),
)
# Use the same key vault collection as the callback.
assert self._io_callbacks.key_vault_coll is not None
@ -700,6 +711,7 @@ class AsyncClientEncryption(Generic[_DocumentType]):
creation. :class:`~pymongo.errors.EncryptionError` will be
raised if the collection already exists.
:param database: the database to create the collection
:param name: the name of the collection to create
:param encrypted_fields: Document that describes the encrypted fields for
Queryable Encryption. The "keyId" may be set to ``None`` to auto-generate the data keys. For example:

View File

@ -57,6 +57,7 @@ class AutoEncryptionOpts:
crypt_shared_lib_required: bool = False,
bypass_query_analysis: bool = False,
encrypted_fields_map: Optional[Mapping[str, Any]] = None,
key_expiration_ms: Optional[int] = None,
) -> None:
"""Options to configure automatic client-side field level encryption.
@ -191,9 +192,14 @@ class AutoEncryptionOpts:
]
}
}
:param key_expiration_ms: The cache expiration time for data encryption keys.
Defaults to ``None`` which defers to libmongocrypt's default which is currently 60000.
Set to 0 to disable key expiration.
.. versionchanged:: 4.12
Added the `key_expiration_ms` parameter.
.. versionchanged:: 4.2
Added `encrypted_fields_map` `crypt_shared_lib_path`, `crypt_shared_lib_required`,
Added the `encrypted_fields_map`, `crypt_shared_lib_path`, `crypt_shared_lib_required`,
and `bypass_query_analysis` parameters.
.. versionchanged:: 4.0
@ -210,7 +216,6 @@ class AutoEncryptionOpts:
if encrypted_fields_map:
validate_is_mapping("encrypted_fields_map", encrypted_fields_map)
self._encrypted_fields_map = encrypted_fields_map
self._bypass_query_analysis = bypass_query_analysis
self._crypt_shared_lib_path = crypt_shared_lib_path
self._crypt_shared_lib_required = crypt_shared_lib_required
self._kms_providers = kms_providers
@ -233,6 +238,7 @@ class AutoEncryptionOpts:
# Maps KMS provider name to a SSLContext.
self._kms_ssl_contexts = _parse_kms_tls_options(kms_tls_options)
self._bypass_query_analysis = bypass_query_analysis
self._key_expiration_ms = key_expiration_ms
class RangeOpts:

View File

@ -442,6 +442,7 @@ class _Encrypter:
bypass_encryption=opts._bypass_auto_encryption,
encrypted_fields_map=encrypted_fields_map,
bypass_query_analysis=opts._bypass_query_analysis,
key_expiration_ms=opts._key_expiration_ms,
),
)
self._closed = False
@ -544,11 +545,10 @@ class QueryType(str, enum.Enum):
def _create_mongocrypt_options(**kwargs: Any) -> MongoCryptOptions:
opts = MongoCryptOptions(**kwargs)
# Opt into range V2 encryption.
if hasattr(opts, "enable_range_v2"):
opts.enable_range_v2 = True
return opts
# For compat with pymongocrypt <1.13, avoid setting the default key_expiration_ms.
if kwargs.get("key_expiration_ms") is None:
kwargs.pop("key_expiration_ms", None)
return MongoCryptOptions(**kwargs)
class ClientEncryption(Generic[_DocumentType]):
@ -561,6 +561,7 @@ class ClientEncryption(Generic[_DocumentType]):
key_vault_client: MongoClient[_DocumentTypeArg],
codec_options: CodecOptions[_DocumentTypeArg],
kms_tls_options: Optional[Mapping[str, Any]] = None,
key_expiration_ms: Optional[int] = None,
) -> None:
"""Explicit client-side field level encryption.
@ -627,7 +628,12 @@ class ClientEncryption(Generic[_DocumentType]):
Or to supply a client certificate::
kms_tls_options={'kmip': {'tlsCertificateKeyFile': 'client.pem'}}
:param key_expiration_ms: The cache expiration time for data encryption keys.
Defaults to ``None`` which defers to libmongocrypt's default which is currently 60000.
Set to 0 to disable key expiration.
.. versionchanged:: 4.12
Added the `key_expiration_ms` parameter.
.. versionchanged:: 4.0
Added the `kms_tls_options` parameter and the "kmip" KMS provider.
@ -659,14 +665,19 @@ class ClientEncryption(Generic[_DocumentType]):
key_vault_coll = key_vault_client[db][coll]
opts = AutoEncryptionOpts(
kms_providers, key_vault_namespace, kms_tls_options=kms_tls_options
kms_providers,
key_vault_namespace,
kms_tls_options=kms_tls_options,
key_expiration_ms=key_expiration_ms,
)
self._io_callbacks: Optional[_EncryptionIO] = _EncryptionIO(
None, key_vault_coll, None, opts
)
self._encryption = ExplicitEncrypter(
self._io_callbacks,
_create_mongocrypt_options(kms_providers=kms_providers, schema_map=None),
_create_mongocrypt_options(
kms_providers=kms_providers, schema_map=None, key_expiration_ms=key_expiration_ms
),
)
# Use the same key vault collection as the callback.
assert self._io_callbacks.key_vault_coll is not None
@ -693,6 +704,7 @@ class ClientEncryption(Generic[_DocumentType]):
creation. :class:`~pymongo.errors.EncryptionError` will be
raised if the collection already exists.
:param database: the database to create the collection
:param name: the name of the collection to create
:param encrypted_fields: Document that describes the encrypted fields for
Queryable Encryption. The "keyId" may be set to ``None`` to auto-generate the data keys. For example:

View File

@ -378,6 +378,7 @@ class EntityMapUtil:
opts["key_vault_client"],
DEFAULT_CODEC_OPTIONS,
opts.get("kms_tls_options", kms_tls_options),
opts.get("key_expiration_ms"),
)
return
elif entity_type == "thread":
@ -439,7 +440,7 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
a class attribute ``TEST_SPEC``.
"""
SCHEMA_VERSION = Version.from_string("1.21")
SCHEMA_VERSION = Version.from_string("1.22")
RUN_ON_LOAD_BALANCER = True
RUN_ON_SERVERLESS = True
TEST_SPEC: Any

View File

@ -18,6 +18,7 @@ from __future__ import annotations
import asyncio
import functools
import os
import time
import unittest
from asyncio import iscoroutinefunction
from collections import abc
@ -314,6 +315,10 @@ class AsyncSpecRunner(AsyncIntegrationTest):
coll = self.client[database][collection]
self.assertNotIn(index, [doc["name"] async for doc in await coll.list_indexes()])
async def wait(self, ms):
"""Run the "wait" test operation."""
await asyncio.sleep(ms / 1000.0)
def assertErrorLabelsContain(self, exc, expected_labels):
labels = [l for l in expected_labels if exc.has_error_label(l)]
self.assertEqual(labels, expected_labels)

View File

@ -6,8 +6,7 @@
"replicaset",
"sharded",
"load-balanced"
],
"serverless": "forbid"
]
}
],
"database_name": "default",

View File

@ -0,0 +1,270 @@
{
"runOn": [
{
"minServerVersion": "4.1.10"
}
],
"database_name": "default",
"collection_name": "default",
"data": [],
"json_schema": {
"properties": {
"encrypted_w_altname": {
"encrypt": {
"keyId": "/altname",
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"encrypted_string": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
},
"random": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"encrypted_string_equivalent": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
},
"bsonType": "object"
},
"key_vault_data": [
{
"status": 1,
"_id": {
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "aws",
"key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
"region": "us-east-1"
},
"updateDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyMaterial": {
"$binary": {
"base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyAltNames": [
"altname",
"another_altname"
]
}
],
"tests": [
{
"description": "Insert with deterministic encryption, then find it",
"clientOptions": {
"autoEncryptOpts": {
"kmsProviders": {
"aws": {}
},
"keyExpirationMS": 1
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0"
}
}
},
{
"name": "wait",
"object": "testRunner",
"arguments": {
"ms": 50
}
},
{
"name": "find",
"arguments": {
"filter": {
"_id": 1
}
},
"result": [
{
"_id": 1,
"encrypted_string": "string0"
}
]
}
],
"expectations": [
{
"command_started_event": {
"command": {
"listCollections": 1,
"filter": {
"name": "default"
}
},
"command_name": "listCollections"
}
},
{
"command_started_event": {
"command": {
"find": "datakeys",
"filter": {
"$or": [
{
"_id": {
"$in": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
]
}
},
{
"keyAltNames": {
"$in": []
}
}
]
},
"$db": "keyvault",
"readConcern": {
"level": "majority"
}
},
"command_name": "find"
}
},
{
"command_started_event": {
"command": {
"insert": "default",
"documents": [
{
"_id": 1,
"encrypted_string": {
"$binary": {
"base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==",
"subType": "06"
}
}
}
],
"ordered": true
},
"command_name": "insert"
}
},
{
"command_started_event": {
"command": {
"find": "default",
"filter": {
"_id": 1
}
},
"command_name": "find"
}
},
{
"command_started_event": {
"command": {
"find": "datakeys",
"filter": {
"$or": [
{
"_id": {
"$in": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
]
}
},
{
"keyAltNames": {
"$in": []
}
}
]
},
"$db": "keyvault",
"readConcern": {
"level": "majority"
}
},
"command_name": "find"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"encrypted_string": {
"$binary": {
"base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==",
"subType": "06"
}
}
}
]
}
}
}
]
}

View File

@ -110,7 +110,7 @@
"listCollections"
],
"blockConnection": true,
"blockTimeMS": 600
"blockTimeMS": 60
}
},
"clientOptions": {
@ -119,7 +119,7 @@
"aws": {}
}
},
"timeoutMS": 500
"timeoutMS": 50
},
"operations": [
{

View File

@ -0,0 +1,198 @@
{
"description": "keyCache-explicit",
"schemaVersion": "1.22",
"runOnRequirements": [
{
"csfle": true
}
],
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent"
]
}
},
{
"clientEncryption": {
"id": "clientEncryption0",
"clientEncryptionOpts": {
"keyVaultClient": "client0",
"keyVaultNamespace": "keyvault.datakeys",
"kmsProviders": {
"local": {
"key": "OCTP9uKPPmvuqpHlqq83gPk4U6rUPxKVRRyVtrjFmVjdoa4Xzm1SzUbr7aIhNI42czkUBmrCtZKF31eaaJnxEBkqf0RFukA9Mo3NEHQWgAQ2cn9duOcRbaFUQo2z0/rB"
}
},
"keyExpirationMS": 1
}
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "keyvault"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "datakeys"
}
}
],
"initialData": [
{
"databaseName": "keyvault",
"collectionName": "datakeys",
"documents": [
{
"_id": {
"$binary": {
"base64": "a+YWzdygTAG62/cNUkqZiQ==",
"subType": "04"
}
},
"keyAltNames": [],
"keyMaterial": {
"$binary": {
"base64": "iocBkhO3YBokiJ+FtxDTS71/qKXQ7tSWhWbcnFTXBcMjarsepvALeJ5li+SdUd9ePuatjidxAdMo7vh1V2ZESLMkQWdpPJ9PaJjA67gKQKbbbB4Ik5F2uKjULvrMBnFNVRMup4JNUwWFQJpqbfMveXnUVcD06+pUpAkml/f+DSXrV3e5rxciiNVtz03dAG8wJrsKsFXWj6vTjFhsfknyBA==",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"updateDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"status": {
"$numberInt": "0"
},
"masterKey": {
"provider": "local"
}
}
]
}
],
"tests": [
{
"description": "decrypt, wait, and decrypt again",
"operations": [
{
"name": "decrypt",
"object": "clientEncryption0",
"arguments": {
"value": {
"$binary": {
"base64": "AWvmFs3coEwButv3DVJKmYkCJ6lUzRX9R28WNlw5uyndb+8gurA+p8q14s7GZ04K2ZvghieRlAr5UwZbow3PMq27u5EIhDDczwBFcbdP1amllw==",
"subType": "06"
}
}
},
"expectResult": "foobar"
},
{
"name": "wait",
"object": "testRunner",
"arguments": {
"ms": 50
}
},
{
"name": "decrypt",
"object": "clientEncryption0",
"arguments": {
"value": {
"$binary": {
"base64": "AWvmFs3coEwButv3DVJKmYkCJ6lUzRX9R28WNlw5uyndb+8gurA+p8q14s7GZ04K2ZvghieRlAr5UwZbow3PMq27u5EIhDDczwBFcbdP1amllw==",
"subType": "06"
}
}
},
"expectResult": "foobar"
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"find": "datakeys",
"filter": {
"$or": [
{
"_id": {
"$in": [
{
"$binary": {
"base64": "a+YWzdygTAG62/cNUkqZiQ==",
"subType": "04"
}
}
]
}
},
{
"keyAltNames": {
"$in": []
}
}
]
},
"$db": "keyvault",
"readConcern": {
"level": "majority"
}
}
}
},
{
"commandStartedEvent": {
"command": {
"find": "datakeys",
"filter": {
"$or": [
{
"_id": {
"$in": [
{
"$binary": {
"base64": "a+YWzdygTAG62/cNUkqZiQ==",
"subType": "04"
}
}
]
}
},
{
"keyAltNames": {
"$in": []
}
}
]
},
"$db": "keyvault",
"readConcern": {
"level": "majority"
}
}
}
}
]
}
]
}
]
}

View File

@ -0,0 +1,38 @@
{
"description": "Secondary with IPv6 literal",
"uri": "mongodb://[::1]/?replicaSet=rs",
"phases": [
{
"responses": [
[
"[::1]:27017",
{
"ok": 1,
"helloOk": true,
"isWritablePrimary": false,
"secondary": true,
"setName": "rs",
"me": "[::1]:27017",
"hosts": [
"[::1]:27017"
],
"minWireVersion": 0,
"maxWireVersion": 26
}
]
],
"outcome": {
"servers": {
"[::1]:27017": {
"type": "RSSecondary",
"setName": "rs"
}
},
"topologyType": "ReplicaSetNoPrimary",
"setName": "rs",
"logicalSessionTimeoutMinutes": null,
"compatible": true
}
}
]
}

View File

@ -809,6 +809,64 @@ class TestBSON(unittest.TestCase):
dtype=BinaryVectorDtype.PACKED_BIT,
) # type: ignore[call-overload]
def assertRepr(self, obj):
new_obj = eval(repr(obj))
self.assertEqual(type(new_obj), type(obj))
self.assertEqual(repr(new_obj), repr(obj))
def test_binaryvector_repr(self):
"""Tests of repr(BinaryVector)"""
data = [1 / 127, -7 / 6]
one = BinaryVector(data, BinaryVectorDtype.FLOAT32)
self.assertEqual(
repr(one), f"BinaryVector(dtype=BinaryVectorDtype.FLOAT32, padding=0, data={data})"
)
self.assertRepr(one)
data = [127, 7]
two = BinaryVector(data, BinaryVectorDtype.INT8)
self.assertEqual(
repr(two), f"BinaryVector(dtype=BinaryVectorDtype.INT8, padding=0, data={data})"
)
self.assertRepr(two)
three = BinaryVector(data, BinaryVectorDtype.INT8, padding=0)
self.assertEqual(
repr(three), f"BinaryVector(dtype=BinaryVectorDtype.INT8, padding=0, data={data})"
)
self.assertRepr(three)
four = BinaryVector(data, BinaryVectorDtype.PACKED_BIT, padding=3)
self.assertEqual(
repr(four), f"BinaryVector(dtype=BinaryVectorDtype.PACKED_BIT, padding=3, data={data})"
)
self.assertRepr(four)
zero = BinaryVector([], BinaryVectorDtype.INT8)
self.assertEqual(
repr(zero), "BinaryVector(dtype=BinaryVectorDtype.INT8, padding=0, data=[])"
)
self.assertRepr(zero)
def test_binaryvector_equality(self):
"""Tests of == __eq__"""
self.assertEqual(
BinaryVector([1.2, 1 - 1 / 3], BinaryVectorDtype.FLOAT32, 0),
BinaryVector([1.2, 1 - 1.0 / 3.0], BinaryVectorDtype.FLOAT32, 0),
)
self.assertNotEqual(
BinaryVector([1.2, 1 - 1 / 3], BinaryVectorDtype.FLOAT32, 0),
BinaryVector([1.2, 6.0 / 9.0], BinaryVectorDtype.FLOAT32, 0),
)
self.assertEqual(
BinaryVector([], BinaryVectorDtype.FLOAT32, 0),
BinaryVector([], BinaryVectorDtype.FLOAT32, 0),
)
self.assertNotEqual(
BinaryVector([1], BinaryVectorDtype.INT8), BinaryVector([2], BinaryVectorDtype.INT8)
)
def test_unicode_regex(self):
"""Tests we do not get a segfault for C extension on unicode RegExs.
This had been happening.

View File

@ -377,6 +377,7 @@ class EntityMapUtil:
opts["key_vault_client"],
DEFAULT_CODEC_OPTIONS,
opts.get("kms_tls_options", kms_tls_options),
opts.get("key_expiration_ms"),
)
return
elif entity_type == "thread":
@ -438,7 +439,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
a class attribute ``TEST_SPEC``.
"""
SCHEMA_VERSION = Version.from_string("1.21")
SCHEMA_VERSION = Version.from_string("1.22")
RUN_ON_LOAD_BALANCER = True
RUN_ON_SERVERLESS = True
TEST_SPEC: Any

View File

@ -18,6 +18,7 @@ from __future__ import annotations
import asyncio
import functools
import os
import time
import unittest
from asyncio import iscoroutinefunction
from collections import abc
@ -314,6 +315,10 @@ class SpecRunner(IntegrationTest):
coll = self.client[database][collection]
self.assertNotIn(index, [doc["name"] for doc in coll.list_indexes()])
def wait(self, ms):
"""Run the "wait" test operation."""
time.sleep(ms / 1000.0)
def assertErrorLabelsContain(self, exc, expected_labels):
labels = [l for l in expected_labels if exc.has_error_label(l)]
self.assertEqual(labels, expected_labels)

2
uv.lock generated
View File

@ -1133,7 +1133,7 @@ wheels = [
[[package]]
name = "pymongocrypt"
version = "1.13.0.dev0"
source = { git = "https://github.com/mongodb/libmongocrypt?subdirectory=bindings%2Fpython&rev=master#90476d5db7737bab2ce1c198df5671a12dbaae1a" }
source = { git = "https://github.com/mongodb/libmongocrypt?subdirectory=bindings%2Fpython&rev=master#1e96c283162aa7789cf01f99f211e0ace8e6d49f" }
dependencies = [
{ name = "cffi" },
{ name = "cryptography" },