blob: ac1cd23985ab373550e88a9d446e5e486bf110c1 [file] [log] [blame]
Diana Picus3b2ef822016-10-13 16:53:18 +03001"""Command line interface tests for llvmprojs.py
2
3Note that although this uses the unittest framework, it does *not* contain unit
4tests.
5
6"""
7
8import shutil
9import os
10import subprocess
11import unittest
12
Diana Picus3b2ef822016-10-13 16:53:18 +030013from tempfile import mkdtemp
14from uuid import uuid4
15
16from linaropy.cd import cd
Diana Picus3601bea2017-05-29 11:26:18 +020017from llvmtestcase import LLVMTestCase
Diana Picus3b2ef822016-10-13 16:53:18 +030018
19
Diana Picus3601bea2017-05-29 11:26:18 +020020class Testllvmprojs(LLVMTestCase):
Diana Picusb4307602017-04-05 19:48:39 +020021
Diana Picus3b2ef822016-10-13 16:53:18 +030022 @classmethod
Diana Picus81089db2017-05-05 22:26:49 +020023 def llvm_projects(cls, *args, **kwargs):
Diana Picus3601bea2017-05-29 11:26:18 +020024 return cls.command_with_defaults("projects", *args, **kwargs)
Diana Picus81089db2017-05-05 22:26:49 +020025
26 @classmethod
Diana Picusefc7bda2017-06-09 19:14:08 +020027 def get_subproj_repo(cls, subproj):
28 return os.path.join(cls.repos, subproj)
29
30 @classmethod
Diana Picus3b2ef822016-10-13 16:53:18 +030031 def setUpClass(cls):
32 """Create the file structure and environment that llvmprojs expects"""
33 cls.llvm_root = mkdtemp()
34 cls.repos = os.path.join(cls.llvm_root, "repos")
35
36 cls.all_repos = ("llvm", "clang", "compiler-rt", "lld", "lldb",
37 "libcxx", "libcxxabi", "libunwind", "test-suite")
38
Diana Picus3b2ef822016-10-13 16:53:18 +030039 # Create dummy repos
40 for reponame in cls.all_repos:
Diana Picus3601bea2017-05-29 11:26:18 +020041 cls.create_dummy_repo(cls.get_subproj_repo(reponame))
Diana Picus3b2ef822016-10-13 16:53:18 +030042
43 @classmethod
44 def tearDownClass(cls):
45 shutil.rmtree(cls.llvm_root)
46
47 @classmethod
48 def setUp(cls):
Diana Picus81089db2017-05-05 22:26:49 +020049 cls.env = os.path.join(cls.llvm_root, "env" + str(uuid4()))
50 cls.llvm_src = os.path.join(cls.env, "llvm")
Diana Picus3b2ef822016-10-13 16:53:18 +030051
52 # Create LLVM worktree
53 cls.branch = "br" + str(uuid4())
Diana Picus3601bea2017-05-29 11:26:18 +020054 cls.add_worktree(cls.get_subproj_repo("llvm"), cls.llvm_src,
55 cls.branch)
Diana Picus3b2ef822016-10-13 16:53:18 +030056
Diana Picus3b2ef822016-10-13 16:53:18 +030057 @classmethod
58 def tearDown(cls):
59 # Clean up the directories where we might have added subprojects.
60 # This isn't 100% clean, because we don't clean up the repos between
61 # tests (so any branches will remain), but it's good enough for the
62 # current tests.
63 for subprojdir in (os.path.join(cls.llvm_src, "projects"),
64 os.path.join(cls.llvm_src, "tools")):
65 if os.path.isdir(subprojdir):
66 shutil.rmtree(subprojdir)
67 os.makedirs(subprojdir)
68
69 # Run prune on the original repos, to remove any dangling worktrees.
70 for reponame in cls.all_repos:
Diana Picus3601bea2017-05-29 11:26:18 +020071 repopath = cls.get_subproj_repo(reponame)
Diana Picus3b2ef822016-10-13 16:53:18 +030072 with cd(repopath):
73 cls.run_quietly(["git", "worktree", "prune"])
74
Diana Picusadb07c42017-11-22 16:12:57 +010075 def test_repos_arg_is_compulsory_for_add(self):
Diana Picus81089db2017-05-05 22:26:49 +020076 """
Diana Picusadb07c42017-11-22 16:12:57 +010077 Test that we must pass in the repos when adding a subproject, but not
78 for other combinations of arguments.
Diana Picus81089db2017-05-05 22:26:49 +020079 """
80 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +020081 self.run_with_output(
Diana Picusadb07c42017-11-22 16:12:57 +010082 self.llvm_projects("--add", "clang"))
Diana Picus81089db2017-05-05 22:26:49 +020083
84 self.assertRegex(
85 str(context.exception.output),
Diana Picusadb07c42017-11-22 16:12:57 +010086 "(.*\n)*.*When adding a subproject you must also pass the --repos argument(.*\n)*")
Diana Picus81089db2017-05-05 22:26:49 +020087
Diana Picusadb07c42017-11-22 16:12:57 +010088 # These should not raise.
89 self.run_with_output(self.llvm_projects())
90 self.run_with_output(
91 self.llvm_projects("--remove", "clang"))
Diana Picus81089db2017-05-05 22:26:49 +020092
93 def test_env_arg_is_compulsory(self):
94 """
95 Test that we must pass in the environment for various combinations of
96 input args.
97 """
98 with self.assertRaises(subprocess.CalledProcessError) as context:
99 self.run_with_output(self.llvm_projects(env=None))
100
101 self.assertRegex(
102 str(context.exception.output),
103 "(.*\n)*.*the following arguments are required:(.*)--env(.*\n)*")
104
105 with self.assertRaises(subprocess.CalledProcessError) as context:
106 self.run_with_output(
107 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100108 "--repos", self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200109 "--add", "clang", env=None))
110
111 self.assertRegex(
112 str(context.exception.output),
113 "(.*\n)*.*the following arguments are required:(.*)--env(.*\n)*")
114
115 with self.assertRaises(subprocess.CalledProcessError) as context:
116 self.run_with_output(
117 self.llvm_projects(
118 "--remove", "clang", env=None))
119
120 self.assertRegex(
121 str(context.exception.output),
122 "(.*\n)*.*the following arguments are required:(.*)--env(.*\n)*")
123
Diana Picus3b2ef822016-10-13 16:53:18 +0300124 def test_dump_empty_config(self):
125 """
126 Test that we're correctly dumping an empty configuration (i.e. no
127 projects linked) when running llvmprojs without arguments.
128 """
Diana Picus81089db2017-05-05 22:26:49 +0200129 output = self.run_with_output(self.llvm_projects())
Diana Picusb4307602017-04-05 19:48:39 +0200130 self.assertRegex(output, "Projects linked:.*\n.*none.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300131
132 def test_add_remove_subprojects(self):
133 """
134 Test that we can add and remove one or several subprojects.
135 """
Diana Picusadb07c42017-11-22 16:12:57 +0100136 output = self.run_with_output(self.llvm_projects(
137 "--repos", self.repos,
138 "--add", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200139 self.assertRegex(output, "Projects linked:.*\n.*clang.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300140
Diana Picus81089db2017-05-05 22:26:49 +0200141 output = self.run_with_output(
142 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100143 "--repos", self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200144 "--add", "libcxx", "lldb"))
Diana Picusb4307602017-04-05 19:48:39 +0200145 self.assertRegex(
Diana Picus3b2ef822016-10-13 16:53:18 +0300146 output,
147 "Projects linked:.*\n" +
148 ".*clang.*\n" +
149 ".*libcxx.*\n" +
150 ".*lldb.*")
151
Diana Picus81089db2017-05-05 22:26:49 +0200152 output = self.run_with_output(self.llvm_projects("--remove", "libcxx"))
Diana Picusb4307602017-04-05 19:48:39 +0200153 self.assertRegex(output,
154 "Projects linked:.*\n" +
155 ".*clang.*\n" +
156 ".*lldb.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300157
Diana Picus81089db2017-05-05 22:26:49 +0200158 output = self.run_with_output(
159 self.llvm_projects(
160 "--remove", "clang", "lldb"))
Diana Picusb4307602017-04-05 19:48:39 +0200161 self.assertRegex(output,
162 "Projects linked:.*\n" +
163 ".*none.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300164
165 def test_add_remove_invalid_subprojects(self):
166 """
167 Test that we error out nicely when trying to add/remove invalid
168 subprojects.
169 """
170 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200171 self.run_with_output(
172 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100173 "--repos", self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200174 "--add", "inventedsubproject"))
Diana Picus3b2ef822016-10-13 16:53:18 +0300175
Diana Picusb4307602017-04-05 19:48:39 +0200176 self.assertRegex(
177 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300178 "(.*\n)*.*invalid choice:.*inventedsubproject(.*\n)*")
179
180 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200181 self.run_with_output(
182 self.llvm_projects(
183 "--remove",
184 "inventedsubproject"))
Diana Picus3b2ef822016-10-13 16:53:18 +0300185
Diana Picusb4307602017-04-05 19:48:39 +0200186 self.assertRegex(
187 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300188 "(.*\n)*.*invalid choice:.*inventedsubproject(.*\n)*")
189
190 def test_duplicate_add_remove(self):
191 """
192 Test that we don't crash when trying to add / remove the same subproject
193 twice with the same command.
194 """
Diana Picus81089db2017-05-05 22:26:49 +0200195 output = self.run_with_output(
196 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100197 "--repos", self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200198 "--add", "clang", "lld", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200199 self.assertRegex(output,
200 "Projects linked:.*\n" +
201 ".*clang.*\n" +
202 ".*lld.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300203
Diana Picus81089db2017-05-05 22:26:49 +0200204 output = self.run_with_output(
205 self.llvm_projects(
206 "--remove", "lld", "lld", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200207 self.assertRegex(output,
208 "Projects linked:.*\n" +
209 ".*none.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300210
211 def test_redundant_add_remove(self):
212 """
213 Test that we can add a subproject that already exists (either because it
214 was added by our script or manually) or remove a subproject that doesn't
215 exist.
216 """
Diana Picus3601bea2017-05-29 11:26:18 +0200217 self.add_worktree(self.get_subproj_repo("clang"),
218 os.path.join(self.llvm_src, "tools", "clang"),
219 self.branch)
220 self.add_worktree(
221 self.get_subproj_repo("compiler-rt"),
Diana Picus3b2ef822016-10-13 16:53:18 +0300222 os.path.join(self.llvm_src, "projects", "compiler-rt"),
223 self.branch)
224
Diana Picusadb07c42017-11-22 16:12:57 +0100225 output = self.run_with_output(self.llvm_projects(
226 "--repos", self.repos,
227 "--add", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200228 self.assertRegex(output,
229 "Projects linked:.*\n" +
230 ".*clang.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300231
Diana Picus81089db2017-05-05 22:26:49 +0200232 output = self.run_with_output(
233 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100234 "--repos", self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200235 "--add", "compiler-rt", "lld"))
Diana Picusb4307602017-04-05 19:48:39 +0200236 self.assertRegex(
Diana Picus3b2ef822016-10-13 16:53:18 +0300237 output,
238 "Projects linked:.*\n" +
239 ".*clang.*\n" +
240 ".*compiler-rt.*\n" +
241 ".*lld.*")
242
Diana Picus81089db2017-05-05 22:26:49 +0200243 output = self.run_with_output(
244 self.llvm_projects(
245 "--remove", "lldb", "libcxx", "lld"))
Diana Picusb4307602017-04-05 19:48:39 +0200246 self.assertRegex(
Diana Picus3b2ef822016-10-13 16:53:18 +0300247 output,
248 "Projects linked:.*\n" +
249 ".*clang.*\n" +
250 ".*compiler-rt.*")
251
252 def test_simultaneous_add_remove(self):
253 """
254 Test that we error out when someone is trying to add and remove the same
255 project with the same command.
256 """
257 # Try the really basic case and make sure we're not touching anything
258 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200259 self.run_with_output(
260 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100261 "--repos",
262 self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200263 "--add",
264 "clang",
265 "--remove",
266 "clang"))
Diana Picus3b2ef822016-10-13 16:53:18 +0300267
Diana Picusb4307602017-04-05 19:48:39 +0200268 self.assertRegex(
269 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300270 "(.*\n)*.*Can't add and remove clang at the same time(.*\n)*")
271
272 self.assertFalse(
273 os.path.exists(
274 os.path.join(self.llvm_src, "tools", "clang")))
275
276 # Try something a bit more complicated and make sure we're not touching
277 # anything
Diana Picus3601bea2017-05-29 11:26:18 +0200278 self.add_worktree(
279 self.get_subproj_repo("lld"),
Diana Picus3b2ef822016-10-13 16:53:18 +0300280 os.path.join(self.llvm_src, "tools", "lld"),
281 self.branch)
282
283 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200284 self.run_with_output(
285 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100286 "--repos",
287 self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200288 "--add",
289 "clang",
290 "lld",
291 "libcxx",
292 "--remove",
293 "lld",
294 "libcxx"))
Diana Picusb4307602017-04-05 19:48:39 +0200295 self.assertRegex(
296 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300297 "(.*\n)*" +
298 ".*Can't add and remove (lld|libcxx) at the same time(.*\n)*")
299
300 # Make sure we didn't touch anything
301 self.assertFalse(
302 os.path.exists(
303 os.path.join(self.llvm_src, "tools", "clang")))
304 self.assertTrue(
305 os.path.exists(
306 os.path.join(self.llvm_src, "tools", "lld")))
307 self.assertFalse(
308 os.path.exists(
309 os.path.join(self.llvm_src, "projects", "libcxx")))
310
311 def test_multiple_adds_removes(self):
312 """
313 Test that we can have multiple --add and --remove options in the same
314 command and that only the last one of each kind matters.
315 """
Diana Picus81089db2017-05-05 22:26:49 +0200316 output = self.run_with_output(
317 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100318 "--repos",
319 self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200320 "--add",
321 "libcxxabi",
322 "--remove",
323 "lld",
324 "lldb",
325 "--add",
326 "clang",
327 "libcxx",
328 "--remove",
329 "libunwind"))
Diana Picusb4307602017-04-05 19:48:39 +0200330 self.assertRegex(output,
331 "Projects linked:.*\n" +
332 ".*clang.*\n" +
333 ".*libcxx.*\n")
Diana Picus3b2ef822016-10-13 16:53:18 +0300334
Diana Picus81089db2017-05-05 22:26:49 +0200335 output = self.run_with_output(
336 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100337 "--repos",
338 self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200339 "--add",
340 "libunwind",
341 "libcxxabi",
342 "--remove",
343 "clang",
344 "libcxx",
345 "--add",
346 "compiler-rt",
347 "--remove",
348 "libcxxabi"))
Diana Picusb4307602017-04-05 19:48:39 +0200349 self.assertRegex(output,
350 "Projects linked:.*\n" +
351 ".*clang.*\n" +
352 ".*compiler-rt.*\n" +
353 ".*libcxx.*\n")
Diana Picus3b2ef822016-10-13 16:53:18 +0300354
Diana Picus81089db2017-05-05 22:26:49 +0200355 output = self.run_with_output(
356 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100357 "--repos",
358 self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200359 "--add",
360 "libcxx",
361 "--remove",
362 "lld",
363 "--add",
364 "lld",
365 "--remove",
366 "libcxx"))
Diana Picusb4307602017-04-05 19:48:39 +0200367 self.assertRegex(output,
368 "Projects linked:.*\n" +
369 ".*clang.*\n" +
370 ".*compiler-rt.*\n" +
371 ".*lld.*\n")
Diana Picus81089db2017-05-05 22:26:49 +0200372
373 def test_different_env(self):
374 """
375 Test that we can have different environments in completely different
376 paths and they don't interfere when we try to add/remove projects.
377 """
378 # Create a separate environment
379 new_env = mkdtemp()
380 new_branch = "br" + str(uuid4())
Diana Picus3601bea2017-05-29 11:26:18 +0200381 self.add_worktree(self.get_subproj_repo("llvm"),
382 os.path.join(new_env, "llvm"), new_branch)
Diana Picus81089db2017-05-05 22:26:49 +0200383
384 # Check that we start with a clean slate in both the new environment and
385 # the one that's already set up
386 output = self.run_with_output(self.llvm_projects())
387 self.assertRegex(output, "Projects linked:.*\n.*none.*")
388
389 output = self.run_with_output(self.llvm_projects(env=new_env))
390 self.assertRegex(output, "Projects linked:.*\n.*none.*")
391
392 # Make sure that adding projects works
393 output = self.run_with_output(
394 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100395 "--repos", self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200396 "--add", "clang", "lld"))
397 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n.*lld.*\n")
398
399 output = self.run_with_output(
400 self.llvm_projects(
Diana Picusadb07c42017-11-22 16:12:57 +0100401 "--repos",
402 self.repos,
Diana Picus81089db2017-05-05 22:26:49 +0200403 "--add",
404 "libcxx",
405 "libcxxabi",
406 env=new_env))
407 self.assertRegex(output,
408 "Projects linked:.*\n.*libcxx.*\n.*libcxxabi.*\n.*")
409
410 output = self.run_with_output(self.llvm_projects())
411 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n.*lld.*\n")
412
413 # Make sure that removing projects works
414 output = self.run_with_output(self.llvm_projects("--remove", "lld"))
415 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n")
416
417 output = self.run_with_output(self.llvm_projects("--remove", "libcxx",
418 env=new_env))
419 self.assertRegex(output,
420 "Projects linked:.*\n.*libcxxabi.*\n.*")
421
422 output = self.run_with_output(self.llvm_projects())
423 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n")
424
425 shutil.rmtree(new_env)