blob: a3f48d7b0ac8bbc723458f5cef68e77ed9fb376c [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06002# Copyright 2017 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Tests for cros_sdk."""
7
8from __future__ import print_function
9
10import os
Mike Frysinger66d32cd2019-12-17 14:55:29 -050011import subprocess
Mike Frysingeredc04912019-11-16 01:30:43 -050012import unittest
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060013
14from chromite.lib import cros_build_lib
15from chromite.lib import cros_logging as logging
Benjamin Gordon74645232018-05-04 17:40:42 -060016from chromite.lib import cros_sdk_lib
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060017from chromite.lib import cros_test_lib
18from chromite.lib import osutils
Mike Frysingerdaf57b82019-11-23 17:26:51 -050019from chromite.lib import retry_util
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060020from chromite.lib import sudo
Mike Frysingerdaf57b82019-11-23 17:26:51 -050021from chromite.scripts import cros_sdk
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060022
23
Mike Frysingeredc04912019-11-16 01:30:43 -050024# This long decorator triggers a false positive in the docstring test.
25# https://github.com/PyCQA/pylint/issues/3077
26# pylint: disable=bad-docstring-quotes
27@unittest.skipIf(cros_build_lib.IsInsideChroot(),
28 'Tests only make sense outside the chroot')
Benjamin Gordon03c56e42017-09-11 15:48:39 -040029class CrosSdkPrerequisitesTest(cros_test_lib.TempDirTestCase):
30 """Tests for required packages on the host machine.
31
32 These are not real unit tests. If these tests fail, it means your machine is
33 missing necessary commands to support image-backed chroots. Run cros_sdk in
34 a terminal to get info about what you need to install.
35 """
36
37 def testLvmCommandsPresent(self):
38 """Check for commands from the lvm2 package."""
39 with sudo.SudoKeepAlive():
40 cmd = ['lvs', '--version']
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050041 result = cros_build_lib.run(cmd, check=False)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040042 self.assertEqual(result.returncode, 0)
43
44 def testThinProvisioningToolsPresent(self):
45 """Check for commands from the thin-provisioning-tools package."""
46 with sudo.SudoKeepAlive():
47 cmd = ['thin_check', '-V']
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050048 result = cros_build_lib.run(cmd, check=False)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040049 self.assertEqual(result.returncode, 0)
50
51 def testLosetupCommandPresent(self):
52 """Check for commands from the mount package."""
53 with sudo.SudoKeepAlive():
54 cmd = ['losetup', '--help']
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050055 result = cros_build_lib.run(cmd, check=False)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040056 self.assertEqual(result.returncode, 0)
57
58
Mike Frysingerdaf57b82019-11-23 17:26:51 -050059class CrosSdkUtilsTest(cros_test_lib.MockTempDirTestCase):
60 """Tests for misc util funcs."""
61
62 def testGetArchStageTarballs(self):
63 """Basic test of GetArchStageTarballs."""
64 self.assertCountEqual([
65 'https://storage.googleapis.com/chromiumos-sdk/cros-sdk-123.tar.xz',
66 'https://storage.googleapis.com/chromiumos-sdk/cros-sdk-123.tbz2',
67 ], cros_sdk.GetArchStageTarballs('123'))
68
69 def testFetchRemoteTarballsEmpty(self):
70 """Test FetchRemoteTarballs with no results."""
71 m = self.PatchObject(retry_util, 'RunCurl')
72 with self.assertRaises(ValueError):
73 cros_sdk.FetchRemoteTarballs(self.tempdir, [], 'tarball')
74 m.return_value = cros_build_lib.CommandResult(stdout=b'Foo: bar\n')
75 with self.assertRaises(ValueError):
76 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x.tar'], 'tarball')
77
78 def testFetchRemoteTarballsSuccess(self):
79 """Test FetchRemoteTarballs with a successful download."""
80 curl = cros_build_lib.CommandResult(stdout=(
81 b'HTTP/1.0 200\n'
82 b'Foo: bar\n'
83 b'Content-Length: 100\n'
84 ))
85 self.PatchObject(retry_util, 'RunCurl', return_value=curl)
86 self.assertEqual(
87 os.path.join(self.tempdir, 'tar'),
88 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x/tar'], 'tarball'))
89
90
Mike Frysingeredc04912019-11-16 01:30:43 -050091@unittest.skipIf(cros_build_lib.IsInsideChroot(),
92 'Tests only make sense outside the chroot')
93@unittest.skip(
94 'These are triggering hangs inside lvm when run through run_tests. '
95 'https://crbug.com/764335')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060096class CrosSdkSnapshotTest(cros_test_lib.TempDirTestCase):
97 """Tests for the snapshot functionality in cros_sdk."""
98
99 def setUp(self):
100 with sudo.SudoKeepAlive():
101 # Create just enough of a chroot to fool cros_sdk into accepting it.
102 self.chroot = os.path.join(self.tempdir, 'chroot')
Benjamin Gordon74645232018-05-04 17:40:42 -0600103 cros_sdk_lib.MountChroot(self.chroot, create=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600104 logging.debug('Chroot mounted on %s', self.chroot)
105
106 chroot_etc = os.path.join(self.chroot, 'etc')
107 osutils.SafeMakedirsNonRoot(chroot_etc)
108
109 self.chroot_version_file = os.path.join(chroot_etc, 'cros_chroot_version')
110 osutils.Touch(self.chroot_version_file, makedirs=True)
111
112 def tearDown(self):
113 with sudo.SudoKeepAlive():
Don Garrett36650112018-06-28 15:54:34 -0700114 cros_sdk_lib.CleanupChrootMount(self.chroot, delete=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600115
116 def _crosSdk(self, args):
117 cmd = ['cros_sdk', '--chroot', self.chroot]
118 cmd.extend(args)
119
120 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400121 result = cros_build_lib.run(
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500122 cmd, print_cmd=False, capture_output=True, check=False,
Mike Frysinger66d32cd2019-12-17 14:55:29 -0500123 stderr=subprocess.STDOUT)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600124 except cros_build_lib.RunCommandError as e:
125 raise SystemExit('Running %r failed!: %s' % (cmd, e))
126
127 return result.returncode, result.output
128
129 def testSnapshotsRequireImage(self):
130 code, output = self._crosSdk(['--snapshot-list', '--nouse-image'])
131 self.assertNotEqual(code, 0)
132 self.assertIn('Snapshot operations are not compatible with', output)
133
134 code, output = self._crosSdk(['--snapshot-delete', '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-create', 'test', '--nouse-image'])
139 self.assertNotEqual(code, 0)
140 self.assertIn('Snapshot operations are not compatible with', output)
141
142 code, output = self._crosSdk(['--snapshot-restore', 'test',
143 '--nouse-image'])
144 self.assertNotEqual(code, 0)
145 self.assertIn('Snapshot operations are not compatible with', output)
146
147 def testSnapshotWithDeleteChroot(self):
148 code, output = self._crosSdk(['--delete', '--snapshot-list'])
149 self.assertNotEqual(code, 0)
150 self.assertIn('Trying to enter or snapshot the chroot', output)
151
152 code, output = self._crosSdk(['--delete', '--snapshot-delete', '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-create', 'test'])
157 self.assertNotEqual(code, 0)
158 self.assertIn('Trying to enter or snapshot the chroot', output)
159
160 code, output = self._crosSdk(['--delete', '--snapshot-restore', 'test'])
161 self.assertNotEqual(code, 0)
162 self.assertIn('Trying to enter or snapshot the chroot', output)
163
164 def testEmptySnapshotList(self):
165 code, output = self._crosSdk(['--snapshot-list'])
166 self.assertEqual(code, 0)
167 self.assertEqual(output, '')
168
169 def testOneSnapshot(self):
170 code, _ = self._crosSdk(['--snapshot-create', 'test'])
171 self.assertEqual(code, 0)
172
173 code, output = self._crosSdk(['--snapshot-list'])
174 self.assertEqual(code, 0)
175 self.assertEqual(output.strip(), 'test')
176
177 def testMultipleSnapshots(self):
178 code, _ = self._crosSdk(['--snapshot-create', 'test'])
179 self.assertEqual(code, 0)
180 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
181 self.assertEqual(code, 0)
182
183 code, output = self._crosSdk(['--snapshot-list'])
184 self.assertEqual(code, 0)
185 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
186
187 def testCantCreateSameSnapshotTwice(self):
188 code, _ = self._crosSdk(['--snapshot-create', 'test'])
189 self.assertEqual(code, 0)
190 code, _ = self._crosSdk(['--snapshot-create', 'test'])
191 self.assertNotEqual(code, 0)
192
193 code, output = self._crosSdk(['--snapshot-list'])
194 self.assertEqual(code, 0)
195 self.assertEqual(output.strip(), 'test')
196
197 def testCreateSnapshotMountsAsNeeded(self):
198 with sudo.SudoKeepAlive():
Benjamin Gordon74645232018-05-04 17:40:42 -0600199 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600200
201 code, _ = self._crosSdk(['--snapshot-create', 'test'])
202 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500203 self.assertExists(self.chroot_version_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600204
205 code, output = self._crosSdk(['--snapshot-list'])
206 self.assertEqual(code, 0)
207 self.assertEqual(output.strip(), 'test')
208
209 def testDeleteGoodSnapshot(self):
210 code, _ = self._crosSdk(['--snapshot-create', 'test'])
211 self.assertEqual(code, 0)
212 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
213 self.assertEqual(code, 0)
214
215 code, _ = self._crosSdk(['--snapshot-delete', 'test'])
216 self.assertEqual(code, 0)
217
218 code, output = self._crosSdk(['--snapshot-list'])
219 self.assertEqual(code, 0)
220 self.assertEqual(output.strip(), 'test2')
221
222 def testDeleteMissingSnapshot(self):
223 code, _ = self._crosSdk(['--snapshot-create', 'test'])
224 self.assertEqual(code, 0)
225 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
226 self.assertEqual(code, 0)
227
228 code, _ = self._crosSdk(['--snapshot-delete', 'test3'])
229 self.assertEqual(code, 0)
230
231 code, output = self._crosSdk(['--snapshot-list'])
232 self.assertEqual(code, 0)
233 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
234
235 def testDeleteAndCreateSnapshot(self):
236 code, _ = self._crosSdk(['--snapshot-create', 'test'])
237 self.assertEqual(code, 0)
238 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
239 self.assertEqual(code, 0)
240
241 code, _ = self._crosSdk(['--snapshot-create', 'test',
242 '--snapshot-delete', 'test'])
243 self.assertEqual(code, 0)
244
245 code, output = self._crosSdk(['--snapshot-list'])
246 self.assertEqual(code, 0)
247 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
248
249 def testRestoreSnapshot(self):
250 with sudo.SudoKeepAlive():
251 test_file = os.path.join(self.chroot, 'etc', 'test_file')
252 osutils.Touch(test_file)
253
254 code, _ = self._crosSdk(['--snapshot-create', 'test'])
255 self.assertEqual(code, 0)
256
257 osutils.SafeUnlink(test_file)
258
259 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
260 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600261 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500262 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600263
264 code, output = self._crosSdk(['--snapshot-list'])
265 self.assertEqual(code, 0)
266 self.assertEqual(output, '')
267
268 def testRestoreAndCreateSnapshot(self):
269 with sudo.SudoKeepAlive():
270 test_file = os.path.join(self.chroot, 'etc', 'test_file')
271 osutils.Touch(test_file)
272
273 code, _ = self._crosSdk(['--snapshot-create', 'test'])
274 self.assertEqual(code, 0)
275
276 osutils.SafeUnlink(test_file)
277
278 code, _ = self._crosSdk(['--snapshot-restore', 'test',
279 '--snapshot-create', 'test'])
280 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600281 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500282 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600283
284 code, output = self._crosSdk(['--snapshot-list'])
285 self.assertEqual(code, 0)
286 self.assertEqual(output.strip(), 'test')
287
288 def testDeleteCantRestoreSameSnapshot(self):
289 code, _ = self._crosSdk(['--snapshot-create', 'test'])
290 self.assertEqual(code, 0)
291
292 code, _ = self._crosSdk(['--snapshot-delete', 'test',
293 '--snapshot-restore', 'test'])
294 self.assertNotEqual(code, 0)
295
296 code, output = self._crosSdk(['--snapshot-list'])
297 self.assertEqual(code, 0)
298 self.assertEqual(output.strip(), 'test')
299
300 def testCantRestoreInvalidSnapshot(self):
301 with sudo.SudoKeepAlive():
302 test_file = os.path.join(self.chroot, 'etc', 'test_file')
303 osutils.Touch(test_file)
304
305 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
306 self.assertNotEqual(code, 0)
307 # Failed restore leaves the existing snapshot in place.
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500308 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600309
310 def testRestoreSnapshotMountsAsNeeded(self):
311 with sudo.SudoKeepAlive():
312 test_file = os.path.join(self.chroot, 'etc', 'test_file')
313 osutils.Touch(test_file)
314
315 code, _ = self._crosSdk(['--snapshot-create', 'test'])
316 self.assertEqual(code, 0)
317
318 osutils.SafeUnlink(test_file)
319
Benjamin Gordon74645232018-05-04 17:40:42 -0600320 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600321
322 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
323 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500324 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600325
326 code, output = self._crosSdk(['--snapshot-list'])
327 self.assertEqual(code, 0)
328 self.assertEqual(output, '')