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

Side by Side Diff: chrome/test/mini_installer/test_installer.py

Issue 2747023002: Cleanup machine based on the state in configuration file for mini installer test.
Patch Set: fixup Created 3 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
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """This script tests the installer with test cases specified in the config file. 5 """This script tests the installer with test cases specified in the config file.
6 6
7 For each test case, it checks that the machine states after the execution of 7 For each test case, it checks that the machine states after the execution of
8 each command match the expected machine states. For more details, take a look at 8 each command match the expected machine states. For more details, take a look at
9 the design documentation at http://goo.gl/Q0rGM6 9 the design documentation at http://goo.gl/Q0rGM6
10 """ 10 """
11 11
12 import argparse 12 import argparse
13 import datetime 13 import datetime
14 import inspect 14 import inspect
15 import json 15 import json
16 import os 16 import os
17 import subprocess 17 import subprocess
18 import sys 18 import sys
19 import time 19 import time
20 import traceback 20 import traceback
21 import unittest 21 import unittest
22 import _winreg
23 22
24 from variable_expander import VariableExpander 23 from variable_expander import VariableExpander
24 import cleanup
25 import verifier_runner 25 import verifier_runner
26 26
27 27
28 def LogMessage(message): 28 def LogMessage(message):
29 """Logs a message to stderr. 29 """Logs a message to stderr.
30 30
31 Args: 31 Args:
32 message: The message string to be logged. 32 message: The message string to be logged.
33 """ 33 """
34 now = datetime.datetime.now() 34 now = datetime.datetime.now()
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 state = self._test[i + 1] 115 state = self._test[i + 1]
116 self._VerifyState(state) 116 self._VerifyState(state)
117 117
118 # If the test makes it here, it means it was successful, because RunCommand 118 # If the test makes it here, it means it was successful, because RunCommand
119 # and _VerifyState throw an exception on failure. 119 # and _VerifyState throw an exception on failure.
120 self._clean_on_teardown = False 120 self._clean_on_teardown = False
121 121
122 def tearDown(self): 122 def tearDown(self):
123 """Cleans up the machine if the test case fails.""" 123 """Cleans up the machine if the test case fails."""
124 if self._clean_on_teardown: 124 if self._clean_on_teardown:
125 RunCleanCommand(True, self._variable_expander) 125 RunCleanCommand(True, self._config.states[self._test[-1]],
grt (UTC plus 2) 2017/03/14 09:19:44 rather than baking in the assumption that the last
zmin 2017/03/14 23:13:00 Done.
126 self._variable_expander)
126 127
127 def shortDescription(self): 128 def shortDescription(self):
128 """Overridden from unittest.TestCase. 129 """Overridden from unittest.TestCase.
129 130
130 We return None as the short description to suppress its printing. 131 We return None as the short description to suppress its printing.
131 The default implementation of this method returns the docstring of the 132 The default implementation of this method returns the docstring of the
132 runTest method, which is not useful since it's the same for every test case. 133 runTest method, which is not useful since it's the same for every test case.
133 The description from the __str__ method is informative enough. 134 The description from the __str__ method is informative enough.
134 """ 135 """
135 return None 136 return None
(...skipping 25 matching lines...) Expand all
161 command: A command to run. It is expanded using Expand. 162 command: A command to run. It is expanded using Expand.
162 variable_expander: A VariableExpander object. 163 variable_expander: A VariableExpander object.
163 """ 164 """
164 expanded_command = variable_expander.Expand(command) 165 expanded_command = variable_expander.Expand(command)
165 script_dir = os.path.dirname(os.path.abspath(__file__)) 166 script_dir = os.path.dirname(os.path.abspath(__file__))
166 exit_status = subprocess.call(expanded_command, shell=True, cwd=script_dir) 167 exit_status = subprocess.call(expanded_command, shell=True, cwd=script_dir)
167 if exit_status != 0: 168 if exit_status != 0:
168 raise Exception('Command %s returned non-zero exit status %s' % ( 169 raise Exception('Command %s returned non-zero exit status %s' % (
169 expanded_command, exit_status)) 170 expanded_command, exit_status))
170 171
171 172 def RunCleanCommand(force_clean, clean_state, variable_expander):
172 def DeleteGoogleUpdateRegistration(system_level, registry_subkey,
173 variable_expander):
174 """Deletes Chrome's registration with Google Update.
175
176 Args:
177 system_level: True if system-level Chrome is to be deleted.
178 registry_subkey: The pre-expansion registry subkey for the product.
179 variable_expander: A VariableExpander object.
180 """
181 root = (_winreg.HKEY_LOCAL_MACHINE if system_level
182 else _winreg.HKEY_CURRENT_USER)
183 key_name = variable_expander.Expand(registry_subkey)
184 try:
185 key_handle = _winreg.OpenKey(root, key_name, 0,
186 _winreg.KEY_SET_VALUE |
187 _winreg.KEY_WOW64_32KEY)
188 _winreg.DeleteValue(key_handle, 'pv')
189 except WindowsError:
190 # The key isn't present, so there is no value to delete.
191 pass
192
193
194 def RunCleanCommand(force_clean, variable_expander):
195 """Puts the machine in the clean state (i.e. Chrome not installed). 173 """Puts the machine in the clean state (i.e. Chrome not installed).
196 174
197 Args: 175 Args:
198 force_clean: A boolean indicating whether to force cleaning existing 176 force_clean: A boolean indicating whether to force cleaning existing
199 installations. 177 installations.
200 variable_expander: A VariableExpander object. 178 variable_expander: A VariableExpander object.
201 """ 179 """
202 # A list of (system_level, product_name, product_switch, registry_subkey) 180 # A list of (product_name, product_switch)
203 # tuples for the possible installed products. 181 # tuples for the possible installed products.
204 data = [ 182 data = [
205 (False, '$CHROME_LONG_NAME', '', 183 ('$CHROME_LONG_NAME', ''),
206 '$CHROME_UPDATE_REGISTRY_SUBKEY'), 184 ('$CHROME_LONG_NAME', '--system-level'),
207 (True, '$CHROME_LONG_NAME', '--system-level',
208 '$CHROME_UPDATE_REGISTRY_SUBKEY'),
209 ] 185 ]
210 if variable_expander.Expand('$SUPPORTS_SXS') == 'True': 186 if variable_expander.Expand('$SUPPORTS_SXS') == 'True':
211 data.append((False, '$CHROME_LONG_NAME_SXS', '', 187 data.append(('$CHROME_LONG_NAME_SXS', ''))
212 '$CHROME_UPDATE_REGISTRY_SUBKEY_SXS'))
213 188
214 interactive_option = '--interactive' if not force_clean else '' 189 interactive_option = '--interactive' if not force_clean else ''
215 for system_level, product_name, product_switch, registry_subkey in data: 190 for product_name, product_switch in data:
216 command = ('python uninstall_chrome.py ' 191 command = ('python uninstall_chrome.py '
217 '--chrome-long-name="%s" ' 192 '--chrome-long-name="%s" '
218 '--no-error-if-absent %s %s' % 193 '--no-error-if-absent %s %s' %
219 (product_name, product_switch, interactive_option)) 194 (product_name, product_switch, interactive_option))
220 try: 195 try:
221 RunCommand(command, variable_expander) 196 RunCommand(command, variable_expander)
222 except: 197 except (Exception, OSError, ValueError):
223 message = traceback.format_exception(*sys.exc_info()) 198 message = traceback.format_exception(*sys.exc_info())
224 message.insert(0, 'Error cleaning up an old install with:\n') 199 message.insert(0, 'Error cleaning up an old install with:\n')
225 LogMessage(''.join(message)) 200 LogMessage(''.join(message))
226 if force_clean: 201
227 DeleteGoogleUpdateRegistration(system_level, registry_subkey, 202 if force_clean:
228 variable_expander) 203 cleanup.CleanupRunner.Create().CleanAll(clean_state, variable_expander)
229 204
230 205
231 def MergePropertyDictionaries(current_property, new_property): 206 def MergePropertyDictionaries(current_property, new_property):
232 """Merges the new property dictionary into the current property dictionary. 207 """Merges the new property dictionary into the current property dictionary.
233 208
234 This is different from general dictionary merging in that, in case there are 209 This is different from general dictionary merging in that, in case there are
235 keys with the same name, we merge values together in the first level, and we 210 keys with the same name, we merge values together in the first level, and we
236 override earlier values in the second level. For more details, take a look at 211 override earlier values in the second level. For more details, take a look at
237 http://goo.gl/uE0RoR 212 http://goo.gl/uE0RoR
238 213
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 variable_expander), 291 variable_expander),
317 config.tests) 292 config.tests)
318 for state_name, state_property_filenames in config_data['states']: 293 for state_name, state_property_filenames in config_data['states']:
319 config.states[state_name] = ParsePropertyFiles(directory, 294 config.states[state_name] = ParsePropertyFiles(directory,
320 state_property_filenames, 295 state_property_filenames,
321 variable_expander) 296 variable_expander)
322 for action_name, action_command in config_data['actions']: 297 for action_name, action_command in config_data['actions']:
323 config.actions[action_name] = action_command 298 config.actions[action_name] = action_command
324 return config 299 return config
325 300
301 DEFAULT_CLEAN_STATE = 'clean'
grt (UTC plus 2) 2017/03/14 09:19:44 how about making this an argument for the parser w
326 302
327 def main(): 303 def main():
328 parser = argparse.ArgumentParser() 304 parser = argparse.ArgumentParser()
329 parser.add_argument('--build-dir', default='out', 305 parser.add_argument('--build-dir', default='out',
330 help='Path to main build directory (the parent of the ' 306 help='Path to main build directory (the parent of the '
331 'Release or Debug directory)') 307 'Release or Debug directory)')
332 parser.add_argument('--target', default='Release', 308 parser.add_argument('--target', default='Release',
333 help='Build target (Release or Debug)') 309 help='Build target (Release or Debug)')
334 parser.add_argument('--force-clean', action='store_true', default=False, 310 parser.add_argument('--force-clean', action='store_true', default=False,
335 help='Force cleaning existing installations') 311 help='Force cleaning existing installations')
336 parser.add_argument('-q', '--quiet', action='store_true', default=False, 312 parser.add_argument('-q', '--quiet', action='store_true', default=False,
337 help='Reduce test runner output') 313 help='Reduce test runner output')
338 parser.add_argument('--write-full-results-to', metavar='FILENAME', 314 parser.add_argument('--write-full-results-to', metavar='FILENAME',
339 help='Path to write the list of full results to.') 315 help='Path to write the list of full results to.')
340 parser.add_argument('--config', metavar='FILENAME', 316 parser.add_argument('--config', metavar='FILENAME',
341 help='Path to test configuration file') 317 help='Path to test configuration file')
342 parser.add_argument('test', nargs='*', 318 parser.add_argument('test', nargs='*',
343 help='Name(s) of tests to run.') 319 help=('Name(s) of tests to run. For example, '
320 '__main__.InstallerTest.ChromeUserLevel'))
344 args = parser.parse_args() 321 args = parser.parse_args()
345 if not args.config: 322 if not args.config:
346 parser.error('missing mandatory --config FILENAME argument') 323 parser.error('missing mandatory --config FILENAME argument')
347 324
348 mini_installer_path = os.path.join(args.build_dir, args.target, 325 mini_installer_path = os.path.join(args.build_dir, args.target,
349 'mini_installer.exe') 326 'mini_installer.exe')
350 assert os.path.exists(mini_installer_path), ('Could not find file %s' % 327 assert os.path.exists(mini_installer_path), ('Could not find file %s' %
351 mini_installer_path) 328 mini_installer_path)
352 329
353 next_version_mini_installer_path = os.path.join( 330 next_version_mini_installer_path = os.path.join(
354 args.build_dir, args.target, 'next_version_mini_installer.exe') 331 args.build_dir, args.target, 'next_version_mini_installer.exe')
355 assert os.path.exists(next_version_mini_installer_path), ( 332 assert os.path.exists(next_version_mini_installer_path), (
356 'Could not find file %s' % next_version_mini_installer_path) 333 'Could not find file %s' % next_version_mini_installer_path)
357 334
358 suite = unittest.TestSuite() 335 suite = unittest.TestSuite()
359 336
360 variable_expander = VariableExpander(mini_installer_path, 337 variable_expander = VariableExpander(mini_installer_path,
361 next_version_mini_installer_path) 338 next_version_mini_installer_path)
362 config = ParseConfigFile(args.config, variable_expander) 339 config = ParseConfigFile(args.config, variable_expander)
363 340
364 RunCleanCommand(args.force_clean, variable_expander) 341 RunCleanCommand(args.force_clean, config.states[DEFAULT_CLEAN_STATE],
342 variable_expander)
365 for test in config.tests: 343 for test in config.tests:
366 # If tests were specified via |tests|, their names are formatted like so: 344 # If tests were specified via |tests|, their names are formatted like so:
367 test_name = '%s.%s.%s' % (InstallerTest.__module__, 345 test_name = '%s.%s.%s' % (InstallerTest.__module__,
368 InstallerTest.__name__, 346 InstallerTest.__name__,
369 test['name']) 347 test['name'])
370 if not args.test or test_name in args.test: 348 if not args.test or test_name in args.test:
371 suite.addTest(InstallerTest(test['name'], test['traversal'], config, 349 suite.addTest(InstallerTest(test['name'], test['traversal'], config,
372 variable_expander, args.quiet)) 350 variable_expander, args.quiet))
373 351
374 verbosity = 2 if not args.quiet else 1 352 verbosity = 2 if not args.quiet else 1
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 trie[path] = value 420 trie[path] = value
443 return 421 return
444 directory, rest = path.split(TEST_SEPARATOR, 1) 422 directory, rest = path.split(TEST_SEPARATOR, 1)
445 if directory not in trie: 423 if directory not in trie:
446 trie[directory] = {} 424 trie[directory] = {}
447 _AddPathToTrie(trie[directory], rest, value) 425 _AddPathToTrie(trie[directory], rest, value)
448 426
449 427
450 if __name__ == '__main__': 428 if __name__ == '__main__':
451 sys.exit(main()) 429 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698