diff options
author | sukolsak@chromium.org <sukolsak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-12 20:09:26 +0000 |
---|---|---|
committer | sukolsak@chromium.org <sukolsak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-12 20:09:26 +0000 |
commit | 04dbc630c1d32852c458e6b1a63820d09355623d (patch) | |
tree | ad9dbd37da189d1d7dad249fa8df119e2796b4d7 /chrome/test | |
parent | ee4f02b5e5e72e324e13ed6a95172b0c451a5e61 (diff) | |
download | chromium_src-04dbc630c1d32852c458e6b1a63820d09355623d.zip chromium_src-04dbc630c1d32852c458e6b1a63820d09355623d.tar.gz chromium_src-04dbc630c1d32852c458e6b1a63820d09355623d.tar.bz2 |
Use unittest framework in the Automated Installer Testing Framework.
NOTRY=True
BUG=264859
TEST=
1) Uninstall Chrome.
2) Put mini_installer.exe in the same folder as test_installer.py.
3) Run "python test_installer.py config\config.config".
4) The script will install Chrome and then uninstall Chrome. At each state, it will check that a registry entry for Chrome exists (or doesn't exist). You should see output similar to the following:
"Test: clean -> install chrome -> chrome_installed -> uninstall chrome -> clean ... ok
----------------------------------------------------------------------
Ran 1 test in 12.345s"
Review URL: https://chromiumcodereview.appspot.com/22480002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217059 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test')
-rw-r--r-- | chrome/test/mini_installer/config/chrome_installed.prop | 2 | ||||
-rw-r--r-- | chrome/test/mini_installer/config/chrome_not_installed.prop | 2 | ||||
-rw-r--r-- | chrome/test/mini_installer/registry_verifier.py | 64 | ||||
-rw-r--r-- | chrome/test/mini_installer/settings.py | 8 | ||||
-rw-r--r-- | chrome/test/mini_installer/test_installer.py | 133 | ||||
-rw-r--r-- | chrome/test/mini_installer/verifier.py | 14 |
6 files changed, 124 insertions, 99 deletions
diff --git a/chrome/test/mini_installer/config/chrome_installed.prop b/chrome/test/mini_installer/config/chrome_installed.prop index 289b47d..9db2a19 100644 --- a/chrome/test/mini_installer/config/chrome_installed.prop +++ b/chrome/test/mini_installer/config/chrome_installed.prop @@ -1,6 +1,6 @@ { "RegistryEntries": { "HKEY_CURRENT_USER\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}": - {"expected": true} + {"exists": true} } } diff --git a/chrome/test/mini_installer/config/chrome_not_installed.prop b/chrome/test/mini_installer/config/chrome_not_installed.prop index 6e024ef..a9f7685 100644 --- a/chrome/test/mini_installer/config/chrome_not_installed.prop +++ b/chrome/test/mini_installer/config/chrome_not_installed.prop @@ -1,6 +1,6 @@ { "RegistryEntries": { "HKEY_CURRENT_USER\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}": - {"expected": false} + {"exists": false} } } diff --git a/chrome/test/mini_installer/registry_verifier.py b/chrome/test/mini_installer/registry_verifier.py index ceac20d..da7909e 100644 --- a/chrome/test/mini_installer/registry_verifier.py +++ b/chrome/test/mini_installer/registry_verifier.py @@ -4,20 +4,20 @@ import _winreg -import settings - def VerifyRegistryEntries(entries): - """Verifies that the current registry matches the specified criteria.""" - for key, entry in entries.iteritems(): - # TODO(sukolsak): Use unittest framework instead of prints. - if VerifyRegistryEntry(key, entry): - print 'Passed' - else: - print 'Failed' + """Verifies that the current registry matches the specified criteria. + + Args: + entries: A dictionary whose keys are registry keys and values are + expectation dictionaries. + """ + for key, expectation in entries.iteritems(): + VerifyRegistryEntry(key, expectation) def RootKeyConstant(key): + """Converts a root registry key string into a _winreg.HKEY_* constant.""" if key == 'HKEY_CLASSES_ROOT': return _winreg.HKEY_CLASSES_ROOT if key == 'HKEY_CURRENT_USER': @@ -26,39 +26,31 @@ def RootKeyConstant(key): return _winreg.HKEY_LOCAL_MACHINE if key == 'HKEY_USERS': return _winreg.HKEY_USERS - # TODO(sukolsak): Use unittest framework instead of exceptions. - raise Exception('Unknown registry key') + raise KeyError("Unknown root registry key '%s'" % key) + +def VerifyRegistryEntry(key, expectation): + """Verifies a registry key according to the |expectation|. -def VerifyRegistryEntry(key, entry): - """Verifies that a registry entry exists or doesn't exist and has - the specified value. + The |expectation| specifies whether or not the registry key should exist + (under 'exists') and optionally specifies an expected 'value' for the key. Args: key: Name of the registry key. - entry: A dictionary with the following keys and values: - 'expected' a boolean indicating whether the registry entry exists. - 'value' (optional) a string representing the value of the registry entry. - - Returns: - A boolean indicating whether the registry entry matches the criteria. + expectation: A dictionary with the following keys and values: + 'exists' a boolean indicating whether the registry entry should exist. + 'value' (optional) a string representing the expected value for + the key. """ - expected = entry['expected'] - # TODO(sukolsak): Debug prints to be removed later. - print settings.PRINT_VERIFIER_PREFIX + key, - if expected: - print 'exists...', - else: - print "doesn't exist...", root_key, sub_key = key.split('\\', 1) try: - reg_key = _winreg.OpenKey(RootKeyConstant(root_key), - sub_key, 0, _winreg.KEY_READ) + # Query the Windows registry for the registry key. It will throw a + # WindowsError if the key doesn't exist. + _ = _winreg.OpenKey(RootKeyConstant(root_key), sub_key, 0, _winreg.KEY_READ) except WindowsError: - return not expected - if not expected: - return False - if 'value' in entry: - # TODO(sukolsak): implement value - pass - return True + # Key doesn't exist. See that it matches the expectation. + assert not expectation['exists'], 'Registry entry %s is missing' % key + return + # The key exists, see that it matches the expectation. + assert expectation['exists'], 'Registry entry %s exists' % key + # TODO(sukolsak): Verify the expected value. diff --git a/chrome/test/mini_installer/settings.py b/chrome/test/mini_installer/settings.py deleted file mode 100644 index 9c04a8b..0000000 --- a/chrome/test/mini_installer/settings.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -PRINT_TEST_PREFIX = "Testing: " -PRINT_COMMAND_PREFIX = " * Command: " -PRINT_STATE_PREFIX = " * State: " -PRINT_VERIFIER_PREFIX = " - Verify that " diff --git a/chrome/test/mini_installer/test_installer.py b/chrome/test/mini_installer/test_installer.py index a59bf91..a983478 100644 --- a/chrome/test/mini_installer/test_installer.py +++ b/chrome/test/mini_installer/test_installer.py @@ -13,20 +13,20 @@ import argparse import json import os import subprocess +import unittest -import settings import verifier class Config: """Describes the machine states, actions, and test cases. - A state is a dictionary where each key is a verifier's name and the - associated value is the input to that verifier. An action is a shorthand for - a command. A test is array of alternating state names and action names, - starting and ending with state names. An instance of this class stores a map - from state names to state objects, a map from action names to commands, and - an array of test objects. + Attributes: + states: A dictionary where each key is a state name and the associated value + is a property dictionary describing that state. + actions: A dictionary where each key is an action name and the associated + value is the action's command. + tests: An array of test cases. """ def __init__(self): self.states = {} @@ -34,6 +34,77 @@ class Config: self.tests = [] +class InstallerTest(unittest.TestCase): + """Tests a test case in the config file.""" + + def __init__(self, test, config): + """Constructor. + + Args: + test: An array of alternating state names and action names, starting and + ending with state names. + config: The Config object. + """ + super(InstallerTest, self).__init__() + self._test = test + self._config = config + + def __str__(self): + """Returns a string representing the test case. + + Returns: + A string created by joining state names and action names together with + ' -> ', for example, 'Test: clean -> install chrome -> chrome_installed'. + """ + return 'Test: %s' % (' -> '.join(self._test)) + + def runTest(self): + """Run the test case.""" + # |test| is an array of alternating state names and action names, starting + # and ending with state names. Therefore, its length must be odd. + self.assertEqual(1, len(self._test) % 2, + 'The length of test array must be odd') + + # TODO(sukolsak): run a reset command that puts the machine in clean state. + + state = self._test[0] + self._VerifyState(state) + + # Starting at index 1, we loop through pairs of (action, state). + for i in range(1, len(self._test), 2): + action = self._test[i] + self._RunCommand(self._config.actions[action]) + + state = self._test[i + 1] + self._VerifyState(state) + + def shortDescription(self): + """Overridden from unittest.TestCase. + + We return None as the short description to suppress its printing. + The default implementation of this method returns the docstring of the + runTest method, which is not useful since it's the same for every test case. + The description from the __str__ method is informative enough. + """ + return None + + def _VerifyState(self, state): + """Verifies that the current machine state matches a given state. + + Args: + state: A state name. + """ + try: + verifier.Verify(self._config.states[state]) + except AssertionError as e: + # If an AssertionError occurs, we intercept it and add the state name + # to the error message so that we know where the test fails. + raise AssertionError("In state '%s', %s" % (state, e)) + + def _RunCommand(self, command): + subprocess.call(command, shell=True) + + def MergePropertyDictionaries(current_property, new_property): """Merges the new property dictionary into the current property dictionary. @@ -100,54 +171,16 @@ def ParseConfigFile(filename): return config -def VerifyState(config, state): - """Verifies that the current machine states match the given machine states. - - Args: - config: A Config object. - state: The current state. - """ - # TODO(sukolsak): Think of ways of preserving the log when the test fails but - # not printing these when the test passes. - print settings.PRINT_STATE_PREFIX + state - verifier.Verify(config.states[state]) - - -def RunCommand(command): - print settings.PRINT_COMMAND_PREFIX + command - subprocess.call(command, shell=True) - - -def RunResetCommand(): - print settings.PRINT_COMMAND_PREFIX + 'Reset' - # TODO(sukolsak): Need to figure how exactly we want to reset. - - -def Test(config): +def RunTests(config): """Tests the installer using the given Config object. Args: config: A Config object. """ + suite = unittest.TestSuite() for test in config.tests: - print settings.PRINT_TEST_PREFIX + ' -> '.join(test) - - # A Test object is an array of alternating state names and action names. - # The array starts and ends with states. Therefore, the length must be odd. - assert(len(test) % 2 == 1) - - RunResetCommand() - - current_state = test[0] - VerifyState(config, current_state) - # TODO(sukolsak): Quit the test early if VerifyState fails at any point. - - for i in range(1, len(test), 2): - action = test[i] - RunCommand(config.actions[action]) - - current_state = test[i + 1] - VerifyState(config, current_state) + suite.addTest(InstallerTest(test, config)) + unittest.TextTestRunner(verbosity=2).run(suite) def main(): @@ -157,7 +190,7 @@ def main(): args = parser.parse_args() config = ParseConfigFile(args.config_filename) - Test(config) + RunTests(config) if __name__ == '__main__': diff --git a/chrome/test/mini_installer/verifier.py b/chrome/test/mini_installer/verifier.py index 7b0fae6..8a735ba 100644 --- a/chrome/test/mini_installer/verifier.py +++ b/chrome/test/mini_installer/verifier.py @@ -4,12 +4,20 @@ import registry_verifier + def Verify(property): - """Verifies that the current machine states match the property object.""" + """Verifies that the current machine states match the property dictionary. + + A property dictionary is a dictionary where each key is a verifier's name and + the associated value is the input to that verifier. For details about the + input format for each verifier, take a look at http://goo.gl/1P85WL + + Args: + property: A property dictionary. + """ for verifier_name, value in property.iteritems(): if verifier_name == 'RegistryEntries': registry_verifier.VerifyRegistryEntries(value) else: # TODO(sukolsak): Implement other verifiers - # TODO(sukolsak): Use unittest framework instead of exceptions. - raise Exception('Unknown verifier') + raise KeyError('Unknown verifier %s' % verifier_name) |