Skip to content

Commit

Permalink
Do not collect symlinked tests under Windows (pytest-dev#12050)
Browse files Browse the repository at this point in the history
The check for short paths under Windows via os.path.samefile, introduced in pytest-dev#11936, also found similar tests in symlinked tests in the GH Actions CI.

Fixes pytest-dev#12039.

Co-authored-by: Bruno Oliveira <bruno@soliv.dev>
  • Loading branch information
2 people authored and flying-sheep committed Apr 9, 2024
1 parent b92180b commit c944418
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 2 deletions.
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 @@ def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
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])
# 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 (
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)

0 comments on commit c944418

Please sign in to comment.