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

Upgrade test dependencies pytest and pytest-asyncio #1829

Merged
merged 6 commits into from
Dec 23, 2024

Conversation

flyinghyrax
Copy link
Contributor

@flyinghyrax flyinghyrax commented Dec 1, 2024

Dependency Upgrades

This performs the same version changes as #1656 and #1797 in a single merge request, since the associated issues and fixes appear to be related:

  • pytest => 8.3.4
  • pytest-asyncio => 0.24.0

This is a major version increment for pytest and a 0ver minor version increment for pytest-asyncio.

Unit Test Changes

Locally, I used pytest-randomly to shuffle the test execution order. Varying the test order uncovered a number of places where shared state was causing order-dependent failures.

  1. Tests that indirectly invoke a call to get_running_loop/get_event_loop require an event loop to be available even if the test itself and the code under test is not asynchronous. Depending on execution order an event loop was not always active when needed. I added asyncio marks to test modules wherever tests were failing because of this (or for 3.12, displaying a DeprecationWarning when there was no current event loop).

  2. Storage plugin instances store the current event loop as an attribute, and we cache initialized plugins globally. This led to some situations where

    1. An event loop created for one test was accessed in another, and had been closed closed and replaced with a new event loop
    2. A storage plugin for a non-filesystem backend was re-used by a later test where the filesystem backend was expected.

    I created fixtures to clear cached storage plugins between test modules. Most problems seemed solved by clearing between modules and I made that an autouse fixture. For one function in test_delete the scope needed to be narrower and there's a comment inline explaining that case.

Copy link

codecov bot commented Dec 1, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 86.19%. Comparing base (4d020e8) to head (a4dbbad).
Report is 183 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1829      +/-   ##
==========================================
+ Coverage   79.69%   86.19%   +6.50%     
==========================================
  Files          31       33       +2     
  Lines        4324     4391      +67     
  Branches      780      465     -315     
==========================================
+ Hits         3446     3785     +339     
+ Misses        721      428     -293     
- Partials      157      178      +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@flyinghyrax
Copy link
Contributor Author

The macOS and Linux test failures appear to show test_delete.py using the Swift storage plugin, and the swift http connection failing. That has the smell of the connection pool being created in a different event loop than the one used in delete_path. When I've got the time I'll look at getting a Swift container or something set up so I can debug it properly.

Copy link
Contributor

@cooperlees cooperlees left a comment

Choose a reason for hiding this comment

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

I think we want to use the storage backend loop still ... If I get some time I'll try revert that and see what error we get since I think your key check of

asyncio_default_fixture_loop_scope = function

was the big fix we needed as we need lots of event loops with how our tests are written ...

if dry_run:
logger.info(f" rm {blob_path}")
return 0
blob_exists = await storage_backend.loop.run_in_executor(
blob_exists = await loop.run_in_executor(
Copy link
Contributor

@cooperlees cooperlees Dec 2, 2024

Choose a reason for hiding this comment

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

I bet the backend loop is being patch / mocked or something to make the tests work. Especially for swift (I do need to delete swift support - no one is helping support it).

So I bet we don't want to do this change and workout why the backend's loop is failing here ...

@cooperlees
Copy link
Contributor

I can only repro locally on my Mac running latest minio with py3.11 ... on py3.12 it works ... which is interesting ....

This upgrades the two packages together:
- pytest => 8.x
- pytest-asyncio => 0.24.x

Commands used:

    pip install -U pytest pytest-asyncio
    pip freeze -r requirements_test.txt
0.24.x of pytest-asyncio adds a deprecation warning for the default
event loop fixture scope changing from fixture-cache to per-function.

This pre-emptively sets this option to align with the upcoming default.
Fixes order-dependent test failures in test_main.py caused by tests that
tried to initialize the singleton BandersnatchConfig instance when it
had already been created. This left the config out of sync with what the
tests expected.

Some tests in this module were already doing this with a call to a
'setup' function that erased the Singleton metaclass's stored instances.
This moves that into a pytest fixture and applies it to the whole module.
Tests that are not coroutines themselves may require an event loop to
exist for code that uses get_event_loop/get_running_loop.
Adds an autouse fixture at the module scope that removes all loaded
storage plugins. This prevents plugin instances with closed event loops
from being re-used across tests.

Also adds a non-autouse fixture for resetting the storage plugins at
more narrow scopes when required.
@flyinghyrax flyinghyrax force-pushed the update-pytest-asyncio branch from 63fc8e4 to a4dbbad Compare December 23, 2024 00:39
@flyinghyrax
Copy link
Contributor Author

I'm interested in adding pytest-randomly to test deps and changing CI to use -p no:randomly (so it wouldn't be active in CI) but I will make a separate PR. 🙂

@cooperlees cooperlees added the skip news Skip CI check for news/changelog label Dec 23, 2024
Copy link
Contributor

@cooperlees cooperlees left a comment

Choose a reason for hiding this comment

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

Awesome work and many many thanks @flyinghyrax ... This is a huge cleanup with out test suite and will help keeping it cleaner in the future.

Also, love the comment explaining why stuff was done. Can't click merge fast enough!

I will try get a release out over the holiday break finally for 3.12 and start work on making bandersnatch work for 3.13,.

@cooperlees cooperlees merged commit 48afe5f into pypa:main Dec 23, 2024
11 of 12 checks passed
@flyinghyrax
Copy link
Contributor Author

You're welcome! I'm very happy that I was able to get things working with relatively small changes. 🙂

@flyinghyrax flyinghyrax deleted the update-pytest-asyncio branch December 24, 2024 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
skip news Skip CI check for news/changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants