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

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: Nit party 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
« no previous file with comments | « bin/au_test_harness/au_test.py ('k') | bin/au_test_harness/cros_au_test_harness.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 CleanUp(self):
45 """Called at the end of every test."""
46 pass
47
48 def UpdateImage(self, image_path, src_image_path='', stateful_change='old',
49 proxy_port=None, private_key_path=None):
50 """Implementation of an actual update.
51
52 See PerformUpdate for description of args. Subclasses must override this
53 method with the correct update procedure for the class.
54 """
55 pass
56
57 def UpdateUsingPayload(self, update_path, stateful_change='old',
58 proxy_port=None):
59 """Updates target with the pre-generated update stored in update_path.
60
61 Subclasses must override this method with the correct update procedure for
62 the class.
63
64 Args:
65 update_path: Path to the image to update with. This directory should
66 contain both update.gz, and stateful.image.gz
67 proxy_port: Port to have the client connect to. For use with
68 CrosTestProxy.
69 """
70 pass
71
72 def VerifyImage(self, unittest, percent_required_to_pass=100):
73 """Verifies the image with tests.
74
75 Verifies that the test images passes the percent required. Subclasses must
76 override this method with the correct update procedure for the class.
77
78 Args:
79 unittest: pointer to a unittest to fail if we cannot verify the image.
80 percent_required_to_pass: percentage required to pass. This should be
81 fall between 0-100.
82
83 Returns:
84 Returns the percent that passed.
85 """
86 pass
87
88 # --- INTERFACE TO AU_TEST ---
89
90 def PerformUpdate(self, image_path, src_image_path='', stateful_change='old',
91 proxy_port=None, private_key_path=None):
92 """Performs an update using _UpdateImage and reports any error.
93
94 Subclasses should not override this method but override _UpdateImage
95 instead.
96
97 Args:
98 image_path: Path to the image to update with. This image must be a test
99 image.
100 src_image_path: Optional. If set, perform a delta update using the
101 image specified by the path as the source image.
102 stateful_change: How to modify the stateful partition. Values are:
103 'old': Don't modify stateful partition. Just update normally.
104 'clean': Uses clobber-state to wipe the stateful partition with the
105 exception of code needed for ssh.
106 proxy_port: Port to have the client connect to. For use with
107 CrosTestProxy.
108 private_key_path: Path to a private key to use with update payload.
109 Raises an update_exception.UpdateException if _UpdateImage returns an error.
110 """
111 try:
112 if not self.use_delta_updates: src_image_path = ''
113 if private_key_path:
114 key_to_use = private_key_path
115 else:
116 key_to_use = self.private_key
117
118 self.UpdateImage(image_path, src_image_path, stateful_change,
119 proxy_port, key_to_use)
120 except update_exception.UpdateException as err:
121 # If the update fails, print it out
122 Warning(err.stdout)
123 raise
124
125 @classmethod
126 def SetUpdateCache(cls, update_cache):
127 """Sets the global update cache for getting paths to devserver payloads."""
128 cls.update_cache = update_cache
129
130 # --- METHODS FOR SUB CLASS USE ---
131
132 def PrepareRealBase(self, image_path):
133 """Prepares a remote device for worker test by updating it to the image."""
134 self.UpdateImage(image_path)
135
136 def PrepareVMBase(self, image_path):
137 """Prepares a VM image for worker test by creating the VM file from the img.
138 """
139 # VM Constants.
140 FULL_VDISK_SIZE = 6072
141 FULL_STATEFULFS_SIZE = 3074
142 # Needed for VM delta updates. We need to use the qemu image rather
143 # than the base image on a first update. By tracking the first_update
144 # we can set src_image to the qemu form of the base image when
145 # performing generating the delta payload.
146 self._first_update = True
147 self.vm_image_path = '%s/chromiumos_qemu_image.bin' % os.path.dirname(
148 image_path)
149 if not os.path.exists(self.vm_image_path):
150 cros_lib.Info('Creating %s' % self.vm_image_path)
151 cros_lib.RunCommand(['./image_to_vm.sh',
152 '--full',
153 '--from=%s' % cros_lib.ReinterpretPathForChroot(
154 os.path.dirname(image_path)),
155 '--vdisk_size=%s' % FULL_VDISK_SIZE,
156 '--statefulfs_size=%s' % FULL_STATEFULFS_SIZE,
157 '--board=%s' % self.board,
158 '--test_image'
159 ], enter_chroot=True, cwd=self.crosutils)
160
161 cros_lib.Info('Using %s as base' % self.vm_image_path)
162 assert os.path.exists(self.vm_image_path)
163
164 def GetStatefulChangeFlag(self, stateful_change):
165 """Returns the flag to pass to image_to_vm for the stateful change."""
166 stateful_change_flag = ''
167 if stateful_change:
168 stateful_change_flag = '--stateful_update_flag=%s' % stateful_change
169
170 return stateful_change_flag
171
172 def AppendUpdateFlags(self, cmd, image_path, src_image_path, proxy_port,
173 private_key_path):
174 """Appends common args to an update cmd defined by an array.
175
176 Modifies cmd in places by appending appropriate items given args.
177 """
178 if proxy_port: cmd.append('--proxy_port=%s' % proxy_port)
179
180 # Get pregenerated update if we have one.
181 update_id = dev_server_wrapper.GenerateUpdateId(image_path, src_image_path,
182 private_key_path)
183 cache_path = self.update_cache[update_id]
184 if cache_path:
185 update_url = dev_server_wrapper.DevServerWrapper.GetDevServerURL(
186 proxy_port, cache_path)
187 cmd.append('--update_url=%s' % update_url)
188 else:
189 cmd.append('--image=%s' % image_path)
190 if src_image_path: cmd.append('--src_image=%s' % src_image_path)
191
192 def RunUpdateCmd(self, cmd):
193 """Runs the given update cmd given verbose options.
194
195 Raises an update_exception.UpdateException if the update fails.
196 """
197 if self.verbose:
198 try:
199 cros_lib.RunCommand(cmd)
200 except Exception as e:
201 Warning(str(e))
202 raise update_exception.UpdateException(1, str(e))
203 else:
204 (code, stdout, stderr) = cros_lib.RunCommandCaptureOutput(cmd)
205 if code != 0:
206 Warning(stdout)
207 raise update_exception.UpdateException(code, stdout)
208
209 def AssertEnoughTestsPassed(self, unittest, output, percent_required_to_pass):
210 """Helper function that asserts a sufficient number of tests passed.
211
212 Args:
213 output: stdout from a test run.
214 percent_required_to_pass: percentage required to pass. This should be
215 fall between 0-100.
216 Returns:
217 percent that passed.
218 """
219 cros_lib.Info('Output from VerifyImage():')
220 print >> sys.stderr, output
221 sys.stderr.flush()
222 percent_passed = self._ParseGenerateTestReportOutput(output)
223 cros_lib.Info('Percent passed: %d vs. Percent required: %d' % (
224 percent_passed, percent_required_to_pass))
225 unittest.assertTrue(percent_passed >= percent_required_to_pass)
226 return percent_passed
227
228 # --- PRIVATE HELPER FUNCTIONS ---
229
230 def _ParseGenerateTestReportOutput(self, output):
231 """Returns the percentage of tests that passed based on output."""
232 percent_passed = 0
233 lines = output.split('\n')
234
235 for line in lines:
236 if line.startswith("Total PASS:"):
237 # FORMAT: ^TOTAL PASS: num_passed/num_total (percent%)$
238 percent_passed = line.split()[3].strip('()%')
239 cros_lib.Info('Percent of tests passed %s' % percent_passed)
240 break
241
242 return int(percent_passed)
OLDNEW
« no previous file with comments | « bin/au_test_harness/au_test.py ('k') | bin/au_test_harness/cros_au_test_harness.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698