blob: 6836014a8da6d0e536712caf4867c7d6be34f703 [file] [log] [blame]
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001# Copyright 2017 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"""Tests for cros_sdk."""
6
Chris McDonald59650c32021-07-20 15:29:28 -06007import logging
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06008import os
Mike Frysinger66d32cd2019-12-17 14:55:29 -05009import subprocess
Mike Frysingeredc04912019-11-16 01:30:43 -050010import unittest
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060011
12from chromite.lib import cros_build_lib
Benjamin Gordon74645232018-05-04 17:40:42 -060013from chromite.lib import cros_sdk_lib
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060014from chromite.lib import cros_test_lib
15from chromite.lib import osutils
Mike Frysingerdaf57b82019-11-23 17:26:51 -050016from chromite.lib import retry_util
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060017from chromite.lib import sudo
Mike Frysingerdaf57b82019-11-23 17:26:51 -050018from chromite.scripts import cros_sdk
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060019
20
Mike Frysingeredc04912019-11-16 01:30:43 -050021# This long decorator triggers a false positive in the docstring test.
22# https://github.com/PyCQA/pylint/issues/3077
23# pylint: disable=bad-docstring-quotes
24@unittest.skipIf(cros_build_lib.IsInsideChroot(),
25 'Tests only make sense outside the chroot')
Benjamin Gordon03c56e42017-09-11 15:48:39 -040026class CrosSdkPrerequisitesTest(cros_test_lib.TempDirTestCase):
27 """Tests for required packages on the host machine.
28
29 These are not real unit tests. If these tests fail, it means your machine is
30 missing necessary commands to support image-backed chroots. Run cros_sdk in
31 a terminal to get info about what you need to install.
32 """
33
34 def testLvmCommandsPresent(self):
35 """Check for commands from the lvm2 package."""
36 with sudo.SudoKeepAlive():
37 cmd = ['lvs', '--version']
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050038 result = cros_build_lib.run(cmd, check=False)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040039 self.assertEqual(result.returncode, 0)
40
41 def testThinProvisioningToolsPresent(self):
42 """Check for commands from the thin-provisioning-tools package."""
43 with sudo.SudoKeepAlive():
44 cmd = ['thin_check', '-V']
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050045 result = cros_build_lib.run(cmd, check=False)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040046 self.assertEqual(result.returncode, 0)
47
48 def testLosetupCommandPresent(self):
49 """Check for commands from the mount package."""
50 with sudo.SudoKeepAlive():
51 cmd = ['losetup', '--help']
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050052 result = cros_build_lib.run(cmd, check=False)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040053 self.assertEqual(result.returncode, 0)
54
55
Mike Frysingerdaf57b82019-11-23 17:26:51 -050056class CrosSdkUtilsTest(cros_test_lib.MockTempDirTestCase):
57 """Tests for misc util funcs."""
58
59 def testGetArchStageTarballs(self):
60 """Basic test of GetArchStageTarballs."""
61 self.assertCountEqual([
62 'https://storage.googleapis.com/chromiumos-sdk/cros-sdk-123.tar.xz',
63 'https://storage.googleapis.com/chromiumos-sdk/cros-sdk-123.tbz2',
64 ], cros_sdk.GetArchStageTarballs('123'))
65
66 def testFetchRemoteTarballsEmpty(self):
67 """Test FetchRemoteTarballs with no results."""
68 m = self.PatchObject(retry_util, 'RunCurl')
69 with self.assertRaises(ValueError):
70 cros_sdk.FetchRemoteTarballs(self.tempdir, [], 'tarball')
71 m.return_value = cros_build_lib.CommandResult(stdout=b'Foo: bar\n')
72 with self.assertRaises(ValueError):
73 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x.tar'], 'tarball')
74
75 def testFetchRemoteTarballsSuccess(self):
76 """Test FetchRemoteTarballs with a successful download."""
77 curl = cros_build_lib.CommandResult(stdout=(
78 b'HTTP/1.0 200\n'
79 b'Foo: bar\n'
80 b'Content-Length: 100\n'
81 ))
82 self.PatchObject(retry_util, 'RunCurl', return_value=curl)
83 self.assertEqual(
84 os.path.join(self.tempdir, 'tar'),
85 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x/tar'], 'tarball'))
86
87
Mike Frysingeredc04912019-11-16 01:30:43 -050088@unittest.skipIf(cros_build_lib.IsInsideChroot(),
89 'Tests only make sense outside the chroot')
90@unittest.skip(
91 'These are triggering hangs inside lvm when run through run_tests. '
92 'https://crbug.com/764335')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060093class CrosSdkSnapshotTest(cros_test_lib.TempDirTestCase):
94 """Tests for the snapshot functionality in cros_sdk."""
95
96 def setUp(self):
97 with sudo.SudoKeepAlive():
98 # Create just enough of a chroot to fool cros_sdk into accepting it.
99 self.chroot = os.path.join(self.tempdir, 'chroot')
Benjamin Gordon74645232018-05-04 17:40:42 -0600100 cros_sdk_lib.MountChroot(self.chroot, create=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600101 logging.debug('Chroot mounted on %s', self.chroot)
102
103 chroot_etc = os.path.join(self.chroot, 'etc')
104 osutils.SafeMakedirsNonRoot(chroot_etc)
105
106 self.chroot_version_file = os.path.join(chroot_etc, 'cros_chroot_version')
107 osutils.Touch(self.chroot_version_file, makedirs=True)
108
109 def tearDown(self):
110 with sudo.SudoKeepAlive():
Don Garrett36650112018-06-28 15:54:34 -0700111 cros_sdk_lib.CleanupChrootMount(self.chroot, delete=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600112
113 def _crosSdk(self, args):
114 cmd = ['cros_sdk', '--chroot', self.chroot]
115 cmd.extend(args)
116
117 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400118 result = cros_build_lib.run(
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500119 cmd, print_cmd=False, capture_output=True, check=False,
Mike Frysinger66d32cd2019-12-17 14:55:29 -0500120 stderr=subprocess.STDOUT)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600121 except cros_build_lib.RunCommandError as e:
122 raise SystemExit('Running %r failed!: %s' % (cmd, e))
123
124 return result.returncode, result.output
125
126 def testSnapshotsRequireImage(self):
127 code, output = self._crosSdk(['--snapshot-list', '--nouse-image'])
128 self.assertNotEqual(code, 0)
129 self.assertIn('Snapshot operations are not compatible with', output)
130
131 code, output = self._crosSdk(['--snapshot-delete', 'test', '--nouse-image'])
132 self.assertNotEqual(code, 0)
133 self.assertIn('Snapshot operations are not compatible with', output)
134
135 code, output = self._crosSdk(['--snapshot-create', 'test', '--nouse-image'])
136 self.assertNotEqual(code, 0)
137 self.assertIn('Snapshot operations are not compatible with', output)
138
139 code, output = self._crosSdk(['--snapshot-restore', 'test',
140 '--nouse-image'])
141 self.assertNotEqual(code, 0)
142 self.assertIn('Snapshot operations are not compatible with', output)
143
144 def testSnapshotWithDeleteChroot(self):
145 code, output = self._crosSdk(['--delete', '--snapshot-list'])
146 self.assertNotEqual(code, 0)
147 self.assertIn('Trying to enter or snapshot the chroot', output)
148
149 code, output = self._crosSdk(['--delete', '--snapshot-delete', 'test'])
150 self.assertNotEqual(code, 0)
151 self.assertIn('Trying to enter or snapshot the chroot', output)
152
153 code, output = self._crosSdk(['--delete', '--snapshot-create', 'test'])
154 self.assertNotEqual(code, 0)
155 self.assertIn('Trying to enter or snapshot the chroot', output)
156
157 code, output = self._crosSdk(['--delete', '--snapshot-restore', 'test'])
158 self.assertNotEqual(code, 0)
159 self.assertIn('Trying to enter or snapshot the chroot', output)
160
161 def testEmptySnapshotList(self):
162 code, output = self._crosSdk(['--snapshot-list'])
163 self.assertEqual(code, 0)
164 self.assertEqual(output, '')
165
166 def testOneSnapshot(self):
167 code, _ = self._crosSdk(['--snapshot-create', 'test'])
168 self.assertEqual(code, 0)
169
170 code, output = self._crosSdk(['--snapshot-list'])
171 self.assertEqual(code, 0)
172 self.assertEqual(output.strip(), 'test')
173
174 def testMultipleSnapshots(self):
175 code, _ = self._crosSdk(['--snapshot-create', 'test'])
176 self.assertEqual(code, 0)
177 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
178 self.assertEqual(code, 0)
179
180 code, output = self._crosSdk(['--snapshot-list'])
181 self.assertEqual(code, 0)
182 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
183
184 def testCantCreateSameSnapshotTwice(self):
185 code, _ = self._crosSdk(['--snapshot-create', 'test'])
186 self.assertEqual(code, 0)
187 code, _ = self._crosSdk(['--snapshot-create', 'test'])
188 self.assertNotEqual(code, 0)
189
190 code, output = self._crosSdk(['--snapshot-list'])
191 self.assertEqual(code, 0)
192 self.assertEqual(output.strip(), 'test')
193
194 def testCreateSnapshotMountsAsNeeded(self):
195 with sudo.SudoKeepAlive():
Benjamin Gordon74645232018-05-04 17:40:42 -0600196 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600197
198 code, _ = self._crosSdk(['--snapshot-create', 'test'])
199 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500200 self.assertExists(self.chroot_version_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600201
202 code, output = self._crosSdk(['--snapshot-list'])
203 self.assertEqual(code, 0)
204 self.assertEqual(output.strip(), 'test')
205
206 def testDeleteGoodSnapshot(self):
207 code, _ = self._crosSdk(['--snapshot-create', 'test'])
208 self.assertEqual(code, 0)
209 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
210 self.assertEqual(code, 0)
211
212 code, _ = self._crosSdk(['--snapshot-delete', 'test'])
213 self.assertEqual(code, 0)
214
215 code, output = self._crosSdk(['--snapshot-list'])
216 self.assertEqual(code, 0)
217 self.assertEqual(output.strip(), 'test2')
218
219 def testDeleteMissingSnapshot(self):
220 code, _ = self._crosSdk(['--snapshot-create', 'test'])
221 self.assertEqual(code, 0)
222 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
223 self.assertEqual(code, 0)
224
225 code, _ = self._crosSdk(['--snapshot-delete', 'test3'])
226 self.assertEqual(code, 0)
227
228 code, output = self._crosSdk(['--snapshot-list'])
229 self.assertEqual(code, 0)
230 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
231
232 def testDeleteAndCreateSnapshot(self):
233 code, _ = self._crosSdk(['--snapshot-create', 'test'])
234 self.assertEqual(code, 0)
235 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
236 self.assertEqual(code, 0)
237
238 code, _ = self._crosSdk(['--snapshot-create', 'test',
239 '--snapshot-delete', 'test'])
240 self.assertEqual(code, 0)
241
242 code, output = self._crosSdk(['--snapshot-list'])
243 self.assertEqual(code, 0)
244 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
245
246 def testRestoreSnapshot(self):
247 with sudo.SudoKeepAlive():
248 test_file = os.path.join(self.chroot, 'etc', 'test_file')
249 osutils.Touch(test_file)
250
251 code, _ = self._crosSdk(['--snapshot-create', 'test'])
252 self.assertEqual(code, 0)
253
254 osutils.SafeUnlink(test_file)
255
256 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
257 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600258 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500259 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600260
261 code, output = self._crosSdk(['--snapshot-list'])
262 self.assertEqual(code, 0)
263 self.assertEqual(output, '')
264
265 def testRestoreAndCreateSnapshot(self):
266 with sudo.SudoKeepAlive():
267 test_file = os.path.join(self.chroot, 'etc', 'test_file')
268 osutils.Touch(test_file)
269
270 code, _ = self._crosSdk(['--snapshot-create', 'test'])
271 self.assertEqual(code, 0)
272
273 osutils.SafeUnlink(test_file)
274
275 code, _ = self._crosSdk(['--snapshot-restore', 'test',
276 '--snapshot-create', 'test'])
277 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600278 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500279 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600280
281 code, output = self._crosSdk(['--snapshot-list'])
282 self.assertEqual(code, 0)
283 self.assertEqual(output.strip(), 'test')
284
285 def testDeleteCantRestoreSameSnapshot(self):
286 code, _ = self._crosSdk(['--snapshot-create', 'test'])
287 self.assertEqual(code, 0)
288
289 code, _ = self._crosSdk(['--snapshot-delete', 'test',
290 '--snapshot-restore', 'test'])
291 self.assertNotEqual(code, 0)
292
293 code, output = self._crosSdk(['--snapshot-list'])
294 self.assertEqual(code, 0)
295 self.assertEqual(output.strip(), 'test')
296
297 def testCantRestoreInvalidSnapshot(self):
298 with sudo.SudoKeepAlive():
299 test_file = os.path.join(self.chroot, 'etc', 'test_file')
300 osutils.Touch(test_file)
301
302 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
303 self.assertNotEqual(code, 0)
304 # Failed restore leaves the existing snapshot in place.
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500305 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600306
307 def testRestoreSnapshotMountsAsNeeded(self):
308 with sudo.SudoKeepAlive():
309 test_file = os.path.join(self.chroot, 'etc', 'test_file')
310 osutils.Touch(test_file)
311
312 code, _ = self._crosSdk(['--snapshot-create', 'test'])
313 self.assertEqual(code, 0)
314
315 osutils.SafeUnlink(test_file)
316
Benjamin Gordon74645232018-05-04 17:40:42 -0600317 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600318
319 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
320 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500321 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600322
323 code, output = self._crosSdk(['--snapshot-list'])
324 self.assertEqual(code, 0)
325 self.assertEqual(output, '')