Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I discovered the reason for unstable tests. It was caused by an interaction between one broken fixture, one broken test, and the aiohttp async plugin. The fix is simple, but the actual sequence of events that led to the error was amazing.
Initially, there was no error on my local machine, as the error is unstable and caused by a specific order of tests. I added the following pytest option to my local configuration to reproduce the error:
--randomly-seed=1
. It created a stable pseudo-random test sequence that failed stably on my machine, and then I could debug the reason for the error.The failed test looked pretty innocent, and the error does not seem to be related to the test code:
The error was:
As it turns out, the reason for the error was a completely unrelated fixture:
This is what happened:
TagRulesProcessor
inherits fromTaskManager
, which__init__
creates a task_check_tasks
. We need to properly shutdown classes that inherit from theTaskManager
so all their tasks are properly finished, including the_check_tasks
task. So, the first part of the problem was skipping theshutdown_task_manager()
call in the finalization part of the fixture.The tests in which the fixture is used are not async, and the unhandled task remained in the memory.
Then
test_get_private_key_filename
was executed if the order of tests were unlucky. The function was declared asasync
, but@pytest.mark.asyncio
decorator was not applied to the test, which caused the function to be treated as an async test by theaiohttp
plugin that we use in REST API tests.The
aiohttp
plugin, when executing a test function, do two additional things: first, it runs garbage collection at the end of the test to b sure that all unfinished tasks created in the function generate warnings. Second, it converts warnings to RuntimeError to ensure that they will not be missed accidentally.The garbage collection triggered the warning from the task created in a previous test, and the warning became converted to
RuntimeError
, leading to the failed test.As a fix, I:
async
from the test functions that does not execute any async code, so theaiohttp
plugin no longer tries to handle these tests;shutdown
method toTagRulesProcessor
;tag_rules_processor
fixture code to a generator to be able to callprocessor.shutdown()
at the end of the fixture.In the future, we probably need to add some safety checks to be sure a coroutine created in one test cannot cause an error in the following test during the garbage collection phase. We can add a plugin that triggers garbage collection at the end of each test as an option. It may slow down test execution, but it should make tests more stable.