|
14 | 14 |
|
15 | 15 | """Unittests for the forall subcmd.""" |
16 | 16 |
|
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 |
22 | 20 | from unittest import mock |
23 | 21 |
|
24 | 22 | import utils_for_test |
|
28 | 26 | import subcmds |
29 | 27 |
|
30 | 28 |
|
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. |
118 | 92 | with mock.patch.object( |
119 | 93 | project.Project, "GetRevisionId", return_value="refs/heads/main" |
120 | 94 | ): |
121 | | - # Run the forall command |
| 95 | + # Run the forall command. |
122 | 96 | cmd.Execute(opts, args) |
123 | 97 |
|
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