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

Do not collect symlinked tests under Windows #12050

Merged
merged 7 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ Mike Hoyle (hoylemd)
Mike Lundy
Milan Lesnek
Miro Hrončok
mrbean-bremen
Nathaniel Compton
Nathaniel Waisbrot
Ned Batchelder
Expand Down
1 change: 1 addition & 0 deletions changelog/12039.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a regression in ``8.0.2`` where tests created using :fixture:`tmp_path` have been collected multiple times in CI under Windows.
9 changes: 8 additions & 1 deletion src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,14 @@
if sys.platform == "win32" and not is_match:
# In case the file paths do not match, fallback to samefile() to
# account for short-paths on Windows (#11895).
is_match = os.path.samefile(node.path, matchparts[0])
same_file = os.path.samefile(node.path, matchparts[0])

Check warning on line 927 in src/_pytest/main.py

View check run for this annotation

Codecov / codecov/patch

src/_pytest/main.py#L927

Added line #L927 was not covered by tests
# We don't want to match links to the current node,
# otherwise we would match the same file more than once (#12039).
is_match = same_file and (

Check warning on line 930 in src/_pytest/main.py

View check run for this annotation

Codecov / codecov/patch

src/_pytest/main.py#L930

Added line #L930 was not covered by tests
os.path.islink(node.path)
== os.path.islink(matchparts[0])
)

# Name part e.g. `TestIt` in `/a/b/test_file.py::TestIt::test_it`.
else:
# TODO: Remove parametrized workaround once collection structure contains
Expand Down
27 changes: 26 additions & 1 deletion testing/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1765,7 +1765,7 @@ def test_foo(): assert True

@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
def test_collect_short_file_windows(pytester: Pytester) -> None:
"""Reproducer for #11895: short paths not colleced on Windows."""
"""Reproducer for #11895: short paths not collected on Windows."""
short_path = tempfile.mkdtemp()
if "~" not in short_path: # pragma: no cover
if running_on_ci():
Expand Down Expand Up @@ -1832,3 +1832,28 @@ def test_pyargs_collection_tree(pytester: Pytester, monkeypatch: MonkeyPatch) ->
],
consecutive=True,
)


def test_do_not_collect_symlink_siblings(
pytester: Pytester, tmp_path: Path, request: pytest.FixtureRequest
) -> None:
"""
Regression test for #12039: Do not collect from directories that are symlinks to other directories in the same path.

The check for short paths under Windows via os.path.samefile, introduced in #11936, also finds the symlinked
directory created by tmp_path/tmpdir.
"""
# Use tmp_path because it creates a symlink with the name "current" next to the directory it creates.
symlink_path = tmp_path.parent / (tmp_path.name[:-1] + "current")
assert symlink_path.is_symlink() is True

# Create test file.
tmp_path.joinpath("test_foo.py").write_text("def test(): pass", encoding="UTF-8")

# Ensure we collect it only once if we pass the tmp_path.
result = pytester.runpytest(tmp_path, "-sv")
result.assert_outcomes(passed=1)

# Ensure we collect it only once if we pass the symlinked directory.
result = pytester.runpytest(symlink_path, "-sv")
result.assert_outcomes(passed=1)
Loading