Repository navigation
Audit the test suite for unnecessary and flaky tests #1239
Description
Summary
Audit tests/pyathena/ for tests that are not needed and for flaky tests, then fix them in grouped PRs. A test is needed when it protects a contract that no other test protects, at the lowest cost that still exercises the real behavior.
Facts (master 59169c5, 2026-10-17)
-
tests/pyathena/collects 4,396 tests:Directory Tests filesystem 1,321 top-level files 798 sqlalchemy 726 pandas 574 aio 379 polars 202 arrow 157 spark 123 s3fs 116 -
The largest files:
File Tests filesystem/test_s3.py616 sqlalchemy/test_compiler.py247 pandas/test_result_set.py243 sqlalchemy/test_base.py229 filesystem/test_s3_async.py215 pandas/test_cursor.py212 filesystem/test_s3_core.py210 -
In the 400 Test workflow runs since 2026-10-09, these tests failed in one run and passed in another run of the same commit:
Failures Test 2 filesystem/test_s3_async.py::TestAioS3StreamedFile::test_write_failed_part_while_waiting(test_write_failed_part_while_waiting fails intermittently since queued parts are cancelled #1237)2 polars/test_cursor.py::TestPolarsCursor::test_null_vs_empty_string1 polars/test_result_set.py::TestPolarsDataFrameIterator::test_itertuples_value_python_does_not_hold1 arrow/test_cursor.py::TestArrowCursor::test_complex_unload_as_polars1 test_cursor.py::TestCursor::test_contain_special_character_query_with_parameter1 aio/test_util.py::test_create_in_thread_cancelled_construction_errorOlder failed runs (2026-09-19 to 2026-10-09, mostly the SQLAlchemy reflection suite) are not classified yet.
-
test_write_failed_part_while_waiting fails intermittently since queued parts are cancelled #1237 shows the pattern this audit looks for. The test asserted which parts called
upload_part, an implementation detail. A correct change to the cancellation order made it flaky. -
PYTEST_RERUNreruns a test once only for two Athena service errors ("Amazon Athena experienced an internal error", "Invalid S3 request"). It does not hide other flakiness.
Criteria
A test is a candidate for removal or rewriting when it:
- asserts implementation details instead of observable behavior, such as call order, call counts, private method sequencing, or log text that is not part of a contract;
- duplicates another test's contract, through parametrization or a near copy in sync, async, and aio variants, where a shared helper already covers them;
- depends on thread or task timing, wall-clock sleeps, or ordering between concurrent workers without synchronizing it;
- calls AWS where a stubbed or offline test exercises the same behavior, or runs more queries than its contract needs;
- passes without the behavior it names, because a mock or fake omits what it checks.
The SQLAlchemy compliance suite under tests/sqlalchemy/ keeps its upstream classes and plugin conventions, so this audit only records its flakiness.
Plan
- Flakiness
- Classify the older failures by whether another run of the same commit passed.
- Reproduce each candidate under
pytest -n 8load. - Record the cause.
- Necessity
- Review
tests/pyathena/by directory against the criteria. - List each finding with
file::test, the criterion, the cost, and the proposed change: remove, merge, rewrite, or make offline.
- Review
- Results
- Post the inventory on this issue for the maintainer's review before changing tests.
- Then open one sub-issue per fixing PR, with numbered sections.
- Each PR keeps test IDs, marks, fixture scopes, and cleanup where tests are reorganized, as the test conventions require.
Activity
laughingman7743 commentedon Oct 17, 2026
Handoff: first findings from the flakiness classification. This session continues #1233; the audit continues in another session.
Data: 1,340 Test workflow runs from 2026-09-01 to 2026-10-17, 56 of them failed. A candidate failed in one run and passed in another run of the same commit. The scripts and data are in a local scratch directory and are not committed, so the commands below reproduce them.
Of the 11 candidates, most are not timing-dependent. Some assert library- or version-specific details that differ between runs of one commit, which may use different Python or dependency versions. Others, at a commit under development, depended on state that the tests set up:
filesystem/test_s3_async.py::TestAioS3StreamedFile::test_write_failed_part_while_waiting[2] == [1, 2]aio/test_util.py::test_create_in_thread_cancelled_construction_errorpolars/test_result_set.py::TestPolarsDataFrameIterator::test_itertuples_value_python_does_not_hold'year 0'against'year must be in 1..9999, not 0'arrow/test_cursor.py::TestArrowCursor::test_complex_unload_as_polarsMap(Int32, Int32)againstList(Struct(...))polars/test_cursor.py::TestPolarsCursor::test_null_vs_empty_string,test_cursor.py::TestCursor::test_contain_special_character_query_with_parameterformat requires a parenthesised mapping key;'NoneType' object has no attribute 'to_list'arrow/test_cursor.py::TestArrowCursor::test_managed_results_match_result_filepandas/test_cursor.py::TestPandasCursor::test_get_csv_engine_explicit_specificationno attribute '_metadata'aio/test_cursor.py::TestAioCursor::test_throttled_metadata_reads_glue,test_cursor.py::TestCursor::test_throttled_metadata_reads_glue,test_glue.py::TestGlueMetadataClient::test_reads_what_athena_reportspresto_view,location, ...) differThe maintainer noted on 2026-10-17 that AI-written tests are of poor quality. Patterns to add to the criteria:
Keep the write tests that check behavior (GH-1239)
laughingman7743 commentedon Oct 17, 2026
Inventory of the necessity audit at master 59169c5. Every test function in
tests/pyathena/was reviewed. No test is changed before the maintainer's review. Each sub-issue below lists its rows with the covering test.Criteria added on 2026-10-17
The audit applied criteria 1–5 above, with the patterns of the previous comment counted under criteria 1 and 8, and these three:
__repr__, or a dataclass field, or tests Python or a third-party library instead of PyAthena;Baseline
tests/pyathena/and 16 in the compliance suitetests/sqlalchemy/test_suite.py.tests/pyathena/has 2,048 test functions.TestPandasCursorandTestAsyncPandasCursortests, where({"unload": True}, "pyarrow")repeats({"unload": True}, "auto"), or wherechunksizeand the engine do not change the query;TestAsyncPandasCursortests (test_many_as_pandas,test_show_columns,test_empty_result_ddl, ...) that run the sync tests' queries through the sameAthenaPandasResultSet;sqlalchemy/test_base.py::TestSQLAlchemyAthena::test_reflect_table: restoreMetaData(), which 7793651 changed toMetaData(schema=ENV.schema), making the test a copy oftest_reflect_table_with_schema;pandas/test_util.py::test_to_sql_with_multiple_partitions:assert sorted(cursor.fetchall()), [...]always passes; change,to==.Counts
Test functions at master 59169c5, after the cross-check corrections below.
filesystem/test_s3.py,test_s3_writer.py,test_s3_object.py,test_reader.py,test_init.py)filesystem/test_s3_async.py,test_s3_core.py,test_s3_executor.py,test_s3_path_pairing.py,test_s3_path.py,test_s3_errors.py)sqlalchemy/,aio/sqlalchemy/)test_*.py)pandas/,aio/pandas/)aio/exceptsqlalchemy/,pandas/;spark/)polars/,arrow/,s3fs/)The open PRs change these counts:
test_result_set.py, 4 inpandas/test_result_set.py, 4 inpolars/test_result_set.py, andaio/test_util.py::test_async_retry_api_call_stop_when.TestS3File::test_write_interrupted_while_waiting_for_part(REMOVE) andTestS3File::test_upload_chunk_empty_file_touches(REWRITE). After it,TestS3File::test_discardandtest_commit_stops_at_failed_partare KEEP, andtest_upload_chunk_small_fileandtest_upload_chunk_multipartare REWRITE: they are the only tests that a secondcommit()ordiscard()sends no request.TestAioS3StreamedFile::test_write_failed_part_while_waiting(test_write_failed_part_while_waiting fails intermittently since queued parts are cancelled #1237); Remove and rewrite unnecessary tests in the async S3 filesystem and S3 core tests #1241 re-checks it after Move S3File writes onto a multipart write session #1232.Patterns
TestAioS3FileSystemthat pass through one-line_sync_fsdelegations (test_info_file,test_ls_dirs,test_checksum,test_sign);TestAsyncPandasCursor::test_integer_na_values;TestAioArrowCursor::test_fetchalland its Polars and S3FS copies.TestS3FileSystem::test_mv_null_version_onto_key(_copy_file,_delete_objects); theTestS3Filemax-parts tests that readexecutor.submit_to.call_args_listor patch the modulewait;spark/test_common.pytests that patch_calculateand_wait_for_idle_session;TestPandasCursor::test_get_csv_engine_explicit_specification, which failed in CI on_metadata.TestComplexDataTypestests (43 queries assertingis not Noneorisinstance(list));TestSQLAlchemyAthena::test_filter_func(len(result) >= 0);TestCursor::test_callback_thread_safety;test_to_sql_with_multiple_partitions.test_binary_parameters_and_literals(100 queries between them);test_throttled_columns_across_cursor_types(6 cursor types for a shared internal cursor);TestCursor::test_executemany_rowcount(3 DML kinds);TestCursor::test_binary_parameter(7 queries for 7 values).sqlalchemy/test_map.py;TestS3ObjectSummary::test_frozen;TestS3AioThreadPool::test_init(ThreadPoolExecutor'smin(32, cpu + 4));TestExecuteOptions::test_defaults; thetest_arraysize_defaultcopies in the aio cursors.TestArrowCursor::test_complex_as_polars,test_complex_unload_as_polars, andtest_many_as_polars(pl.from_arrow);TestPolarsCursor::test_as_arrow(to_arrow).abort=Truebranch ofS3FileSystem._finish_multipart_upload(see below).Of the flaky tests listed above,
TestArrowCursor::test_complex_unload_as_polarsandTestPandasCursor::test_get_csv_engine_explicit_specificationare REMOVE, andtest_glue.py::TestGlueMetadataClient::test_reads_what_athena_reportsmerges intotest_cursor.py::TestCursor::test_throttled_metadata_reads_glue.TestPolarsDataFrameIterator::test_itertuples_value_python_does_not_holdhas matched only "year" since 90c94d9 and is KEEP. The others are KEEP and remain for the flakiness classification.Verification
TestS3FileSystem::test_setxattr_omits_unset_system_metadataandTestS3MultipartUploadPart::test_to_api_repr_with_checksum.test_connection.py::TestConnection::test_cursor_arraysize_over_page_sizewas REMOVE, but the aio arraysize tests merge into it, andAioCursorhas its ownarraysizesetter (pyathena/aio/cursor.py:96). It is KEEP.Source finding
S3FileSystem._finish_multipart_upload(..., abort=True)has no caller. Its only caller,_copy_object_with_multipart_upload(pyathena/filesystem/s3.py:1706), passesabort=Falseand aborts the upload itself. At master,S3File.commit()has its own copy of the wait logic (s3.py:3362). #1232 (fb54bea) moves that wait into_S3WriteSessionand leaves_finish_multipart_uploadand its caller unchanged. Fivetest_finish_multipart_upload*tests exercise only theabort=Truebranch. #1240 removes three of them and rewrites two through the multipart copy path. Removing the parameter and the branch is a source change outside this audit.Order
#1232 (82d2ad2) already fixes #1237: both parts of
TestAioS3StreamedFile::test_write_failed_part_while_waitingmeet at athreading.Barrier(2)in theupload_partmock before either fails, so #1237 can close with #1232.TestS3Filerows and the write tests they cite.test_result_set.pyand changestest_util.pyandtests/pyathena/util.py.test_read_parquet_filesystem; #1245 addsaio/test_common.py::TestWithAsyncFetch::test_cancel_without_queryand merges the arraysize tests.laughingman7743 commentedon Oct 17, 2026
Tests of #1232 reviewed against these criteria
#1232 (merged as d0d3b64) moved the write path of
S3Fileonto_S3WriteSession. Before the merge, its tests were revised against the criteria of this issue and the maintainer's guidance of 2026-10-17. Mock-based local tests are fine when the logic is complex and the test tries several patterns. Coverage-only and self-evident tests are not.Removed
TestS3WriteSessiontests. They repeated a contract that theS3Filetests check, or they only guarded misuse of the internal API.TestS3File.test_write_interrupted_while_waiting_for_part, which had the same contract astest_part_scheduling_interrupted.test_concurrent_aborts: no public seam can make the second abort enter while the first runs. The asynchronous file (Move AioS3StreamedFile writes onto the multipart write session #1228) is to test it through its own paths.Kept in
tests/pyathena/filesystem/test_s3_writer.py::TestS3WriteSession: only contracts that noS3Filetest reaches.Synchronization in
TestS3File: the private hooks that the tests used to synchronize are gone. They now use public seams:submit_to;Two private patches remain, both documented in the tests:
ready(), patched in three tests to inject an interrupt into the wait for the creation.Against S3:
test_write_transaction_rollbacknow also checks that no multipart upload is left and that a latercommit()raises.Evidence: each kept or rewritten test fails against a mutation that removes the behavior it names. For example, the abort ordering tests failed in 30 of 30 runs with the abort's wait removed. Codex reviewed the revision 5 times; the last review was clean.
Not covered by this review: the other tests of
tests/pyathena/filesystem/test_s3.pyandtest_s3_async.py, which Move S3File writes onto a multipart write session #1232 only adapted to the session. They remain in scope of Remove and rewrite unnecessary tests in the sync S3 filesystem tests #1240 and Remove and rewrite unnecessary tests in the async S3 filesystem and S3 core tests #1241. test_write_failed_part_while_waiting fails intermittently since queued parts are cancelled #1237 is closed; Move S3File writes onto a multipart write session #1232 fixed it with a barrier in 82d2ad2.Restore the tests that only they protected and bound the copy checks (G…
23 remaining items
Remove and rewrite redundant S3 executor tests (GH-1239)
Restore the async and executor checks that round one found uncovered (G…
Wake every overlapping call once the peak is reached (GH-1239)
Restore the async checks that the independent review found uncovered (G…
Bound and tighten the repaired async and executor tests (GH-1239)
Break the reference cycle of the stopped retry in the cancelled read …
Bound the one-worker copy tests and let overlapping_calls see an exce…
Check that the async delegations pass their arguments through (GH-1239)
Fail the bounded awaits without waiting for the cancellation (GH-1239)
Compare the async delegations by everything they return or write (GH-…
Drop the test watchdog (GH-1239)
Fail the part copy once the other part runs in a waiting test (GH-1239)
Keep the running part of the abort test until the failure stops it (G…
laughingman7743 commentedon Oct 18, 2026
Closing note: the flakiness classification and every sub-issue are complete.
arrow/test_cursor.py::TestArrowCursor::test_complex_unload_as_polars,pandas/test_cursor.py::TestPandasCursor::test_get_csv_engine_explicit_specification, andtest_glue.py::TestGlueMetadataClient::test_reads_what_athena_reports.test_itertuples_value_python_does_not_holdmatches only "year";test_create_in_thread_cancelled_construction_errorchecks that the loop's exception handler receives nothing instead of counting log records;test_throttled_metadata_reads_gluecompares the reported metadata through_metadata_viewinstead of Glue's whole parameter dictionaries; test_write_failed_part_while_waiting fails intermittently since queued parts are cancelled #1237 is closed.polars/test_cursor.py::TestPolarsCursor::test_null_vs_empty_string,test_cursor.py::TestCursor::test_contain_special_character_query_with_parameter) was aworkflow_dispatchoffeat/python-3-15at 9d405b8. Only the Python 3.15 job failed, before the support of Support Python 3.15 #1164 was complete.arrow/test_cursor.py::TestArrowCursor::test_managed_results_match_result_file) tested Read managed query results as a CSV result file in the pandas, Arrow, and Polars cursors #1061 at 301b22e, the PR that added this test in fd80f98.mastersucceeded, through 9acbcca on 2026-10-18.This parent issue has no closing PR of its own, so it is closed manually.