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

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

Issue 22480002: Use unittest framework in the Automated Installer Testing Framework. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Address mathp's comments. 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
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 json 13 import json
14 import os 14 import os
15 import subprocess 15 import subprocess
16 import unittest
16 17
17 import settings
18 import verifier 18 import verifier
19 19
20 20
21 class Config: 21 class Config:
22 """Describes the machine states, actions, and test cases. 22 """Describes the machine states, actions, and test cases.
23 23
24 A state is a dictionary where each key is a verifier's name and the 24 Attributes:
25 associated value is the input to that verifier. An action is a shorthand for 25 states: A dictionary where each key is a state name and the associated value
26 a command. A test is array of alternating state names and action names, 26 is a property dictionary describing that state.
27 starting and ending with state names. An instance of this class stores a map 27 actions: A dictionary where each key is an action name and the associated
28 from state names to state objects, a map from action names to commands, and 28 value is the action's command.
29 an array of test objects. 29 tests: An array of test cases.
30 """ 30 """
31 def __init__(self): 31 def __init__(self):
32 self.states = {} 32 self.states = {}
33 self.actions = {} 33 self.actions = {}
34 self.tests = [] 34 self.tests = []
35 35
36 36
37 class InstallerTest(unittest.TestCase):
38 """Tests a test case in the config file."""
39
40 def __init__(self, test, config):
41 """Constructor.
42
43 Args:
44 test: An array of alternating state names and action names, starting and
45 ending with state names.
46 config: The Config object.
47 """
48 super(InstallerTest, self).__init__()
49 self._test = test
50 self._config = config
51
52 def __str__(self):
53 """Returns a string representing the test case.
54
55 Returns:
56 A string created by joining state names and action names together with
57 ' -> ', for example, 'Test: clean -> install chrome -> chrome_installed'.
58 """
59 return 'Test: %s' % (' -> '.join(self._test))
60
61 def runTest(self):
62 """Run the test case."""
63 # |test| is an array of alternating state names and action names, starting
64 # and ending with state names. Therefore, its length must be odd.
65 self.assertEqual(1, len(self._test) % 2,
66 'The length of test array must be odd')
67
68 # TODO(sukolsak): run a reset command that puts the machine in clean state.
69
70 state = self._test[0]
71 self._VerifyState(state)
72
73 # Starting at index 1, we loop through pairs of (action, state).
74 for i in range(1, len(self._test), 2):
75 action = self._test[i]
76 self._RunCommand(self._config.actions[action])
77
78 state = self._test[i + 1]
79 self._VerifyState(state)
80
81 def shortDescription(self):
82 """Overridden from unittest.TestCase.
83
84 We return None as the short description to suppress its printing.
85 The default implementation of this method returns the docstring of the
86 runTest method, which is not useful since it's the same for every test case.
87 The description from the __str__ method is informative enough.
88 """
89 return None
90
91 def _VerifyState(self, state):
92 """Verifies that the current machine state matches a given state.
93
94 Args:
95 state: A state name.
96 """
97 try:
98 verifier.Verify(self._config.states[state])
99 except AssertionError as e:
100 # If an AssertionError occurs, we intercept it and add the state name
101 # to the error message so that we know where the test fails.
102 raise AssertionError("In state '%s', %s" % (state, e))
103
104 def _RunCommand(self, command):
105 subprocess.call(command, shell=True)
106
107
37 def MergePropertyDictionaries(current_property, new_property): 108 def MergePropertyDictionaries(current_property, new_property):
38 """Merges the new property dictionary into the current property dictionary. 109 """Merges the new property dictionary into the current property dictionary.
39 110
40 This is different from general dictionary merging in that, in case there are 111 This is different from general dictionary merging in that, in case there are
41 keys with the same name, we merge values together in the first level, and we 112 keys with the same name, we merge values together in the first level, and we
42 override earlier values in the second level. For more details, take a look at 113 override earlier values in the second level. For more details, take a look at
43 http://goo.gl/uE0RoR 114 http://goo.gl/uE0RoR
44 115
45 Args: 116 Args:
46 current_property: The property dictionary to be modified. 117 current_property: The property dictionary to be modified.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 config = Config() 164 config = Config()
94 config.tests = config_data['tests'] 165 config.tests = config_data['tests']
95 for state_name, state_property_filenames in config_data['states']: 166 for state_name, state_property_filenames in config_data['states']:
96 config.states[state_name] = ParsePropertyFiles(directory, 167 config.states[state_name] = ParsePropertyFiles(directory,
97 state_property_filenames) 168 state_property_filenames)
98 for action_name, action_command in config_data['actions']: 169 for action_name, action_command in config_data['actions']:
99 config.actions[action_name] = action_command 170 config.actions[action_name] = action_command
100 return config 171 return config
101 172
102 173
103 def VerifyState(config, state): 174 def RunTests(config):
104 """Verifies that the current machine states match the given machine states.
105
106 Args:
107 config: A Config object.
108 state: The current state.
109 """
110 # TODO(sukolsak): Think of ways of preserving the log when the test fails but
111 # not printing these when the test passes.
112 print settings.PRINT_STATE_PREFIX + state
113 verifier.Verify(config.states[state])
114
115
116 def RunCommand(command):
117 print settings.PRINT_COMMAND_PREFIX + command
118 subprocess.call(command, shell=True)
119
120
121 def RunResetCommand():
122 print settings.PRINT_COMMAND_PREFIX + 'Reset'
123 # TODO(sukolsak): Need to figure how exactly we want to reset.
124
125
126 def Test(config):
127 """Tests the installer using the given Config object. 175 """Tests the installer using the given Config object.
128 176
129 Args: 177 Args:
130 config: A Config object. 178 config: A Config object.
131 """ 179 """
180 suite = unittest.TestSuite()
132 for test in config.tests: 181 for test in config.tests:
133 print settings.PRINT_TEST_PREFIX + ' -> '.join(test) 182 suite.addTest(InstallerTest(test, config))
134 183 unittest.TextTestRunner(verbosity=2).run(suite)
135 # A Test object is an array of alternating state names and action names.
136 # The array starts and ends with states. Therefore, the length must be odd.
137 assert(len(test) % 2 == 1)
138
139 RunResetCommand()
140
141 current_state = test[0]
142 VerifyState(config, current_state)
143 # TODO(sukolsak): Quit the test early if VerifyState fails at any point.
144
145 for i in range(1, len(test), 2):
146 action = test[i]
147 RunCommand(config.actions[action])
148
149 current_state = test[i + 1]
150 VerifyState(config, current_state)
151 184
152 185
153 def main(): 186 def main():
154 parser = argparse.ArgumentParser(description='Test the installer.') 187 parser = argparse.ArgumentParser(description='Test the installer.')
155 parser.add_argument('config_filename', 188 parser.add_argument('config_filename',
156 help='The relative/absolute path to the config file.') 189 help='The relative/absolute path to the config file.')
157 args = parser.parse_args() 190 args = parser.parse_args()
158 191
159 config = ParseConfigFile(args.config_filename) 192 config = ParseConfigFile(args.config_filename)
160 Test(config) 193 RunTests(config)
161 194
162 195
163 if __name__ == '__main__': 196 if __name__ == '__main__':
164 main() 197 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698