blob: a9b9de1c30a1faecb5d2b16289439d6b8081aadb [file] [log] [blame]
Alex Kleinc05f3d12019-05-29 14:16:21 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""field_handler module tests."""
6
Alex Kleinc05f3d12019-05-29 14:16:21 -06007import os
8
9from chromite.api import field_handler
10from chromite.api.gen.chromite.api import build_api_test_pb2
11from chromite.api.gen.chromiumos import common_pb2
12from chromite.lib import chroot_lib
13from chromite.lib import cros_test_lib
14from chromite.lib import osutils
Joanna Wang92cad812021-11-03 14:52:08 -070015from chromite.lib import remoteexec_util
Alex Kleinc05f3d12019-05-29 14:16:21 -060016
17
18class ChrootHandlerTest(cros_test_lib.TestCase):
19 """ChrootHandler tests."""
20
21 def setUp(self):
22 self.path = '/chroot/dir'
23 self.cache_dir = '/cache/dir'
Alex Klein5e4b1bc2019-07-02 12:27:06 -060024 self.chrome_dir = '/chrome/dir'
Alex Kleinb7485bb2019-09-19 13:23:37 -060025 self.env = {'FEATURES': 'thing', 'CHROME_ORIGIN': 'LOCAL_SOURCE'}
Alex Klein5e4b1bc2019-07-02 12:27:06 -060026 self.expected_chroot = chroot_lib.Chroot(path=self.path,
27 cache_dir=self.cache_dir,
28 chrome_root=self.chrome_dir,
29 env=self.env)
Alex Kleinc05f3d12019-05-29 14:16:21 -060030
31 def test_parse_chroot_success(self):
32 """Test successful Chroot message parse."""
33 chroot_msg = common_pb2.Chroot()
34 chroot_msg.path = self.path
35 chroot_msg.cache_dir = self.cache_dir
Alex Klein5e4b1bc2019-07-02 12:27:06 -060036 chroot_msg.chrome_dir = self.chrome_dir
Alex Kleinc05f3d12019-05-29 14:16:21 -060037 chroot_msg.env.features.add().feature = 'thing'
38
Alex Kleinc7d647f2020-01-06 12:00:48 -070039 chroot_handler = field_handler.ChrootHandler(clear_field=False)
Alex Kleinc05f3d12019-05-29 14:16:21 -060040 parsed_chroot = chroot_handler.parse_chroot(chroot_msg)
41
42 self.assertEqual(self.expected_chroot, parsed_chroot)
43
44 def test_handle_success(self):
45 """Test a successful Chroot message parse from a parent message."""
46 message = build_api_test_pb2.TestRequestMessage()
47 message.chroot.path = self.path
48 message.chroot.cache_dir = self.cache_dir
Alex Klein5e4b1bc2019-07-02 12:27:06 -060049 message.chroot.chrome_dir = self.chrome_dir
Alex Kleinc05f3d12019-05-29 14:16:21 -060050 message.chroot.env.features.add().feature = 'thing'
51
52 # First a no-clear parse.
Alex Kleinc7d647f2020-01-06 12:00:48 -070053 chroot_handler = field_handler.ChrootHandler(clear_field=False)
Alex Kleinc05f3d12019-05-29 14:16:21 -060054 chroot = chroot_handler.handle(message)
55
56 self.assertEqual(self.expected_chroot, chroot)
57 self.assertEqual(message.chroot.path, self.path)
58
59 # A clear field parse.
Alex Kleinc7d647f2020-01-06 12:00:48 -070060 clear_chroot_handler = field_handler.ChrootHandler(clear_field=True)
Alex Kleinc05f3d12019-05-29 14:16:21 -060061 chroot = clear_chroot_handler.handle(message)
62
63 self.assertEqual(self.expected_chroot, chroot)
64 self.assertFalse(message.chroot.path)
65
66 def test_handle_empty_chroot_message(self):
67 """Test handling of an empty chroot message."""
68 message = build_api_test_pb2.TestRequestMessage()
Alex Kleinb49be8a2019-12-20 10:23:03 -070069 empty_chroot = chroot_lib.Chroot()
Alex Kleinc05f3d12019-05-29 14:16:21 -060070
Alex Kleinc7d647f2020-01-06 12:00:48 -070071 chroot_handler = field_handler.ChrootHandler(clear_field=False)
Alex Kleinc05f3d12019-05-29 14:16:21 -060072 chroot = chroot_handler.handle(message)
73
74 self.assertEqual(empty_chroot, chroot)
75
76
Joanna Wang92cad812021-11-03 14:52:08 -070077class HandleRemoteexec(cros_test_lib.TempDirTestCase):
78 """Tests for handling remoteexec."""
79
80 def test_handle_remoteexec(self):
81 """Test handling remoteexec when there is a RemoteexecConfig."""
82 reclient_dir = os.path.join(self.tempdir, 'cipd/rbe')
83 reproxy_cfg_file = os.path.join(self.tempdir,
84 'reclient_cfgs/reproxy_config.cfg')
85
86 osutils.SafeMakedirs(reclient_dir)
87 osutils.Touch(reproxy_cfg_file, makedirs=True)
88 remoteexec_config = common_pb2.RemoteexecConfig(
89 reclient_dir=reclient_dir, reproxy_cfg_file=reproxy_cfg_file)
90 message = build_api_test_pb2.TestRequestMessage(
91 remoteexec_config=remoteexec_config)
92
93 expected = remoteexec_util.Remoteexec(reclient_dir, reproxy_cfg_file)
94 self.assertEqual(expected, field_handler.handle_remoteexec(message))
95
96 def test_handle_remoteexec_no_config(self):
97 """Test handling remoteexec when there is no RmoteexecConfig."""
98 message = build_api_test_pb2.TestRequestMessage()
99 self.assertIsNone(field_handler.handle_remoteexec(message))
100
101
Alex Kleinaae49772019-07-26 10:20:50 -0600102class CopyPathInTest(cros_test_lib.TempDirTestCase):
Alex Kleinc05f3d12019-05-29 14:16:21 -0600103 """PathHandler tests."""
104
105 def setUp(self):
106 self.source_dir = os.path.join(self.tempdir, 'source')
107 self.dest_dir = os.path.join(self.tempdir, 'destination')
108 osutils.SafeMakedirs(self.source_dir)
109 osutils.SafeMakedirs(self.dest_dir)
110
111 self.source_file1 = os.path.join(self.source_dir, 'file1')
112 self.file1_contents = 'file 1'
113 osutils.WriteFile(self.source_file1, self.file1_contents)
114
115 self.file2_contents = 'some data'
116 self.source_file2 = os.path.join(self.source_dir, 'file2')
117 osutils.WriteFile(self.source_file2, self.file2_contents)
118
119 def _path_checks(self, source_file, dest_file, contents=None):
120 """Set of common checks for the copied files/directories."""
121 # Message should now reflect the new path.
122 self.assertNotEqual(source_file, dest_file)
123 # The new path should be in the destination directory.
124 self.assertStartsWith(dest_file, self.dest_dir)
125 # The new file should exist.
126 self.assertExists(dest_file)
127
128 if contents:
129 # The contents should be the same as the source file.
130 self.assertFileContents(dest_file, contents)
131
132 def test_handle_file(self):
133 """Test handling of a single file."""
134 message = build_api_test_pb2.TestRequestMessage()
135 message.path.path = self.source_file1
136 message.path.location = common_pb2.Path.OUTSIDE
137
Alex Kleinaae49772019-07-26 10:20:50 -0600138 with field_handler.copy_paths_in(message, self.dest_dir, delete=True):
Alex Kleinc05f3d12019-05-29 14:16:21 -0600139 new_path = message.path.path
140 self._path_checks(self.source_file1, new_path, self.file1_contents)
141
142 # The file should have been deleted on exit with delete=True.
143 self.assertNotExists(new_path)
Alex Kleinaae49772019-07-26 10:20:50 -0600144 # The original should still exist.
145 self.assertExists(self.source_file1)
146 # The path should get reset.
Alex Kleinaa705412019-06-04 15:00:30 -0600147 self.assertEqual(message.path.path, self.source_file1)
Alex Kleinc05f3d12019-05-29 14:16:21 -0600148
149 def test_handle_files(self):
150 """Test handling of multiple files."""
151 message = build_api_test_pb2.TestRequestMessage()
152 message.path.path = self.source_file1
153 message.path.location = common_pb2.Path.OUTSIDE
154 message.another_path.path = self.source_file2
155 message.another_path.location = common_pb2.Path.OUTSIDE
156
Alex Kleinaae49772019-07-26 10:20:50 -0600157 with field_handler.copy_paths_in(message, self.dest_dir, delete=False):
Alex Kleinc05f3d12019-05-29 14:16:21 -0600158 new_path1 = message.path.path
159 new_path2 = message.another_path.path
160
161 self._path_checks(self.source_file1, new_path1, self.file1_contents)
162 self._path_checks(self.source_file2, new_path2, self.file2_contents)
163
164 # The files should still exist with delete=False.
165 self.assertExists(new_path1)
166 self.assertExists(new_path2)
167
Alex Kleinaa705412019-06-04 15:00:30 -0600168 def test_handle_nested_file(self):
169 """Test the nested path handling."""
170 message = build_api_test_pb2.TestRequestMessage()
171 message.nested_path.path.path = self.source_file1
172 message.nested_path.path.location = common_pb2.Path.OUTSIDE
173
Alex Kleinaae49772019-07-26 10:20:50 -0600174 with field_handler.copy_paths_in(message, self.dest_dir):
Alex Kleinaa705412019-06-04 15:00:30 -0600175 new_path = message.nested_path.path.path
176 self._path_checks(self.source_file1, new_path, self.file1_contents)
177
Alex Kleinc05f3d12019-05-29 14:16:21 -0600178 def test_handle_directory(self):
179 """Test handling of a directory."""
180 message = build_api_test_pb2.TestRequestMessage()
181 message.path.path = self.source_dir
182 message.path.location = common_pb2.Path.OUTSIDE
183
Alex Kleinaae49772019-07-26 10:20:50 -0600184 with field_handler.copy_paths_in(message, self.dest_dir):
Alex Kleinc05f3d12019-05-29 14:16:21 -0600185 new_path = message.path.path
186
187 self._path_checks(self.source_dir, self.dest_dir)
188 # Make sure both directories have the same files.
Mike Frysinger678735c2019-09-28 18:23:28 -0400189 self.assertCountEqual(os.listdir(self.source_dir), os.listdir(new_path))
Alex Kleinc05f3d12019-05-29 14:16:21 -0600190
191 def test_direction(self):
192 """Test the direction argument preventing copies."""
193 message = build_api_test_pb2.TestRequestMessage()
194 message.path.path = self.source_file1
195 message.path.location = common_pb2.Path.INSIDE
196
Alex Kleinaae49772019-07-26 10:20:50 -0600197 with field_handler.copy_paths_in(message, self.dest_dir, delete=True):
Alex Kleinc05f3d12019-05-29 14:16:21 -0600198 self.assertEqual(self.source_file1, message.path.path)
199
200 # It should not be deleting the file when it doesn't need to copy it even
201 # with delete=True.
202 self.assertExists(self.source_file1)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600203
204 def test_prefix_inside(self):
205 """Test the transfer inside prefix handling."""
206 message = build_api_test_pb2.TestRequestMessage()
207 message.path.path = self.source_dir
208 message.path.location = common_pb2.Path.OUTSIDE
209
Alex Kleinaae49772019-07-26 10:20:50 -0600210 with field_handler.copy_paths_in(message, self.dest_dir,
211 prefix=self.tempdir):
Alex Kleinbd6edf82019-07-18 10:30:49 -0600212 new_path = message.path.path
213 # The prefix should be removed.
214 self.assertFalse(new_path.startswith(self.tempdir))
215
Alex Kleinbd6edf82019-07-18 10:30:49 -0600216
Alex Kleinf0717a62019-12-06 09:45:00 -0700217class SyncDirsTest(cros_test_lib.TempDirTestCase):
218 """Tests for sync_dirs."""
219
220 def setUp(self):
221 D = cros_test_lib.Directory
222 filesystem = (
223 D('chroot', (
224 D('tmp', (
225 D('tempdir', ()),
226 )),
227 )),
228 D('sources', (
229 D('single_file', ('single_file.txt',)),
230 D('nested_directories', (
231 'basedir_file.log',
232 D('nested1', (
233 'nested1.txt',
234 D('nested2', ('nested2.txt',)),
235 )),
236 )),
237 )),
238 )
239 cros_test_lib.CreateOnDiskHierarchy(self.tempdir, filesystem)
240
241 self.chroot = os.path.join(self.tempdir, 'chroot')
242 self.chroot_tmp = os.path.join(self.chroot, 'tmp')
243 self.destination = os.path.join(self.chroot_tmp, 'tempdir')
244 self.inside_path = '/tmp/tempdir'
245
246 self.single_file_src = os.path.join(self.tempdir, 'sources', 'single_file')
247 self.sf_src_file = os.path.join(self.single_file_src, 'single_file.txt')
248 self.sf_dest_file = os.path.join(self.destination, 'single_file.txt')
249
250 self.nested_dirs_src = (
251 os.path.join(self.tempdir, 'sources', 'nested_directories'))
252 self.nested_src_files = (
253 os.path.join(self.nested_dirs_src, 'basedir_file.log'),
254 os.path.join(self.nested_dirs_src, 'nested1', 'nested1.txt'),
255 os.path.join(self.nested_dirs_src, 'nested1', 'nested2', 'nested2.txt'),
256 )
257 self.nested_dest_files = (
258 os.path.join(self.destination, 'basedir_file.log'),
259 os.path.join(self.destination, 'nested1', 'nested1.txt'),
260 os.path.join(self.destination, 'nested1', 'nested2', 'nested2.txt'),
261 )
262
263 self.message = build_api_test_pb2.TestRequestMessage()
264
265 def _assertExist(self, files):
266 for f in files:
267 self.assertExists(f)
268
269 def _assertNotExist(self, files):
270 for f in files:
271 self.assertNotExists(f)
272
273 def testSingleFileTransfer(self):
274 """Single source file syncs."""
275 self.message.synced_dir.dir = self.single_file_src
276
277 # Verify source files exist and destination files do not.
278 self.assertExists(self.sf_src_file)
279 self.assertNotExists(self.sf_dest_file)
280
281 with field_handler.sync_dirs(self.message, self.destination, self.chroot):
282 # Verify the prefix is getting correctly stripped.
283 self.assertEqual(self.message.synced_dir.dir, self.inside_path)
284 # Verify the files have all been correctly copied in.
285 self.assertExists(self.sf_dest_file)
286
287 self.assertEqual(self.message.synced_dir.dir, self.single_file_src)
288 # Verify the files have all been copied out.
289 self.assertExists(self.sf_src_file)
290
291 def testNestedFileSync(self):
292 """Nested directories and files sync."""
293 self.message.synced_dir.dir = self.nested_dirs_src
294
295 self._assertExist(self.nested_src_files)
296 self._assertNotExist(self.nested_dest_files)
297
298 with field_handler.sync_dirs(self.message, self.destination, self.chroot):
299 self.assertEqual(self.message.synced_dir.dir, self.inside_path)
300 self._assertExist(self.nested_dest_files)
301
302 self.assertEqual(self.message.synced_dir.dir, self.nested_dirs_src)
303 self._assertExist(self.nested_src_files)
304
305 def testDeletion(self):
306 """Test file deletions are exported correctly."""
307 self.message.synced_dir.dir = self.nested_dirs_src
308
309 deleted_src = os.path.join(self.nested_dirs_src, 'nested1', 'nested1.txt')
310 deleted_dest = os.path.join(self.destination, 'nested1', 'nested1.txt')
311
312 self._assertExist(self.nested_src_files)
313 self._assertNotExist(self.nested_dest_files)
314
315 with field_handler.sync_dirs(self.message, self.destination, self.chroot):
316 self._assertExist(self.nested_dest_files)
317 osutils.SafeUnlink(deleted_dest)
318
319 self._assertExist(set(self.nested_src_files) - {deleted_src})
320 self.assertNotExists(deleted_src)
321
322 def testCreation(self):
323 """Test file creations are exported correctly."""
324 self.message.synced_dir.dir = self.nested_dirs_src
325
326 new_src = os.path.join(self.nested_dirs_src, 'new_dir', 'new_file')
327 new_dest = os.path.join(self.destination, 'new_dir', 'new_file')
328
329 self._assertExist(self.nested_src_files)
330 self._assertNotExist(self.nested_dest_files)
331
332 with field_handler.sync_dirs(self.message, self.destination, self.chroot):
333 self._assertExist(self.nested_dest_files)
334 osutils.Touch(new_dest, makedirs=True)
335
336 self._assertExist(self.nested_src_files)
337 self.assertExists(new_src)
338
339 def testModification(self):
340 """Test file modifications are exported correctly."""
341 self.message.synced_dir.dir = self.single_file_src
342
343 self.assertExists(self.sf_src_file)
344 self.assertNotExists(self.sf_dest_file)
345
346 self.assertEqual('', osutils.ReadFile(self.sf_src_file))
347 file_content = 'Content!'
348
349 with field_handler.sync_dirs(self.message, self.destination, self.chroot):
350 self.assertExists(self.sf_dest_file)
351 osutils.WriteFile(self.sf_dest_file, file_content)
352
353 self.assertExists(self.sf_src_file)
354 self.assertEqual(file_content, osutils.ReadFile(self.sf_src_file))
355
356
Alex Kleinaae49772019-07-26 10:20:50 -0600357class ExtractResultsTest(cros_test_lib.TempDirTestCase):
358 """Tests for extract_results."""
Alex Kleinbd6edf82019-07-18 10:30:49 -0600359
360 def setUp(self):
361 # Setup the directories.
362 self.chroot_dir = os.path.join(self.tempdir, 'chroot')
363 self.source_dir = '/source'
364 self.chroot_source = os.path.join(self.chroot_dir,
365 self.source_dir.lstrip(os.sep))
366 self.source_dir2 = '/source2'
367 self.chroot_source2 = os.path.join(self.chroot_dir,
368 self.source_dir2.lstrip(os.sep))
369 self.dest_dir = os.path.join(self.tempdir, 'destination')
370 osutils.SafeMakedirs(self.chroot_source)
371 osutils.SafeMakedirs(self.chroot_source2)
372 osutils.SafeMakedirs(self.dest_dir)
373
374 # Two files in the same directory inside the chroot.
375 self.source_file1 = os.path.join(self.chroot_source, 'file1')
376 self.source_file1_inside = os.path.join(self.source_dir, 'file1')
377 self.file1_contents = 'file 1'
378 osutils.WriteFile(self.source_file1, self.file1_contents)
379
380 self.file2_contents = 'some data'
381 self.source_file2 = os.path.join(self.chroot_source, 'file2')
382 self.source_file2_inside = os.path.join(self.source_dir, 'file2')
383 osutils.WriteFile(self.source_file2, self.file2_contents)
384
385 # Third file in a different location.
386 self.file3_contents = 'another file'
387 self.source_file3 = os.path.join(self.chroot_source2, 'file3')
388 self.source_file3_inside = os.path.join(self.source_dir2, 'file3')
389 osutils.WriteFile(self.source_file3, self.file3_contents)
390
391 self.request = build_api_test_pb2.TestRequestMessage()
392 self.request.result_path.path.path = self.dest_dir
393 self.request.result_path.path.location = common_pb2.Path.OUTSIDE
394 self.response = build_api_test_pb2.TestResultMessage()
395 self.chroot = chroot_lib.Chroot(path=self.chroot_dir)
396
397 def _path_checks(self, path, destination, contents=None):
398 self.assertTrue(path)
399 self.assertStartsWith(path, destination)
400 self.assertExists(path)
401 if contents:
402 self.assertFileContents(path, contents)
403
404 def test_single_file(self):
Alex Klein3164d132020-11-19 15:11:31 -0700405 """Test a single file.
406
407 Verify:
408 /path/to/chroot/file -> /path/to/destination/file
409 """
Alex Kleinbd6edf82019-07-18 10:30:49 -0600410 self.response.artifact.path = self.source_file1_inside
411 self.response.artifact.location = common_pb2.Path.INSIDE
412
Alex Kleinaae49772019-07-26 10:20:50 -0600413 field_handler.extract_results(self.request, self.response, self.chroot)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600414
415 self._path_checks(self.response.artifact.path, self.dest_dir,
416 contents=self.file1_contents)
417
418 def test_single_directory(self):
Alex Klein3164d132020-11-19 15:11:31 -0700419 """Test a single directory.
420
421 Verify:
422 /path/to/chroot/directory/* -> /path/to/destination/directory/*
423 """
Alex Kleinbd6edf82019-07-18 10:30:49 -0600424 self.response.artifact.path = self.source_dir
425 self.response.artifact.location = common_pb2.Path.INSIDE
426
Alex Kleinaae49772019-07-26 10:20:50 -0600427 field_handler.extract_results(self.request, self.response, self.chroot)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600428
429 self._path_checks(self.response.artifact.path, self.dest_dir)
Mike Frysinger678735c2019-09-28 18:23:28 -0400430 self.assertCountEqual(os.listdir(self.chroot_source),
Alex Kleinbd6edf82019-07-18 10:30:49 -0600431 os.listdir(self.response.artifact.path))
432
433 def test_multiple_files(self):
Alex Klein3164d132020-11-19 15:11:31 -0700434 """Test multiple files.
435
436 Verify:
437 /path/to/chroot/some/path/file1 -> /path/to/destination/file1
438 /path/to/chroot/different/path/file2 -> /path/to/destination/file2
439 etc.
440 """
Alex Kleinbd6edf82019-07-18 10:30:49 -0600441 self.response.artifact.path = self.source_file1_inside
442 self.response.artifact.location = common_pb2.Path.INSIDE
443 self.response.nested_artifact.path.path = self.source_file2_inside
444 self.response.nested_artifact.path.location = common_pb2.Path.INSIDE
445
446 artifact3 = self.response.artifacts.add()
447 artifact3.path = self.source_file3_inside
448 artifact3.location = common_pb2.Path.INSIDE
449
Alex Kleinaae49772019-07-26 10:20:50 -0600450 field_handler.extract_results(self.request, self.response, self.chroot)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600451
452 self._path_checks(self.response.artifact.path, self.dest_dir,
453 contents=self.file1_contents)
454 self._path_checks(self.response.nested_artifact.path.path, self.dest_dir,
455 contents=self.file2_contents)
456
457 self.assertEqual(1, len(self.response.artifacts))
458 for artifact in self.response.artifacts:
459 self._path_checks(artifact.path, self.dest_dir,
460 contents=self.file3_contents)
461
462 def test_multiple_directories(self):
Alex Klein3164d132020-11-19 15:11:31 -0700463 """Test multiple directories.
464
465 Verify:
466 /path/to/chroot/some/directory -> /path/to/destination/directory
467 /path/to/chroot/another/directory2 -> /path/to/destination/directory2
468 etc.
469 """
Alex Kleinbd6edf82019-07-18 10:30:49 -0600470 self.response.artifact.path = self.source_dir
471 self.response.artifact.location = common_pb2.Path.INSIDE
472 self.response.nested_artifact.path.path = self.source_dir2
473 self.response.nested_artifact.path.location = common_pb2.Path.INSIDE
474
Alex Kleinaae49772019-07-26 10:20:50 -0600475 field_handler.extract_results(self.request, self.response, self.chroot)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600476
477 self._path_checks(self.response.artifact.path, self.dest_dir)
478 self._path_checks(self.response.nested_artifact.path.path, self.dest_dir)
479
480 expected = os.listdir(self.chroot_source)
481 expected.extend(os.listdir(self.chroot_source2))
Mike Frysinger678735c2019-09-28 18:23:28 -0400482 self.assertCountEqual(expected, os.listdir(self.response.artifact.path))