Commit 92a819b0 authored by grt's avatar grt Committed by Commit bot

Reduce flakes in the mini_installer test.

This change makes the test more resilient to unexpected state on the
machine.

- RegistryVerifier can now verify that registry values are not present
  (and, as a result, optional registry keys). A key's "exists" property
  can be one of "required", "forbidden", or "optional". The first two
  behave identically to the true and false boolean values of the
  previous implementation. For an "optional" key, values within it may
  have an empty dict (i.e., with no "type" or "data" members) to
  indicate that the value must not be present in the key if the key is
  present.

- Each test now begins with the "no_pv" state rather than the "clean"
  state. This is more permissive, and simply ensures that Chrome is not
  registered with Google Update.

- After attempting to force-uninstall Chrome (either before executing a
  test or after a test failure), the harness will unconditionally delete
  the Google Update registration of that Chrome if it is present. This
  will clean the machine sufficiently for a subsequent test run.

BUG=375739,401148,402081
R=robertshield@chromium.org
NOTRY=true

Review URL: https://codereview.chromium.org/520633005

Cr-Commit-Position: refs/heads/master@{#292943}
parent bf8d3186
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
}, },
"RegistryEntries": { "RegistryEntries": {
"HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY": { "HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY": {
"exists": true, "exists": "required",
"values": { "values": {
"pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"} "pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"}
} }
}, },
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": { "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": {
"exists": true, "exists": "required",
"values": { "values": {
"UninstallString": { "UninstallString": {
"type": "SZ", "type": "SZ",
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
}, },
"HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": { "HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": {
"condition": "$WINDOWS_VERSION >= $VERSION_WIN8", "condition": "$WINDOWS_VERSION >= $VERSION_WIN8",
"exists": true "exists": "required"
} }
} }
} }
{
"RegistryEntries": {
"HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY": {
"exists": "optional",
"values": {
"pv": {}
}
}
}
}
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
"$PROGRAM_FILES\\$CHROME_DIR\\Application": {"exists": false} "$PROGRAM_FILES\\$CHROME_DIR\\Application": {"exists": false}
}, },
"RegistryEntries": { "RegistryEntries": {
"HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY": {"exists": false}, "HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY": {
"exists": "forbidden"},
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME":
{"exists": false}, {"exists": "forbidden"},
"HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": { "HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": {
"exists": false "exists": "forbidden"
} }
} }
} }
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
}, },
"RegistryEntries": { "RegistryEntries": {
"HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY": { "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY": {
"exists": true, "exists": "required",
"values": { "values": {
"pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"} "pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"}
} }
}, },
"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": { "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": {
"exists": true, "exists": "required",
"values": { "values": {
"UninstallString": { "UninstallString": {
"type": "SZ", "type": "SZ",
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
}, },
"HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": { "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": {
"condition": "$WINDOWS_VERSION >= $VERSION_WIN8", "condition": "$WINDOWS_VERSION >= $VERSION_WIN8",
"exists": true "exists": "required"
} }
} }
} }
{
"RegistryEntries": {
"HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY": {
"exists": "optional",
"values": {
"pv": {}
}
}
}
}
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
}, },
"RegistryEntries": { "RegistryEntries": {
"HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY\\Commands": "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY\\Commands":
{"exists": false}, {"exists": "forbidden"},
"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME":
{"exists": false}, {"exists": "forbidden"},
"HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": { "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": {
"exists": false "exists": "forbidden"
} }
} }
} }
{ {
"states": [ "states": [
["no_pv", ["chrome_user_no_pv.prop",
"chrome_system_no_pv.prop"]],
["clean", ["chrome_user_not_installed.prop", ["clean", ["chrome_user_not_installed.prop",
"chrome_system_not_installed.prop", "chrome_system_not_installed.prop",
"chrome_user_not_inuse.prop", "chrome_user_not_inuse.prop",
...@@ -43,7 +45,7 @@ ...@@ -43,7 +45,7 @@
{ {
"name": "ChromeUserLevel", "name": "ChromeUserLevel",
"traversal": [ "traversal": [
"clean", "no_pv",
"install_chrome_user", "chrome_user_installed_not_inuse", "install_chrome_user", "chrome_user_installed_not_inuse",
"launch_chrome_user", "chrome_user_installed_inuse", "launch_chrome_user", "chrome_user_installed_inuse",
"quit_chrome_user", "chrome_user_installed_not_inuse", "quit_chrome_user", "chrome_user_installed_not_inuse",
...@@ -53,7 +55,7 @@ ...@@ -53,7 +55,7 @@
{ {
"name": "ChromeSystemLevel", "name": "ChromeSystemLevel",
"traversal": [ "traversal": [
"clean", "no_pv",
"install_chrome_system", "chrome_system_installed_not_inuse", "install_chrome_system", "chrome_system_installed_not_inuse",
"launch_chrome_system", "chrome_system_installed_inuse", "launch_chrome_system", "chrome_system_installed_inuse",
"quit_chrome_system", "chrome_system_installed_not_inuse", "quit_chrome_system", "chrome_system_installed_not_inuse",
......
...@@ -49,13 +49,17 @@ class RegistryVerifier(verifier.Verifier): ...@@ -49,13 +49,17 @@ class RegistryVerifier(verifier.Verifier):
expectation_name: The registry key being verified. It is expanded using expectation_name: The registry key being verified. It is expanded using
Expand. Expand.
expectation: A dictionary with the following keys and values: expectation: A dictionary with the following keys and values:
'exists' a boolean indicating whether the registry key should exist. 'exists' a string indicating whether the registry key's existence is
'required', 'optional', or 'forbidden'. Values are not checked if
an 'optional' key is not present in the registry.
'values' (optional) a dictionary where each key is a registry value 'values' (optional) a dictionary where each key is a registry value
and its associated value is a dictionary with the following key and its associated value is a dictionary with the following key
and values: and values:
'type' a string indicating the type of the registry value. 'type' (optional) a string indicating the type of the registry
'data' the associated data of the registry value. If it is a value. If not present, the corresponding value is expected
string, it is expanded using Expand. to be absent in the registry.
'data' the associated data of the registry value if 'type' is
specified. If it is a string, it is expanded using Expand.
variable_expander: A VariableExpander object. variable_expander: A VariableExpander object.
""" """
key = variable_expander.Expand(expectation_name) key = variable_expander.Expand(expectation_name)
...@@ -67,11 +71,13 @@ class RegistryVerifier(verifier.Verifier): ...@@ -67,11 +71,13 @@ class RegistryVerifier(verifier.Verifier):
_winreg.KEY_QUERY_VALUE) _winreg.KEY_QUERY_VALUE)
except WindowsError: except WindowsError:
# Key doesn't exist. See that it matches the expectation. # Key doesn't exist. See that it matches the expectation.
assert not expectation['exists'], ('Registry key %s is missing' % assert expectation['exists'] is not 'required', ('Registry key %s is '
key) 'missing' % key)
# Values are not checked if the missing key's existence is optional.
return return
# The key exists, see that it matches the expectation. # The key exists, see that it matches the expectation.
assert expectation['exists'], ('Registry key %s exists' % key) assert expectation['exists'] is not 'forbidden', ('Registry key %s exists' %
key)
# Verify the expected values. # Verify the expected values.
if 'values' not in expectation: if 'values' not in expectation:
...@@ -82,8 +88,13 @@ class RegistryVerifier(verifier.Verifier): ...@@ -82,8 +88,13 @@ class RegistryVerifier(verifier.Verifier):
try: try:
data, value_type = _winreg.QueryValueEx(key_handle, value) data, value_type = _winreg.QueryValueEx(key_handle, value)
except WindowsError: except WindowsError:
raise KeyError("Value '%s' of registry key %s is missing" % ( # The value does not exist. See that this matches the expectation.
value, key)) assert 'type' not in value_expectation, ('Value %s of registry key %s '
'is missing' % (value, key))
continue
assert 'type' in value_expectation, ('Value %s of registry key %s exists '
'with value %s' % (value, key, data))
# Verify the type of the value. # Verify the type of the value.
expected_value_type = value_expectation['type'] expected_value_type = value_expectation['type']
......
...@@ -16,6 +16,7 @@ import subprocess ...@@ -16,6 +16,7 @@ import subprocess
import sys import sys
import time import time
import unittest import unittest
import _winreg
from variable_expander import VariableExpander from variable_expander import VariableExpander
import verifier_runner import verifier_runner
...@@ -144,6 +145,26 @@ def RunCommand(command, variable_expander): ...@@ -144,6 +145,26 @@ def RunCommand(command, variable_expander):
expanded_command, exit_status)) expanded_command, exit_status))
def DeleteGoogleUpdateRegistration(system_level, variable_expander):
"""Deletes Chrome's registration with Google Update.
Args:
system_level: True if system-level Chrome is to be deleted.
variable_expander: A VariableExpander object.
"""
root = (_winreg.HKEY_LOCAL_MACHINE if system_level
else _winreg.HKEY_CURRENT_USER)
key_name = variable_expander.Expand('$CHROME_UPDATE_REGISTRY_SUBKEY')
try:
key_handle = _winreg.OpenKey(root, key_name, 0,
_winreg.KEY_SET_VALUE |
_winreg.KEY_WOW64_32KEY)
_winreg.DeleteValue(key_handle, 'pv')
except WindowsError:
# The key isn't present, so there is no value to delete.
pass
def RunCleanCommand(force_clean, variable_expander): def RunCleanCommand(force_clean, variable_expander):
"""Puts the machine in the clean state (i.e. Chrome not installed). """Puts the machine in the clean state (i.e. Chrome not installed).
...@@ -152,17 +173,17 @@ def RunCleanCommand(force_clean, variable_expander): ...@@ -152,17 +173,17 @@ def RunCleanCommand(force_clean, variable_expander):
installations. installations.
variable_expander: A VariableExpander object. variable_expander: A VariableExpander object.
""" """
# TODO(sukolsak): Read the clean state from the config file and clean
# the machine according to it.
# TODO(sukolsak): Handle Chrome SxS installs. # TODO(sukolsak): Handle Chrome SxS installs.
commands = []
interactive_option = '--interactive' if not force_clean else '' interactive_option = '--interactive' if not force_clean else ''
for level_option in ('', '--system-level'): for system_level in (False, True):
commands.append('python uninstall_chrome.py ' level_option = '--system-level' if system_level else ''
'--chrome-long-name="$CHROME_LONG_NAME" ' command = ('python uninstall_chrome.py '
'--no-error-if-absent %s %s' % '--chrome-long-name="$CHROME_LONG_NAME" '
(level_option, interactive_option)) '--no-error-if-absent %s %s' %
RunCommand(' && '.join(commands), variable_expander) (level_option, interactive_option))
RunCommand(command, variable_expander)
if force_clean:
DeleteGoogleUpdateRegistration(system_level, variable_expander)
def MergePropertyDictionaries(current_property, new_property): def MergePropertyDictionaries(current_property, new_property):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment