blob: 39f0ef6a446c31394af73f90e4b5411b3841963b [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2021 The ChromiumOS Authors
Mike Frysingerd0b43852021-02-12 19:04:57 -05002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unittests for wrapper3"""
6
7import os
8from pathlib import Path
9import sys
10from typing import List, Union
11
12from chromite.lib import constants
13from chromite.lib import cros_build_lib
14from chromite.lib import cros_test_lib
15from chromite.lib import timeout_util
Mike Frysingerd0b43852021-02-12 19:04:57 -050016
17
Alex Klein1699fab2022-09-08 08:46:06 -060018WRAPPER = Path(__file__).resolve().parent / "wrapper3.py"
Mike Frysingerd0b43852021-02-12 19:04:57 -050019
20
21class FindTargetTests(cros_test_lib.TempDirTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -060022 """Tests for FindTarget()."""
Mike Frysingerd0b43852021-02-12 19:04:57 -050023
Alex Klein1699fab2022-09-08 08:46:06 -060024 def setUp(self):
25 # Create a skeleton chromite layout.
26 # tmpdir/
27 # chromite/
28 # bin/<wrapper>
29 # scripts/
30 # api -> <real chromite>/api/
31 # lib -> <real chromite>/lib/
32 # utils -> <real chromite>/utils/
33 # __init__.py -> <real chromite>/__init__.py
34 # PRESUBMIT.cfg # Marker file for our wrapper to find chromite.
35 self.chromite_dir = self.tempdir / "chromite"
36 self.bindir = self.chromite_dir / "bin"
37 self.bindir.mkdir(parents=True)
38 self.scripts_dir = self.chromite_dir / "scripts"
39 self.scripts_dir.mkdir()
40 for subdir in ("api", "cbuildbot", "lib", "third_party", "utils"):
41 (self.chromite_dir / subdir).symlink_to(
42 Path(constants.CHROMITE_DIR) / subdir
43 )
44 for subfile in ("__init__.py",):
45 (self.chromite_dir / subfile).symlink_to(
46 Path(constants.CHROMITE_DIR) / subfile
47 )
48 for subfile in ("PRESUBMIT.cfg",):
49 (self.chromite_dir / subfile).touch()
50 self.wrapper = self.scripts_dir / WRAPPER.name
51 # Copy over the wrapper. We can't just symlink it because the code also
52 # walks & resolves symlinks on itself. Try hardlink at first, but if the
53 # tempdir is on a diff mount, fallback to a copy.
54 try:
55 if sys.version_info >= (3, 8):
56 self.wrapper.link_to(WRAPPER)
57 else:
58 os.link(WRAPPER, self.wrapper)
59 except OSError:
60 self.wrapper.write_bytes(WRAPPER.read_bytes())
61 self.wrapper.chmod(0o755)
Mike Frysingerd0b43852021-02-12 19:04:57 -050062
Alex Klein1699fab2022-09-08 08:46:06 -060063 @staticmethod
64 def insert_path(var: str, value: str):
65 """Insert |value| into the start of the environment |var|."""
66 if var in os.environ:
67 value += f":{os.environ[var]}"
68 os.environ[var] = value
Mike Frysingerd0b43852021-02-12 19:04:57 -050069
Alex Klein1699fab2022-09-08 08:46:06 -060070 def gen_script(self, path: Path, wrapper: Path = None):
71 """Create a script at |path|."""
72 path.parent.mkdir(parents=True, exist_ok=True)
73 path = path.with_suffix(".py")
Mike Frysingerecc59262023-01-21 05:53:54 -050074 path.write_text(
75 'def main(argv):\n print("hi", argv)\n', encoding="utf-8"
76 )
Alex Klein1699fab2022-09-08 08:46:06 -060077 if wrapper is None:
78 wrapper = path.with_suffix("")
79 wrapper.symlink_to(self.wrapper)
Mike Frysingerd0b43852021-02-12 19:04:57 -050080
Alex Klein1699fab2022-09-08 08:46:06 -060081 def run_script(self, argv: List[Union[Path, str]], **kwargs):
82 """Run |prog| and return the output."""
83 # Log the directory layout to help with debugging.
84 try:
85 cros_build_lib.run(
86 ["tree", "-p", str(self.tempdir)],
87 encoding="utf-8",
88 print_cmd=False,
89 )
90 except cros_build_lib.RunCommandError:
91 pass
Mike Frysingerd0b43852021-02-12 19:04:57 -050092
Alex Klein1699fab2022-09-08 08:46:06 -060093 # Helper to include a small timeout in case of bugs.
94 with timeout_util.Timeout(30):
95 return cros_build_lib.run(
96 [str(x) for x in argv],
97 capture_output=True,
98 encoding="utf-8",
99 **kwargs,
100 )
Mike Frysingerd0b43852021-02-12 19:04:57 -0500101
Alex Klein1699fab2022-09-08 08:46:06 -0600102 def _run_tests(self, prog: Path, verify=None, **kwargs):
103 """Run |prog| in the different fun ways."""
104 if verify is None:
105 verify = lambda result: self.assertEqual("hi []\n", result.stdout)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 # Execute absolute path.
108 result = self.run_script([prog], **kwargs)
109 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500110
Alex Klein1699fab2022-09-08 08:46:06 -0600111 # Execute ./ relative path.
112 result = self.run_script([f"./{prog.name}"], cwd=prog.parent, **kwargs)
113 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500114
Alex Klein1699fab2022-09-08 08:46:06 -0600115 # Execute ./path/ relative path.
116 result = self.run_script(
117 [f"./{prog.parent.name}/{prog.name}"],
118 cwd=prog.parent.parent,
119 **kwargs,
120 )
121 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500122
Alex Klein1699fab2022-09-08 08:46:06 -0600123 # Run via $PATH.
124 self.insert_path("PATH", str(prog.parent))
125 result = self.run_script([prog.name], **kwargs)
126 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500127
Alex Klein1699fab2022-09-08 08:46:06 -0600128 def testExternal(self):
129 """Verify use from outside of chromite/ works with main() scripts."""
130 prog = self.tempdir / "path" / "prog"
131 self.gen_script(prog)
132 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500133
Alex Klein1699fab2022-09-08 08:46:06 -0600134 def testChromiteBin(self):
135 """Verify chromite/bin/ works with module in chromite/scripts/."""
136 prog = self.bindir / "prog"
137 self.gen_script(self.scripts_dir / prog.name, prog)
138 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500139
Alex Klein1699fab2022-09-08 08:46:06 -0600140 def testChromiteScripts(self):
141 """Verify chromite/scripts/ works with main() scripts."""
142 prog = self.scripts_dir / "prog"
143 self.gen_script(prog)
144 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500145
Alex Klein1699fab2022-09-08 08:46:06 -0600146 def testChromiteCustomdir(self):
147 """Verify chromite/customdir/ works with main() scripts."""
148 prog = self.chromite_dir / "customdir" / "prog"
149 self.gen_script(prog)
150 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500151
Alex Klein1699fab2022-09-08 08:46:06 -0600152 def testChromiteTopdir(self):
153 """Verify chromite/ works with main() scripts."""
154 prog = self.chromite_dir / "prog"
155 self.gen_script(prog)
156 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500157
Alex Klein1699fab2022-09-08 08:46:06 -0600158 def testUnittests(self):
159 """Allow direct execution of unittests."""
160 prog = self.chromite_dir / "subdir" / "prog_unittest"
161 prog.parent.mkdir(parents=True, exist_ok=True)
162 path = prog.with_suffix(".py")
Mike Frysingerecc59262023-01-21 05:53:54 -0500163 path.write_text(
164 'import sys; print("hi", sys.argv[1:])\n', encoding="utf-8"
165 )
Alex Klein1699fab2022-09-08 08:46:06 -0600166 prog.symlink_to(self.wrapper)
167 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500168
Alex Klein1699fab2022-09-08 08:46:06 -0600169 def testTests(self):
170 """Allow direct execution of tests."""
171 prog = self.chromite_dir / "subdir" / "prog_unittest"
172 prog.parent.mkdir(parents=True, exist_ok=True)
173 prog.symlink_to(self.wrapper)
174 prog.with_suffix(".py").write_text(
Mike Frysingerecc59262023-01-21 05:53:54 -0500175 'import sys; print("hi", sys.argv[1:])\n', encoding="utf-8"
Alex Klein1699fab2022-09-08 08:46:06 -0600176 )
177 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500178
Alex Klein1699fab2022-09-08 08:46:06 -0600179 def testWrapper(self):
180 """Fail quickly when running the wrapper directly."""
181 verify = lambda result: self.assertEqual(result.returncode, 100)
182 self._run_tests(self.wrapper, verify=verify, check=False)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500183
Alex Klein1699fab2022-09-08 08:46:06 -0600184 def testMissingScript(self):
185 """Fail quickly if wrapped script is missing."""
186 verify = lambda result: self.assertNotEqual(result.returncode, 0)
187 prog = self.bindir / "prog"
188 prog.symlink_to(self.wrapper)
189 self._run_tests(prog, verify=verify, check=False)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500190
Alex Klein1699fab2022-09-08 08:46:06 -0600191 def testBrokenScript(self):
192 """Fail quickly if wrapped script is corrupt."""
193 verify = lambda result: self.assertNotEqual(result.returncode, 0)
194 prog = self.scripts_dir / "prog"
195 prog.symlink_to(self.wrapper)
196 # Script has syntax errors and cannot be imported.
Mike Frysingerecc59262023-01-21 05:53:54 -0500197 prog.with_suffix(".py").write_text("}", encoding="utf-8")
Alex Klein1699fab2022-09-08 08:46:06 -0600198 self._run_tests(prog, verify=verify, check=False)
Mike Frysingerd07b8542021-06-21 11:57:20 -0400199
Alex Klein1699fab2022-09-08 08:46:06 -0600200 def testDashes(self):
201 """Check behavior of scripts with dashes in their names."""
202 script = self.chromite_dir / "scripts" / "p_r_o_g"
203 self.gen_script(script)
204 prog = self.chromite_dir / "bin" / "p-r-o-g"
205 prog.symlink_to(self.wrapper)
206 self._run_tests(prog)