blob: 5e4330703032869aa71c092d8e8084b44f4c0b1a [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',
Mike Frysingerdaf57b82019-11-23 17:26:51 -050063 ], cros_sdk.GetArchStageTarballs('123'))
64
65 def testFetchRemoteTarballsEmpty(self):
66 """Test FetchRemoteTarballs with no results."""
67 m = self.PatchObject(retry_util, 'RunCurl')
68 with self.assertRaises(ValueError):
Mike Frysingerf744d032022-05-07 20:38:39 -040069 cros_sdk.FetchRemoteTarballs(self.tempdir, [])
Mike Frysingerdaf57b82019-11-23 17:26:51 -050070 m.return_value = cros_build_lib.CommandResult(stdout=b'Foo: bar\n')
71 with self.assertRaises(ValueError):
Mike Frysingerf744d032022-05-07 20:38:39 -040072 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x.tar'])
Mike Frysingerdaf57b82019-11-23 17:26:51 -050073
74 def testFetchRemoteTarballsSuccess(self):
75 """Test FetchRemoteTarballs with a successful download."""
76 curl = cros_build_lib.CommandResult(stdout=(
77 b'HTTP/1.0 200\n'
78 b'Foo: bar\n'
79 b'Content-Length: 100\n'
80 ))
81 self.PatchObject(retry_util, 'RunCurl', return_value=curl)
82 self.assertEqual(
83 os.path.join(self.tempdir, 'tar'),
Mike Frysingerf744d032022-05-07 20:38:39 -040084 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x/tar']))
Mike Frysingerdaf57b82019-11-23 17:26:51 -050085
86
Mike Frysingeredc04912019-11-16 01:30:43 -050087@unittest.skipIf(cros_build_lib.IsInsideChroot(),
88 'Tests only make sense outside the chroot')
89@unittest.skip(
90 'These are triggering hangs inside lvm when run through run_tests. '
91 'https://crbug.com/764335')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060092class CrosSdkSnapshotTest(cros_test_lib.TempDirTestCase):
93 """Tests for the snapshot functionality in cros_sdk."""
94
95 def setUp(self):
96 with sudo.SudoKeepAlive():
97 # Create just enough of a chroot to fool cros_sdk into accepting it.
98 self.chroot = os.path.join(self.tempdir, 'chroot')
Benjamin Gordon74645232018-05-04 17:40:42 -060099 cros_sdk_lib.MountChroot(self.chroot, create=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600100 logging.debug('Chroot mounted on %s', self.chroot)
101
102 chroot_etc = os.path.join(self.chroot, 'etc')
103 osutils.SafeMakedirsNonRoot(chroot_etc)
104
105 self.chroot_version_file = os.path.join(chroot_etc, 'cros_chroot_version')
106 osutils.Touch(self.chroot_version_file, makedirs=True)
107
108 def tearDown(self):
109 with sudo.SudoKeepAlive():
Don Garrett36650112018-06-28 15:54:34 -0700110 cros_sdk_lib.CleanupChrootMount(self.chroot, delete=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600111
112 def _crosSdk(self, args):
113 cmd = ['cros_sdk', '--chroot', self.chroot]
114 cmd.extend(args)
115
116 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400117 result = cros_build_lib.run(
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500118 cmd, print_cmd=False, capture_output=True, check=False,
Mike Frysinger66d32cd2019-12-17 14:55:29 -0500119 stderr=subprocess.STDOUT)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600120 except cros_build_lib.RunCommandError as e:
121 raise SystemExit('Running %r failed!: %s' % (cmd, e))
122
Mike Frysinger876a8e52022-06-23 18:07:30 -0400123 return result.returncode, result.stdout
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600124
125 def testSnapshotsRequireImage(self):
126 code, output = self._crosSdk(['--snapshot-list', '--nouse-image'])
127 self.assertNotEqual(code, 0)
128 self.assertIn('Snapshot operations are not compatible with', output)
129
130 code, output = self._crosSdk(['--snapshot-delete', 'test', '--nouse-image'])
131 self.assertNotEqual(code, 0)
132 self.assertIn('Snapshot operations are not compatible with', output)
133
134 code, output = self._crosSdk(['--snapshot-create', 'test', '--nouse-image'])
135 self.assertNotEqual(code, 0)
136 self.assertIn('Snapshot operations are not compatible with', output)
137
138 code, output = self._crosSdk(['--snapshot-restore', 'test',
139 '--nouse-image'])
140 self.assertNotEqual(code, 0)
141 self.assertIn('Snapshot operations are not compatible with', output)
142
143 def testSnapshotWithDeleteChroot(self):
144 code, output = self._crosSdk(['--delete', '--snapshot-list'])
145 self.assertNotEqual(code, 0)
146 self.assertIn('Trying to enter or snapshot the chroot', output)
147
148 code, output = self._crosSdk(['--delete', '--snapshot-delete', 'test'])
149 self.assertNotEqual(code, 0)
150 self.assertIn('Trying to enter or snapshot the chroot', output)
151
152 code, output = self._crosSdk(['--delete', '--snapshot-create', 'test'])
153 self.assertNotEqual(code, 0)
154 self.assertIn('Trying to enter or snapshot the chroot', output)
155
156 code, output = self._crosSdk(['--delete', '--snapshot-restore', 'test'])
157 self.assertNotEqual(code, 0)
158 self.assertIn('Trying to enter or snapshot the chroot', output)
159
160 def testEmptySnapshotList(self):
161 code, output = self._crosSdk(['--snapshot-list'])
162 self.assertEqual(code, 0)
163 self.assertEqual(output, '')
164
165 def testOneSnapshot(self):
166 code, _ = self._crosSdk(['--snapshot-create', 'test'])
167 self.assertEqual(code, 0)
168
169 code, output = self._crosSdk(['--snapshot-list'])
170 self.assertEqual(code, 0)
171 self.assertEqual(output.strip(), 'test')
172
173 def testMultipleSnapshots(self):
174 code, _ = self._crosSdk(['--snapshot-create', 'test'])
175 self.assertEqual(code, 0)
176 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
177 self.assertEqual(code, 0)
178
179 code, output = self._crosSdk(['--snapshot-list'])
180 self.assertEqual(code, 0)
181 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
182
183 def testCantCreateSameSnapshotTwice(self):
184 code, _ = self._crosSdk(['--snapshot-create', 'test'])
185 self.assertEqual(code, 0)
186 code, _ = self._crosSdk(['--snapshot-create', 'test'])
187 self.assertNotEqual(code, 0)
188
189 code, output = self._crosSdk(['--snapshot-list'])
190 self.assertEqual(code, 0)
191 self.assertEqual(output.strip(), 'test')
192
193 def testCreateSnapshotMountsAsNeeded(self):
194 with sudo.SudoKeepAlive():
Benjamin Gordon74645232018-05-04 17:40:42 -0600195 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600196
197 code, _ = self._crosSdk(['--snapshot-create', 'test'])
198 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500199 self.assertExists(self.chroot_version_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600200
201 code, output = self._crosSdk(['--snapshot-list'])
202 self.assertEqual(code, 0)
203 self.assertEqual(output.strip(), 'test')
204
205 def testDeleteGoodSnapshot(self):
206 code, _ = self._crosSdk(['--snapshot-create', 'test'])
207 self.assertEqual(code, 0)
208 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
209 self.assertEqual(code, 0)
210
211 code, _ = self._crosSdk(['--snapshot-delete', 'test'])
212 self.assertEqual(code, 0)
213
214 code, output = self._crosSdk(['--snapshot-list'])
215 self.assertEqual(code, 0)
216 self.assertEqual(output.strip(), 'test2')
217
218 def testDeleteMissingSnapshot(self):
219 code, _ = self._crosSdk(['--snapshot-create', 'test'])
220 self.assertEqual(code, 0)
221 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
222 self.assertEqual(code, 0)
223
224 code, _ = self._crosSdk(['--snapshot-delete', 'test3'])
225 self.assertEqual(code, 0)
226
227 code, output = self._crosSdk(['--snapshot-list'])
228 self.assertEqual(code, 0)
229 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
230
231 def testDeleteAndCreateSnapshot(self):
232 code, _ = self._crosSdk(['--snapshot-create', 'test'])
233 self.assertEqual(code, 0)
234 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
235 self.assertEqual(code, 0)
236
237 code, _ = self._crosSdk(['--snapshot-create', 'test',
238 '--snapshot-delete', 'test'])
239 self.assertEqual(code, 0)
240
241 code, output = self._crosSdk(['--snapshot-list'])
242 self.assertEqual(code, 0)
243 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
244
245 def testRestoreSnapshot(self):
246 with sudo.SudoKeepAlive():
247 test_file = os.path.join(self.chroot, 'etc', 'test_file')
248 osutils.Touch(test_file)
249
250 code, _ = self._crosSdk(['--snapshot-create', 'test'])
251 self.assertEqual(code, 0)
252
253 osutils.SafeUnlink(test_file)
254
255 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
256 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600257 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500258 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600259
260 code, output = self._crosSdk(['--snapshot-list'])
261 self.assertEqual(code, 0)
262 self.assertEqual(output, '')
263
264 def testRestoreAndCreateSnapshot(self):
265 with sudo.SudoKeepAlive():
266 test_file = os.path.join(self.chroot, 'etc', 'test_file')
267 osutils.Touch(test_file)
268
269 code, _ = self._crosSdk(['--snapshot-create', 'test'])
270 self.assertEqual(code, 0)
271
272 osutils.SafeUnlink(test_file)
273
274 code, _ = self._crosSdk(['--snapshot-restore', 'test',
275 '--snapshot-create', 'test'])
276 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600277 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500278 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600279
280 code, output = self._crosSdk(['--snapshot-list'])
281 self.assertEqual(code, 0)
282 self.assertEqual(output.strip(), 'test')
283
284 def testDeleteCantRestoreSameSnapshot(self):
285 code, _ = self._crosSdk(['--snapshot-create', 'test'])
286 self.assertEqual(code, 0)
287
288 code, _ = self._crosSdk(['--snapshot-delete', 'test',
289 '--snapshot-restore', 'test'])
290 self.assertNotEqual(code, 0)
291
292 code, output = self._crosSdk(['--snapshot-list'])
293 self.assertEqual(code, 0)
294 self.assertEqual(output.strip(), 'test')
295
296 def testCantRestoreInvalidSnapshot(self):
297 with sudo.SudoKeepAlive():
298 test_file = os.path.join(self.chroot, 'etc', 'test_file')
299 osutils.Touch(test_file)
300
301 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
302 self.assertNotEqual(code, 0)
303 # Failed restore leaves the existing snapshot in place.
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500304 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600305
306 def testRestoreSnapshotMountsAsNeeded(self):
307 with sudo.SudoKeepAlive():
308 test_file = os.path.join(self.chroot, 'etc', 'test_file')
309 osutils.Touch(test_file)
310
311 code, _ = self._crosSdk(['--snapshot-create', 'test'])
312 self.assertEqual(code, 0)
313
314 osutils.SafeUnlink(test_file)
315
Benjamin Gordon74645232018-05-04 17:40:42 -0600316 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600317
318 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
319 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500320 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600321
322 code, output = self._crosSdk(['--snapshot-list'])
323 self.assertEqual(code, 0)
324 self.assertEqual(output, '')