diff --git a/README.md b/README.md index f5e2cdf46..bd0755620 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The PyMongo distribution contains tools for interacting with MongoDB database from Python. The `bson` package is an implementation of the [BSON format](http://bsonspec.org) for Python. The `pymongo` package is a native Python driver for MongoDB. The `gridfs` package is a -[gridfs](https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.rst/) +[gridfs](https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.md/) implementation on top of `pymongo`. PyMongo supports MongoDB 4.0, 4.2, 4.4, 5.0, 6.0, 7.0, and 8.0. diff --git a/bson/json_util.py b/bson/json_util.py index 6f34e4103..a171327ea 100644 --- a/bson/json_util.py +++ b/bson/json_util.py @@ -22,7 +22,7 @@ is emitted and parsed, with the default being the Relaxed Extended JSON format. when :const:`CANONICAL_JSON_OPTIONS` or :const:`LEGACY_JSON_OPTIONS` is provided, respectively. -.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json.rst +.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md Example usage (deserialization): diff --git a/doc/api/index.rst b/doc/api/index.rst index 30ae3608c..437f2cc6a 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -6,7 +6,7 @@ interacting with MongoDB. :mod:`bson` is an implementation of the `BSON format `_, :mod:`pymongo` is a full-featured driver for MongoDB, and :mod:`gridfs` is a set of tools for working with the `GridFS -`_ storage +`_ storage specification. .. toctree:: diff --git a/doc/changelog.rst b/doc/changelog.rst index 29fddb7b5..bd4eafe3e 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -12,6 +12,7 @@ PyMongo 4.11 brings a number of changes including: - Dropped support for Python 3.8. - Dropped support for MongoDB 3.6. +- Dropped support for the MONGODB-CR authenticate mechanism, which is no longer supported by MongoDB 4.0+. - Added support for free-threaded Python with the GIL disabled. For more information see: `Free-threaded CPython `_. - :attr:`~pymongo.asynchronous.mongo_client.AsyncMongoClient.address` and @@ -23,6 +24,10 @@ PyMongo 4.11 brings a number of changes including: :meth:`~pymongo.collection.Collection.update_one`, :meth:`~pymongo.collection.Collection.replace_one`, :class:`~pymongo.operations.UpdateOne`, and :class:`~pymongo.operations.UpdateMany`, +- :meth:`~pymongo.mongo_client.MongoClient.bulk_write` and + :meth:`~pymongo.asynchronous.mongo_client.AsyncMongoClient.bulk_write` now throw an error + when ``ordered=True`` or ``verboseResults=True`` are used with unacknowledged writes. + These are unavoidable breaking changes. Issues Resolved ............... @@ -1022,7 +1027,7 @@ See the `PyMongo 4.0 release notes in JIRA`_ for the list of resolved issues in this release. .. _PyMongo 4.0 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=18463 -.. _DBRef specification: https://github.com/mongodb/specifications/blob/5a8c8d7/source/dbref.rst +.. _DBRef specification: https://github.com/mongodb/specifications/blob/master/source/dbref/dbref.md Changes in Version 3.13.0 (2022/11/01) -------------------------------------- @@ -1557,7 +1562,7 @@ Unavoidable breaking changes: bumped to 1.16.0. This is a breaking change for applications that use PyMongo's SRV support with a version of ``dnspython`` older than 1.16.0. -.. _URI options specification: https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.rst +.. _URI options specification: https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.md Issues Resolved @@ -1581,7 +1586,7 @@ Changes in Version 3.8.0 (2019/04/22) must upgrade to PyPy3.5+. - :class:`~bson.objectid.ObjectId` now implements the `ObjectID specification - version 0.2 `_. + version 0.2 `_. - For better performance and to better follow the GridFS spec, :class:`~gridfs.grid_file.GridOut` now uses a single cursor to read all the chunks in the file. Previously, each chunk in the file was queried @@ -1943,7 +1948,7 @@ Highlights include: :class:`~pymongo.operations.UpdateOne`, and :class:`~pymongo.operations.UpdateMany`. - Implemented the `MongoDB Extended JSON - `_ + `_ specification. - :class:`~bson.decimal128.Decimal128` now works when cdecimal is installed. - PyMongo is now tested against a wider array of operating systems and CPU diff --git a/doc/conf.py b/doc/conf.py index f0d9f921b..f82c71936 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -85,7 +85,7 @@ pygments_style = "sphinx" # wiki.centos.org has been flakey. # sourceforge.net is giving a 403 error, but is still accessible from the browser. linkcheck_ignore = [ - "https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.rst#requesting-an-immediate-check", + "https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.md#requesting-an-immediate-check", "https://github.com/mongodb/libmongocrypt/blob/master/bindings/python/README.rst#installing-from-source", r"https://wiki.centos.org/[\w/]*", r"http://sourceforge.net/", diff --git a/doc/developer/periodic_executor.rst b/doc/developer/periodic_executor.rst index effe18efc..67eaa89f1 100644 --- a/doc/developer/periodic_executor.rst +++ b/doc/developer/periodic_executor.rst @@ -106,7 +106,7 @@ Thus the current design of periodic executors is surprisingly simple: they do a simple ``time.sleep`` for a half-second, check if it is time to wake or terminate, and sleep again. -.. _Server Discovery And Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.rst#requesting-an-immediate-check +.. _Server Discovery And Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.md#requesting-an-immediate-check .. _PYTHON-863: https://jira.mongodb.org/browse/PYTHON-863 diff --git a/doc/examples/authentication.rst b/doc/examples/authentication.rst index 6c89910f3..b319df814 100644 --- a/doc/examples/authentication.rst +++ b/doc/examples/authentication.rst @@ -76,24 +76,6 @@ For best performance on Python versions older than 2.7.8 install `backports.pbkd .. _backports.pbkdf2: https://pypi.python.org/pypi/backports.pbkdf2/ -MONGODB-CR ----------- - -.. warning:: MONGODB-CR was deprecated with the release of MongoDB 3.6 and - is no longer supported by MongoDB 4.0. - -Before MongoDB 3.0 the default authentication mechanism was MONGODB-CR, -the "MongoDB Challenge-Response" protocol:: - - >>> from pymongo import MongoClient - >>> client = MongoClient('example.com', - ... username='user', - ... password='password', - ... authMechanism='MONGODB-CR') - >>> - >>> uri = "mongodb://user:password@example.com/?authSource=the_database&authMechanism=MONGODB-CR" - >>> client = MongoClient(uri) - Default Authentication Mechanism -------------------------------- @@ -221,8 +203,7 @@ SASL PLAIN (RFC 4616) MongoDB Enterprise Edition version 2.6 and newer support the SASL PLAIN authentication mechanism, initially intended for delegating authentication -to an LDAP server. Using the PLAIN mechanism is very similar to MONGODB-CR. -These examples use the $external virtual database for LDAP support:: +to an LDAP server. These examples use the $external virtual database for LDAP support:: >>> from pymongo import MongoClient >>> uri = "mongodb://user:password@example.com/?authMechanism=PLAIN" diff --git a/doc/examples/uuid.rst b/doc/examples/uuid.rst index 90ec71ebe..350db14d9 100644 --- a/doc/examples/uuid.rst +++ b/doc/examples/uuid.rst @@ -84,7 +84,7 @@ Finally, the same UUID would historically be serialized by the Java driver as:: .. note:: For in-depth information about the the byte-order historically used by different drivers, see the `Handling of Native UUID Types Specification - `_. + `_. This difference in the byte-order of UUIDs encoded by different drivers can result in highly unintuitive behavior in some scenarios. We detail two such diff --git a/doc/migrate-to-pymongo4.rst b/doc/migrate-to-pymongo4.rst index bc6da8556..3e992a824 100644 --- a/doc/migrate-to-pymongo4.rst +++ b/doc/migrate-to-pymongo4.rst @@ -118,7 +118,7 @@ Renamed URI options Several deprecated URI options have been renamed to the standardized option names defined in the -`URI options specification `_. +`URI options specification `_. The old option names and their renamed equivalents are summarized in the table below. Some renamed options have different semantics from the option being replaced as noted in the 'Migration Notes' column. @@ -965,7 +965,7 @@ correct type. Otherwise the document is returned as normal. Previously, any subdocument containing a ``$ref`` field would be decoded as a :class:`~bson.dbref.DBRef`. -.. _DBRef specification: https://github.com/mongodb/specifications/blob/5a8c8d7/source/dbref.rst +.. _DBRef specification: https://github.com/mongodb/specifications/blob/master/source/dbref/dbref.md Encoding a UUID raises an error by default .......................................... diff --git a/pymongo/asynchronous/auth.py b/pymongo/asynchronous/auth.py index 1fb28f6c4..fc563ec48 100644 --- a/pymongo/asynchronous/auth.py +++ b/pymongo/asynchronous/auth.py @@ -329,21 +329,6 @@ async def _authenticate_x509(credentials: MongoCredential, conn: AsyncConnection await conn.command("$external", cmd) -async def _authenticate_mongo_cr(credentials: MongoCredential, conn: AsyncConnection) -> None: - """Authenticate using MONGODB-CR.""" - source = credentials.source - username = credentials.username - password = credentials.password - # Get a nonce - response = await conn.command(source, {"getnonce": 1}) - nonce = response["nonce"] - key = _auth_key(nonce, username, password) - - # Actually authenticate - query = {"authenticate": 1, "user": username, "nonce": nonce, "key": key} - await conn.command(source, query) - - async def _authenticate_default(credentials: MongoCredential, conn: AsyncConnection) -> None: if conn.max_wire_version >= 7: if conn.negotiated_mechs: @@ -365,7 +350,6 @@ async def _authenticate_default(credentials: MongoCredential, conn: AsyncConnect _AUTH_MAP: Mapping[str, Callable[..., Coroutine[Any, Any, None]]] = { "GSSAPI": _authenticate_gssapi, - "MONGODB-CR": _authenticate_mongo_cr, "MONGODB-X509": _authenticate_x509, "MONGODB-AWS": _authenticate_aws, "MONGODB-OIDC": _authenticate_oidc, # type:ignore[dict-item] diff --git a/pymongo/asynchronous/client_bulk.py b/pymongo/asynchronous/client_bulk.py index 96571c21e..a6f7178e4 100644 --- a/pymongo/asynchronous/client_bulk.py +++ b/pymongo/asynchronous/client_bulk.py @@ -681,11 +681,11 @@ class _AsyncClientBulk: _throw_client_bulk_write_exception(full_result, self.verbose_results) return full_result - async def execute_command_unack_unordered( + async def execute_command_unack( self, conn: AsyncConnection, ) -> None: - """Execute commands with OP_MSG and w=0 writeConcern, unordered.""" + """Execute commands with OP_MSG and w=0 writeConcern. Always unordered.""" db_name = "admin" cmd_name = "bulkWrite" listeners = self.client._event_listeners @@ -704,8 +704,8 @@ class _AsyncClientBulk: while self.idx_offset < self.total_ops: # Construct the server command, specifying the relevant options. cmd = {"bulkWrite": 1} - cmd["errorsOnly"] = not self.verbose_results - cmd["ordered"] = self.ordered # type: ignore[assignment] + cmd["errorsOnly"] = True + cmd["ordered"] = False if self.bypass_doc_val is not None: cmd["bypassDocumentValidation"] = self.bypass_doc_val cmd["writeConcern"] = {"w": 0} # type: ignore[assignment] @@ -723,43 +723,6 @@ class _AsyncClientBulk: self.idx_offset += len(to_send_ops) - async def execute_command_unack_ordered( - self, - conn: AsyncConnection, - ) -> None: - """Execute commands with OP_MSG and w=0 WriteConcern, ordered.""" - full_result: MutableMapping[str, Any] = { - "anySuccessful": False, - "error": None, - "writeErrors": [], - "writeConcernErrors": [], - "nInserted": 0, - "nUpserted": 0, - "nMatched": 0, - "nModified": 0, - "nDeleted": 0, - "insertResults": {}, - "updateResults": {}, - "deleteResults": {}, - } - # Ordered bulk writes have to be acknowledged so that we stop - # processing at the first error, even when the application - # specified unacknowledged writeConcern. - initial_write_concern = WriteConcern() - op_id = _randint() - try: - await self._execute_command( - initial_write_concern, - None, - conn, - op_id, - False, - full_result, - self.write_concern, - ) - except OperationFailure: - pass - async def execute_no_results( self, conn: AsyncConnection, @@ -775,9 +738,7 @@ class _AsyncClientBulk: "Cannot set bypass_document_validation with unacknowledged write concern" ) - if self.ordered: - return await self.execute_command_unack_ordered(conn) - return await self.execute_command_unack_unordered(conn) + return await self.execute_command_unack(conn) async def execute( self, diff --git a/pymongo/asynchronous/mongo_client.py b/pymongo/asynchronous/mongo_client.py index a71e4cb5c..e4fdf25c2 100644 --- a/pymongo/asynchronous/mongo_client.py +++ b/pymongo/asynchronous/mongo_client.py @@ -221,7 +221,7 @@ class AsyncMongoClient(common.BaseObject, Generic[_DocumentType]): `_. See the `Initial DNS Seedlist Discovery spec `_ + initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md>`_ for more details. Note that the use of SRV URIs implicitly enables TLS support. Pass tls=false in the URI to override. @@ -367,7 +367,7 @@ class AsyncMongoClient(common.BaseObject, Generic[_DocumentType]): :meth:`~pymongo.asynchronous.collection.AsyncCollection.aggregate` using the ``$out`` pipeline operator and any operation with an unacknowledged write concern (e.g. {w: 0})). See - https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst + https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.md - `retryReads`: (boolean) Whether supported read operations executed within this AsyncMongoClient will be retried once after a network error. Defaults to ``True``. @@ -394,7 +394,7 @@ class AsyncMongoClient(common.BaseObject, Generic[_DocumentType]): transient errors such as network failures, database upgrades, and replica set failovers. For an exact definition of which errors trigger a retry, see the `retryable reads specification - `_. + `_. - `compressors`: Comma separated list of compressors for wire protocol compression. The list is used to negotiate a compressor diff --git a/pymongo/auth_shared.py b/pymongo/auth_shared.py index 7e3acd9df..fa25aa3fa 100644 --- a/pymongo/auth_shared.py +++ b/pymongo/auth_shared.py @@ -34,7 +34,6 @@ from pymongo.errors import ConfigurationError MECHANISMS = frozenset( [ "GSSAPI", - "MONGODB-CR", "MONGODB-OIDC", "MONGODB-X509", "MONGODB-AWS", @@ -78,7 +77,7 @@ MongoCredential = namedtuple( GSSAPIProperties = namedtuple( - "GSSAPIProperties", ["service_name", "canonicalize_host_name", "service_realm"] + "GSSAPIProperties", ["service_name", "canonicalize_host_name", "service_realm", "service_host"] ) """Mechanism properties for GSSAPI authentication.""" @@ -87,6 +86,16 @@ _AWSProperties = namedtuple("_AWSProperties", ["aws_session_token"]) """Mechanism properties for MONGODB-AWS authentication.""" +def _validate_canonicalize_host_name(value: str | bool) -> str | bool: + valid_names = [False, True, "none", "forward", "forwardAndReverse"] + if value in ["true", "false", True, False]: + return value in ["true", True] + + if value not in valid_names: + raise ValueError(f"CANONICALIZE_HOST_NAME '{value}' not in valid options: {valid_names}") + return value + + def _build_credentials_tuple( mech: str, source: Optional[str], @@ -103,12 +112,15 @@ def _build_credentials_tuple( raise ValueError("authentication source must be $external or None for GSSAPI") properties = extra.get("authmechanismproperties", {}) service_name = properties.get("SERVICE_NAME", "mongodb") - canonicalize = bool(properties.get("CANONICALIZE_HOST_NAME", False)) + service_host = properties.get("SERVICE_HOST", None) + canonicalize = properties.get("CANONICALIZE_HOST_NAME", "false") + canonicalize = _validate_canonicalize_host_name(canonicalize) service_realm = properties.get("SERVICE_REALM") props = GSSAPIProperties( service_name=service_name, canonicalize_host_name=canonicalize, service_realm=service_realm, + service_host=service_host, ) # Source is always $external. return MongoCredential(mech, "$external", user, passwd, props, None) diff --git a/pymongo/common.py b/pymongo/common.py index 87aa936f5..d4601a0eb 100644 --- a/pymongo/common.py +++ b/pymongo/common.py @@ -139,6 +139,9 @@ SRV_SERVICE_NAME = "mongodb" # Default value for serverMonitoringMode SERVER_MONITORING_MODE = "auto" # poll/stream/auto +# Auth mechanism properties that must raise an error instead of warning if they invalidate. +_MECH_PROP_MUST_RAISE = ["CANONICALIZE_HOST_NAME"] + def partition_node(node: str) -> tuple[str, int]: """Split a host:port string into (host, int(port)) pair.""" @@ -423,6 +426,7 @@ def validate_read_preference_tags(name: str, value: Any) -> list[dict[str, str]] _MECHANISM_PROPS = frozenset( [ "SERVICE_NAME", + "SERVICE_HOST", "CANONICALIZE_HOST_NAME", "SERVICE_REALM", "AWS_SESSION_TOKEN", @@ -476,7 +480,9 @@ def validate_auth_mechanism_properties(option: str, value: Any) -> dict[str, Uni ) if key == "CANONICALIZE_HOST_NAME": - props[key] = validate_boolean_or_string(key, val) + from pymongo.auth_shared import _validate_canonicalize_host_name + + props[key] = _validate_canonicalize_host_name(val) else: props[key] = val @@ -867,6 +873,10 @@ def get_validated_options( validator = _get_validator(opt, URI_OPTIONS_VALIDATOR_MAP, normed_key=normed_key) validated = validator(opt, value) except (ValueError, TypeError, ConfigurationError) as exc: + if normed_key == "authmechanismproperties" and any( + p in str(exc) for p in _MECH_PROP_MUST_RAISE + ): + raise if warn: warnings.warn(str(exc), stacklevel=2) else: diff --git a/pymongo/pool_options.py b/pymongo/pool_options.py index 61486c91c..f3ed6cd2c 100644 --- a/pymongo/pool_options.py +++ b/pymongo/pool_options.py @@ -216,7 +216,7 @@ def _metadata_env() -> dict[str, Any]: _MAX_METADATA_SIZE = 512 -# See: https://github.com/mongodb/specifications/blob/5112bcc/source/mongodb-handshake/handshake.rst#limitations +# See: https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.md#limitations def _truncate_metadata(metadata: MutableMapping[str, Any]) -> None: """Perform metadata truncation.""" if len(bson.encode(metadata)) <= _MAX_METADATA_SIZE: diff --git a/pymongo/synchronous/auth.py b/pymongo/synchronous/auth.py index 9a3477679..7b370843c 100644 --- a/pymongo/synchronous/auth.py +++ b/pymongo/synchronous/auth.py @@ -326,21 +326,6 @@ def _authenticate_x509(credentials: MongoCredential, conn: Connection) -> None: conn.command("$external", cmd) -def _authenticate_mongo_cr(credentials: MongoCredential, conn: Connection) -> None: - """Authenticate using MONGODB-CR.""" - source = credentials.source - username = credentials.username - password = credentials.password - # Get a nonce - response = conn.command(source, {"getnonce": 1}) - nonce = response["nonce"] - key = _auth_key(nonce, username, password) - - # Actually authenticate - query = {"authenticate": 1, "user": username, "nonce": nonce, "key": key} - conn.command(source, query) - - def _authenticate_default(credentials: MongoCredential, conn: Connection) -> None: if conn.max_wire_version >= 7: if conn.negotiated_mechs: @@ -360,7 +345,6 @@ def _authenticate_default(credentials: MongoCredential, conn: Connection) -> Non _AUTH_MAP: Mapping[str, Callable[..., None]] = { "GSSAPI": _authenticate_gssapi, - "MONGODB-CR": _authenticate_mongo_cr, "MONGODB-X509": _authenticate_x509, "MONGODB-AWS": _authenticate_aws, "MONGODB-OIDC": _authenticate_oidc, # type:ignore[dict-item] diff --git a/pymongo/synchronous/client_bulk.py b/pymongo/synchronous/client_bulk.py index 2c38b1d76..6cb427541 100644 --- a/pymongo/synchronous/client_bulk.py +++ b/pymongo/synchronous/client_bulk.py @@ -679,11 +679,11 @@ class _ClientBulk: _throw_client_bulk_write_exception(full_result, self.verbose_results) return full_result - def execute_command_unack_unordered( + def execute_command_unack( self, conn: Connection, ) -> None: - """Execute commands with OP_MSG and w=0 writeConcern, unordered.""" + """Execute commands with OP_MSG and w=0 writeConcern. Always unordered.""" db_name = "admin" cmd_name = "bulkWrite" listeners = self.client._event_listeners @@ -702,8 +702,8 @@ class _ClientBulk: while self.idx_offset < self.total_ops: # Construct the server command, specifying the relevant options. cmd = {"bulkWrite": 1} - cmd["errorsOnly"] = not self.verbose_results - cmd["ordered"] = self.ordered # type: ignore[assignment] + cmd["errorsOnly"] = True + cmd["ordered"] = False if self.bypass_doc_val is not None: cmd["bypassDocumentValidation"] = self.bypass_doc_val cmd["writeConcern"] = {"w": 0} # type: ignore[assignment] @@ -721,43 +721,6 @@ class _ClientBulk: self.idx_offset += len(to_send_ops) - def execute_command_unack_ordered( - self, - conn: Connection, - ) -> None: - """Execute commands with OP_MSG and w=0 WriteConcern, ordered.""" - full_result: MutableMapping[str, Any] = { - "anySuccessful": False, - "error": None, - "writeErrors": [], - "writeConcernErrors": [], - "nInserted": 0, - "nUpserted": 0, - "nMatched": 0, - "nModified": 0, - "nDeleted": 0, - "insertResults": {}, - "updateResults": {}, - "deleteResults": {}, - } - # Ordered bulk writes have to be acknowledged so that we stop - # processing at the first error, even when the application - # specified unacknowledged writeConcern. - initial_write_concern = WriteConcern() - op_id = _randint() - try: - self._execute_command( - initial_write_concern, - None, - conn, - op_id, - False, - full_result, - self.write_concern, - ) - except OperationFailure: - pass - def execute_no_results( self, conn: Connection, @@ -773,9 +736,7 @@ class _ClientBulk: "Cannot set bypass_document_validation with unacknowledged write concern" ) - if self.ordered: - return self.execute_command_unack_ordered(conn) - return self.execute_command_unack_unordered(conn) + return self.execute_command_unack(conn) def execute( self, diff --git a/pymongo/synchronous/mongo_client.py b/pymongo/synchronous/mongo_client.py index 24696f0c8..0380d4468 100644 --- a/pymongo/synchronous/mongo_client.py +++ b/pymongo/synchronous/mongo_client.py @@ -216,7 +216,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): `_. See the `Initial DNS Seedlist Discovery spec `_ + initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md>`_ for more details. Note that the use of SRV URIs implicitly enables TLS support. Pass tls=false in the URI to override. @@ -365,7 +365,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): :meth:`~pymongo.collection.Collection.aggregate` using the ``$out`` pipeline operator and any operation with an unacknowledged write concern (e.g. {w: 0})). See - https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst + https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.md - `retryReads`: (boolean) Whether supported read operations executed within this MongoClient will be retried once after a network error. Defaults to ``True``. @@ -392,7 +392,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): transient errors such as network failures, database upgrades, and replica set failovers. For an exact definition of which errors trigger a retry, see the `retryable reads specification - `_. + `_. - `compressors`: Comma separated list of compressors for wire protocol compression. The list is used to negotiate a compressor diff --git a/test/asynchronous/test_auth.py b/test/asynchronous/test_auth.py index 926271437..4f26200fb 100644 --- a/test/asynchronous/test_auth.py +++ b/test/asynchronous/test_auth.py @@ -375,7 +375,7 @@ class TestSCRAMSHA1(AsyncIntegrationTest): await db.command("dbstats") -# https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst#scram-sha-256-and-mechanism-negotiation +# https://github.com/mongodb/specifications/blob/master/source/auth/auth.md#scram-sha-256-and-mechanism-negotiation class TestSCRAM(AsyncIntegrationTest): @async_client_context.require_auth @async_client_context.require_version_min(3, 7, 2) diff --git a/test/asynchronous/test_encryption.py b/test/asynchronous/test_encryption.py index 40f1acd32..e42c85aa7 100644 --- a/test/asynchronous/test_encryption.py +++ b/test/asynchronous/test_encryption.py @@ -1610,7 +1610,7 @@ class TestGCPEncryption(AzureGCPEncryptionTestMixin, AsyncEncryptionIntegrationT return await self._test_automatic(expected_document_extjson, {"secret_gcp": "string0"}) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#deadlock-tests +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#deadlock-tests class TestDeadlockProse(AsyncEncryptionIntegrationTest): async def asyncSetUp(self): self.client_test = await self.async_rs_or_single_client( @@ -1837,7 +1837,7 @@ class TestDeadlockProse(AsyncEncryptionIntegrationTest): self.assertEqual(len(self.topology_listener.results["opened"]), 1) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#14-decryption-events +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#14-decryption-events class TestDecryptProse(AsyncEncryptionIntegrationTest): async def asyncSetUp(self): self.client = async_client_context.client @@ -1909,7 +1909,7 @@ class TestDecryptProse(AsyncEncryptionIntegrationTest): self.assertEqual(event.reply["cursor"]["firstBatch"][0]["encrypted"], self.cipher_text) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#bypass-spawning-mongocryptd +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#bypass-spawning-mongocryptd class TestBypassSpawningMongocryptdProse(AsyncEncryptionIntegrationTest): @unittest.skipIf( os.environ.get("TEST_CRYPT_SHARED"), @@ -1990,7 +1990,7 @@ class TestBypassSpawningMongocryptdProse(AsyncEncryptionIntegrationTest): with self.assertRaises(ServerSelectionTimeoutError): await no_mongocryptd_client.db.command("ping") - # https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#20-bypass-creating-mongocryptd-client-when-shared-library-is-loaded + # https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#20-bypass-creating-mongocryptd-client-when-shared-library-is-loaded @unittest.skipUnless(os.environ.get("TEST_CRYPT_SHARED"), "crypt_shared lib is not installed") async def test_client_via_loading_shared_library(self): connection_established = False @@ -2066,7 +2066,7 @@ class TestKmsTLSProse(AsyncEncryptionIntegrationTest): await self.client_encrypted.create_data_key("aws", master_key=key) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#kms-tls-options-tests +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#kms-tls-options-tests class TestKmsTLSOptions(AsyncEncryptionIntegrationTest): @unittest.skipUnless(any(AWS_CREDS.values()), "AWS environment credentials are not set") async def asyncSetUp(self): @@ -2272,7 +2272,7 @@ class TestKmsTLSOptions(AsyncEncryptionIntegrationTest): await self.client_encryption_with_names.create_data_key("kmip:with_tls") -# https://github.com/mongodb/specifications/blob/50e26fe/source/client-side-encryption/tests/README.rst#unique-index-on-keyaltnames +# https://github.com/mongodb/specifications/blob/50e26fe/source/client-side-encryption/tests/README.md#unique-index-on-keyaltnames class TestUniqueIndexOnKeyAltNamesProse(AsyncEncryptionIntegrationTest): async def asyncSetUp(self): self.client = async_client_context.client @@ -2303,7 +2303,7 @@ class TestUniqueIndexOnKeyAltNamesProse(AsyncEncryptionIntegrationTest): assert key_doc["keyAltNames"] == ["def"] -# https://github.com/mongodb/specifications/blob/d4c9432/source/client-side-encryption/tests/README.rst#explicit-encryption +# https://github.com/mongodb/specifications/blob/d4c9432/source/client-side-encryption/tests/README.md#explicit-encryption class TestExplicitQueryableEncryption(AsyncEncryptionIntegrationTest): @async_client_context.require_no_standalone @async_client_context.require_version_min(7, 0, -1) @@ -2423,7 +2423,7 @@ class TestExplicitQueryableEncryption(AsyncEncryptionIntegrationTest): self.assertEqual(decrypted, val) -# https://github.com/mongodb/specifications/blob/072601/source/client-side-encryption/tests/README.rst#rewrap +# https://github.com/mongodb/specifications/blob/072601/source/client-side-encryption/tests/README.md#rewrap class TestRewrapWithSeparateClientEncryption(AsyncEncryptionIntegrationTest): MASTER_KEYS: Mapping[str, Mapping[str, Any]] = { "aws": { @@ -2505,7 +2505,7 @@ class TestRewrapWithSeparateClientEncryption(AsyncEncryptionIntegrationTest): ) -# https://github.com/mongodb/specifications/blob/5cf3ed/source/client-side-encryption/tests/README.rst#on-demand-aws-credentials +# https://github.com/mongodb/specifications/blob/5cf3ed/source/client-side-encryption/tests/README.md#on-demand-aws-credentials class TestOnDemandAWSCredentials(AsyncEncryptionIntegrationTest): async def asyncSetUp(self): await super().asyncSetUp() @@ -2869,7 +2869,7 @@ class TestRangeQueryDefaultsProse(AsyncEncryptionIntegrationTest): assert len(payload) > len(self.payload_defaults) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#automatic-data-encryption-keys +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#automatic-data-encryption-keys class TestAutomaticDecryptionKeys(AsyncEncryptionIntegrationTest): @async_client_context.require_no_standalone @async_client_context.require_version_min(7, 0, -1) diff --git a/test/asynchronous/unified_format.py b/test/asynchronous/unified_format.py index 8f32ac4a2..b382db474 100644 --- a/test/asynchronous/unified_format.py +++ b/test/asynchronous/unified_format.py @@ -14,7 +14,7 @@ """Unified test format runner. -https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst +https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md """ from __future__ import annotations @@ -431,7 +431,7 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest): """Mixin class to run test cases from test specification files. Assumes that tests conform to the `unified test format - `_. + `_. Specification of the test suite being currently run is available as a class attribute ``TEST_SPEC``. diff --git a/test/auth/legacy/connection-string.json b/test/auth/legacy/connection-string.json index 57fd9d4a1..67aafbff6 100644 --- a/test/auth/legacy/connection-string.json +++ b/test/auth/legacy/connection-string.json @@ -80,7 +80,7 @@ }, { "description": "should accept generic mechanism property (GSSAPI)", - "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com", "valid": true, "credential": { "username": "user@DOMAIN.COM", @@ -89,10 +89,46 @@ "mechanism": "GSSAPI", "mechanism_properties": { "SERVICE_NAME": "other", - "CANONICALIZE_HOST_NAME": true + "SERVICE_HOST": "example.com", + "CANONICALIZE_HOST_NAME": "forward" } } }, + { + "description": "should accept forwardAndReverse hostname canonicalization (GSSAPI)", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forwardAndReverse", + "valid": true, + "credential": { + "username": "user@DOMAIN.COM", + "password": null, + "source": "$external", + "mechanism": "GSSAPI", + "mechanism_properties": { + "SERVICE_NAME": "other", + "CANONICALIZE_HOST_NAME": "forwardAndReverse" + } + } + }, + { + "description": "should accept no hostname canonicalization (GSSAPI)", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:none", + "valid": true, + "credential": { + "username": "user@DOMAIN.COM", + "password": null, + "source": "$external", + "mechanism": "GSSAPI", + "mechanism_properties": { + "SERVICE_NAME": "other", + "CANONICALIZE_HOST_NAME": "none" + } + } + }, + { + "description": "must raise an error when the hostname canonicalization is invalid", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:invalid", + "valid": false + }, { "description": "should accept the password (GSSAPI)", "uri": "mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI&authSource=$external", @@ -127,47 +163,6 @@ "uri": "mongodb://localhost/?authMechanism=GSSAPI", "valid": false }, - { - "description": "should recognize the mechanism (MONGODB-CR)", - "uri": "mongodb://user:password@localhost/?authMechanism=MONGODB-CR", - "valid": true, - "credential": { - "username": "user", - "password": "password", - "source": "admin", - "mechanism": "MONGODB-CR", - "mechanism_properties": null - } - }, - { - "description": "should use the database when no authSource is specified (MONGODB-CR)", - "uri": "mongodb://user:password@localhost/foo?authMechanism=MONGODB-CR", - "valid": true, - "credential": { - "username": "user", - "password": "password", - "source": "foo", - "mechanism": "MONGODB-CR", - "mechanism_properties": null - } - }, - { - "description": "should use the authSource when specified (MONGODB-CR)", - "uri": "mongodb://user:password@localhost/foo?authMechanism=MONGODB-CR&authSource=bar", - "valid": true, - "credential": { - "username": "user", - "password": "password", - "source": "bar", - "mechanism": "MONGODB-CR", - "mechanism_properties": null - } - }, - { - "description": "should throw an exception if no username is supplied (MONGODB-CR)", - "uri": "mongodb://localhost/?authMechanism=MONGODB-CR", - "valid": false - }, { "description": "should recognize the mechanism (MONGODB-X509)", "uri": "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509", @@ -474,14 +469,14 @@ } }, { - "description": "should throw an exception if username and password is specified for test environment (MONGODB-OIDC)", + "description": "should throw an exception if supplied a password (MONGODB-OIDC)", "uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test", "valid": false, "credential": null }, { - "description": "should throw an exception if username is specified for test environment (MONGODB-OIDC)", - "uri": "mongodb://principalName@localhost/?authMechanism=MONGODB-OIDC&ENVIRONMENT:test", + "description": "should throw an exception if username is specified for test (MONGODB-OIDC)", + "uri": "mongodb://principalName@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test", "valid": false, "credential": null }, @@ -492,11 +487,17 @@ "credential": null }, { - "description": "should throw an exception if neither provider nor callbacks specified (MONGODB-OIDC)", + "description": "should throw an exception if neither environment nor callbacks specified (MONGODB-OIDC)", "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC", "valid": false, "credential": null }, + { + "description": "should throw an exception when unsupported auth property is specified (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=UnsupportedProperty:unexisted", + "valid": false, + "credential": null + }, { "description": "should recognise the mechanism with azure provider (MONGODB-OIDC)", "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo", @@ -627,4 +628,4 @@ "credential": null } ] -} \ No newline at end of file +} diff --git a/test/connection_string/test/valid-auth.json b/test/connection_string/test/valid-auth.json index 4f684ff18..60f63f4e3 100644 --- a/test/connection_string/test/valid-auth.json +++ b/test/connection_string/test/valid-auth.json @@ -220,29 +220,8 @@ "options": null }, { - "description": "Escaped user info and database (MONGODB-CR)", - "uri": "mongodb://%24am:f%3Azzb%40z%2Fz%3D@127.0.0.1/admin%3F?authMechanism=MONGODB-CR", - "valid": true, - "warning": false, - "hosts": [ - { - "type": "ipv4", - "host": "127.0.0.1", - "port": null - } - ], - "auth": { - "username": "$am", - "password": "f:zzb@z/z=", - "db": "admin?" - }, - "options": { - "authmechanism": "MONGODB-CR" - } - }, - { - "description": "Subdelimiters in user/pass don't need escaping (MONGODB-CR)", - "uri": "mongodb://!$&'()*+,;=:!$&'()*+,;=@127.0.0.1/admin?authMechanism=MONGODB-CR", + "description": "Subdelimiters in user/pass don't need escaping (PLAIN)", + "uri": "mongodb://!$&'()*+,;=:!$&'()*+,;=@127.0.0.1/admin?authMechanism=PLAIN", "valid": true, "warning": false, "hosts": [ @@ -258,7 +237,7 @@ "db": "admin" }, "options": { - "authmechanism": "MONGODB-CR" + "authmechanism": "PLAIN" } }, { @@ -284,7 +263,7 @@ }, { "description": "Escaped username (GSSAPI)", - "uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authMechanism=GSSAPI", + "uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com&authMechanism=GSSAPI", "valid": true, "warning": false, "hosts": [ @@ -303,7 +282,8 @@ "authmechanism": "GSSAPI", "authmechanismproperties": { "SERVICE_NAME": "other", - "CANONICALIZE_HOST_NAME": true + "SERVICE_HOST": "example.com", + "CANONICALIZE_HOST_NAME": "forward" } } }, diff --git a/test/connection_string/test/valid-options.json b/test/connection_string/test/valid-options.json index 3c79fe7ae..6c86172d0 100644 --- a/test/connection_string/test/valid-options.json +++ b/test/connection_string/test/valid-options.json @@ -2,7 +2,7 @@ "tests": [ { "description": "Option names are normalized to lowercase", - "uri": "mongodb://alice:secret@example.com/admin?AUTHMechanism=MONGODB-CR", + "uri": "mongodb://alice:secret@example.com/admin?AUTHMechanism=PLAIN", "valid": true, "warning": false, "hosts": [ @@ -18,7 +18,7 @@ "db": "admin" }, "options": { - "authmechanism": "MONGODB-CR" + "authmechanism": "PLAIN" } }, { diff --git a/test/mockupdb/test_handshake.py b/test/mockupdb/test_handshake.py index 752c4f842..c2c978c4a 100644 --- a/test/mockupdb/test_handshake.py +++ b/test/mockupdb/test_handshake.py @@ -218,50 +218,19 @@ class TestHandshake(unittest.TestCase): request.ok( "ismaster", True, - saslSupportedMechs=["SCRAM-SHA-256"], + # Unsupported auth mech should be ignored. + saslSupportedMechs=["SCRAM-SHA-256", "does_not_exist"], speculativeAuthenticate=auth, minWireVersion=2, maxWireVersion=MIN_SUPPORTED_WIRE_VERSION, ) # Authentication should immediately fail with: # OperationFailure: Server returned an invalid nonce. - with self.assertRaises(OperationFailure): + with self.assertRaises(OperationFailure) as cm: future() + self.assertEqual(str(cm.exception), "Server returned an invalid nonce.") return - def test_client_handshake_saslSupportedMechs_unknown(self): - server = MockupDB() - server.run() - self.addCleanup(server.stop) - - primary_response = OpReply( - "ismaster", - True, - minWireVersion=2, - maxWireVersion=MIN_SUPPORTED_WIRE_VERSION, - saslSupportedMechs=["SCRAM-SHA-256", "does_not_exist"], - ) - client = MongoClient( - server.uri, authmechanism="PLAIN", username="username", password="password" - ) - - self.addCleanup(client.close) - - # New monitoring connections send data during handshake. - heartbeat = server.receives("ismaster") - heartbeat.ok(primary_response) - - future = go(client.db.command, "whatever") - for request in server: - if request.matches("ismaster"): - request.ok(primary_response) - elif request.matches("saslStart"): - request.ok("saslStart", True, conversationId=1, payload=b"", done=True, ok=1) - else: - request.ok() - future() - return - def test_handshake_load_balanced(self): self.hello_with_option_helper(OpMsg, loadBalanced=True) with self.assertRaisesRegex(AssertionError, "does not match"): diff --git a/test/test_auth.py b/test/test_auth.py index 310006aff..70c061b74 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -373,7 +373,7 @@ class TestSCRAMSHA1(IntegrationTest): db.command("dbstats") -# https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst#scram-sha-256-and-mechanism-negotiation +# https://github.com/mongodb/specifications/blob/master/source/auth/auth.md#scram-sha-256-and-mechanism-negotiation class TestSCRAM(IntegrationTest): @client_context.require_auth @client_context.require_version_min(3, 7, 2) diff --git a/test/test_dbref.py b/test/test_dbref.py index d170f43f5..ac2767a1c 100644 --- a/test/test_dbref.py +++ b/test/test_dbref.py @@ -128,7 +128,7 @@ class TestDBRef(unittest.TestCase): self.assertNotEqual(hash(dbref_1a), hash(dbref_2a)) -# https://github.com/mongodb/specifications/blob/master/source/dbref.rst#test-plan +# https://github.com/mongodb/specifications/blob/master/source/dbref/dbref.md#test-plan class TestDBRefSpec(unittest.TestCase): def test_decoding_1_2_3(self): doc: Any diff --git a/test/test_encryption.py b/test/test_encryption.py index 373981b1d..0806f91a0 100644 --- a/test/test_encryption.py +++ b/test/test_encryption.py @@ -1604,7 +1604,7 @@ class TestGCPEncryption(AzureGCPEncryptionTestMixin, EncryptionIntegrationTest): return self._test_automatic(expected_document_extjson, {"secret_gcp": "string0"}) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#deadlock-tests +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#deadlock-tests class TestDeadlockProse(EncryptionIntegrationTest): def setUp(self): self.client_test = self.rs_or_single_client( @@ -1829,7 +1829,7 @@ class TestDeadlockProse(EncryptionIntegrationTest): self.assertEqual(len(self.topology_listener.results["opened"]), 1) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#14-decryption-events +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#14-decryption-events class TestDecryptProse(EncryptionIntegrationTest): def setUp(self): self.client = client_context.client @@ -1901,7 +1901,7 @@ class TestDecryptProse(EncryptionIntegrationTest): self.assertEqual(event.reply["cursor"]["firstBatch"][0]["encrypted"], self.cipher_text) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#bypass-spawning-mongocryptd +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#bypass-spawning-mongocryptd class TestBypassSpawningMongocryptdProse(EncryptionIntegrationTest): @unittest.skipIf( os.environ.get("TEST_CRYPT_SHARED"), @@ -1982,7 +1982,7 @@ class TestBypassSpawningMongocryptdProse(EncryptionIntegrationTest): with self.assertRaises(ServerSelectionTimeoutError): no_mongocryptd_client.db.command("ping") - # https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#20-bypass-creating-mongocryptd-client-when-shared-library-is-loaded + # https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#20-bypass-creating-mongocryptd-client-when-shared-library-is-loaded @unittest.skipUnless(os.environ.get("TEST_CRYPT_SHARED"), "crypt_shared lib is not installed") def test_client_via_loading_shared_library(self): connection_established = False @@ -2058,7 +2058,7 @@ class TestKmsTLSProse(EncryptionIntegrationTest): self.client_encrypted.create_data_key("aws", master_key=key) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#kms-tls-options-tests +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#kms-tls-options-tests class TestKmsTLSOptions(EncryptionIntegrationTest): @unittest.skipUnless(any(AWS_CREDS.values()), "AWS environment credentials are not set") def setUp(self): @@ -2264,7 +2264,7 @@ class TestKmsTLSOptions(EncryptionIntegrationTest): self.client_encryption_with_names.create_data_key("kmip:with_tls") -# https://github.com/mongodb/specifications/blob/50e26fe/source/client-side-encryption/tests/README.rst#unique-index-on-keyaltnames +# https://github.com/mongodb/specifications/blob/50e26fe/source/client-side-encryption/tests/README.md#unique-index-on-keyaltnames class TestUniqueIndexOnKeyAltNamesProse(EncryptionIntegrationTest): def setUp(self): self.client = client_context.client @@ -2293,7 +2293,7 @@ class TestUniqueIndexOnKeyAltNamesProse(EncryptionIntegrationTest): assert key_doc["keyAltNames"] == ["def"] -# https://github.com/mongodb/specifications/blob/d4c9432/source/client-side-encryption/tests/README.rst#explicit-encryption +# https://github.com/mongodb/specifications/blob/d4c9432/source/client-side-encryption/tests/README.md#explicit-encryption class TestExplicitQueryableEncryption(EncryptionIntegrationTest): @client_context.require_no_standalone @client_context.require_version_min(7, 0, -1) @@ -2407,7 +2407,7 @@ class TestExplicitQueryableEncryption(EncryptionIntegrationTest): self.assertEqual(decrypted, val) -# https://github.com/mongodb/specifications/blob/072601/source/client-side-encryption/tests/README.rst#rewrap +# https://github.com/mongodb/specifications/blob/072601/source/client-side-encryption/tests/README.md#rewrap class TestRewrapWithSeparateClientEncryption(EncryptionIntegrationTest): MASTER_KEYS: Mapping[str, Mapping[str, Any]] = { "aws": { @@ -2489,7 +2489,7 @@ class TestRewrapWithSeparateClientEncryption(EncryptionIntegrationTest): ) -# https://github.com/mongodb/specifications/blob/5cf3ed/source/client-side-encryption/tests/README.rst#on-demand-aws-credentials +# https://github.com/mongodb/specifications/blob/5cf3ed/source/client-side-encryption/tests/README.md#on-demand-aws-credentials class TestOnDemandAWSCredentials(EncryptionIntegrationTest): def setUp(self): super().setUp() @@ -2851,7 +2851,7 @@ class TestRangeQueryDefaultsProse(EncryptionIntegrationTest): assert len(payload) > len(self.payload_defaults) -# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#automatic-data-encryption-keys +# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#automatic-data-encryption-keys class TestAutomaticDecryptionKeys(EncryptionIntegrationTest): @client_context.require_no_standalone @client_context.require_version_min(7, 0, -1) diff --git a/test/test_streaming_protocol.py b/test/test_streaming_protocol.py index b3b68703a..d782aa1dd 100644 --- a/test/test_streaming_protocol.py +++ b/test/test_streaming_protocol.py @@ -142,7 +142,7 @@ class TestStreamingProtocol(IntegrationTest): @client_context.require_failCommand_appName def test_monitor_waits_after_server_check_error(self): # This test implements: - # https://github.com/mongodb/specifications/blob/6c5b2ac/source/server-discovery-and-monitoring/server-discovery-and-monitoring-tests.rst#monitors-sleep-at-least-minheartbeatfreqencyms-between-checks + # https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-tests.md#monitors-sleep-at-least-minheartbeatfreqencyms-between-checks fail_hello = { "mode": {"times": 5}, "data": { diff --git a/test/test_uri_parser.py b/test/test_uri_parser.py index 2a68e9a2c..f95717e95 100644 --- a/test/test_uri_parser.py +++ b/test/test_uri_parser.py @@ -142,7 +142,6 @@ class TestURI(unittest.TestCase): self.assertEqual({"fsync": True}, split_options("fsync=true")) self.assertEqual({"fsync": False}, split_options("fsync=false")) self.assertEqual({"authmechanism": "GSSAPI"}, split_options("authMechanism=GSSAPI")) - self.assertEqual({"authmechanism": "MONGODB-CR"}, split_options("authMechanism=MONGODB-CR")) self.assertEqual( {"authmechanism": "SCRAM-SHA-1"}, split_options("authMechanism=SCRAM-SHA-1") ) @@ -295,30 +294,30 @@ class TestURI(unittest.TestCase): # Various authentication tests res = copy.deepcopy(orig) - res["options"] = {"authmechanism": "MONGODB-CR"} + res["options"] = {"authmechanism": "SCRAM-SHA-256"} res["username"] = "user" res["password"] = "password" self.assertEqual( - res, parse_uri("mongodb://user:password@localhost/?authMechanism=MONGODB-CR") + res, parse_uri("mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-256") ) res = copy.deepcopy(orig) - res["options"] = {"authmechanism": "MONGODB-CR", "authsource": "bar"} + res["options"] = {"authmechanism": "SCRAM-SHA-256", "authsource": "bar"} res["username"] = "user" res["password"] = "password" res["database"] = "foo" self.assertEqual( res, parse_uri( - "mongodb://user:password@localhost/foo?authSource=bar;authMechanism=MONGODB-CR" + "mongodb://user:password@localhost/foo?authSource=bar;authMechanism=SCRAM-SHA-256" ), ) res = copy.deepcopy(orig) - res["options"] = {"authmechanism": "MONGODB-CR"} + res["options"] = {"authmechanism": "SCRAM-SHA-256"} res["username"] = "user" res["password"] = "" - self.assertEqual(res, parse_uri("mongodb://user:@localhost/?authMechanism=MONGODB-CR")) + self.assertEqual(res, parse_uri("mongodb://user:@localhost/?authMechanism=SCRAM-SHA-256")) res = copy.deepcopy(orig) res["username"] = "user@domain.com" diff --git a/test/unified_format.py b/test/unified_format.py index be7fc1f8a..0da616830 100644 --- a/test/unified_format.py +++ b/test/unified_format.py @@ -14,7 +14,7 @@ """Unified test format runner. -https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst +https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md """ from __future__ import annotations @@ -431,7 +431,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest): """Mixin class to run test cases from test specification files. Assumes that tests conform to the `unified test format - `_. + `_. Specification of the test suite being currently run is available as a class attribute ``TEST_SPEC``. diff --git a/test/unified_format_shared.py b/test/unified_format_shared.py index f1b908a7a..f315a77f4 100644 --- a/test/unified_format_shared.py +++ b/test/unified_format_shared.py @@ -14,7 +14,7 @@ """Shared utility functions and constants for the unified test format runner. -https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst +https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md """ from __future__ import annotations