blob: 394f3ac2067f20714a6662af41a03fabfc63a94d [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 Picus3b2ef822016-10-13 16:53:18 +030027 def setUpClass(cls):
28 """Create the file structure and environment that llvmprojs expects"""
29 cls.llvm_root = mkdtemp()
30 cls.repos = os.path.join(cls.llvm_root, "repos")
31
32 cls.all_repos = ("llvm", "clang", "compiler-rt", "lld", "lldb",
33 "libcxx", "libcxxabi", "libunwind", "test-suite")
34
Diana Picus3b2ef822016-10-13 16:53:18 +030035 # Create dummy repos
36 for reponame in cls.all_repos:
Diana Picus3601bea2017-05-29 11:26:18 +020037 cls.create_dummy_repo(cls.get_subproj_repo(reponame))
Diana Picus3b2ef822016-10-13 16:53:18 +030038
39 @classmethod
40 def tearDownClass(cls):
41 shutil.rmtree(cls.llvm_root)
42
43 @classmethod
44 def setUp(cls):
Diana Picus81089db2017-05-05 22:26:49 +020045 cls.env = os.path.join(cls.llvm_root, "env" + str(uuid4()))
46 cls.llvm_src = os.path.join(cls.env, "llvm")
Diana Picus3b2ef822016-10-13 16:53:18 +030047
48 # Create LLVM worktree
49 cls.branch = "br" + str(uuid4())
Diana Picus3601bea2017-05-29 11:26:18 +020050 cls.add_worktree(cls.get_subproj_repo("llvm"), cls.llvm_src,
51 cls.branch)
Diana Picus3b2ef822016-10-13 16:53:18 +030052
Diana Picus3b2ef822016-10-13 16:53:18 +030053 @classmethod
54 def tearDown(cls):
55 # Clean up the directories where we might have added subprojects.
56 # This isn't 100% clean, because we don't clean up the repos between
57 # tests (so any branches will remain), but it's good enough for the
58 # current tests.
59 for subprojdir in (os.path.join(cls.llvm_src, "projects"),
60 os.path.join(cls.llvm_src, "tools")):
61 if os.path.isdir(subprojdir):
62 shutil.rmtree(subprojdir)
63 os.makedirs(subprojdir)
64
65 # Run prune on the original repos, to remove any dangling worktrees.
66 for reponame in cls.all_repos:
Diana Picus3601bea2017-05-29 11:26:18 +020067 repopath = cls.get_subproj_repo(reponame)
Diana Picus3b2ef822016-10-13 16:53:18 +030068 with cd(repopath):
69 cls.run_quietly(["git", "worktree", "prune"])
70
Diana Picus81089db2017-05-05 22:26:49 +020071 def test_repos_arg_is_compulsory(self):
72 """
73 Test that we must pass in the repos for various combinations of input
74 args.
75 """
76 with self.assertRaises(subprocess.CalledProcessError) as context:
77 self.run_with_output(self.llvm_projects(repos=None))
78
79 self.assertRegex(
80 str(context.exception.output),
81 "(.*\n)*.*the following arguments are required:(.*)--repos(.*\n)*")
82
83 with self.assertRaises(subprocess.CalledProcessError) as context:
84 self.run_with_output(
85 self.llvm_projects(
86 "--add", "clang", repos=None))
87
88 self.assertRegex(
89 str(context.exception.output),
90 "(.*\n)*.*the following arguments are required:(.*)--repos(.*\n)*")
91
92 with self.assertRaises(subprocess.CalledProcessError) as context:
93 self.run_with_output(
94 self.llvm_projects(
95 "--remove",
96 "clang",
97 repos=None))
98
99 self.assertRegex(
100 str(context.exception.output),
101 "(.*\n)*.*the following arguments are required:(.*)--repos(.*\n)*")
102
103 def test_env_arg_is_compulsory(self):
104 """
105 Test that we must pass in the environment for various combinations of
106 input args.
107 """
108 with self.assertRaises(subprocess.CalledProcessError) as context:
109 self.run_with_output(self.llvm_projects(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 "--add", "clang", env=None))
119
120 self.assertRegex(
121 str(context.exception.output),
122 "(.*\n)*.*the following arguments are required:(.*)--env(.*\n)*")
123
124 with self.assertRaises(subprocess.CalledProcessError) as context:
125 self.run_with_output(
126 self.llvm_projects(
127 "--remove", "clang", env=None))
128
129 self.assertRegex(
130 str(context.exception.output),
131 "(.*\n)*.*the following arguments are required:(.*)--env(.*\n)*")
132
Diana Picus3b2ef822016-10-13 16:53:18 +0300133 def test_dump_empty_config(self):
134 """
135 Test that we're correctly dumping an empty configuration (i.e. no
136 projects linked) when running llvmprojs without arguments.
137 """
Diana Picus81089db2017-05-05 22:26:49 +0200138 output = self.run_with_output(self.llvm_projects())
Diana Picusb4307602017-04-05 19:48:39 +0200139 self.assertRegex(output, "Projects linked:.*\n.*none.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300140
141 def test_add_remove_subprojects(self):
142 """
143 Test that we can add and remove one or several subprojects.
144 """
Diana Picus81089db2017-05-05 22:26:49 +0200145 output = self.run_with_output(self.llvm_projects("--add", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200146 self.assertRegex(output, "Projects linked:.*\n.*clang.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300147
Diana Picus81089db2017-05-05 22:26:49 +0200148 output = self.run_with_output(
149 self.llvm_projects(
150 "--add", "libcxx", "lldb"))
Diana Picusb4307602017-04-05 19:48:39 +0200151 self.assertRegex(
Diana Picus3b2ef822016-10-13 16:53:18 +0300152 output,
153 "Projects linked:.*\n" +
154 ".*clang.*\n" +
155 ".*libcxx.*\n" +
156 ".*lldb.*")
157
Diana Picus81089db2017-05-05 22:26:49 +0200158 output = self.run_with_output(self.llvm_projects("--remove", "libcxx"))
Diana Picusb4307602017-04-05 19:48:39 +0200159 self.assertRegex(output,
160 "Projects linked:.*\n" +
161 ".*clang.*\n" +
162 ".*lldb.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300163
Diana Picus81089db2017-05-05 22:26:49 +0200164 output = self.run_with_output(
165 self.llvm_projects(
166 "--remove", "clang", "lldb"))
Diana Picusb4307602017-04-05 19:48:39 +0200167 self.assertRegex(output,
168 "Projects linked:.*\n" +
169 ".*none.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300170
171 def test_add_remove_invalid_subprojects(self):
172 """
173 Test that we error out nicely when trying to add/remove invalid
174 subprojects.
175 """
176 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200177 self.run_with_output(
178 self.llvm_projects(
179 "--add", "inventedsubproject"))
Diana Picus3b2ef822016-10-13 16:53:18 +0300180
Diana Picusb4307602017-04-05 19:48:39 +0200181 self.assertRegex(
182 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300183 "(.*\n)*.*invalid choice:.*inventedsubproject(.*\n)*")
184
185 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200186 self.run_with_output(
187 self.llvm_projects(
188 "--remove",
189 "inventedsubproject"))
Diana Picus3b2ef822016-10-13 16:53:18 +0300190
Diana Picusb4307602017-04-05 19:48:39 +0200191 self.assertRegex(
192 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300193 "(.*\n)*.*invalid choice:.*inventedsubproject(.*\n)*")
194
195 def test_duplicate_add_remove(self):
196 """
197 Test that we don't crash when trying to add / remove the same subproject
198 twice with the same command.
199 """
Diana Picus81089db2017-05-05 22:26:49 +0200200 output = self.run_with_output(
201 self.llvm_projects(
202 "--add", "clang", "lld", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200203 self.assertRegex(output,
204 "Projects linked:.*\n" +
205 ".*clang.*\n" +
206 ".*lld.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300207
Diana Picus81089db2017-05-05 22:26:49 +0200208 output = self.run_with_output(
209 self.llvm_projects(
210 "--remove", "lld", "lld", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200211 self.assertRegex(output,
212 "Projects linked:.*\n" +
213 ".*none.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300214
215 def test_redundant_add_remove(self):
216 """
217 Test that we can add a subproject that already exists (either because it
218 was added by our script or manually) or remove a subproject that doesn't
219 exist.
220 """
Diana Picus3601bea2017-05-29 11:26:18 +0200221 self.add_worktree(self.get_subproj_repo("clang"),
222 os.path.join(self.llvm_src, "tools", "clang"),
223 self.branch)
224 self.add_worktree(
225 self.get_subproj_repo("compiler-rt"),
Diana Picus3b2ef822016-10-13 16:53:18 +0300226 os.path.join(self.llvm_src, "projects", "compiler-rt"),
227 self.branch)
228
Diana Picus81089db2017-05-05 22:26:49 +0200229 output = self.run_with_output(self.llvm_projects("--add", "clang"))
Diana Picusb4307602017-04-05 19:48:39 +0200230 self.assertRegex(output,
231 "Projects linked:.*\n" +
232 ".*clang.*")
Diana Picus3b2ef822016-10-13 16:53:18 +0300233
Diana Picus81089db2017-05-05 22:26:49 +0200234 output = self.run_with_output(
235 self.llvm_projects(
236 "--add", "compiler-rt", "lld"))
Diana Picusb4307602017-04-05 19:48:39 +0200237 self.assertRegex(
Diana Picus3b2ef822016-10-13 16:53:18 +0300238 output,
239 "Projects linked:.*\n" +
240 ".*clang.*\n" +
241 ".*compiler-rt.*\n" +
242 ".*lld.*")
243
Diana Picus81089db2017-05-05 22:26:49 +0200244 output = self.run_with_output(
245 self.llvm_projects(
246 "--remove", "lldb", "libcxx", "lld"))
Diana Picusb4307602017-04-05 19:48:39 +0200247 self.assertRegex(
Diana Picus3b2ef822016-10-13 16:53:18 +0300248 output,
249 "Projects linked:.*\n" +
250 ".*clang.*\n" +
251 ".*compiler-rt.*")
252
253 def test_simultaneous_add_remove(self):
254 """
255 Test that we error out when someone is trying to add and remove the same
256 project with the same command.
257 """
258 # Try the really basic case and make sure we're not touching anything
259 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200260 self.run_with_output(
261 self.llvm_projects(
262 "--add",
263 "clang",
264 "--remove",
265 "clang"))
Diana Picus3b2ef822016-10-13 16:53:18 +0300266
Diana Picusb4307602017-04-05 19:48:39 +0200267 self.assertRegex(
268 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300269 "(.*\n)*.*Can't add and remove clang at the same time(.*\n)*")
270
271 self.assertFalse(
272 os.path.exists(
273 os.path.join(self.llvm_src, "tools", "clang")))
274
275 # Try something a bit more complicated and make sure we're not touching
276 # anything
Diana Picus3601bea2017-05-29 11:26:18 +0200277 self.add_worktree(
278 self.get_subproj_repo("lld"),
Diana Picus3b2ef822016-10-13 16:53:18 +0300279 os.path.join(self.llvm_src, "tools", "lld"),
280 self.branch)
281
282 with self.assertRaises(subprocess.CalledProcessError) as context:
Diana Picus81089db2017-05-05 22:26:49 +0200283 self.run_with_output(
284 self.llvm_projects(
285 "--add",
286 "clang",
287 "lld",
288 "libcxx",
289 "--remove",
290 "lld",
291 "libcxx"))
Diana Picusb4307602017-04-05 19:48:39 +0200292 self.assertRegex(
293 str(context.exception.output),
Diana Picus3b2ef822016-10-13 16:53:18 +0300294 "(.*\n)*" +
295 ".*Can't add and remove (lld|libcxx) at the same time(.*\n)*")
296
297 # Make sure we didn't touch anything
298 self.assertFalse(
299 os.path.exists(
300 os.path.join(self.llvm_src, "tools", "clang")))
301 self.assertTrue(
302 os.path.exists(
303 os.path.join(self.llvm_src, "tools", "lld")))
304 self.assertFalse(
305 os.path.exists(
306 os.path.join(self.llvm_src, "projects", "libcxx")))
307
308 def test_multiple_adds_removes(self):
309 """
310 Test that we can have multiple --add and --remove options in the same
311 command and that only the last one of each kind matters.
312 """
Diana Picus81089db2017-05-05 22:26:49 +0200313 output = self.run_with_output(
314 self.llvm_projects(
315 "--add",
316 "libcxxabi",
317 "--remove",
318 "lld",
319 "lldb",
320 "--add",
321 "clang",
322 "libcxx",
323 "--remove",
324 "libunwind"))
Diana Picusb4307602017-04-05 19:48:39 +0200325 self.assertRegex(output,
326 "Projects linked:.*\n" +
327 ".*clang.*\n" +
328 ".*libcxx.*\n")
Diana Picus3b2ef822016-10-13 16:53:18 +0300329
Diana Picus81089db2017-05-05 22:26:49 +0200330 output = self.run_with_output(
331 self.llvm_projects(
332 "--add",
333 "libunwind",
334 "libcxxabi",
335 "--remove",
336 "clang",
337 "libcxx",
338 "--add",
339 "compiler-rt",
340 "--remove",
341 "libcxxabi"))
Diana Picusb4307602017-04-05 19:48:39 +0200342 self.assertRegex(output,
343 "Projects linked:.*\n" +
344 ".*clang.*\n" +
345 ".*compiler-rt.*\n" +
346 ".*libcxx.*\n")
Diana Picus3b2ef822016-10-13 16:53:18 +0300347
Diana Picus81089db2017-05-05 22:26:49 +0200348 output = self.run_with_output(
349 self.llvm_projects(
350 "--add",
351 "libcxx",
352 "--remove",
353 "lld",
354 "--add",
355 "lld",
356 "--remove",
357 "libcxx"))
Diana Picusb4307602017-04-05 19:48:39 +0200358 self.assertRegex(output,
359 "Projects linked:.*\n" +
360 ".*clang.*\n" +
361 ".*compiler-rt.*\n" +
362 ".*lld.*\n")
Diana Picus81089db2017-05-05 22:26:49 +0200363
364 def test_different_env(self):
365 """
366 Test that we can have different environments in completely different
367 paths and they don't interfere when we try to add/remove projects.
368 """
369 # Create a separate environment
370 new_env = mkdtemp()
371 new_branch = "br" + str(uuid4())
Diana Picus3601bea2017-05-29 11:26:18 +0200372 self.add_worktree(self.get_subproj_repo("llvm"),
373 os.path.join(new_env, "llvm"), new_branch)
Diana Picus81089db2017-05-05 22:26:49 +0200374
375 # Check that we start with a clean slate in both the new environment and
376 # the one that's already set up
377 output = self.run_with_output(self.llvm_projects())
378 self.assertRegex(output, "Projects linked:.*\n.*none.*")
379
380 output = self.run_with_output(self.llvm_projects(env=new_env))
381 self.assertRegex(output, "Projects linked:.*\n.*none.*")
382
383 # Make sure that adding projects works
384 output = self.run_with_output(
385 self.llvm_projects(
386 "--add", "clang", "lld"))
387 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n.*lld.*\n")
388
389 output = self.run_with_output(
390 self.llvm_projects(
391 "--add",
392 "libcxx",
393 "libcxxabi",
394 env=new_env))
395 self.assertRegex(output,
396 "Projects linked:.*\n.*libcxx.*\n.*libcxxabi.*\n.*")
397
398 output = self.run_with_output(self.llvm_projects())
399 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n.*lld.*\n")
400
401 # Make sure that removing projects works
402 output = self.run_with_output(self.llvm_projects("--remove", "lld"))
403 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n")
404
405 output = self.run_with_output(self.llvm_projects("--remove", "libcxx",
406 env=new_env))
407 self.assertRegex(output,
408 "Projects linked:.*\n.*libcxxabi.*\n.*")
409
410 output = self.run_with_output(self.llvm_projects())
411 self.assertRegex(output, "Projects linked:.*\n.*clang.*\n")
412
413 shutil.rmtree(new_env)