From 7b2ebb762a15f15d520d3eb79e4fbbf3bbee069f Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Thu, 27 Aug 2026 11:17:06 -0400 Subject: [PATCH 1/2] PYTHON-6056 - Search index helper prose tests are flaky --- test/asynchronous/test_index_management.py | 9 +++++++++ test/test_index_management.py | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/test/asynchronous/test_index_management.py b/test/asynchronous/test_index_management.py index 09b4f364c0..a94906bb5e 100644 --- a/test/asynchronous/test_index_management.py +++ b/test/asynchronous/test_index_management.py @@ -27,6 +27,8 @@ import pytest +from test.asynchronous.utils import flaky + sys.path[0:0] = [""] from pymongo.errors import OperationFailure @@ -138,6 +140,7 @@ async def test_comment_field(self): class TestSearchIndexProse(SearchIndexIntegrationBase): db_name = "test_search_index_prose" + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_1(self): """Driver can successfully create and list search indexes.""" @@ -156,6 +159,7 @@ async def test_case_1(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], model["definition"]) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_2(self): """Driver can successfully create multiple indexes in batch.""" @@ -188,6 +192,7 @@ async def test_case_2(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], definition) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_3(self): """Driver can successfully drop search indexes.""" @@ -215,6 +220,7 @@ async def test_case_3(self): raise TimeoutError("Timed out waiting for index deletion") await asyncio.sleep(5) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_4(self): """Driver can update a search index.""" @@ -245,6 +251,7 @@ async def test_case_4(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], model2["definition"]) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_5(self): """``dropSearchIndex`` suppresses namespace not found errors.""" # Create a driver-side collection object for a randomly generated collection name. Do not create this collection on the server. @@ -253,6 +260,7 @@ async def test_case_5(self): # Run a ``dropSearchIndex`` command and assert that no error is thrown. await coll0.drop_search_index("foo") + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_6(self): """Driver can successfully create and list search indexes with non-default readConcern and writeConcern.""" @@ -277,6 +285,7 @@ async def test_case_6(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], model["definition"]) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) async def test_case_7(self): """Driver handles index types.""" diff --git a/test/test_index_management.py b/test/test_index_management.py index 6dbd7b9c01..6af2534cff 100644 --- a/test/test_index_management.py +++ b/test/test_index_management.py @@ -27,6 +27,8 @@ import pytest +from test.utils import flaky + sys.path[0:0] = [""] from pymongo.errors import OperationFailure @@ -136,6 +138,7 @@ def test_comment_field(self): class TestSearchIndexProse(SearchIndexIntegrationBase): db_name = "test_search_index_prose" + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_1(self): """Driver can successfully create and list search indexes.""" @@ -154,6 +157,7 @@ def test_case_1(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], model["definition"]) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_2(self): """Driver can successfully create multiple indexes in batch.""" @@ -186,6 +190,7 @@ def test_case_2(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], definition) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_3(self): """Driver can successfully drop search indexes.""" @@ -213,6 +218,7 @@ def test_case_3(self): raise TimeoutError("Timed out waiting for index deletion") time.sleep(5) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_4(self): """Driver can update a search index.""" @@ -243,6 +249,7 @@ def test_case_4(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], model2["definition"]) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_5(self): """``dropSearchIndex`` suppresses namespace not found errors.""" # Create a driver-side collection object for a randomly generated collection name. Do not create this collection on the server. @@ -251,6 +258,7 @@ def test_case_5(self): # Run a ``dropSearchIndex`` command and assert that no error is thrown. coll0.drop_search_index("foo") + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_6(self): """Driver can successfully create and list search indexes with non-default readConcern and writeConcern.""" @@ -275,6 +283,7 @@ def test_case_6(self): self.assertIn("latestDefinition", index) self.assertEqual(index["latestDefinition"], model["definition"]) + @flaky(reason="PYTHON-6056", affects_cpython_linux=True) def test_case_7(self): """Driver handles index types.""" From 51ced7f66b38909fb17a1084e988dd0b78d01d29 Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Fri, 28 Aug 2026 16:33:56 -0400 Subject: [PATCH 2/2] Cleanup indexes between attemots --- test/asynchronous/test_index_management.py | 22 +++++++++++++++++++++- test/test_index_management.py | 22 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/test/asynchronous/test_index_management.py b/test/asynchronous/test_index_management.py index a94906bb5e..59ce89e686 100644 --- a/test/asynchronous/test_index_management.py +++ b/test/asynchronous/test_index_management.py @@ -18,7 +18,6 @@ import asyncio import os -import pathlib import sys import time import uuid @@ -114,6 +113,18 @@ async def wait_for_ready(self, coll, name=_NAME, predicate=None): return indices[0] await asyncio.sleep(5) + async def drop_and_wait(self, coll, name): + """Drop a search index and wait for it to be dropped.""" + await coll.drop_search_index(name) + start = time.time() + while True: + indices = await (await coll.list_search_indexes(name)).to_list() + if not indices: + return + if (time.time() - start) / 60 > 5: + raise TimeoutError("Timed out waiting for index deletion") + await asyncio.sleep(5) + class TestSearchIndexIntegration(SearchIndexIntegrationBase): db_name = "test_search_index" @@ -147,6 +158,7 @@ async def test_case_1(self): # Create a new search index on ``self.coll0`` with the ``createSearchIndex`` helper. Use the following definition: model = {"name": _NAME, "definition": {"mappings": {"dynamic": False}}} resp = await self.coll0.create_search_index(model) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, _NAME) # Assert that the command returns the name of the index: ``"test-search-index"``. self.assertEqual(resp, _NAME) @@ -174,6 +186,8 @@ async def test_case_2(self): await self.coll0.create_search_indexes( [SearchIndexModel(i["definition"], i["name"]) for i in index_definitions] ) + for index in index_definitions: + self.addAsyncCleanup(self.drop_and_wait, self.coll0, index["name"]) # .Assert that the command returns an array containing the new indexes' names: ``["test-search-index-1", "test-search-index-2"]``. indices = await (await self.coll0.list_search_indexes()).to_list() @@ -199,6 +213,7 @@ async def test_case_3(self): # Create a new search index on ``self.coll0``. model = {"name": _NAME, "definition": {"mappings": {"dynamic": False}}} resp = await self.coll0.create_search_index(model) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, _NAME) # Assert that the command returns the name of the index: ``"test-search-index"``. self.assertEqual(resp, "test-search-index") @@ -227,6 +242,7 @@ async def test_case_4(self): # Create a new search index on ``self.coll0``. model = {"name": _NAME, "definition": {"mappings": {"dynamic": False}}} resp = await self.coll0.create_search_index(model) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, _NAME) # Assert that the command returns the name of the index: ``"test-search-index"``. self.assertEqual(resp, _NAME) @@ -273,6 +289,7 @@ async def test_case_6(self): name = "test-search-index-case6" model = {"name": name, "definition": {"mappings": {"dynamic": False}}} resp = await coll0.create_search_index(model) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, name) # Assert that the command returns the name of the index: ``"test-search-index-case6"``. self.assertEqual(resp, name) @@ -306,6 +323,7 @@ async def test_case_7(self): implicit_search_resp = await self.coll0.create_search_index( model={"name": _NAME + "-implicit", "definition": search_definition} ) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, _NAME + "-implicit") # Get the index definition. resp = await (await self.coll0.list_search_indexes(name=implicit_search_resp)).next() @@ -317,6 +335,7 @@ async def test_case_7(self): explicit_search_resp = await self.coll0.create_search_index( model={"name": _NAME + "-explicit", "type": "search", "definition": search_definition} ) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, _NAME + "-explicit") # Get the index definition. resp = await (await self.coll0.list_search_indexes(name=explicit_search_resp)).next() @@ -332,6 +351,7 @@ async def test_case_7(self): "definition": vector_search_definition, } ) + self.addAsyncCleanup(self.drop_and_wait, self.coll0, _NAME + "-vector") # Get the index definition. resp = await (await self.coll0.list_search_indexes(name=explicit_vector_resp)).next() diff --git a/test/test_index_management.py b/test/test_index_management.py index 6af2534cff..557f9ab93d 100644 --- a/test/test_index_management.py +++ b/test/test_index_management.py @@ -18,7 +18,6 @@ import asyncio import os -import pathlib import sys import time import uuid @@ -114,6 +113,18 @@ def wait_for_ready(self, coll, name=_NAME, predicate=None): return indices[0] time.sleep(5) + def drop_and_wait(self, coll, name): + """Drop a search index and wait for it to be dropped.""" + coll.drop_search_index(name) + start = time.time() + while True: + indices = (coll.list_search_indexes(name)).to_list() + if not indices: + return + if (time.time() - start) / 60 > 5: + raise TimeoutError("Timed out waiting for index deletion") + time.sleep(5) + class TestSearchIndexIntegration(SearchIndexIntegrationBase): db_name = "test_search_index" @@ -145,6 +156,7 @@ def test_case_1(self): # Create a new search index on ``self.coll0`` with the ``createSearchIndex`` helper. Use the following definition: model = {"name": _NAME, "definition": {"mappings": {"dynamic": False}}} resp = self.coll0.create_search_index(model) + self.addCleanup(self.drop_and_wait, self.coll0, _NAME) # Assert that the command returns the name of the index: ``"test-search-index"``. self.assertEqual(resp, _NAME) @@ -172,6 +184,8 @@ def test_case_2(self): self.coll0.create_search_indexes( [SearchIndexModel(i["definition"], i["name"]) for i in index_definitions] ) + for index in index_definitions: + self.addCleanup(self.drop_and_wait, self.coll0, index["name"]) # .Assert that the command returns an array containing the new indexes' names: ``["test-search-index-1", "test-search-index-2"]``. indices = (self.coll0.list_search_indexes()).to_list() @@ -197,6 +211,7 @@ def test_case_3(self): # Create a new search index on ``self.coll0``. model = {"name": _NAME, "definition": {"mappings": {"dynamic": False}}} resp = self.coll0.create_search_index(model) + self.addCleanup(self.drop_and_wait, self.coll0, _NAME) # Assert that the command returns the name of the index: ``"test-search-index"``. self.assertEqual(resp, "test-search-index") @@ -225,6 +240,7 @@ def test_case_4(self): # Create a new search index on ``self.coll0``. model = {"name": _NAME, "definition": {"mappings": {"dynamic": False}}} resp = self.coll0.create_search_index(model) + self.addCleanup(self.drop_and_wait, self.coll0, _NAME) # Assert that the command returns the name of the index: ``"test-search-index"``. self.assertEqual(resp, _NAME) @@ -271,6 +287,7 @@ def test_case_6(self): name = "test-search-index-case6" model = {"name": name, "definition": {"mappings": {"dynamic": False}}} resp = coll0.create_search_index(model) + self.addCleanup(self.drop_and_wait, self.coll0, name) # Assert that the command returns the name of the index: ``"test-search-index-case6"``. self.assertEqual(resp, name) @@ -304,6 +321,7 @@ def test_case_7(self): implicit_search_resp = self.coll0.create_search_index( model={"name": _NAME + "-implicit", "definition": search_definition} ) + self.addCleanup(self.drop_and_wait, self.coll0, _NAME + "-implicit") # Get the index definition. resp = (self.coll0.list_search_indexes(name=implicit_search_resp)).next() @@ -315,6 +333,7 @@ def test_case_7(self): explicit_search_resp = self.coll0.create_search_index( model={"name": _NAME + "-explicit", "type": "search", "definition": search_definition} ) + self.addCleanup(self.drop_and_wait, self.coll0, _NAME + "-explicit") # Get the index definition. resp = (self.coll0.list_search_indexes(name=explicit_search_resp)).next() @@ -330,6 +349,7 @@ def test_case_7(self): "definition": vector_search_definition, } ) + self.addCleanup(self.drop_and_wait, self.coll0, _NAME + "-vector") # Get the index definition. resp = (self.coll0.list_search_indexes(name=explicit_vector_resp)).next()