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

Side by Side Diff: bin/au_test_harness/au_test.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/__init__.py ('k') | bin/au_test_harness/au_worker.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 containing a test suite that is run to test auto updates."""
6
7 import os
8 import time
9 import unittest
10
11 import cros_build_lib as cros_lib
12
13 import cros_test_proxy
14 import dummy_au_worker
15 import real_au_worker
16 import vm_au_worker
17
18
19 class AUTest(unittest.TestCase):
20 """Test harness that uses an au_worker to perform and validate updates.
21
22 Defines a test suite that is run using an au_worker. An au_worker can
23 be created to perform and validates updates on both virtual and real devices.
24 See documentation for au_worker for more information.
25 """
26 @classmethod
27 def ProcessOptions(cls, options, use_dummy_worker):
28 """Processes options for the test suite and sets up the worker class.
29
30 Args:
31 options: options class to be parsed from main class.
32 use_dummy_worker: If True, use a dummy_worker_class rather than deriving
33 one from options.type.
34 """
35 cls.base_image_path = options.base_image
36 cls.target_image_path = options.target_image
37 cls.clean = options.clean
38
39 assert options.type in ['real', 'vm'], 'Failed to specify either real|vm.'
40 if use_dummy_worker:
41 cls.worker_class = dummy_au_worker.DummyAUWorker
42 elif options.type == 'vm':
43 cls.worker_class = vm_au_worker.VMAUWorker
44 else:
45 cls.worker_class = real_au_worker.RealAUWorker
46
47 # Sanity checks.
48 if not cls.base_image_path:
49 cros_lib.Die('Need path to base image for vm.')
50 elif not os.path.exists(cls.base_image_path):
51 cros_lib.Die('%s does not exist' % cls.base_image_path)
52
53 if not cls.target_image_path:
54 cros_lib.Die('Need path to target image to update with.')
55 elif not os.path.exists(cls.target_image_path):
56 cros_lib.Die('%s does not exist' % cls.target_image_path)
57
58 # Cache away options to instantiate workers later.
59 cls.options = options
60
61 def AttemptUpdateWithPayloadExpectedFailure(self, payload, expected_msg):
62 """Attempt a payload update, expect it to fail with expected log"""
63 try:
64 self.worker.UpdateUsingPayload(payload)
65 except UpdateException as err:
66 # Will raise ValueError if expected is not found.
67 if re.search(re.escape(expected_msg), err.stdout, re.MULTILINE):
68 return
69 else:
70 cros_lib.Warning("Didn't find '%s' in:" % expected_msg)
71 cros_lib.Warning(err.stdout)
72
73 self.fail('We managed to update when failure was expected')
74
75 def AttemptUpdateWithFilter(self, filter, proxy_port=8081):
76 """Update through a proxy, with a specified filter, and expect success."""
77 self.worker.PrepareBase(self.target_image_path)
78
79 # The devserver runs at port 8080 by default. We assume that here, and
80 # start our proxy at a different one. We then tell our update tools to
81 # have the client connect to our proxy_port instead of 8080.
82 proxy = cros_test_proxy.CrosTestProxy(port_in=proxy_port,
83 address_out='127.0.0.1',
84 port_out=8080,
85 filter=filter)
86 proxy.serve_forever_in_thread()
87 try:
88 self.worker.PerformUpdate(self.target_image_path, self.target_image_path,
89 proxy_port=proxy_port)
90 finally:
91 proxy.shutdown()
92
93 # --- UNITTEST SPECIFIC METHODS ---
94
95 def setUp(self):
96 """Overrides unittest.TestCase.setUp and called before every test.
97
98 Sets instance specific variables and initializes worker.
99 """
100 unittest.TestCase.setUp(self)
101 self.worker = self.worker_class(self.options)
102 self.crosutils = os.path.join(os.path.dirname(__file__), '..', '..')
103 self.download_folder = os.path.join(self.crosutils, 'latest_download')
104 if not os.path.exists(self.download_folder):
105 os.makedirs(self.download_folder)
106
107 def tearDown(self):
108 """Overrides unittest.TestCase.tearDown and called after every test."""
109 self.worker.CleanUp()
110
111 def testUpdateKeepStateful(self):
112 """Tests if we can update normally.
113
114 This test checks that we can update by updating the stateful partition
115 rather than wiping it.
116 """
117 # Just make sure some tests pass on original image. Some old images
118 # don't pass many tests.
119 self.worker.PrepareBase(self.base_image_path)
120 # TODO(sosa): move to 100% once we start testing using the autotest paired
121 # with the dev channel.
122 percent_passed = self.worker.VerifyImage(self, 10)
123
124 # Update to - all tests should pass on new image.
125 self.worker.PerformUpdate(self.target_image_path, self.base_image_path)
126 percent_passed = self.worker.VerifyImage(self)
127
128 # Update from - same percentage should pass that originally passed.
129 self.worker.PerformUpdate(self.base_image_path, self.target_image_path)
130 self.worker.VerifyImage(self, percent_passed)
131
132 def testUpdateWipeStateful(self):
133 """Tests if we can update after cleaning the stateful partition.
134
135 This test checks that we can update successfully after wiping the
136 stateful partition.
137 """
138 # Just make sure some tests pass on original image. Some old images
139 # don't pass many tests.
140 self.worker.PrepareBase(self.base_image_path)
141 percent_passed = self.worker.VerifyImage(self, 10)
142
143 # Update to - all tests should pass on new image.
144 self.worker.PerformUpdate(self.target_image_path, self.base_image_path,
145 'clean')
146 self.worker.VerifyImage(self)
147
148 # Update from - same percentage should pass that originally passed.
149 self.worker.PerformUpdate(self.base_image_path, self.target_image_path,
150 'clean')
151 self.worker.VerifyImage(self, percent_passed)
152
153 def testInterruptedUpdate(self):
154 """Tests what happens if we interrupt payload delivery 3 times."""
155
156 class InterruptionFilter(cros_test_proxy.Filter):
157 """This filter causes the proxy to interrupt the download 3 times
158
159 It does this by closing the first three connections to transfer
160 2M total in the outbound connection after they transfer the
161 2M.
162 """
163 def __init__(self):
164 """Defines variable shared across all connections"""
165 self.close_count = 0
166
167 def setup(self):
168 """Called once at the start of each connection."""
169 self.data_size = 0
170
171 def OutBound(self, data):
172 """Called once per packet for outgoing data.
173
174 The first three connections transferring more than 2M
175 outbound will be closed.
176 """
177 if self.close_count < 3:
178 if self.data_size > (2 * 1024 * 1024):
179 self.close_count += 1
180 return None
181
182 self.data_size += len(data)
183 return data
184
185 self.AttemptUpdateWithFilter(InterruptionFilter(), proxy_port=8082)
186
187 def testDelayedUpdate(self):
188 """Tests what happens if some data is delayed during update delivery"""
189
190 class DelayedFilter(cros_test_proxy.Filter):
191 """Causes intermittent delays in data transmission.
192
193 It does this by inserting 3 20 second delays when transmitting
194 data after 2M has been sent.
195 """
196 def setup(self):
197 """Called once at the start of each connection."""
198 self.data_size = 0
199 self.delay_count = 0
200
201 def OutBound(self, data):
202 """Called once per packet for outgoing data.
203
204 The first three packets after we reach 2M transferred
205 are delayed by 20 seconds.
206 """
207 if self.delay_count < 3:
208 if self.data_size > (2 * 1024 * 1024):
209 self.delay_count += 1
210 time.sleep(20)
211
212 self.data_size += len(data)
213 return data
214
215 self.AttemptUpdateWithFilter(DelayedFilter(), proxy_port=8083)
216
217 def SimpleTest(self):
218 """A simple update that updates once from a base image to a target.
219
220 We explicitly don't use test prefix so that isn't run by default. Can be
221 run using test_prefix option.
222 """
223 self.worker.PrepareBase(self.base_image_path)
224 self.worker.PerformUpdate(self.target_image_path, self.base_image_path)
225 self.worker.VerifyImage(self)
226
227 # --- DISABLED TESTS ---
228
229 # TODO(sosa): Get test to work with verbose.
230 def NotestPartialUpdate(self):
231 """Tests what happens if we attempt to update with a truncated payload."""
232 # Preload with the version we are trying to test.
233 self.worker.PrepareBase(self.target_image_path)
234
235 # Image can be updated at:
236 # ~chrome-eng/chromeos/localmirror/autest-images
237 url = 'http://gsdview.appspot.com/chromeos-localmirror/' \
238 'autest-images/truncated_image.gz'
239 payload = os.path.join(self.download_folder, 'truncated_image.gz')
240
241 # Read from the URL and write to the local file
242 urllib.urlretrieve(url, payload)
243
244 expected_msg = 'download_hash_data == update_check_response_hash failed'
245 self.AttemptUpdateWithPayloadExpectedFailure(payload, expected_msg)
246
247 # TODO(sosa): Get test to work with verbose.
248 def NotestCorruptedUpdate(self):
249 """Tests what happens if we attempt to update with a corrupted payload."""
250 # Preload with the version we are trying to test.
251 self.worker.PrepareBase(self.target_image_path)
252
253 # Image can be updated at:
254 # ~chrome-eng/chromeos/localmirror/autest-images
255 url = 'http://gsdview.appspot.com/chromeos-localmirror/' \
256 'autest-images/corrupted_image.gz'
257 payload = os.path.join(self.download_folder, 'corrupted.gz')
258
259 # Read from the URL and write to the local file
260 urllib.urlretrieve(url, payload)
261
262 # This update is expected to fail...
263 expected_msg = 'zlib inflate() error:-3'
264 self.AttemptUpdateWithPayloadExpectedFailure(payload, expected_msg)
OLDNEW
« no previous file with comments | « bin/au_test_harness/__init__.py ('k') | bin/au_test_harness/au_worker.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698