Statistics
| Branch: | Tag: | Revision:

root / test / py / testutils.py @ 560ef132

History | View | Annotate | Download (6.6 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21

    
22
"""Utilities for unit testing"""
23

    
24
import os
25
import sys
26
import stat
27
import tempfile
28
import unittest
29
import logging
30

    
31
from ganeti import utils
32

    
33

    
34
def GetSourceDir():
35
  return os.environ.get("TOP_SRCDIR", ".")
36

    
37

    
38
def TestDataFilename(name):
39
  """Returns the filename of a given test data file.
40

41
  @type name: str
42
  @param name: the 'base' of the file name, as present in
43
      the test/data directory
44
  @rtype: str
45
  @return: the full path to the filename, such that it can
46
      be used in 'make distcheck' rules
47

48
  """
49
  return "%s/test/data/%s" % (GetSourceDir(), name)
50

    
51

    
52
def ReadTestData(name):
53
  """Returns the content of a test data file.
54

55
  This is just a very simple wrapper over utils.ReadFile with the
56
  proper test file name.
57

58
  """
59
  return utils.ReadFile(TestDataFilename(name))
60

    
61

    
62
def _SetupLogging(verbose):
63
  """Setupup logging infrastructure.
64

65
  """
66
  fmt = logging.Formatter("%(asctime)s: %(threadName)s"
67
                          " %(levelname)s %(message)s")
68

    
69
  if verbose:
70
    handler = logging.StreamHandler()
71
  else:
72
    handler = logging.FileHandler(os.devnull, "a")
73

    
74
  handler.setLevel(logging.NOTSET)
75
  handler.setFormatter(fmt)
76

    
77
  root_logger = logging.getLogger("")
78
  root_logger.setLevel(logging.NOTSET)
79
  root_logger.addHandler(handler)
80

    
81

    
82
class GanetiTestProgram(unittest.TestProgram):
83
  def runTests(self):
84
    """Runs all tests.
85

86
    """
87
    _SetupLogging("LOGTOSTDERR" in os.environ)
88

    
89
    sys.stderr.write("Running %s\n" % self.progName)
90
    sys.stderr.flush()
91

    
92
    # Ensure assertions will be evaluated
93
    if not __debug__:
94
      raise Exception("Not running in debug mode, assertions would not be"
95
                      " evaluated")
96

    
97
    # Check again, this time with a real assertion
98
    try:
99
      assert False
100
    except AssertionError:
101
      pass
102
    else:
103
      raise Exception("Assertion not evaluated")
104

    
105
    return unittest.TestProgram.runTests(self)
106

    
107

    
108
class GanetiTestCase(unittest.TestCase):
109
  """Helper class for unittesting.
110

111
  This class defines a few utility functions that help in building
112
  unittests. Child classes must call the parent setup and cleanup.
113

114
  """
115
  def setUp(self):
116
    self._temp_files = []
117

    
118
  def tearDown(self):
119
    while self._temp_files:
120
      try:
121
        utils.RemoveFile(self._temp_files.pop())
122
      except EnvironmentError:
123
        pass
124

    
125
  def assertFileContent(self, file_name, expected_content):
126
    """Checks that the content of a file is what we expect.
127

128
    @type file_name: str
129
    @param file_name: the file whose contents we should check
130
    @type expected_content: str
131
    @param expected_content: the content we expect
132

133
    """
134
    actual_content = utils.ReadFile(file_name)
135
    self.assertEqual(actual_content, expected_content)
136

    
137
  def assertFileMode(self, file_name, expected_mode):
138
    """Checks that the mode of a file is what we expect.
139

140
    @type file_name: str
141
    @param file_name: the file whose contents we should check
142
    @type expected_mode: int
143
    @param expected_mode: the mode we expect
144

145
    """
146
    st = os.stat(file_name)
147
    actual_mode = stat.S_IMODE(st.st_mode)
148
    self.assertEqual(actual_mode, expected_mode)
149

    
150
  def assertFileUid(self, file_name, expected_uid):
151
    """Checks that the user id of a file is what we expect.
152

153
    @type file_name: str
154
    @param file_name: the file whose contents we should check
155
    @type expected_uid: int
156
    @param expected_uid: the user id we expect
157

158
    """
159
    st = os.stat(file_name)
160
    actual_uid = st.st_uid
161
    self.assertEqual(actual_uid, expected_uid)
162

    
163
  def assertFileGid(self, file_name, expected_gid):
164
    """Checks that the group id of a file is what we expect.
165

166
    @type file_name: str
167
    @param file_name: the file whose contents we should check
168
    @type expected_gid: int
169
    @param expected_gid: the group id we expect
170

171
    """
172
    st = os.stat(file_name)
173
    actual_gid = st.st_gid
174
    self.assertEqual(actual_gid, expected_gid)
175

    
176
  def assertEqualValues(self, first, second, msg=None):
177
    """Compares two values whether they're equal.
178

179
    Tuples are automatically converted to lists before comparing.
180

181
    """
182
    return self.assertEqual(UnifyValueType(first),
183
                            UnifyValueType(second),
184
                            msg=msg)
185

    
186
  def _CreateTempFile(self):
187
    """Creates a temporary file and adds it to the internal cleanup list.
188

189
    This method simplifies the creation and cleanup of temporary files
190
    during tests.
191

192
    """
193
    fh, fname = tempfile.mkstemp(prefix="ganeti-test", suffix=".tmp")
194
    os.close(fh)
195
    self._temp_files.append(fname)
196
    return fname
197

    
198

    
199
def patch_object(*args, **kwargs):
200
  """Unified patch_object for various versions of Python Mock.
201

202
  Different Python Mock versions provide incompatible versions of patching an
203
  object. More recent versions use _patch_object, older ones used patch_object.
204
  This function unifies the different variations.
205

206
  """
207
  import mock
208
  try:
209
    # pylint: disable=W0212
210
    return mock._patch_object(*args, **kwargs)
211
  except AttributeError:
212
    # pylint: disable=E1101
213
    return mock.patch_object(*args, **kwargs)
214

    
215

    
216
def UnifyValueType(data):
217
  """Converts all tuples into lists.
218

219
  This is useful for unittests where an external library doesn't keep types.
220

221
  """
222
  if isinstance(data, (tuple, list)):
223
    return [UnifyValueType(i) for i in data]
224

    
225
  elif isinstance(data, dict):
226
    return dict([(UnifyValueType(key), UnifyValueType(value))
227
                 for (key, value) in data.iteritems()])
228

    
229
  return data
230

    
231

    
232
class CallCounter(object):
233
  """Utility class to count number of calls to a function/method.
234

235
  """
236
  def __init__(self, fn):
237
    """Initializes this class.
238

239
    @type fn: Callable
240

241
    """
242
    self._fn = fn
243
    self._count = 0
244

    
245
  def __call__(self, *args, **kwargs):
246
    """Calls wrapped function with given parameters.
247

248
    """
249
    self._count += 1
250
    return self._fn(*args, **kwargs)
251

    
252
  def Count(self):
253
    """Returns number of calls.
254

255
    @rtype: number
256

257
    """
258
    return self._count