blob: 3185ec9f7318aee108161e634ed1112b852a0e8d [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 Frysingeredc04912019-11-16 01:30:43 -050011import unittest
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060012
13from chromite.lib import cros_build_lib
14from chromite.lib import cros_logging as logging
Benjamin Gordon74645232018-05-04 17:40:42 -060015from chromite.lib import cros_sdk_lib
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060016from chromite.lib import cros_test_lib
17from chromite.lib import osutils
Mike Frysingerdaf57b82019-11-23 17:26:51 -050018from chromite.lib import retry_util
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060019from chromite.lib import sudo
Mike Frysingerdaf57b82019-11-23 17:26:51 -050020from chromite.scripts import cros_sdk
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060021
22
Mike Frysingeredc04912019-11-16 01:30:43 -050023# This long decorator triggers a false positive in the docstring test.
24# https://github.com/PyCQA/pylint/issues/3077
25# pylint: disable=bad-docstring-quotes
26@unittest.skipIf(cros_build_lib.IsInsideChroot(),
27 'Tests only make sense outside the chroot')
Benjamin Gordon03c56e42017-09-11 15:48:39 -040028class CrosSdkPrerequisitesTest(cros_test_lib.TempDirTestCase):
29 """Tests for required packages on the host machine.
30
31 These are not real unit tests. If these tests fail, it means your machine is
32 missing necessary commands to support image-backed chroots. Run cros_sdk in
33 a terminal to get info about what you need to install.
34 """
35
36 def testLvmCommandsPresent(self):
37 """Check for commands from the lvm2 package."""
38 with sudo.SudoKeepAlive():
39 cmd = ['lvs', '--version']
Mike Frysinger45602c72019-09-22 02:15:11 -040040 result = cros_build_lib.run(cmd, error_code_ok=True)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040041 self.assertEqual(result.returncode, 0)
42
43 def testThinProvisioningToolsPresent(self):
44 """Check for commands from the thin-provisioning-tools package."""
45 with sudo.SudoKeepAlive():
46 cmd = ['thin_check', '-V']
Mike Frysinger45602c72019-09-22 02:15:11 -040047 result = cros_build_lib.run(cmd, error_code_ok=True)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040048 self.assertEqual(result.returncode, 0)
49
50 def testLosetupCommandPresent(self):
51 """Check for commands from the mount package."""
52 with sudo.SudoKeepAlive():
53 cmd = ['losetup', '--help']
Mike Frysinger45602c72019-09-22 02:15:11 -040054 result = cros_build_lib.run(cmd, error_code_ok=True)
Benjamin Gordon03c56e42017-09-11 15:48:39 -040055 self.assertEqual(result.returncode, 0)
56
57
Mike Frysingerdaf57b82019-11-23 17:26:51 -050058class CrosSdkUtilsTest(cros_test_lib.MockTempDirTestCase):
59 """Tests for misc util funcs."""
60
61 def testGetArchStageTarballs(self):
62 """Basic test of GetArchStageTarballs."""
63 self.assertCountEqual([
64 'https://storage.googleapis.com/chromiumos-sdk/cros-sdk-123.tar.xz',
65 'https://storage.googleapis.com/chromiumos-sdk/cros-sdk-123.tbz2',
66 ], cros_sdk.GetArchStageTarballs('123'))
67
68 def testFetchRemoteTarballsEmpty(self):
69 """Test FetchRemoteTarballs with no results."""
70 m = self.PatchObject(retry_util, 'RunCurl')
71 with self.assertRaises(ValueError):
72 cros_sdk.FetchRemoteTarballs(self.tempdir, [], 'tarball')
73 m.return_value = cros_build_lib.CommandResult(stdout=b'Foo: bar\n')
74 with self.assertRaises(ValueError):
75 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x.tar'], 'tarball')
76
77 def testFetchRemoteTarballsSuccess(self):
78 """Test FetchRemoteTarballs with a successful download."""
79 curl = cros_build_lib.CommandResult(stdout=(
80 b'HTTP/1.0 200\n'
81 b'Foo: bar\n'
82 b'Content-Length: 100\n'
83 ))
84 self.PatchObject(retry_util, 'RunCurl', return_value=curl)
85 self.assertEqual(
86 os.path.join(self.tempdir, 'tar'),
87 cros_sdk.FetchRemoteTarballs(self.tempdir, ['gs://x/tar'], 'tarball'))
88
89
Mike Frysingeredc04912019-11-16 01:30:43 -050090@unittest.skipIf(cros_build_lib.IsInsideChroot(),
91 'Tests only make sense outside the chroot')
92@unittest.skip(
93 'These are triggering hangs inside lvm when run through run_tests. '
94 'https://crbug.com/764335')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060095class CrosSdkSnapshotTest(cros_test_lib.TempDirTestCase):
96 """Tests for the snapshot functionality in cros_sdk."""
97
98 def setUp(self):
99 with sudo.SudoKeepAlive():
100 # Create just enough of a chroot to fool cros_sdk into accepting it.
101 self.chroot = os.path.join(self.tempdir, 'chroot')
Benjamin Gordon74645232018-05-04 17:40:42 -0600102 cros_sdk_lib.MountChroot(self.chroot, create=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600103 logging.debug('Chroot mounted on %s', self.chroot)
104
105 chroot_etc = os.path.join(self.chroot, 'etc')
106 osutils.SafeMakedirsNonRoot(chroot_etc)
107
108 self.chroot_version_file = os.path.join(chroot_etc, 'cros_chroot_version')
109 osutils.Touch(self.chroot_version_file, makedirs=True)
110
111 def tearDown(self):
112 with sudo.SudoKeepAlive():
Don Garrett36650112018-06-28 15:54:34 -0700113 cros_sdk_lib.CleanupChrootMount(self.chroot, delete=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600114
115 def _crosSdk(self, args):
116 cmd = ['cros_sdk', '--chroot', self.chroot]
117 cmd.extend(args)
118
119 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400120 result = cros_build_lib.run(
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600121 cmd, print_cmd=False, capture_output=True, error_code_ok=True,
122 combine_stdout_stderr=True)
123 except cros_build_lib.RunCommandError as e:
124 raise SystemExit('Running %r failed!: %s' % (cmd, e))
125
126 return result.returncode, result.output
127
128 def testSnapshotsRequireImage(self):
129 code, output = self._crosSdk(['--snapshot-list', '--nouse-image'])
130 self.assertNotEqual(code, 0)
131 self.assertIn('Snapshot operations are not compatible with', output)
132
133 code, output = self._crosSdk(['--snapshot-delete', 'test', '--nouse-image'])
134 self.assertNotEqual(code, 0)
135 self.assertIn('Snapshot operations are not compatible with', output)
136
137 code, output = self._crosSdk(['--snapshot-create', 'test', '--nouse-image'])
138 self.assertNotEqual(code, 0)
139 self.assertIn('Snapshot operations are not compatible with', output)
140
141 code, output = self._crosSdk(['--snapshot-restore', 'test',
142 '--nouse-image'])
143 self.assertNotEqual(code, 0)
144 self.assertIn('Snapshot operations are not compatible with', output)
145
146 def testSnapshotWithDeleteChroot(self):
147 code, output = self._crosSdk(['--delete', '--snapshot-list'])
148 self.assertNotEqual(code, 0)
149 self.assertIn('Trying to enter or snapshot the chroot', output)
150
151 code, output = self._crosSdk(['--delete', '--snapshot-delete', 'test'])
152 self.assertNotEqual(code, 0)
153 self.assertIn('Trying to enter or snapshot the chroot', output)
154
155 code, output = self._crosSdk(['--delete', '--snapshot-create', 'test'])
156 self.assertNotEqual(code, 0)
157 self.assertIn('Trying to enter or snapshot the chroot', output)
158
159 code, output = self._crosSdk(['--delete', '--snapshot-restore', 'test'])
160 self.assertNotEqual(code, 0)
161 self.assertIn('Trying to enter or snapshot the chroot', output)
162
163 def testEmptySnapshotList(self):
164 code, output = self._crosSdk(['--snapshot-list'])
165 self.assertEqual(code, 0)
166 self.assertEqual(output, '')
167
168 def testOneSnapshot(self):
169 code, _ = self._crosSdk(['--snapshot-create', 'test'])
170 self.assertEqual(code, 0)
171
172 code, output = self._crosSdk(['--snapshot-list'])
173 self.assertEqual(code, 0)
174 self.assertEqual(output.strip(), 'test')
175
176 def testMultipleSnapshots(self):
177 code, _ = self._crosSdk(['--snapshot-create', 'test'])
178 self.assertEqual(code, 0)
179 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
180 self.assertEqual(code, 0)
181
182 code, output = self._crosSdk(['--snapshot-list'])
183 self.assertEqual(code, 0)
184 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
185
186 def testCantCreateSameSnapshotTwice(self):
187 code, _ = self._crosSdk(['--snapshot-create', 'test'])
188 self.assertEqual(code, 0)
189 code, _ = self._crosSdk(['--snapshot-create', 'test'])
190 self.assertNotEqual(code, 0)
191
192 code, output = self._crosSdk(['--snapshot-list'])
193 self.assertEqual(code, 0)
194 self.assertEqual(output.strip(), 'test')
195
196 def testCreateSnapshotMountsAsNeeded(self):
197 with sudo.SudoKeepAlive():
Benjamin Gordon74645232018-05-04 17:40:42 -0600198 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600199
200 code, _ = self._crosSdk(['--snapshot-create', 'test'])
201 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500202 self.assertExists(self.chroot_version_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600203
204 code, output = self._crosSdk(['--snapshot-list'])
205 self.assertEqual(code, 0)
206 self.assertEqual(output.strip(), 'test')
207
208 def testDeleteGoodSnapshot(self):
209 code, _ = self._crosSdk(['--snapshot-create', 'test'])
210 self.assertEqual(code, 0)
211 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
212 self.assertEqual(code, 0)
213
214 code, _ = self._crosSdk(['--snapshot-delete', 'test'])
215 self.assertEqual(code, 0)
216
217 code, output = self._crosSdk(['--snapshot-list'])
218 self.assertEqual(code, 0)
219 self.assertEqual(output.strip(), 'test2')
220
221 def testDeleteMissingSnapshot(self):
222 code, _ = self._crosSdk(['--snapshot-create', 'test'])
223 self.assertEqual(code, 0)
224 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
225 self.assertEqual(code, 0)
226
227 code, _ = self._crosSdk(['--snapshot-delete', 'test3'])
228 self.assertEqual(code, 0)
229
230 code, output = self._crosSdk(['--snapshot-list'])
231 self.assertEqual(code, 0)
232 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
233
234 def testDeleteAndCreateSnapshot(self):
235 code, _ = self._crosSdk(['--snapshot-create', 'test'])
236 self.assertEqual(code, 0)
237 code, _ = self._crosSdk(['--snapshot-create', 'test2'])
238 self.assertEqual(code, 0)
239
240 code, _ = self._crosSdk(['--snapshot-create', 'test',
241 '--snapshot-delete', 'test'])
242 self.assertEqual(code, 0)
243
244 code, output = self._crosSdk(['--snapshot-list'])
245 self.assertEqual(code, 0)
246 self.assertSetEqual(set(output.strip().split('\n')), {'test', 'test2'})
247
248 def testRestoreSnapshot(self):
249 with sudo.SudoKeepAlive():
250 test_file = os.path.join(self.chroot, 'etc', 'test_file')
251 osutils.Touch(test_file)
252
253 code, _ = self._crosSdk(['--snapshot-create', 'test'])
254 self.assertEqual(code, 0)
255
256 osutils.SafeUnlink(test_file)
257
258 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
259 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600260 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500261 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600262
263 code, output = self._crosSdk(['--snapshot-list'])
264 self.assertEqual(code, 0)
265 self.assertEqual(output, '')
266
267 def testRestoreAndCreateSnapshot(self):
268 with sudo.SudoKeepAlive():
269 test_file = os.path.join(self.chroot, 'etc', 'test_file')
270 osutils.Touch(test_file)
271
272 code, _ = self._crosSdk(['--snapshot-create', 'test'])
273 self.assertEqual(code, 0)
274
275 osutils.SafeUnlink(test_file)
276
277 code, _ = self._crosSdk(['--snapshot-restore', 'test',
278 '--snapshot-create', 'test'])
279 self.assertEqual(code, 0)
Benjamin Gordon74645232018-05-04 17:40:42 -0600280 self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False))
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500281 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600282
283 code, output = self._crosSdk(['--snapshot-list'])
284 self.assertEqual(code, 0)
285 self.assertEqual(output.strip(), 'test')
286
287 def testDeleteCantRestoreSameSnapshot(self):
288 code, _ = self._crosSdk(['--snapshot-create', 'test'])
289 self.assertEqual(code, 0)
290
291 code, _ = self._crosSdk(['--snapshot-delete', 'test',
292 '--snapshot-restore', 'test'])
293 self.assertNotEqual(code, 0)
294
295 code, output = self._crosSdk(['--snapshot-list'])
296 self.assertEqual(code, 0)
297 self.assertEqual(output.strip(), 'test')
298
299 def testCantRestoreInvalidSnapshot(self):
300 with sudo.SudoKeepAlive():
301 test_file = os.path.join(self.chroot, 'etc', 'test_file')
302 osutils.Touch(test_file)
303
304 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
305 self.assertNotEqual(code, 0)
306 # Failed restore leaves the existing snapshot in place.
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500307 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600308
309 def testRestoreSnapshotMountsAsNeeded(self):
310 with sudo.SudoKeepAlive():
311 test_file = os.path.join(self.chroot, 'etc', 'test_file')
312 osutils.Touch(test_file)
313
314 code, _ = self._crosSdk(['--snapshot-create', 'test'])
315 self.assertEqual(code, 0)
316
317 osutils.SafeUnlink(test_file)
318
Benjamin Gordon74645232018-05-04 17:40:42 -0600319 cros_sdk_lib.CleanupChrootMount(self.chroot)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600320
321 code, _ = self._crosSdk(['--snapshot-restore', 'test'])
322 self.assertEqual(code, 0)
Mike Frysingerf2fa7d62017-12-14 18:33:59 -0500323 self.assertExists(test_file)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600324
325 code, output = self._crosSdk(['--snapshot-list'])
326 self.assertEqual(code, 0)
327 self.assertEqual(output, '')