blob: dfdfe8bbf9cc29045da53bd206b42135447864e7 [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")
74 path.write_text('def main(argv):\n print("hi", argv)\n')
75 if wrapper is None:
76 wrapper = path.with_suffix("")
77 wrapper.symlink_to(self.wrapper)
Mike Frysingerd0b43852021-02-12 19:04:57 -050078
Alex Klein1699fab2022-09-08 08:46:06 -060079 def run_script(self, argv: List[Union[Path, str]], **kwargs):
80 """Run |prog| and return the output."""
81 # Log the directory layout to help with debugging.
82 try:
83 cros_build_lib.run(
84 ["tree", "-p", str(self.tempdir)],
85 encoding="utf-8",
86 print_cmd=False,
87 )
88 except cros_build_lib.RunCommandError:
89 pass
Mike Frysingerd0b43852021-02-12 19:04:57 -050090
Alex Klein1699fab2022-09-08 08:46:06 -060091 # Helper to include a small timeout in case of bugs.
92 with timeout_util.Timeout(30):
93 return cros_build_lib.run(
94 [str(x) for x in argv],
95 capture_output=True,
96 encoding="utf-8",
97 **kwargs,
98 )
Mike Frysingerd0b43852021-02-12 19:04:57 -050099
Alex Klein1699fab2022-09-08 08:46:06 -0600100 def _run_tests(self, prog: Path, verify=None, **kwargs):
101 """Run |prog| in the different fun ways."""
102 if verify is None:
103 verify = lambda result: self.assertEqual("hi []\n", result.stdout)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 # Execute absolute path.
106 result = self.run_script([prog], **kwargs)
107 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500108
Alex Klein1699fab2022-09-08 08:46:06 -0600109 # Execute ./ relative path.
110 result = self.run_script([f"./{prog.name}"], cwd=prog.parent, **kwargs)
111 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 # Execute ./path/ relative path.
114 result = self.run_script(
115 [f"./{prog.parent.name}/{prog.name}"],
116 cwd=prog.parent.parent,
117 **kwargs,
118 )
119 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500120
Alex Klein1699fab2022-09-08 08:46:06 -0600121 # Run via $PATH.
122 self.insert_path("PATH", str(prog.parent))
123 result = self.run_script([prog.name], **kwargs)
124 verify(result)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500125
Alex Klein1699fab2022-09-08 08:46:06 -0600126 def testExternal(self):
127 """Verify use from outside of chromite/ works with main() scripts."""
128 prog = self.tempdir / "path" / "prog"
129 self.gen_script(prog)
130 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500131
Alex Klein1699fab2022-09-08 08:46:06 -0600132 def testChromiteBin(self):
133 """Verify chromite/bin/ works with module in chromite/scripts/."""
134 prog = self.bindir / "prog"
135 self.gen_script(self.scripts_dir / prog.name, prog)
136 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500137
Alex Klein1699fab2022-09-08 08:46:06 -0600138 def testChromiteScripts(self):
139 """Verify chromite/scripts/ works with main() scripts."""
140 prog = self.scripts_dir / "prog"
141 self.gen_script(prog)
142 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500143
Alex Klein1699fab2022-09-08 08:46:06 -0600144 def testChromiteCustomdir(self):
145 """Verify chromite/customdir/ works with main() scripts."""
146 prog = self.chromite_dir / "customdir" / "prog"
147 self.gen_script(prog)
148 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500149
Alex Klein1699fab2022-09-08 08:46:06 -0600150 def testChromiteTopdir(self):
151 """Verify chromite/ works with main() scripts."""
152 prog = self.chromite_dir / "prog"
153 self.gen_script(prog)
154 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500155
Alex Klein1699fab2022-09-08 08:46:06 -0600156 def testUnittests(self):
157 """Allow direct execution of unittests."""
158 prog = self.chromite_dir / "subdir" / "prog_unittest"
159 prog.parent.mkdir(parents=True, exist_ok=True)
160 path = prog.with_suffix(".py")
161 path.write_text('import sys; print("hi", sys.argv[1:])\n')
162 prog.symlink_to(self.wrapper)
163 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500164
Alex Klein1699fab2022-09-08 08:46:06 -0600165 def testTests(self):
166 """Allow direct execution of tests."""
167 prog = self.chromite_dir / "subdir" / "prog_unittest"
168 prog.parent.mkdir(parents=True, exist_ok=True)
169 prog.symlink_to(self.wrapper)
170 prog.with_suffix(".py").write_text(
171 'import sys; print("hi", sys.argv[1:])\n'
172 )
173 self._run_tests(prog)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500174
Alex Klein1699fab2022-09-08 08:46:06 -0600175 def testWrapper(self):
176 """Fail quickly when running the wrapper directly."""
177 verify = lambda result: self.assertEqual(result.returncode, 100)
178 self._run_tests(self.wrapper, verify=verify, check=False)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500179
Alex Klein1699fab2022-09-08 08:46:06 -0600180 def testMissingScript(self):
181 """Fail quickly if wrapped script is missing."""
182 verify = lambda result: self.assertNotEqual(result.returncode, 0)
183 prog = self.bindir / "prog"
184 prog.symlink_to(self.wrapper)
185 self._run_tests(prog, verify=verify, check=False)
Mike Frysingerd0b43852021-02-12 19:04:57 -0500186
Alex Klein1699fab2022-09-08 08:46:06 -0600187 def testBrokenScript(self):
188 """Fail quickly if wrapped script is corrupt."""
189 verify = lambda result: self.assertNotEqual(result.returncode, 0)
190 prog = self.scripts_dir / "prog"
191 prog.symlink_to(self.wrapper)
192 # Script has syntax errors and cannot be imported.
193 prog.with_suffix(".py").write_text("}")
194 self._run_tests(prog, verify=verify, check=False)
Mike Frysingerd07b8542021-06-21 11:57:20 -0400195
Alex Klein1699fab2022-09-08 08:46:06 -0600196 def testDashes(self):
197 """Check behavior of scripts with dashes in their names."""
198 script = self.chromite_dir / "scripts" / "p_r_o_g"
199 self.gen_script(script)
200 prog = self.chromite_dir / "bin" / "p-r-o-g"
201 prog.symlink_to(self.wrapper)
202 self._run_tests(prog)