Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: bin/cros_au_test_harness.py

Issue 5373008: Add testPartialUpdate, testCorruptedUpdate. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git@master
Patch Set: Restore a missing import. Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 import optparse 7 import optparse
8 import os 8 import os
9 import shutil
9 import sys 10 import sys
10 import unittest 11 import unittest
12 import urllib
11 13
12 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) 14 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib'))
13 from cros_build_lib import Die 15 from cros_build_lib import Die
14 from cros_build_lib import Info 16 from cros_build_lib import Info
15 from cros_build_lib import ReinterpretPathForChroot 17 from cros_build_lib import ReinterpretPathForChroot
16 from cros_build_lib import RunCommand 18 from cros_build_lib import RunCommand
19 from cros_build_lib import RunCommandCaptureOutput
17 from cros_build_lib import Warning 20 from cros_build_lib import Warning
18 21
19 # VM Constants. 22 # VM Constants.
20 _FULL_VDISK_SIZE = 6072 23 _FULL_VDISK_SIZE = 6072
21 _FULL_STATEFULFS_SIZE = 3074 24 _FULL_STATEFULFS_SIZE = 3074
22 _KVM_PID_FILE = '/tmp/harness_pid' 25 _KVM_PID_FILE = '/tmp/harness_pid'
23 _VERIFY_SUITE = 'suite_Smoke' 26 _VERIFY_SUITE = 'suite_Smoke'
24 27
25 # Globals to communicate options to unit tests. 28 # Globals to communicate options to unit tests.
26 global base_image_path 29 global base_image_path
27 global board 30 global board
28 global remote 31 global remote
29 global target_image_path 32 global target_image_path
30 global vm_graphics_flag 33 global vm_graphics_flag
31 34
35 class UpdateException(Exception):
36 """Exception thrown when UpdateImage or UpdatePayload fail"""
37 def __init__(self, code, stdout):
38 self.code = code
39 self.stdout = stdout
32 40
33 class AUTest(object): 41 class AUTest(object):
34 """Abstract interface that defines an Auto Update test.""" 42 """Abstract interface that defines an Auto Update test."""
35 source_image = '' 43 source_image = ''
36 use_delta_updates = False 44 use_delta_updates = False
37 45
38 def setUp(self): 46 def setUp(self):
39 unittest.TestCase.setUp(self) 47 unittest.TestCase.setUp(self)
40 # Set these up as they are used often. 48 # Set these up as they are used often.
41 self.crosutils = os.path.join(os.path.dirname(__file__), '..') 49 self.crosutils = os.path.join(os.path.dirname(__file__), '..')
42 self.crosutilsbin = os.path.join(os.path.dirname(__file__)) 50 self.crosutilsbin = os.path.join(os.path.dirname(__file__))
51 self.download = os.path.join(self.crosutilsbin, 'latest_download')
sosa 2010/12/01 18:37:39 self.download_folder?
dgarrett 2010/12/02 22:20:20 Done.
43 52
44 def GetStatefulChangeFlag(self, stateful_change): 53 def GetStatefulChangeFlag(self, stateful_change):
45 """Returns the flag to pass to image_to_vm for the stateful change.""" 54 """Returns the flag to pass to image_to_vm for the stateful change."""
46 stateful_change_flag = '' 55 stateful_change_flag = ''
47 if stateful_change: 56 if stateful_change:
48 stateful_change_flag = '--stateful_update_flag=%s' % stateful_change 57 stateful_change_flag = '--stateful_update_flag=%s' % stateful_change
49 58
50 return stateful_change_flag 59 return stateful_change_flag
51 60
52 def ParseGenerateTestReportOutput(self, output): 61 def ParseGenerateTestReportOutput(self, output):
(...skipping 14 matching lines...) Expand all
67 def TryDeltaAndFallbackToFull(self, src_image, image, stateful_change='old'): 76 def TryDeltaAndFallbackToFull(self, src_image, image, stateful_change='old'):
68 """Tries the delta update first if set and falls back to full update.""" 77 """Tries the delta update first if set and falls back to full update."""
69 if self.use_delta_updates: 78 if self.use_delta_updates:
70 try: 79 try:
71 self.source_image = src_image 80 self.source_image = src_image
72 self.UpdateImage(image) 81 self.UpdateImage(image)
73 except: 82 except:
74 Warning('Delta update failed, disabling delta updates and retrying.') 83 Warning('Delta update failed, disabling delta updates and retrying.')
75 self.use_delta_updates = False 84 self.use_delta_updates = False
76 self.source_image = '' 85 self.source_image = ''
77 self.UpdateImage(image) 86 self.UpdateImageReportError(image)
78 else: 87 else:
79 self.UpdateImage(image) 88 self.UpdateImageReportError(image)
89
90 def UpdateImageReportError(self, image_path, stateful_change='old'):
sosa 2010/12/01 18:37:39 needs docstring .. may also want to make private
dgarrett 2010/12/02 22:20:20 Done.
91 try:
92 self.UpdateImage(image_path, stateful_change)
93 except UpdateException as err:
94 # If the update fails, print it out
95 print err.stdout
sosa 2010/12/01 18:37:39 Use warning?
dgarrett 2010/12/02 22:20:20 Done.
96 raise
80 97
81 def PrepareBase(self): 98 def PrepareBase(self):
82 """Prepares target with base_image_path.""" 99 """Prepares target with base_image_path."""
83 pass 100 pass
84 101
85 def UpdateImage(self, image_path, stateful_change='old'): 102 def UpdateImage(self, image_path, stateful_change='old'):
86 """Updates target with the image given by the image_path. 103 """Updates target with the image given by the image_path.
87 104
88 Args: 105 Args:
89 image_path: Path to the image to update with. This image must be a test 106 image_path: Path to the image to update with. This image must be a test
90 image. 107 image.
91 stateful_change: How to modify the stateful partition. Values are: 108 stateful_change: How to modify the stateful partition. Values are:
92 'old': Don't modify stateful partition. Just update normally. 109 'old': Don't modify stateful partition. Just update normally.
93 'clean': Uses clobber-state to wipe the stateful partition with the 110 'clean': Uses clobber-state to wipe the stateful partition with the
94 exception of code needed for ssh. 111 exception of code needed for ssh.
95 """ 112 """
96 pass 113 pass
97 114
115 def UpdatePayload(self, update_path, stateful_change='old'):
sosa 2010/12/01 18:37:39 Maybe UpdateUsingPayload
dgarrett 2010/12/02 22:20:20 Done.
116 """Updates target with the pre-generated update stored in update_path
117
118 Args:
119 update_path: Path to the image to update with. This directory should
120 contain both update.gz, and stateful.image.gz
121 """
122 pass
123
98 def VerifyImage(self, percent_required_to_pass): 124 def VerifyImage(self, percent_required_to_pass):
99 """Verifies the image with tests. 125 """Verifies the image with tests.
100 126
101 Verifies that the test images passes the percent required. 127 Verifies that the test images passes the percent required.
102 128
103 Args: 129 Args:
104 percent_required_to_pass: percentage required to pass. This should be 130 percent_required_to_pass: percentage required to pass. This should be
105 fall between 0-100. 131 fall between 0-100.
106 132
107 Returns: 133 Returns:
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 # Update to - all tests should pass on new image. 197 # Update to - all tests should pass on new image.
172 Info('Updating from base image on vm to target image and wiping stateful.') 198 Info('Updating from base image on vm to target image and wiping stateful.')
173 self.TryDeltaAndFallbackToFull(base_image_path, target_image_path, 'clean') 199 self.TryDeltaAndFallbackToFull(base_image_path, target_image_path, 'clean')
174 self.VerifyImage(100) 200 self.VerifyImage(100)
175 201
176 # Update from - same percentage should pass that originally passed. 202 # Update from - same percentage should pass that originally passed.
177 Info('Updating from updated image back to base image and wiping stateful.') 203 Info('Updating from updated image back to base image and wiping stateful.')
178 self.TryDeltaAndFallbackToFull(target_image_path, base_image_path, 'clean') 204 self.TryDeltaAndFallbackToFull(target_image_path, base_image_path, 'clean')
179 self.VerifyImage(percent_passed) 205 self.VerifyImage(percent_passed)
180 206
207 def testPartialUpdate(self):
208 """Tests what happens if we attempt to update with a truncated payload.
sosa 2010/12/01 18:37:39 Only needs to be a one liner (i.e end triple quote
dgarrett 2010/12/02 22:20:20 Done.
209 """
210 # Preload with the version we are trying to test.
211 self.UpdateImageReportError(target_image_path)
sosa 2010/12/01 18:37:39 Move into PrepareBase and use PrepareBase (e.g. we
212 percent_passed = self.VerifyImage(100)
213
214 # Image can be updated at:
215 # ~chrome-eng/chromeos/localmirror/autest-images
216 url = 'http://gsdview.appspot.com/chromeos-localmirror/autest-images/truncat ed_image.gz'
sosa 2010/12/01 18:37:39 80 chars
dgarrett 2010/12/02 22:20:20 Done.
217 payload = os.path.join(self.download, 'truncated_image.gz')
218
219 # Read from the URL and write to the local file
220 shutil.copyfileobj(urllib.urlopen(url), open(payload, 'w'))
sosa 2010/12/01 18:37:39 Maybe use urllib.urlretrieve?
dgarrett 2010/12/02 22:20:20 Nice, I looked for something like that, but missed
221
222 # This update is expected to fail...
223 try:
224 self.UpdatePayload(payload)
225 except UpdateException as err:
226 # Will raise ValueError if expected is not found.
227 try:
228 expectedMsg='download_hash_data == update_check_response_hash failed'
sosa 2010/12/01 18:37:39 Might be easier to read with an expected regex rat
229 err.stdout.index(expectedMsg)
230 except ValueError:
231 print "Didn't find '%s' in:" % expectedMsg
sosa 2010/12/01 18:37:39 Use Info or Warning
dgarrett 2010/12/02 22:20:20 Done.
232 print err.stdout
233 raise
234 return
235
236 unittest.fail('We managed to update with a partial payload')
237
238 def testCorruptedUpdate(self):
239 """Tests what happens if we attempt to update with a corrupted payload.
sosa 2010/12/01 18:37:39 Don't need a second line for docstring
dgarrett 2010/12/02 22:20:20 Done.
240 """
241 # Preload with the version we are trying to test.
242 self.UpdateImageReportError(target_image_path)
sosa 2010/12/01 18:37:39 PrepareBase
dgarrett 2010/12/02 22:20:20 Done.
243 percent_passed = self.VerifyImage(100)
244
245 # Image can be updated at:
246 # ~chrome-eng/chromeos/localmirror/autest-images
247 url = 'http://gsdview.appspot.com/chromeos-localmirror/autest-images/corrupt ed_image.gz'
sosa 2010/12/01 18:37:39 80 chars
dgarrett 2010/12/02 22:20:20 Done.
248 payload = os.path.join(self.download, 'corrupted.gz')
249
250 # Read from the URL and write to the local file
251 shutil.copyfileobj(urllib.urlopen(url), open(payload, 'w'))
252
253 # This update is expected to fail...
254 try:
255 self.UpdatePayload(payload)
256 except UpdateException as err:
257 # Will raise ValueError if expected is not found.
258 try:
259 # There are a number of different errors that can occur here, but
260 # we're just trying to test the whole thing.
261 expectedMsg='zlib inflate() error:-3'
sosa 2010/12/01 18:37:39 expected_msg
dgarrett 2010/12/02 22:20:20 Done.
262 err.stdout.index(expectedMsg)
263 except ValueError:
264 print "Didn't find '%s' in:" % expectedMsg
265 print err.stdoutKeepStateful
266 raise
267 return
268
269 unittest.fail('We managed to update with a corrupted payload')
sosa 2010/12/01 18:37:39 This code seems almost the same as the test before
dgarrett 2010/12/02 22:20:20 Done.
181 270
182 class RealAUTest(unittest.TestCase, AUTest): 271 class RealAUTest(unittest.TestCase, AUTest):
183 """Test harness for updating real images.""" 272 """Test harness for updating real images."""
184 273
185 def setUp(self): 274 def setUp(self):
186 AUTest.setUp(self) 275 AUTest.setUp(self)
187 276
188 def PrepareBase(self): 277 def PrepareBase(self):
189 """Auto-update to base image to prepare for test.""" 278 """Auto-update to base image to prepare for test."""
190 self.UpdateImage(base_image_path) 279 self.UpdateImageReportError(base_image_path)
191 280
192 def UpdateImage(self, image_path, stateful_change='old'): 281 def UpdateImage(self, image_path, stateful_change='old'):
193 """Updates a remote image using image_to_live.sh.""" 282 """Updates a remote image using image_to_live.sh."""
194 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change) 283 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
195 284
196 RunCommand([ 285 (code, stdout, stderr) = RunCommandCaptureOutput([
197 '%s/image_to_live.sh' % self.crosutils, 286 '%s/image_to_live.sh' % self.crosutils,
198 '--image=%s' % image_path, 287 '--image=%s' % image_path,
199 '--remote=%s' % remote, 288 '--remote=%s' % remote,
200 stateful_change_flag, 289 stateful_change_flag,
201 '--verify', 290 '--verify',
202 '--src_image=%s' % self.source_image, 291 '--src_image=%s' % self.source_image
203 ], enter_chroot=False) 292 ])
204 293
294 if code != 0:
295 raise UpdateException(code, stdout)
296
297 def UpdatePayload(self, update_path, stateful_change='old'):
298 """Updates a remote image using image_to_live.sh."""
299 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
300
301 (code, stdout, stderr) = RunCommandCaptureOutput([
302 '%s/image_to_live.sh' % self.crosutils,
303 '--payload=%s' % update_path,
304 '--remote=%s' % remote,
305 stateful_change_flag,
306 '--verify',
307 ])
308
309 if code != 0:
310 raise UpdateException(code, stdout)
205 311
206 def VerifyImage(self, percent_required_to_pass): 312 def VerifyImage(self, percent_required_to_pass):
207 """Verifies an image using run_remote_tests.sh with verification suite.""" 313 """Verifies an image using run_remote_tests.sh with verification suite."""
208 output = RunCommand([ 314 output = RunCommand([
209 '%s/run_remote_tests.sh' % self.crosutils, 315 '%s/run_remote_tests.sh' % self.crosutils,
210 '--remote=%s' % remote, 316 '--remote=%s' % remote,
211 _VERIFY_SUITE, 317 _VERIFY_SUITE,
212 ], error_ok=True, enter_chroot=False, redirect_stdout=True) 318 ], error_ok=True, enter_chroot=False, redirect_stdout=True)
213 return self.CommonVerifyImage(self, output, percent_required_to_pass) 319 return self.CommonVerifyImage(self, output, percent_required_to_pass)
214 320
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 Info('Using existing VM image %s' % self.vm_image_path) 358 Info('Using existing VM image %s' % self.vm_image_path)
253 359
254 self.assertTrue(os.path.exists(self.vm_image_path)) 360 self.assertTrue(os.path.exists(self.vm_image_path))
255 361
256 def UpdateImage(self, image_path, stateful_change='old'): 362 def UpdateImage(self, image_path, stateful_change='old'):
257 """Updates VM image with image_path.""" 363 """Updates VM image with image_path."""
258 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change) 364 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
259 if self.source_image == base_image_path: 365 if self.source_image == base_image_path:
260 self.source_image = self.vm_image_path 366 self.source_image = self.vm_image_path
261 367
262 RunCommand(['%s/cros_run_vm_update' % self.crosutilsbin, 368 (code, stdout, stderr) = RunCommandCaptureOutput([
263 '--update_image_path=%s' % image_path, 369 '%s/cros_run_vm_update' % self.crosutilsbin,
264 '--vm_image_path=%s' % self.vm_image_path, 370 '--update_image_path=%s' % image_path,
265 '--snapshot', 371 '--vm_image_path=%s' % self.vm_image_path,
266 vm_graphics_flag, 372 '--snapshot',
267 '--persist', 373 vm_graphics_flag,
268 '--kvm_pid=%s' % _KVM_PID_FILE, 374 '--persist',
269 stateful_change_flag, 375 '--kvm_pid=%s' % _KVM_PID_FILE,
270 '--src_image=%s' % self.source_image, 376 stateful_change_flag,
271 ], enter_chroot=False) 377 '--src_image=%s' % self.source_image,
378 ])
379
380 if code != 0:
381 raise UpdateException(code, stdout)
382
383 def UpdatePayload(self, update_path, stateful_change='old'):
384 """Updates a remote image using image_to_live.sh."""
385 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
386
387 (code, stdout, stderr) = RunCommandCaptureOutput([
sosa 2010/12/01 18:37:39 Does this work for VM's? The port isn't correct .
dgarrett 2010/12/02 22:20:20 It did not, and the fix was larger than I was expe
388 '%s/image_to_live.sh' % self.crosutils,
389 '--payload=%s' % update_path,
390 stateful_change_flag,
391 '--for_vm',
392 '--verify',
393 ])
394
395 if code != 0:
396 raise UpdateException(code, stdout)
272 397
273 def VerifyImage(self, percent_required_to_pass): 398 def VerifyImage(self, percent_required_to_pass):
274 """Runs vm smoke suite to verify image.""" 399 """Runs vm smoke suite to verify image."""
275 # image_to_live already verifies lsb-release matching. This is just 400 # image_to_live already verifies lsb-release matching. This is just
276 # for additional steps. 401 # for additional steps.
277 402
278 commandWithArgs = ['%s/cros_run_vm_test' % self.crosutilsbin, 403 commandWithArgs = ['%s/cros_run_vm_test' % self.crosutilsbin,
279 '--image_path=%s' % self.vm_image_path, 404 '--image_path=%s' % self.vm_image_path,
280 '--snapshot', 405 '--snapshot',
281 '--persist', 406 '--persist',
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 else: 473 else:
349 remote = options.remote 474 remote = options.remote
350 475
351 suite = unittest.TestLoader().loadTestsFromTestCase(RealAUTest) 476 suite = unittest.TestLoader().loadTestsFromTestCase(RealAUTest)
352 test_result = unittest.TextTestRunner(verbosity=2).run(suite) 477 test_result = unittest.TextTestRunner(verbosity=2).run(suite)
353 else: 478 else:
354 parser.error('Could not parse harness type %s.' % options.type) 479 parser.error('Could not parse harness type %s.' % options.type)
355 480
356 if not test_result.wasSuccessful(): 481 if not test_result.wasSuccessful():
357 Die('Test harness was not successful') 482 Die('Test harness was not successful')
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698