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

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: Change verifiers to classes. 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 from verifier 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 A state is a dictionary where each key is a verifier's name and the
Mathieu 2013/08/09 17:25:15 Change this to be: Attributes: state: ... act
sukolsak 2013/08/09 21:12:38 Done.
25 associated value is the input to that verifier. An action is a shorthand for 25 associated value is the input to that verifier. An action is a shorthand for
26 a command. A test is array of alternating state names and action names, 26 a command. A test is array of alternating state names and action names,
27 starting and ending with state names. An instance of this class stores a map 27 starting and ending with state names. An instance of this class stores a map
28 from state names to state objects, a map from action names to commands, and 28 from state names to state objects, a map from action names to commands, and
29 an array of test objects. 29 an array of test objects.
30 """ 30 """
31 def __init__(self): 31 def __init__(self):
32 self.states = {} 32 self.states = {}
Mathieu 2013/08/09 17:25:15 Is this used?
sukolsak 2013/08/09 21:12:38 It is used.
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."""
Mathieu 2013/08/09 17:25:15 The guide says you should describe class attribute
sukolsak 2013/08/09 21:12:38 Done.
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__()
Mathieu 2013/08/09 17:25:15 initialize self._current_state to None. It's best
sukolsak 2013/08/09 21:12:38 Done.
49 self.test = test
Mathieu 2013/08/09 17:25:15 therefore self._test self._config self._verifier
sukolsak 2013/08/09 21:12:38 Done.
50 self.config = config
51 self.verifier = Verifier(self)
Mathieu 2013/08/09 16:08:43 you are passing the whole object in the Verifier c
gab 2013/08/09 16:16:11 We would love to avoid this! Is there any way to i
Mathieu 2013/08/09 17:25:15 How about throwing an exception with a useful mess
sukolsak 2013/08/09 21:19:40 I have removed |testcase| from verifier (and thus
52
53 def runTest(self):
54 """Run the test case."""
55 test = self.test
Mathieu 2013/08/09 17:25:15 use self._test throughout
sukolsak 2013/08/09 21:12:38 Done.
56
57 # |test| is an array of alternating state names and action names, starting
58 # and ending with state names. Therefore, its length must be odd.
59 self.assertEqual(len(test) % 2, 1, 'The length of test array must be odd')
Mathieu 2013/08/09 17:25:15 -expectation should be 1st param self.assertEqual
sukolsak 2013/08/09 21:12:38 Done.
60
61 self._RunResetCommand()
62
63 self.current_state = test[0]
64 self._VerifyCurrentState()
65
66 for i in range(1, len(test), 2):
Mathieu 2013/08/09 17:25:15 Add a comment saying exactly what you're looping o
sukolsak 2013/08/09 21:12:38 Done.
67 action = test[i]
68 self._RunCommand(self.config.actions[action])
69
70 self.current_state = test[i + 1]
71 self._VerifyCurrentState()
72
73 def __str__(self):
Mathieu 2013/08/09 17:25:15 nit: bring it up to be next to __init__?
sukolsak 2013/08/09 21:12:38 Done.
74 """Returns a string representing the test case.
75
76 This method returns a string created by joining state names and action names
Mathieu 2013/08/09 17:25:15 "This method returns" -> Returns: A string cre
sukolsak 2013/08/09 21:12:38 Done.
77 together with ' -> ', for example,
78 'Test: clean -> install chrome -> chrome_installed'.
79 """
80 return 'Test: %s' % (' -> '.join(self.test))
81
82 def shortDescription(self):
83 """Returns None as the short description to suppress its printing.
84
Mathieu 2013/08/09 17:25:15 Add a line saying: Overriden from unittest.TestCa
sukolsak 2013/08/09 21:12:38 Done.
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 failureException(self, msg):
92 """Returns an AssertionError with the current state information.
93
94 The default implementation of this method returns AssertionError(msg).
95 We add the current state information to the message so that we know where
96 the test fails.
97
98 Args:
99 msg: The error message.
100
101 Returns:
102 An AssertionError.
103 """
104 return AssertionError("In state '%s', %s" % (self.current_state, msg))
105
106 def _VerifyCurrentState(self):
107 """Verifies that the current machine state matches the expected machine
Mathieu 2013/08/09 17:25:15 Make it fit on one line
sukolsak 2013/08/09 21:12:38 Done.
108 state."""
109 self.verifier.Verify(self.config.states[self.current_state])
110
111 def _RunCommand(self, command):
112 subprocess.call(command, shell=True)
113
114 def _RunResetCommand(self):
115 # TODO(sukolsak): Need to figure how exactly we want to reset.
Mathieu 2013/08/09 17:25:15 nit: put this TODO in place of _RunResetCommand, a
sukolsak 2013/08/09 21:12:38 Done.
116 pass
117
118
37 def MergePropertyDictionaries(current_property, new_property): 119 def MergePropertyDictionaries(current_property, new_property):
38 """Merges the new property dictionary into the current property dictionary. 120 """Merges the new property dictionary into the current property dictionary.
39 121
40 This is different from general dictionary merging in that, in case there are 122 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 123 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 124 override earlier values in the second level. For more details, take a look at
43 http://goo.gl/uE0RoR 125 http://goo.gl/uE0RoR
44 126
45 Args: 127 Args:
46 current_property: The property dictionary to be modified. 128 current_property: The property dictionary to be modified.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 config = Config() 175 config = Config()
94 config.tests = config_data['tests'] 176 config.tests = config_data['tests']
95 for state_name, state_property_filenames in config_data['states']: 177 for state_name, state_property_filenames in config_data['states']:
96 config.states[state_name] = ParsePropertyFiles(directory, 178 config.states[state_name] = ParsePropertyFiles(directory,
97 state_property_filenames) 179 state_property_filenames)
98 for action_name, action_command in config_data['actions']: 180 for action_name, action_command in config_data['actions']:
99 config.actions[action_name] = action_command 181 config.actions[action_name] = action_command
100 return config 182 return config
101 183
102 184
103 def VerifyState(config, state):
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): 185 def Test(config):
Mathieu 2013/08/09 17:25:15 rename to RunTests? Having test everywhere makes m
sukolsak 2013/08/09 21:12:38 Done.
127 """Tests the installer using the given Config object. 186 """Tests the installer using the given Config object.
128 187
129 Args: 188 Args:
130 config: A Config object. 189 config: A Config object.
131 """ 190 """
191 suite = unittest.TestSuite()
132 for test in config.tests: 192 for test in config.tests:
133 print settings.PRINT_TEST_PREFIX + ' -> '.join(test) 193 suite.addTest(InstallerTest(test, config))
134 194 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 195
152 196
153 def main(): 197 def main():
154 parser = argparse.ArgumentParser(description='Test the installer.') 198 parser = argparse.ArgumentParser(description='Test the installer.')
155 parser.add_argument('config_filename', 199 parser.add_argument('config_filename',
156 help='The relative/absolute path to the config file.') 200 help='The relative/absolute path to the config file.')
157 args = parser.parse_args() 201 args = parser.parse_args()
158 202
159 config = ParseConfigFile(args.config_filename) 203 config = ParseConfigFile(args.config_filename)
160 Test(config) 204 Test(config)
161 205
162 206
163 if __name__ == '__main__': 207 if __name__ == '__main__':
164 main() 208 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698