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

Side by Side Diff: bin/au_test_harness/au_worker.py

Issue 6597122: Refactor au_test_harness into modules and refactor to use worker design. (Closed) Base URL: http://git.chromium.org/git/crosutils.git@master
Patch Set: 80 char Created 9 years, 9 months 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
OLDNEW
(Empty)
1 # Copyright (c) 2011 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 """Module that contains the interface for au_test_harness workers.
6
7 An au test harnss worker is a class that contains the logic for performing
8 and validating updates on a target. This should be subclassed to handle
9 various types of target. Types of targets include VM's, real devices, etc.
10 """
11
12 import os
13 import sys
14
15 import cros_build_lib as cros_lib
16
17 import dev_server_wrapper
18 import update_exception
19
20
21 class AUWorker(object):
22 """Interface for a worker that updates and verifies images."""
23
24 update_cache = None
25
26 # --- INTERFACE ---
27
28 def __init__(self, options):
29 """Processes options for the specific-type of worker."""
30 self.board = options.board
31 self.private_key = options.private_key
32 self.use_delta_updates = options.delta
33 self.verbose = options.verbose
34 self.vm_image_path = None
35 if options.quick_test:
36 self.verify_suite = 'build_RootFilesystemSize'
37 else:
38 self.verify_suite = 'suite_Smoke'
39
40 # Set these up as they are used often.
41 self.crosutils = os.path.join(os.path.dirname(__file__), '..', '..')
42 self.crosutilsbin = os.path.join(os.path.dirname(__file__), '..')
43
44 def UpdateImage(self, image_path, src_image_path='', stateful_change='old',
45 proxy_port=None, private_key_path=None):
46 """Implementation of an actual update.
47
48 See PerformUpdate for description of args. Subclasses must override this
49 method with the correct update procedure for the class.
50 """
51 pass
52
53 def UpdateUsingPayload(self, update_path, stateful_change='old',
54 proxy_port=None):
55 """Updates target with the pre-generated update stored in update_path.
56
57 Subclasses must override this method with the correct update procedure for
58 the class.
59
60 Args:
61 update_path: Path to the image to update with. This directory should
62 contain both update.gz, and stateful.image.gz
63 proxy_port: Port to have the client connect to. For use with
64 CrosTestProxy.
65 """
66 pass
67
68 def VerifyImage(self, unittest, percent_required_to_pass=100):
69 """Verifies the image with tests.
70
71 Verifies that the test images passes the percent required. Subclasses must
72 override this method with the correct update procedure for the class.
73
74 Args:
75 unittest: pointer to a unittest to fail if we cannot verify the image.
76 percent_required_to_pass: percentage required to pass. This should be
77 fall between 0-100.
78
79 Returns:
80 Returns the percent that passed.
81 """
82 pass
83
84 # --- INTERFACE TO AU_TEST ---
85
86 def PerformUpdate(self, image_path, src_image_path='', stateful_change='old',
87 proxy_port=None, private_key_path=None):
88 """Performs an update using _UpdateImage and reports any error.
89
90 Subclasses should not override this method but override _UpdateImage
91 instead.
92
93 Args:
94 image_path: Path to the image to update with. This image must be a test
95 image.
96 src_image_path: Optional. If set, perform a delta update using the
97 image specified by the path as the source image.
98 stateful_change: How to modify the stateful partition. Values are:
99 'old': Don't modify stateful partition. Just update normally.
100 'clean': Uses clobber-state to wipe the stateful partition with the
101 exception of code needed for ssh.
102 proxy_port: Port to have the client connect to. For use with
103 CrosTestProxy.
104 private_key_path: Path to a private key to use with update payload.
105 Raises an update_exception.UpdateException if _UpdateImage returns an error.
106 """
107 try:
108 if not self.use_delta_updates: src_image_path = ''
109 if private_key_path:
110 key_to_use = private_key_path
111 else:
112 key_to_use = self.private_key
113
114 self.UpdateImage(image_path, src_image_path, stateful_change,
115 proxy_port, key_to_use)
116 except update_exception.UpdateException as err:
117 # If the update fails, print it out
118 Warning(err.stdout)
119 raise
120
121 @classmethod
dgarrett 2011/03/03 02:17:21 Why classmethod here?
sosa 2011/03/03 03:11:41 Sets a static variable. I'm using class variables
122 def SetUpdateCache(cls, update_cache):
123 """Sets the global update cache for getting paths to devserver payloads."""
124 cls.update_cache = update_cache
125
126 # --- METHODS FOR SUB CLASS USE ---
127
128 def PrepareRealBase(self, image_path):
129 """Prepares a remote device for worker test by updating it to the image."""
130 self.UpdateImage(image_path)
131
132 def PrepareVMBase(self, image_path):
133 """Prepares a VM image for worker test by creating the VM file from the img.
134 """
135 # VM Constants.
136 FULL_VDISK_SIZE = 6072
137 FULL_STATEFULFS_SIZE = 3074
138 # Needed for VM delta updates. We need to use the qemu image rather
139 # than the base image on a first update. By tracking the first_update
140 # we can set src_image to the qemu form of the base image when
141 # performing generating the delta payload.
142 self._first_update = True
143 self.vm_image_path = '%s/chromiumos_qemu_image.bin' % os.path.dirname(
144 image_path)
145 if not os.path.exists(self.vm_image_path):
146 cros_lib.Info('Creating %s' % self.vm_image_path)
147 cros_lib.RunCommand(['./image_to_vm.sh',
148 '--full',
149 '--from=%s' % cros_lib.ReinterpretPathForChroot(
150 os.path.dirname(image_path)),
151 '--vdisk_size=%s' % FULL_VDISK_SIZE,
152 '--statefulfs_size=%s' % FULL_STATEFULFS_SIZE,
153 '--board=%s' % self.board,
154 '--test_image'
155 ], enter_chroot=True, cwd=self.crosutils)
156
157 cros_lib.Info('Using %s as base' % self.vm_image_path)
158 assert os.path.exists(self.vm_image_path)
159
160 def GetStatefulChangeFlag(self, stateful_change):
161 """Returns the flag to pass to image_to_vm for the stateful change."""
162 stateful_change_flag = ''
163 if stateful_change:
164 stateful_change_flag = '--stateful_update_flag=%s' % stateful_change
165
166 return stateful_change_flag
167
168 def AppendUpdateFlags(self, cmd, image_path, src_image_path, proxy_port,
169 private_key_path):
170 """Appends common args to an update cmd defined by an array.
171
172 Modifies cmd in places by appending appropriate items given args.
173 """
174 if proxy_port: cmd.append('--proxy_port=%s' % proxy_port)
175
176 # Get pregenerated update if we have one.
177 update_id = dev_server_wrapper.GenerateUpdateId(image_path, src_image_path,
178 private_key_path)
179 cache_path = self.update_cache[update_id]
180 if cache_path:
181 update_url = dev_server_wrapper.DevServerWrapper.GetDevServerURL(
182 proxy_port, cache_path)
183 cmd.append('--update_url=%s' % update_url)
184 else:
185 cmd.append('--image=%s' % image_path)
186 if src_image_path: cmd.append('--src_image=%s' % src_image_path)
187
188 def RunUpdateCmd(self, cmd):
189 """Runs the given update cmd given verbose options.
190
191 Raises an update_exception.UpdateException if the update fails.
192 """
193 if self.verbose:
194 try:
195 cros_lib.RunCommand(cmd)
196 except Exception, e:
dgarrett 2011/03/03 02:17:21 This syntax is morphing. What you are doing works,
sosa 2011/03/03 03:11:41 Done.
197 Warning(str(e))
198 raise update_exception.UpdateException(1, str(e))
199 else:
200 (code, stdout, stderr) = cros_lib.RunCommandCaptureOutput(cmd)
201 if code != 0:
202 Warning(stdout)
203 raise update_exception.UpdateException(code, stdout)
204
205 def AssertEnoughTestsPassed(self, unittest, output, percent_required_to_pass):
206 """Helper function that asserts a sufficient number of tests passed.
207
208 Args:
209 output: stdout from a test run.
210 percent_required_to_pass: percentage required to pass. This should be
211 fall between 0-100.
212 Returns:
213 percent that passed.
214 """
215 cros_lib.Info('Output from VerifyImage():')
216 print >> sys.stderr, output
217 sys.stderr.flush()
218 percent_passed = self._ParseGenerateTestReportOutput(output)
219 cros_lib.Info('Percent passed: %d vs. Percent required: %d' % (
220 percent_passed, percent_required_to_pass))
221 unittest.assertTrue(percent_passed >= percent_required_to_pass)
222 return percent_passed
223
224 # --- PRIVATE HELPER FUNCTIONS ---
225
226 def _ParseGenerateTestReportOutput(self, output):
227 """Returns the percentage of tests that passed based on output."""
228 percent_passed = 0
229 lines = output.split('\n')
230
231 for line in lines:
232 if line.startswith("Total PASS:"):
233 # FORMAT: ^TOTAL PASS: num_passed/num_total (percent%)$
234 percent_passed = line.split()[3].strip('()%')
235 cros_lib.Info('Percent of tests passed %s' % percent_passed)
236 break
237
238 return int(percent_passed)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698