Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PYTHON-5073 Convert test.test_connection_monitoring to async #2087

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

sleepyStick
Copy link
Contributor

Convert test.test_connection_monitoring to async

@sleepyStick sleepyStick requested a review from NoahStapp January 29, 2025 03:30
#
async def test_1_client_connection_pool_options(self):
client = await self.async_rs_or_single_client(**self.POOL_OPTIONS)
self.addAsyncCleanup(client.close)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our helper methods like self.async_rs_or_single_client call self.addAsyncCleanup(client.close) for us, so we don't need to do it ourselves.

def start(self, op):
"""Run the 'start' thread operation."""
target = op["target"]
thread = SpecRunnerThread(target)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a separate ticket to create an asynchronous version of SpecRunnerThread using asyncio tasks: https://jira.mongodb.org/browse/PYTHON-4864. Until we implement that ticket, we don't want to use a thread-based SpecRunnerThread for asynchronous tests due to the poor performance and inconsistent behavior of mixing threads and asyncio.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, until that ticket is complete, what should I do for the tests? (or is this going to need to wait for that ticket to be completed?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait ignore me, my brain is finally waking up and realizing that's what the last comment was for HAHA


class AsyncTestCMAP(AsyncIntegrationTest):
# Location of JSON test specifications.
TEST_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "connection_monitoring")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update this path to reflect the asynchronous subfolder inside test. The pattern is the same across all asynchronous tests that use a TEST_PATH:

if _IS_SYNC:
    _TEST_PATH = os.path.join(pathlib.Path(__file__).resolve().parent, <module_name>)
else:
    _TEST_PATH = os.path.join(pathlib.Path(__file__).resolve().parent.parent, <module_name>)

return [scenario_def]


test_creator = CMAPSpecTestCreator(create_test, AsyncTestCMAP, AsyncTestCMAP.TEST_PATH)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To only run the SpecRunnerThread tests on the sync API:

if _IS_SYNC:
    test_creator = CMAPSpecTestCreator(create_test, AsyncTestCMAP, AsyncTestCMAP.TEST_PATH)
    test_creator.create_tests()

@sleepyStick sleepyStick changed the title PYTHON-5072 Convert test.test_connection_monitoring to async PYTHON-5073 Convert test.test_connection_monitoring to async Jan 29, 2025
@sleepyStick sleepyStick marked this pull request as ready for review January 29, 2025 17:48
Copy link
Contributor

@NoahStapp NoahStapp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, just one minor cleanup!

@@ -83,7 +84,12 @@

class AsyncTestCMAP(AsyncIntegrationTest):
# Location of JSON test specifications.
TEST_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "connection_monitoring")
if _IS_SYNC:
TEST_PATH = os.path.join(pathlib.Path(__file__).resolve().parent, "connection_monitoring")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do Path instead of pathlib.Path and change the import to from pathlib import Path for clarity here.

@sleepyStick sleepyStick requested a review from NoahStapp January 29, 2025 20:17
Copy link
Contributor

@NoahStapp NoahStapp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, let's wait to merge this until #2094 is merged so we can add in the tests that rely on SpecRunnerThread too.

@sleepyStick sleepyStick requested a review from NoahStapp February 5, 2025 19:30
@@ -222,14 +222,14 @@ async def _create_tests(self):
test_type = os.path.splitext(filename)[0]

# Construct test from scenario.
for test_def in self.tests(scenario_def):
for test_def in await self.tests(scenario_def):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.tests is not asynchronous, so no await needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay i thought it was really weird too, but without the await i got the following error:

Traceback (most recent call last):
  File "/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/warnings.py", line 555, in _warn_unawaited_coroutine
    warn(msg, category=RuntimeWarning, stacklevel=2, source=coro)
RuntimeWarning: coroutine 'CMAPSpecTestCreator.tests' was never awaited

test/asynchronous/test_connection_monitoring.py:None (test/asynchronous/test_connection_monitoring.py)
test_connection_monitoring.py:475: in <module>
    test_creator.create_tests()
utils_spec_runner.py:243: in create_tests
    asyncio.run(self._create_tests())
/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py:194: in run
    return runner.run(main)
/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py:118: in run
    return self._loop.run_until_complete(task)
/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/base_events.py:686: in run_until_complete
    return future.result()
utils_spec_runner.py:225: in _create_tests
    for test_def in self.tests(scenario_def):
E   TypeError: 'coroutine' object is not iterable```

Copy link
Contributor

@NoahStapp NoahStapp Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, found the issue:

class CMAPSpecTestCreator(AsyncSpecTestCreator):
    async def tests(self, scenario_def):
		...

should be

class CMAPSpecTestCreator(AsyncSpecTestCreator):
   def tests(self, scenario_def):
		...

And then await self.tests() can become self.tests()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh! good find! thanks!

@sleepyStick sleepyStick requested a review from NoahStapp February 6, 2025 18:16
@NoahStapp
Copy link
Contributor

Encryption test failure is due to test_encryption's create_test being async when it should be sync: https://evergreen.mongodb.com/test_log/mongo_python_driver_encryption_rhel8_python3.10_test_4.0_sharded_cluster_auth_ssl_sync_async_patch_3dd44e6e5f89ffc6171c8ffc7ed052b620e35065_67a4fc4e7a1a330007e6f608_25_02_06_18_15_43/0?test_name=4b8a3fb7e7ebd8ee1a0182780cc2ba8a#L0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants