1
# Copyright (C) 2005 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
import bzrlib.commands
35
MODULES_TO_DOCTEST = []
37
from logging import debug, warning, error
39
class CommandFailed(Exception):
42
class TestCase(unittest.TestCase):
43
"""Base class for bzr unit tests.
45
Tests that need access to disk resources should subclass
46
TestCaseInTempDir not TestCase.
48
Error and debug log messages are redirected from their usual
49
location into a temporary file, the contents of which can be
50
retrieved by _get_log().
52
There are also convenience functions to invoke bzr's command-line
53
routine, and to build and check bzr trees."""
58
# this replaces the default testsweet.TestCase; we don't want logging changed
59
unittest.TestCase.setUp(self)
60
bzrlib.trace.disable_default_logging()
61
self._enable_file_logging()
64
def _enable_file_logging(self):
65
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
67
self._log_file = os.fdopen(fileno, 'w+')
69
hdlr = logging.StreamHandler(self._log_file)
70
hdlr.setLevel(logging.DEBUG)
71
hdlr.setFormatter(logging.Formatter('%(levelname)4.4s %(message)s'))
72
logging.getLogger('').addHandler(hdlr)
73
logging.getLogger('').setLevel(logging.DEBUG)
75
debug('opened log file %s', name)
77
self._log_file_name = name
80
logging.getLogger('').removeHandler(self._log_hdlr)
81
bzrlib.trace.enable_default_logging()
82
logging.debug('%s teardown', self.id())
83
self._log_file.close()
84
unittest.TestCase.tearDown(self)
91
"""Return as a string the log for this test"""
92
return open(self._log_file_name).read()
94
def run_bzr(self, *args, **kwargs):
95
"""Invoke bzr, as if it were run from the command line.
97
This should be the main method for tests that want to exercise the
98
overall behavior of the bzr application (rather than a unit test
99
or a functional test of the library.)
101
Much of the old code runs bzr by forking a new copy of Python, but
102
that is slower, harder to debug, and generally not necessary.
104
retcode = kwargs.get('retcode', 0)
105
result = self.apply_redirected(None, None, None,
106
bzrlib.commands.run_bzr, args)
107
self.assertEquals(result, retcode)
110
def check_inventory_shape(self, inv, shape):
112
Compare an inventory to a list of expected names.
114
Fail if they are not precisely equal.
117
shape = list(shape) # copy
118
for path, ie in inv.entries():
119
name = path.replace('\\', '/')
127
self.fail("expected paths not found in inventory: %r" % shape)
129
self.fail("unexpected paths found in inventory: %r" % extras)
131
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
132
a_callable=None, *args, **kwargs):
133
"""Call callable with redirected std io pipes.
135
Returns the return code."""
136
from StringIO import StringIO
137
if not callable(a_callable):
138
raise ValueError("a_callable must be callable.")
142
if hasattr(self, "_log_file"):
143
stdout = self._log_file
147
if hasattr(self, "_log_file"):
148
stderr = self._log_file
151
real_stdin = sys.stdin
152
real_stdout = sys.stdout
153
real_stderr = sys.stderr
158
return a_callable(*args, **kwargs)
160
sys.stdout = real_stdout
161
sys.stderr = real_stderr
162
sys.stdin = real_stdin
165
BzrTestBase = TestCase
168
class TestCaseInTempDir(TestCase):
169
"""Derived class that runs a test within a temporary directory.
171
This is useful for tests that need to create a branch, etc.
173
The directory is created in a slightly complex way: for each
174
Python invocation, a new temporary top-level directory is created.
175
All test cases create their own directory within that. If the
176
tests complete successfully, the directory is removed.
178
InTempDir is an old alias for FunctionalTestCase.
183
OVERRIDE_PYTHON = 'python'
185
def check_file_contents(self, filename, expect):
186
self.log("check contents of file %s" % filename)
187
contents = file(filename, 'r').read()
188
if contents != expect:
189
self.log("expected: %r" % expect)
190
self.log("actually: %r" % contents)
191
self.fail("contents of %s not as expected")
193
def _make_test_root(self):
194
if TestCaseInTempDir.TEST_ROOT is not None:
198
root = 'test%04d.tmp' % i
202
if e.errno == errno.EEXIST:
207
# successfully created
208
TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
210
# make a fake bzr directory there to prevent any tests propagating
211
# up onto the source directory's real branch
212
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
215
super(TestCaseInTempDir, self).setUp()
217
self._make_test_root()
218
self._currentdir = os.getcwdu()
219
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
220
os.mkdir(self.test_dir)
221
os.chdir(self.test_dir)
225
os.chdir(self._currentdir)
226
super(TestCaseInTempDir, self).tearDown()
228
def _formcmd(self, cmd):
229
if isinstance(cmd, basestring):
232
cmd[0] = self.BZRPATH
233
if self.OVERRIDE_PYTHON:
234
cmd.insert(0, self.OVERRIDE_PYTHON)
235
self.log('$ %r' % cmd)
238
def runcmd(self, cmd, retcode=0):
239
"""Run one command and check the return code.
241
Returns a tuple of (stdout,stderr) strings.
243
If a single string is based, it is split into words.
244
For commands that are not simple space-separated words, please
245
pass a list instead."""
246
cmd = self._formcmd(cmd)
247
self.log('$ ' + ' '.join(cmd))
248
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
249
stderr=self._log_file)
250
if retcode != actual_retcode:
251
raise CommandFailed("test failed: %r returned %d, expected %d"
252
% (cmd, actual_retcode, retcode))
254
def backtick(self, cmd, retcode=0):
255
"""Run a command and return its output"""
256
cmd = self._formcmd(cmd)
257
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
258
outd, errd = child.communicate()
260
actual_retcode = child.wait()
262
outd = outd.replace('\r', '')
264
if retcode != actual_retcode:
265
raise CommandFailed("test failed: %r returned %d, expected %d"
266
% (cmd, actual_retcode, retcode))
272
def build_tree(self, shape):
273
"""Build a test tree according to a pattern.
275
shape is a sequence of file specifications. If the final
276
character is '/', a directory is created.
278
This doesn't add anything to a branch.
280
# XXX: It's OK to just create them using forward slashes on windows?
283
assert isinstance(name, basestring)
288
print >>f, "contents of", name
293
class MetaTestLog(TestCase):
294
def test_logging(self):
295
"""Test logs are captured when a test fails."""
296
logging.info('an info message')
297
warning('something looks dodgy...')
298
logging.debug('hello, test is running')
302
def selftest(verbose=False, pattern=".*"):
303
return testsweet.run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
307
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
308
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
309
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
310
from doctest import DocTestSuite
316
global MODULES_TO_TEST, MODULES_TO_DOCTEST
319
['bzrlib.selftest.MetaTestLog',
320
'bzrlib.selftest.test_parent',
321
'bzrlib.selftest.testinv',
322
'bzrlib.selftest.testfetch',
323
'bzrlib.selftest.versioning',
324
'bzrlib.selftest.whitebox',
325
'bzrlib.selftest.testmerge3',
326
'bzrlib.selftest.testhashcache',
327
'bzrlib.selftest.teststatus',
328
'bzrlib.selftest.testlog',
329
'bzrlib.selftest.blackbox',
330
'bzrlib.selftest.testrevisionnamespaces',
331
'bzrlib.selftest.testbranch',
332
'bzrlib.selftest.testrevision',
333
'bzrlib.selftest.test_merge_core',
334
'bzrlib.selftest.test_smart_add',
335
'bzrlib.selftest.testdiff',
336
'bzrlib.selftest.test_xml',
338
'bzrlib.selftest.teststore',
339
'bzrlib.selftest.testgraph',
342
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
343
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
344
if m not in MODULES_TO_DOCTEST:
345
MODULES_TO_DOCTEST.append(m)
347
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
348
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
351
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
352
for m in MODULES_TO_TEST:
353
suite.addTest(TestLoader().loadTestsFromModule(m))
354
for m in (MODULES_TO_DOCTEST):
355
suite.addTest(DocTestSuite(m))
356
for p in bzrlib.plugin.all_plugins:
357
if hasattr(p, 'test_suite'):
358
suite.addTest(p.test_suite())