diff --git a/.evergreen/generated_configs/tasks.yml b/.evergreen/generated_configs/tasks.yml index b2b8dc119..89d8ff8d6 100644 --- a/.evergreen/generated_configs/tasks.yml +++ b/.evergreen/generated_configs/tasks.yml @@ -820,19 +820,7 @@ tasks: - name: coverage-report commands: - func: download and merge coverage - depends_on: - - name: .standalone - variant: .coverage_tag - status: "*" - patch_optional: true - - name: .replica_set - variant: .coverage_tag - status: "*" - patch_optional: true - - name: .sharded_cluster - variant: .coverage_tag - status: "*" - patch_optional: true + depends_on: [{ name: .server-version, variant: .coverage_tag, status: "*", patch_optional: true }] tags: [coverage] # Doctest tests @@ -8031,6 +8019,274 @@ tasks: - nossl - sync_async + # Server version tests + - name: test-python3.9-auth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.9" + tags: [server-version, "3.9", sharded_cluster-auth-ssl] + - name: test-python3.10-auth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.10" + tags: [server-version, "3.10", sharded_cluster-auth-ssl] + - name: test-python3.11-auth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.11" + tags: [server-version, "3.11", sharded_cluster-auth-ssl] + - name: test-python3.12-auth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.12" + tags: [server-version, "3.12", sharded_cluster-auth-ssl] + - name: test-python3.13-auth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.13" + tags: [server-version, "3.13", sharded_cluster-auth-ssl] + - name: test-pypy3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + PYTHON_VERSION: pypy3.10 + tags: [server-version, pypy3.10, sharded_cluster-auth-ssl] + - name: test-python3.9-auth-ssl-standalone-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: standalone + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: standalone + COVERAGE: "1" + PYTHON_VERSION: "3.9" + tags: [server-version, "3.9", standalone-auth-ssl] + - name: test-python3.10-auth-nossl-standalone-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: nossl + TOPOLOGY: standalone + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: nossl + TOPOLOGY: standalone + COVERAGE: "1" + PYTHON_VERSION: "3.10" + tags: [server-version, "3.10", standalone-auth-nossl] + - name: test-python3.11-noauth-ssl-standalone-cov + commands: + - func: run server + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: standalone + COVERAGE: "1" + - func: run tests + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: standalone + COVERAGE: "1" + PYTHON_VERSION: "3.11" + tags: [server-version, "3.11", standalone-noauth-ssl] + - name: test-python3.12-noauth-nossl-standalone-cov + commands: + - func: run server + vars: + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone + COVERAGE: "1" + - func: run tests + vars: + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone + COVERAGE: "1" + PYTHON_VERSION: "3.12" + tags: [server-version, "3.12", standalone-noauth-nossl] + - name: test-python3.13-auth-ssl-replica-set-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: replica_set + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: replica_set + COVERAGE: "1" + PYTHON_VERSION: "3.13" + tags: [server-version, "3.13", replica_set-auth-ssl] + - name: test-pypy3.10-auth-nossl-replica-set + commands: + - func: run server + vars: + AUTH: auth + SSL: nossl + TOPOLOGY: replica_set + - func: run tests + vars: + AUTH: auth + SSL: nossl + TOPOLOGY: replica_set + PYTHON_VERSION: pypy3.10 + tags: [server-version, pypy3.10, replica_set-auth-nossl] + - name: test-python3.9-noauth-ssl-replica-set-cov + commands: + - func: run server + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: replica_set + COVERAGE: "1" + - func: run tests + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: replica_set + COVERAGE: "1" + PYTHON_VERSION: "3.9" + tags: [server-version, "3.9", replica_set-noauth-ssl] + - name: test-python3.10-noauth-nossl-replica-set-cov + commands: + - func: run server + vars: + AUTH: noauth + SSL: nossl + TOPOLOGY: replica_set + COVERAGE: "1" + - func: run tests + vars: + AUTH: noauth + SSL: nossl + TOPOLOGY: replica_set + COVERAGE: "1" + PYTHON_VERSION: "3.10" + tags: [server-version, "3.10", replica_set-noauth-nossl] + - name: test-python3.12-auth-nossl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: nossl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: auth + SSL: nossl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.12" + tags: [server-version, "3.12", sharded_cluster-auth-nossl] + - name: test-python3.13-noauth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + - func: run tests + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: sharded_cluster + COVERAGE: "1" + PYTHON_VERSION: "3.13" + tags: [server-version, "3.13", sharded_cluster-noauth-ssl] + - name: test-pypy3.10-noauth-nossl-sharded-cluster + commands: + - func: run server + vars: + AUTH: noauth + SSL: nossl + TOPOLOGY: sharded_cluster + - func: run tests + vars: + AUTH: noauth + SSL: nossl + TOPOLOGY: sharded_cluster + PYTHON_VERSION: pypy3.10 + tags: [server-version, pypy3.10, sharded_cluster-noauth-nossl] + # Serverless tests - name: test-serverless commands: diff --git a/.evergreen/generated_configs/variants.yml b/.evergreen/generated_configs/variants.yml index 940c4e9b0..0aa2ac745 100644 --- a/.evergreen/generated_configs/variants.yml +++ b/.evergreen/generated_configs/variants.yml @@ -805,114 +805,6 @@ buildvariants: PYTHON_BINARY: /opt/python/3.9/bin/python3 # Server tests - - name: test-rhel8-python3.9-cov-no-c - tasks: - - name: .standalone .sync_async - - name: .replica_set .sync_async - - name: .sharded_cluster .sync_async - display_name: "* Test RHEL8 Python3.9 cov No C" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - NO_EXT: "1" - PYTHON_BINARY: /opt/python/3.9/bin/python3 - tags: [coverage_tag] - - name: test-rhel8-python3.9-cov - tasks: - - name: .standalone .sync_async - - name: .replica_set .sync_async - - name: .sharded_cluster .sync_async - display_name: "* Test RHEL8 Python3.9 cov" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - PYTHON_BINARY: /opt/python/3.9/bin/python3 - tags: [coverage_tag] - - name: test-rhel8-python3.13-cov-no-c - tasks: - - name: .standalone .sync_async - - name: .replica_set .sync_async - - name: .sharded_cluster .sync_async - display_name: "* Test RHEL8 Python3.13 cov No C" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - NO_EXT: "1" - PYTHON_BINARY: /opt/python/3.13/bin/python3 - tags: [coverage_tag] - - name: test-rhel8-python3.13-cov - tasks: - - name: .standalone .sync_async - - name: .replica_set .sync_async - - name: .sharded_cluster .sync_async - display_name: "* Test RHEL8 Python3.13 cov" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - PYTHON_BINARY: /opt/python/3.13/bin/python3 - tags: [coverage_tag] - - name: test-rhel8-pypy3.10-cov-no-c - tasks: - - name: .standalone .sync_async - - name: .replica_set .sync_async - - name: .sharded_cluster .sync_async - display_name: "* Test RHEL8 PyPy3.10 cov No C" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - NO_EXT: "1" - PYTHON_BINARY: /opt/python/pypy3.10/bin/python3 - tags: [coverage_tag] - - name: test-rhel8-pypy3.10-cov - tasks: - - name: .standalone .sync_async - - name: .replica_set .sync_async - - name: .sharded_cluster .sync_async - display_name: "* Test RHEL8 PyPy3.10 cov" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - PYTHON_BINARY: /opt/python/pypy3.10/bin/python3 - tags: [coverage_tag] - - name: test-rhel8-python3.10 - tasks: - - name: .sharded_cluster .auth .ssl .sync_async - - name: .replica_set .noauth .ssl .sync_async - - name: .standalone .noauth .nossl .sync_async - display_name: "* Test RHEL8 Python3.10" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - PYTHON_BINARY: /opt/python/3.10/bin/python3 - - name: test-rhel8-python3.11 - tasks: - - name: .sharded_cluster .auth .ssl .sync_async - - name: .replica_set .noauth .ssl .sync_async - - name: .standalone .noauth .nossl .sync_async - display_name: "* Test RHEL8 Python3.11" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - PYTHON_BINARY: /opt/python/3.11/bin/python3 - - name: test-rhel8-python3.12 - tasks: - - name: .sharded_cluster .auth .ssl .sync_async - - name: .replica_set .noauth .ssl .sync_async - - name: .standalone .noauth .nossl .sync_async - display_name: "* Test RHEL8 Python3.12" - run_on: - - rhel87-small - expansions: - COVERAGE: coverage - PYTHON_BINARY: /opt/python/3.12/bin/python3 - name: test-macos-python3.9 tasks: - name: .sharded_cluster .auth .ssl !.sync_async @@ -1018,6 +910,71 @@ buildvariants: expansions: PYTHON_BINARY: C:/python/32/Python313/python.exe + # Server version tests + - name: mongodb-v4.0 + tasks: + - name: .server-version + display_name: "* MongoDB v4.0" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-v4.2 + tasks: + - name: .server-version + display_name: "* MongoDB v4.2" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-v4.4 + tasks: + - name: .server-version + display_name: "* MongoDB v4.4" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-v5.0 + tasks: + - name: .server-version + display_name: "* MongoDB v5.0" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-v6.0 + tasks: + - name: .server-version + display_name: "* MongoDB v6.0" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-v7.0 + tasks: + - name: .server-version + display_name: "* MongoDB v7.0" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-v8.0 + tasks: + - name: .server-version + display_name: "* MongoDB v8.0" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-rapid + tasks: + - name: .server-version + display_name: "* MongoDB rapid" + run_on: + - rhel87-small + tags: [coverage_tag] + - name: mongodb-latest + tasks: + - name: .server-version + display_name: "* MongoDB latest" + run_on: + - rhel87-small + tags: [coverage_tag] + # Serverless tests - name: serverless-rhel8-python3.9 tasks: diff --git a/.evergreen/scripts/generate_config.py b/.evergreen/scripts/generate_config.py index afa97f390..2f1e97825 100644 --- a/.evergreen/scripts/generate_config.py +++ b/.evergreen/scripts/generate_config.py @@ -66,39 +66,20 @@ def create_ocsp_variants() -> list[BuildVariant]: return variants +def create_server_version_variants() -> list[BuildVariant]: + variants = [] + for version in ALL_VERSIONS: + display_name = get_variant_name("* MongoDB", version=version) + variant = create_variant( + [".server-version"], display_name, host=DEFAULT_HOST, tags=["coverage_tag"] + ) + variants.append(variant) + return variants + + def create_server_variants() -> list[BuildVariant]: variants = [] - - # Run the full matrix on linux with min and max CPython, and latest pypy. - host = DEFAULT_HOST - # Prefix the display name with an asterisk so it is sorted first. base_display_name = "* Test" - for python, c_ext in product([*MIN_MAX_PYTHON, PYPYS[-1]], C_EXTS): - expansions = dict(COVERAGE="coverage") - handle_c_ext(c_ext, expansions) - display_name = get_variant_name(base_display_name, host, python=python, **expansions) - variant = create_variant( - [f".{t} .sync_async" for t in TOPOLOGIES], - display_name, - python=python, - host=host, - tags=["coverage_tag"], - expansions=expansions, - ) - variants.append(variant) - - # Test the rest of the pythons. - for python in CPYTHONS[1:-1] + PYPYS[:-1]: - display_name = f"Test {host}" - display_name = get_variant_name(base_display_name, host, python=python) - variant = create_variant( - [f"{t} .sync_async" for t in SUB_TASKS], - display_name, - python=python, - host=host, - expansions=expansions, - ) - variants.append(variant) # Test a subset on each of the other platforms. for host_name in ("macos", "macos-arm64", "win64", "win32"): @@ -597,6 +578,32 @@ def create_aws_lambda_variants(): ############## +def create_server_version_tasks(): + tasks = [] + # Test all pythons with sharded_cluster, auth, and ssl. + task_types = [(p, "sharded_cluster", "auth", "ssl") for p in ALL_PYTHONS] + # Test all combinations of topology, auth, and ssl, with rotating pythons. + for (topology, auth, ssl), python in zip_cycle( + list(product(TOPOLOGIES, ["auth", "noauth"], ["ssl", "nossl"])), ALL_PYTHONS + ): + # Skip the ones we already have. + if topology == "sharded_cluster" and auth == "auth" and ssl == "ssl": + continue + task_types.append((python, topology, auth, ssl)) + for python, topology, auth, ssl in task_types: + tags = ["server-version", python, f"{topology}-{auth}-{ssl}"] + expansions = dict(AUTH=auth, SSL=ssl, TOPOLOGY=topology) + if python not in PYPYS: + expansions["COVERAGE"] = "1" + name = get_task_name("test", python=python, **expansions) + server_func = FunctionCall(func="run server", vars=expansions) + test_vars = expansions.copy() + test_vars["PYTHON_VERSION"] = python + test_func = FunctionCall(func="run tests", vars=test_vars) + tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func])) + return tasks + + def create_server_tasks(): tasks = [] for topo, version, (auth, ssl), sync in product(TOPOLOGIES, ALL_VERSIONS, AUTH_SSLS, SYNCS): @@ -882,11 +889,11 @@ def create_coverage_report_tasks(): # Instead list out all coverage tasks using tags. # Run the coverage task even if some tasks fail. # Run the coverage task even if some tasks are not scheduled in a patch build. - task_deps = [] - for name in [".standalone", ".replica_set", ".sharded_cluster"]: - task_deps.append( - EvgTaskDependency(name=name, variant=".coverage_tag", status="*", patch_optional=True) + task_deps = [ + EvgTaskDependency( + name=".server-version", variant=".coverage_tag", status="*", patch_optional=True ) + ] cmd = FunctionCall(func="download and merge coverage") return [EvgTask(name=task_name, tags=tags, depends_on=task_deps, commands=[cmd])] diff --git a/.evergreen/scripts/generate_config_utils.py b/.evergreen/scripts/generate_config_utils.py index a91501cf2..59de5beb7 100644 --- a/.evergreen/scripts/generate_config_utils.py +++ b/.evergreen/scripts/generate_config_utils.py @@ -40,8 +40,11 @@ SYNCS = ["sync", "async", "sync_async"] DISPLAY_LOOKUP = dict( ssl=dict(ssl="SSL", nossl="NoSSL"), auth=dict(auth="Auth", noauth="NoAuth"), + topology=dict( + standalone="Standalone", replica_set="Replica Set", sharded_cluster="Sharded Cluster" + ), test_suites=dict(default="Sync", default_async="Async"), - coverage=dict(coverage="cov"), + coverage={"1": "cov"}, no_ext={"1": "No C"}, ) HOSTS = dict() diff --git a/doc/changelog.rst b/doc/changelog.rst index 077c85bb4..e82804565 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,6 +1,23 @@ Changelog ========= + +Changes in Version 4.12.1 (XXXX/XX/XX) +-------------------------------------- + +Version 4.12.1 is a bug fix release. + +- Fixed a bug that could raise ``UnboundLocalError`` when creating asynchronous connections over SSL. +- Fixed a bug causing SRV hostname validation to fail when resolver and resolved hostnames are identical with three domain levels. + +Issues Resolved +............... + +See the `PyMongo 4.12.1 release notes in JIRA`_ for the list of resolved issues +in this release. + +.. _PyMongo 4.12.1 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=43094 + Changes in Version 4.12.0 (2025/04/08) -------------------------------------- diff --git a/pymongo/asynchronous/srv_resolver.py b/pymongo/asynchronous/srv_resolver.py index f7c67af3e..9d1b8fe14 100644 --- a/pymongo/asynchronous/srv_resolver.py +++ b/pymongo/asynchronous/srv_resolver.py @@ -96,6 +96,7 @@ class _SrvResolver: except Exception: raise ConfigurationError(_INVALID_HOST_MSG % (fqdn,)) from None self.__slen = len(self.__plist) + self.nparts = len(split_fqdn) async def get_options(self) -> Optional[str]: from dns import resolver @@ -137,12 +138,13 @@ class _SrvResolver: # Validate hosts for node in nodes: - if self.__fqdn == node[0].lower(): + srv_host = node[0].lower() + if self.__fqdn == srv_host and self.nparts < 3: raise ConfigurationError( "Invalid SRV host: return address is identical to SRV hostname" ) try: - nlist = node[0].lower().split(".")[1:][-self.__slen :] + nlist = srv_host.split(".")[1:][-self.__slen :] except Exception: raise ConfigurationError(f"Invalid SRV host: {node[0]}") from None if self.__plist != nlist: diff --git a/pymongo/pool_shared.py b/pymongo/pool_shared.py index a46a4d230..be7c416dc 100644 --- a/pymongo/pool_shared.py +++ b/pymongo/pool_shared.py @@ -346,12 +346,10 @@ async def _configured_protocol_interface( ssl=ssl_context, ) except _CertificateError: - transport.abort() # Raise _CertificateError directly like we do after match_hostname # below. raise except (OSError, SSLError) as exc: - transport.abort() # We raise AutoReconnect for transient and permanent SSL handshake # failures alike. Permanent handshake failures, like protocol # mismatch, will be turned into ServerSelectionTimeoutErrors later. diff --git a/pymongo/synchronous/srv_resolver.py b/pymongo/synchronous/srv_resolver.py index cf7b0842a..0817c6dcd 100644 --- a/pymongo/synchronous/srv_resolver.py +++ b/pymongo/synchronous/srv_resolver.py @@ -96,6 +96,7 @@ class _SrvResolver: except Exception: raise ConfigurationError(_INVALID_HOST_MSG % (fqdn,)) from None self.__slen = len(self.__plist) + self.nparts = len(split_fqdn) def get_options(self) -> Optional[str]: from dns import resolver @@ -137,12 +138,13 @@ class _SrvResolver: # Validate hosts for node in nodes: - if self.__fqdn == node[0].lower(): + srv_host = node[0].lower() + if self.__fqdn == srv_host and self.nparts < 3: raise ConfigurationError( "Invalid SRV host: return address is identical to SRV hostname" ) try: - nlist = node[0].lower().split(".")[1:][-self.__slen :] + nlist = srv_host.split(".")[1:][-self.__slen :] except Exception: raise ConfigurationError(f"Invalid SRV host: {node[0]}") from None if self.__plist != nlist: diff --git a/test/asynchronous/test_dns.py b/test/asynchronous/test_dns.py index 01c8d7b40..566661221 100644 --- a/test/asynchronous/test_dns.py +++ b/test/asynchronous/test_dns.py @@ -220,12 +220,15 @@ class TestInitialDnsSeedlistDiscovery(AsyncPyMongoTestCase): mock_resolver.side_effect = mock_resolve domain = case["query"].split("._tcp.")[1] connection_string = f"mongodb+srv://{domain}" - try: + if "expected_error" not in case: await parse_uri(connection_string) - except ConfigurationError as e: - self.assertIn(case["expected_error"], str(e)) else: - self.fail(f"ConfigurationError was not raised for query: {case['query']}") + try: + await parse_uri(connection_string) + except ConfigurationError as e: + self.assertIn(case["expected_error"], str(e)) + else: + self.fail(f"ConfigurationError was not raised for query: {case['query']}") async def test_1_allow_srv_hosts_with_fewer_than_three_dot_separated_parts(self): with patch("dns.asyncresolver.resolve"): @@ -289,6 +292,17 @@ class TestInitialDnsSeedlistDiscovery(AsyncPyMongoTestCase): ] await self.run_initial_dns_seedlist_discovery_prose_tests(test_cases) + async def test_5_when_srv_hostname_has_two_dot_separated_parts_it_is_valid_for_the_returned_hostname_to_be_identical( + self + ): + test_cases = [ + { + "query": "_mongodb._tcp.blogs.mongodb.com", + "mock_target": "blogs.mongodb.com", + }, + ] + await self.run_initial_dns_seedlist_discovery_prose_tests(test_cases) + if __name__ == "__main__": unittest.main() diff --git a/test/asynchronous/test_monitor.py b/test/asynchronous/test_monitor.py index 195f6f9fa..55a20d764 100644 --- a/test/asynchronous/test_monitor.py +++ b/test/asynchronous/test_monitor.py @@ -57,6 +57,7 @@ class TestMonitor(AsyncIntegrationTest): await connected(client) return client + @unittest.skipIf("PyPy" in sys.version, "PYTHON-5283 fails often on PyPy") async def test_cleanup_executors_on_client_del(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") diff --git a/test/test_dns.py b/test/test_dns.py index 9360f3f28..8f88562e3 100644 --- a/test/test_dns.py +++ b/test/test_dns.py @@ -218,12 +218,15 @@ class TestInitialDnsSeedlistDiscovery(PyMongoTestCase): mock_resolver.side_effect = mock_resolve domain = case["query"].split("._tcp.")[1] connection_string = f"mongodb+srv://{domain}" - try: + if "expected_error" not in case: parse_uri(connection_string) - except ConfigurationError as e: - self.assertIn(case["expected_error"], str(e)) else: - self.fail(f"ConfigurationError was not raised for query: {case['query']}") + try: + parse_uri(connection_string) + except ConfigurationError as e: + self.assertIn(case["expected_error"], str(e)) + else: + self.fail(f"ConfigurationError was not raised for query: {case['query']}") def test_1_allow_srv_hosts_with_fewer_than_three_dot_separated_parts(self): with patch("dns.resolver.resolve"): @@ -287,6 +290,17 @@ class TestInitialDnsSeedlistDiscovery(PyMongoTestCase): ] self.run_initial_dns_seedlist_discovery_prose_tests(test_cases) + def test_5_when_srv_hostname_has_two_dot_separated_parts_it_is_valid_for_the_returned_hostname_to_be_identical( + self + ): + test_cases = [ + { + "query": "_mongodb._tcp.blogs.mongodb.com", + "mock_target": "blogs.mongodb.com", + }, + ] + self.run_initial_dns_seedlist_discovery_prose_tests(test_cases) + if __name__ == "__main__": unittest.main() diff --git a/test/test_monitor.py b/test/test_monitor.py index 25620a99e..8bcdf7130 100644 --- a/test/test_monitor.py +++ b/test/test_monitor.py @@ -57,6 +57,7 @@ class TestMonitor(IntegrationTest): connected(client) return client + @unittest.skipIf("PyPy" in sys.version, "PYTHON-5283 fails often on PyPy") def test_cleanup_executors_on_client_del(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always")