Skip to content

Commit e8338b5

Browse files
quic-nassergLUCI
authored andcommitted
tests: Convert forall subcmd test to pytest
Rewrite tests/test_subcmds_forall.py from unittest.TestCase to pytest function-style tests to match the surrounding test suite conventions. Replace setUp/tearDown and class-based helpers with tmp_path-based setup, switch stdout capture to contextlib.redirect_stdout, and keep the existing behavior checks intact (all eight projects are invoked exactly once). Change-Id: I9243f3461aa6850f867bdb864f4a34c442f817f6 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/569821 Reviewed-by: Gavin Mak <gavinmak@google.com> Commit-Queue: Nasser Grainawi <nasser.grainawi@oss.qualcomm.com> Tested-by: Nasser Grainawi <nasser.grainawi@oss.qualcomm.com> Reviewed-by: Mike Frysinger <vapier@google.com>
1 parent 951666f commit e8338b5

1 file changed

Lines changed: 76 additions & 108 deletions

File tree

tests/test_subcmds_forall.py

Lines changed: 76 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414

1515
"""Unittests for the forall subcmd."""
1616

17-
from io import StringIO
18-
import os
19-
from shutil import rmtree
20-
import tempfile
21-
import unittest
17+
import contextlib
18+
import io
19+
from pathlib import Path
2220
from unittest import mock
2321

2422
import utils_for_test
@@ -28,111 +26,81 @@
2826
import subcmds
2927

3028

31-
class AllCommands(unittest.TestCase):
32-
"""Check registered all_commands."""
33-
34-
def setUp(self):
35-
"""Common setup."""
36-
self.tempdirobj = tempfile.TemporaryDirectory(prefix="forall_tests")
37-
self.tempdir = self.tempdirobj.name
38-
self.repodir = os.path.join(self.tempdir, ".repo")
39-
self.manifest_dir = os.path.join(self.repodir, "manifests")
40-
self.manifest_file = os.path.join(
41-
self.repodir, manifest_xml.MANIFEST_FILE_NAME
42-
)
43-
self.local_manifest_dir = os.path.join(
44-
self.repodir, manifest_xml.LOCAL_MANIFESTS_DIR_NAME
45-
)
46-
os.mkdir(self.repodir)
47-
os.mkdir(self.manifest_dir)
48-
49-
def tearDown(self):
50-
"""Common teardown."""
51-
rmtree(self.tempdir, ignore_errors=True)
52-
53-
def getXmlManifestWith8Projects(self):
54-
"""Create and return a setup of 8 projects with enough dummy
55-
files and setup to execute forall."""
56-
57-
# Set up a manifest git dir for parsing to work
58-
gitdir = os.path.join(self.repodir, "manifests.git")
59-
os.mkdir(gitdir)
60-
with open(os.path.join(gitdir, "config"), "w") as fp:
61-
fp.write(
62-
"""[remote "origin"]
63-
url = https://localhost:0/manifest
64-
verbose = false
65-
"""
66-
)
67-
68-
# Add the manifest data
69-
manifest_data = """
70-
<manifest>
71-
<remote name="origin" fetch="http://localhost" />
72-
<default remote="origin" revision="refs/heads/main" />
73-
<project name="project1" path="tests/path1" />
74-
<project name="project2" path="tests/path2" />
75-
<project name="project3" path="tests/path3" />
76-
<project name="project4" path="tests/path4" />
77-
<project name="project5" path="tests/path5" />
78-
<project name="project6" path="tests/path6" />
79-
<project name="project7" path="tests/path7" />
80-
<project name="project8" path="tests/path8" />
81-
</manifest>
82-
"""
83-
with open(self.manifest_file, "w", encoding="utf-8") as fp:
84-
fp.write(manifest_data)
85-
86-
# Set up 8 empty projects to match the manifest
87-
for x in range(1, 9):
88-
os.makedirs(
89-
os.path.join(
90-
self.repodir, "projects/tests/path" + str(x) + ".git"
91-
)
92-
)
93-
os.makedirs(
94-
os.path.join(
95-
self.repodir, "project-objects/project" + str(x) + ".git"
96-
)
97-
)
98-
git_path = os.path.join(self.tempdir, "tests/path" + str(x))
99-
utils_for_test.init_git_tree(git_path)
100-
101-
return manifest_xml.XmlManifest(self.repodir, self.manifest_file)
102-
103-
# Use mock to capture stdout from the forall run
104-
@unittest.mock.patch("sys.stdout", new_callable=StringIO)
105-
def test_forall_all_projects_called_once(self, mock_stdout):
106-
"""Test that all projects get a command run once each."""
107-
108-
manifest_with_8_projects = self.getXmlManifestWith8Projects()
109-
110-
cmd = subcmds.forall.Forall()
111-
cmd.manifest = manifest_with_8_projects
112-
113-
# Use echo project names as the test of forall
114-
opts, args = cmd.OptionParser.parse_args(["-c", "echo $REPO_PROJECT"])
115-
opts.verbose = False
116-
117-
# Mock to not have the Execute fail on remote check
29+
def _create_manifest_with_8_projects(
30+
topdir: Path,
31+
) -> manifest_xml.XmlManifest:
32+
"""Create a setup of 8 projects to execute forall."""
33+
repodir = topdir / ".repo"
34+
manifest_dir = repodir / "manifests"
35+
manifest_file = repodir / manifest_xml.MANIFEST_FILE_NAME
36+
37+
repodir.mkdir()
38+
manifest_dir.mkdir()
39+
40+
# Set up a manifest git dir for parsing to work.
41+
gitdir = repodir / "manifests.git"
42+
gitdir.mkdir()
43+
(gitdir / "config").write_text(
44+
"""[remote "origin"]
45+
url = https://localhost:0/manifest
46+
verbose = false
47+
"""
48+
)
49+
50+
# Add the manifest data.
51+
manifest_file.write_text(
52+
"""
53+
<manifest>
54+
<remote name="origin" fetch="http://localhost" />
55+
<default remote="origin" revision="refs/heads/main" />
56+
<project name="project1" path="tests/path1" />
57+
<project name="project2" path="tests/path2" />
58+
<project name="project3" path="tests/path3" />
59+
<project name="project4" path="tests/path4" />
60+
<project name="project5" path="tests/path5" />
61+
<project name="project6" path="tests/path6" />
62+
<project name="project7" path="tests/path7" />
63+
<project name="project8" path="tests/path8" />
64+
</manifest>
65+
""",
66+
encoding="utf-8",
67+
)
68+
69+
# Set up 8 empty projects to match the manifest.
70+
for x in range(1, 9):
71+
(repodir / "projects" / "tests" / f"path{x}.git").mkdir(parents=True)
72+
(repodir / "project-objects" / f"project{x}.git").mkdir(parents=True)
73+
git_path = topdir / "tests" / f"path{x}"
74+
utils_for_test.init_git_tree(git_path)
75+
76+
return manifest_xml.XmlManifest(str(repodir), str(manifest_file))
77+
78+
79+
def test_forall_all_projects_called_once(tmp_path: Path) -> None:
80+
"""Test that all projects get a command run once each."""
81+
manifest = _create_manifest_with_8_projects(tmp_path)
82+
83+
cmd = subcmds.forall.Forall()
84+
cmd.manifest = manifest
85+
86+
# Use echo project names as the test of forall.
87+
opts, args = cmd.OptionParser.parse_args(["-c", "echo $REPO_PROJECT"])
88+
opts.verbose = False
89+
90+
with contextlib.redirect_stdout(io.StringIO()) as stdout:
91+
# Mock to not have the Execute fail on remote check.
11892
with mock.patch.object(
11993
project.Project, "GetRevisionId", return_value="refs/heads/main"
12094
):
121-
# Run the forall command
95+
# Run the forall command.
12296
cmd.Execute(opts, args)
12397

124-
# Verify that we got every project name in the prints
125-
for x in range(1, 9):
126-
self.assertIn("project" + str(x), mock_stdout.getvalue())
127-
128-
# Split the captured output into lines to count them
129-
line_count = 0
130-
for line in mock_stdout.getvalue().split("\n"):
131-
# A commented out print to stderr as a reminder
132-
# that stdout is mocked, include sys and uncomment if needed
133-
# print(line, file=sys.stderr)
134-
if len(line) > 0:
135-
line_count += 1
136-
137-
# Verify that we didn't get more lines than expected
138-
assert line_count == 8
98+
output = stdout.getvalue()
99+
# Verify that we got every project name in the output.
100+
for x in range(1, 9):
101+
assert f"project{x}" in output
102+
103+
# Split the captured output into lines to count them.
104+
line_count = sum(1 for x in output.splitlines() if x)
105+
# Verify that we didn't get more lines than expected.
106+
assert line_count == 8

0 commit comments

Comments
 (0)