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

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

Issue 20578004: Initial commit for the Automated Installer Testing Framework. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 4 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
« no previous file with comments | « chrome/test/mini_installer/settings.py ('k') | chrome/test/mini_installer/uninstall_chrome.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 2013 The Chromium 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 """This script tests the installer with a series of test cases specified in
6 the config file. For each test case, it checks that the machine states after
7 the execution of each command match the expected machine states.
8
9 For more details take a look at the design documentation at http://goo.gl/Q0rGM6
10 """
11
12 import optparse
gab 2013/08/05 15:43:48 nit: Fix alphabetical order of imports
sukolsak 2013/08/05 18:03:51 Done.
13 import json
14 import os
15 import settings
16 import subprocess
17 import verifier
18
19
20 class Config:
21 """Describes the machine states, actions, and test cases.
22
23 A state is a dictionary where each key is a verifier's name and the
24 associated value is the input to that verifier. An action is a shorthand for
25 a command. A test is array of alternating state names and action names,
26 starting and ending with state names. An instance of this class stores a map
27 from state names to state objects, a map from action names to commands, and
28 an array of test objects.
29 """
30 def __init__(self):
31 self.states = {}
32 self.actions = {}
33 self.tests = []
34
35
36 def MergeProperties(current_property, new_property):
37 """Merges the new Property object into the current Property object
38
39 Args:
40 current_property: The Property object to be modified.
41 new_property: The new Property object.
42 """
43 for key, value in new_property.iteritems():
44 if key not in current_property:
45 current_property[key] = value
46 else:
47 assert(isinstance(current_property[key], dict) and
48 isinstance(value, dict))
49 # This merges two dictionaries together. In case there are properties with
50 # the same name, the latter will override the former.
51 current_property[key] = dict(
52 current_property[key].items() + value.items())
53
54
55 def ParseProperty(directory, property_filename):
56 """Parses a .prop file.
57
58 Args:
59 property_filename: A Property filename.
60 directory: The directory where the Config file and all Property files
61 reside in.
62
63 Returns:
64 A Property object.
65 """
66 property_path = os.path.join(directory, property_filename)
67 with open(property_path, "r") as property_file:
68 return json.load(property_file)
69
70
71 def ParseProperties(directory, property_filenames):
72 """Parses an array of .prop files.
73
74 Args:
75 property_filenames: An array of Property filenames.
76 directory: The directory where the Config file and all Property files
77 reside in.
78
79 Returns:
80 A Property object created by merging all Property objects specified in
81 the array.
82 """
83 current_property = {}
84 for property_filename in property_filenames:
85 new_property = ParseProperty(directory, property_filename)
86 MergeProperties(current_property, new_property)
87 return current_property
88
89
90 def ParseConfig(config_filename):
91 """Parses a .config file.
92
93 Args:
94 config_filename: A Config filename.
95
96 Returns:
97 A config object.
98 """
99 config = Config()
100
101 with open(config_filename, "r") as config_file:
102 config_data = json.load(config_file)
103 directory = os.path.dirname(os.path.abspath(config_filename))
104
105 for state_name, state_property_filenames in config_data["states"]:
106 config.states[state_name] = ParseProperties(directory,
107 state_property_filenames)
108 for action_name, action_command in config_data["actions"]:
109 config.actions[action_name] = action_command
110 config.tests = config_data["tests"]
111 return config
112
113
114 def VerifyState(config, state):
115 """Verifies that the current machine states match the given machine states.
116
117 Args:
118 config: A Config object.
119 state: The current state.
120 """
121 # TODO(sukolsak): Think of ways of preserving the log when the test fails but
122 # not printing these when the test passes.
123 print settings.PRINT_STATE_PREFIX + state
124 verifier.Verify(config.states[state])
125
126
127 def RunCommand(command):
128 print settings.PRINT_COMMAND_PREFIX + command
129 subprocess.call(command, shell=True)
130
131
132 def RunResetCommand():
133 print settings.PRINT_COMMAND_PREFIX + "Reset"
134 # TODO(sukolsak): Need to figure how exactly we want to reset.
135
136
137 def Test(config):
138 """Tests the installer using the given Config object.
139
140 Args:
141 config: A Config object.
142 """
143 for test in config.tests:
144 print settings.PRINT_TEST_PREFIX + " -> ".join(test)
145
146 # A Test object is an array of alternating state names and action names.
147 # The array starts and ends with states. Therefore, the length must be odd.
148 assert(len(test) % 2 == 1)
149
150 RunResetCommand()
151
152 current_state = test[0]
153 VerifyState(config, current_state)
154 # TODO(sukolsak): Quit the test early if VerifyState fails at any point.
155
156 for i in range(1, len(test), 2):
157 action = test[i]
158 RunCommand(config.actions[action])
159
160 current_state = test[i + 1]
161 VerifyState(config, current_state)
162
163
164 def main():
165 usage = "usage: %prog configfile"
166 parser = optparse.OptionParser(usage, description="Test the installer.")
gab 2013/08/05 15:43:48 Use parser.add_option, see https://code.google.com
sukolsak 2013/08/05 18:03:51 add_option doesn't support required arguments. The
gab 2013/08/05 18:13:05 I see then the error message below should be a mor
167 (options, args) = parser.parse_args()
gab 2013/08/05 15:43:48 Do not even store |args|, see https://code.google.
168 if len(args) != 1:
169 parser.error("incorrect number of arguments")
170
171 config = ParseConfig(args[0])
172 Test(config)
173
174
175 if __name__ == "__main__":
176 main()
OLDNEW
« no previous file with comments | « chrome/test/mini_installer/settings.py ('k') | chrome/test/mini_installer/uninstall_chrome.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698