4 # Copyright (C) 2006, 2007, 2008 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Utilities for unit testing"""
32 from ganeti import utils
36 return os.environ.get("TOP_SRCDIR", ".")
39 def _SetupLogging(verbose):
40 """Setupup logging infrastructure.
43 fmt = logging.Formatter("%(asctime)s: %(threadName)s"
44 " %(levelname)s %(message)s")
47 handler = logging.StreamHandler()
49 handler = logging.FileHandler(os.devnull, "a")
51 handler.setLevel(logging.NOTSET)
52 handler.setFormatter(fmt)
54 root_logger = logging.getLogger("")
55 root_logger.setLevel(logging.NOTSET)
56 root_logger.addHandler(handler)
59 class GanetiTestProgram(unittest.TestProgram):
64 _SetupLogging("LOGTOSTDERR" in os.environ)
66 sys.stderr.write("Running %s\n" % self.progName)
69 # Ensure assertions will be evaluated
71 raise Exception("Not running in debug mode, assertions would not be"
74 # Check again, this time with a real assertion
77 except AssertionError:
80 raise Exception("Assertion not evaluated")
82 # The following piece of code is a backport from Python 2.6. Python 2.4/2.5
83 # only accept class instances as test runners. Being able to pass classes
84 # reduces the amount of code necessary for using a custom test runner.
85 # 2.6 and above should use their own code, however.
86 if (self.testRunner and sys.hexversion < 0x2060000 and
87 isinstance(self.testRunner, (type, types.ClassType))):
89 self.testRunner = self.testRunner(verbosity=self.verbosity)
91 # didn't accept the verbosity argument
92 self.testRunner = self.testRunner()
94 return unittest.TestProgram.runTests(self)
97 class GanetiTestCase(unittest.TestCase):
98 """Helper class for unittesting.
100 This class defines a few utility functions that help in building
101 unittests. Child classes must call the parent setup and cleanup.
105 self._temp_files = []
108 while self._temp_files:
110 utils.RemoveFile(self._temp_files.pop())
111 except EnvironmentError, err:
114 def assertFileContent(self, file_name, expected_content):
115 """Checks that the content of a file is what we expect.
118 @param file_name: the file whose contents we should check
119 @type expected_content: str
120 @param expected_content: the content we expect
123 actual_content = utils.ReadFile(file_name)
124 self.assertEqual(actual_content, expected_content)
126 def assertFileMode(self, file_name, expected_mode):
127 """Checks that the mode of a file is what we expect.
130 @param file_name: the file whose contents we should check
131 @type expected_mode: int
132 @param expected_mode: the mode we expect
135 st = os.stat(file_name)
136 actual_mode = stat.S_IMODE(st.st_mode)
137 self.assertEqual(actual_mode, expected_mode)
139 def assertFileUid(self, file_name, expected_uid):
140 """Checks that the user id of a file is what we expect.
143 @param file_name: the file whose contents we should check
144 @type expected_uid: int
145 @param expected_uid: the user id we expect
148 st = os.stat(file_name)
149 actual_uid = st.st_uid
150 self.assertEqual(actual_uid, expected_uid)
152 def assertFileGid(self, file_name, expected_gid):
153 """Checks that the group id of a file is what we expect.
156 @param file_name: the file whose contents we should check
157 @type expected_gid: int
158 @param expected_gid: the group id we expect
161 st = os.stat(file_name)
162 actual_gid = st.st_gid
163 self.assertEqual(actual_gid, expected_gid)
165 def assertEqualValues(self, first, second, msg=None):
166 """Compares two values whether they're equal.
168 Tuples are automatically converted to lists before comparing.
171 return self.assertEqual(UnifyValueType(first),
172 UnifyValueType(second),
176 def _TestDataFilename(name):
177 """Returns the filename of a given test data file.
180 @param name: the 'base' of the file name, as present in
181 the test/data directory
183 @return: the full path to the filename, such that it can
184 be used in 'make distcheck' rules
187 return "%s/test/data/%s" % (GetSourceDir(), name)
190 def _ReadTestData(cls, name):
191 """Returns the contents of a test data file.
193 This is just a very simple wrapper over utils.ReadFile with the
194 proper test file name.
197 return utils.ReadFile(cls._TestDataFilename(name))
199 def _CreateTempFile(self):
200 """Creates a temporary file and adds it to the internal cleanup list.
202 This method simplifies the creation and cleanup of temporary files
206 fh, fname = tempfile.mkstemp(prefix="ganeti-test", suffix=".tmp")
208 self._temp_files.append(fname)
212 def UnifyValueType(data):
213 """Converts all tuples into lists.
215 This is useful for unittests where an external library doesn't keep types.
218 if isinstance(data, (tuple, list)):
219 return [UnifyValueType(i) for i in data]
221 elif isinstance(data, dict):
222 return dict([(UnifyValueType(key), UnifyValueType(value))
223 for (key, value) in data.iteritems()])
228 class CallCounter(object):
229 """Utility class to count number of calls to a function/method.
232 def __init__(self, fn):
233 """Initializes this class.
241 def __call__(self, *args, **kwargs):
242 """Calls wrapped function with given parameters.
246 return self._fn(*args, **kwargs)
249 """Returns number of calls.