15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
from testsweet import run_suite
26
import bzrlib.commands
18
from testsweet import TestBase, run_suite, InTempDir
32
20
MODULES_TO_TEST = []
33
21
MODULES_TO_DOCTEST = []
35
from logging import debug, warning, error
37
class CommandFailed(Exception):
40
class TestCase(unittest.TestCase):
41
"""Base class for bzr unit tests.
43
Tests that need access to disk resources should subclass
44
TestCaseInTempDir not TestCase.
46
Error and debug log messages are redirected from their usual
47
location into a temporary file, the contents of which can be
48
retrieved by _get_log().
50
There are also convenience functions to invoke bzr's command-line
51
routine, and to build and check bzr trees."""
56
# this replaces the default testsweet.TestCase; we don't want logging changed
57
unittest.TestCase.setUp(self)
58
bzrlib.trace.disable_default_logging()
59
self._enable_file_logging()
62
def _enable_file_logging(self):
63
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
65
self._log_file = os.fdopen(fileno, 'w+')
67
hdlr = logging.StreamHandler(self._log_file)
68
hdlr.setLevel(logging.DEBUG)
69
hdlr.setFormatter(logging.Formatter('%(levelname)4.4s %(message)s'))
70
logging.getLogger('').addHandler(hdlr)
71
logging.getLogger('').setLevel(logging.DEBUG)
73
debug('opened log file %s', name)
75
self._log_file_name = name
78
logging.getLogger('').removeHandler(self._log_hdlr)
79
bzrlib.trace.enable_default_logging()
80
logging.debug('%s teardown', self.id())
81
self._log_file.close()
82
unittest.TestCase.tearDown(self)
88
"""Return as a string the log for this test"""
89
return open(self._log_file_name).read()
91
def run_bzr(self, *args, **kwargs):
92
"""Invoke bzr, as if it were run from the command line.
94
This should be the main method for tests that want to exercise the
95
overall behavior of the bzr application (rather than a unit test
96
or a functional test of the library.)
98
Much of the old code runs bzr by forking a new copy of Python, but
99
that is slower, harder to debug, and generally not necessary.
101
retcode = kwargs.get('retcode', 0)
102
result = self.apply_redirected(None, None, None,
103
bzrlib.commands.run_bzr, args)
104
self.assertEquals(result, retcode)
107
def check_inventory_shape(self, inv, shape):
109
Compare an inventory to a list of expected names.
111
Fail if they are not precisely equal.
114
shape = list(shape) # copy
115
for path, ie in inv.entries():
116
name = path.replace('\\', '/')
124
self.fail("expected paths not found in inventory: %r" % shape)
126
self.fail("unexpected paths found in inventory: %r" % extras)
128
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
129
a_callable=None, *args, **kwargs):
130
"""Call callable with redirected std io pipes.
132
Returns the return code."""
133
from StringIO import StringIO
134
if not callable(a_callable):
135
raise ValueError("a_callable must be callable.")
139
if hasattr(self, "_log_file"):
140
stdout = self._log_file
144
if hasattr(self, "_log_file"):
145
stderr = self._log_file
148
real_stdin = sys.stdin
149
real_stdout = sys.stdout
150
real_stderr = sys.stderr
155
return a_callable(*args, **kwargs)
157
sys.stdout = real_stdout
158
sys.stderr = real_stderr
159
sys.stdin = real_stdin
162
BzrTestBase = TestCase
165
class TestCaseInTempDir(TestCase):
166
"""Derived class that runs a test within a temporary directory.
168
This is useful for tests that need to create a branch, etc.
170
The directory is created in a slightly complex way: for each
171
Python invocation, a new temporary top-level directory is created.
172
All test cases create their own directory within that. If the
173
tests complete successfully, the directory is removed.
175
InTempDir is an old alias for FunctionalTestCase.
180
OVERRIDE_PYTHON = 'python'
182
def check_file_contents(self, filename, expect):
183
self.log("check contents of file %s" % filename)
184
contents = file(filename, 'r').read()
185
if contents != expect:
186
self.log("expected: %r" % expect)
187
self.log("actually: %r" % contents)
188
self.fail("contents of %s not as expected")
190
def _make_test_root(self):
195
if TestCaseInTempDir.TEST_ROOT is not None:
197
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
198
tempfile.mkdtemp(suffix='.tmp',
199
prefix=self._TEST_NAME + '-',
202
# make a fake bzr directory there to prevent any tests propagating
203
# up onto the source directory's real branch
204
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
207
super(TestCaseInTempDir, self).setUp()
209
self._make_test_root()
210
self._currentdir = os.getcwdu()
211
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
212
os.mkdir(self.test_dir)
213
os.chdir(self.test_dir)
217
os.chdir(self._currentdir)
218
super(TestCaseInTempDir, self).tearDown()
220
def _formcmd(self, cmd):
221
if isinstance(cmd, basestring):
224
cmd[0] = self.BZRPATH
225
if self.OVERRIDE_PYTHON:
226
cmd.insert(0, self.OVERRIDE_PYTHON)
227
self.log('$ %r' % cmd)
230
def runcmd(self, cmd, retcode=0):
231
"""Run one command and check the return code.
233
Returns a tuple of (stdout,stderr) strings.
235
If a single string is based, it is split into words.
236
For commands that are not simple space-separated words, please
237
pass a list instead."""
238
cmd = self._formcmd(cmd)
239
self.log('$ ' + ' '.join(cmd))
240
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
241
stderr=self._log_file)
242
if retcode != actual_retcode:
243
raise CommandFailed("test failed: %r returned %d, expected %d"
244
% (cmd, actual_retcode, retcode))
246
def backtick(self, cmd, retcode=0):
247
"""Run a command and return its output"""
248
cmd = self._formcmd(cmd)
249
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
250
outd, errd = child.communicate()
252
actual_retcode = child.wait()
254
outd = outd.replace('\r', '')
256
if retcode != actual_retcode:
257
raise CommandFailed("test failed: %r returned %d, expected %d"
258
% (cmd, actual_retcode, retcode))
264
def build_tree(self, shape):
265
"""Build a test tree according to a pattern.
267
shape is a sequence of file specifications. If the final
268
character is '/', a directory is created.
270
This doesn't add anything to a branch.
272
# XXX: It's OK to just create them using forward slashes on windows?
275
assert isinstance(name, basestring)
280
print >>f, "contents of", name
285
class MetaTestLog(TestCase):
286
def test_logging(self):
287
"""Test logs are captured when a test fails."""
288
logging.info('an info message')
289
warning('something looks dodgy...')
290
logging.debug('hello, test is running')
294
def selftest(verbose=False, pattern=".*"):
295
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
299
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
23
def selftest(verbose=False):
24
from unittest import TestLoader, TestSuite
300
25
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
301
26
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
27
global MODULES_TO_TEST, MODULES_TO_DOCTEST
29
import bzrlib.selftest.whitebox
30
import bzrlib.selftest.blackbox
31
import bzrlib.selftest.versioning
32
import bzrlib.selftest.testmerge3
33
import bzrlib.selftest.testhashcache
34
import bzrlib.selftest.testrevisionnamespaces
35
import bzrlib.selftest.testbranch
36
import bzrlib.selftest.teststatus
37
import bzrlib.selftest.testinv
38
import bzrlib.selftest.testdiff
39
import bzrlib.merge_core
302
40
from doctest import DocTestSuite
308
global MODULES_TO_TEST, MODULES_TO_DOCTEST
311
['bzrlib.selftest.MetaTestLog',
312
'bzrlib.selftest.test_parent',
313
'bzrlib.selftest.testinv',
314
'bzrlib.selftest.testfetch',
315
'bzrlib.selftest.versioning',
316
'bzrlib.selftest.whitebox',
317
'bzrlib.selftest.testmerge3',
318
'bzrlib.selftest.testmerge',
319
'bzrlib.selftest.testhashcache',
320
'bzrlib.selftest.teststatus',
321
'bzrlib.selftest.testlog',
322
'bzrlib.selftest.blackbox',
323
'bzrlib.selftest.testrevisionnamespaces',
324
'bzrlib.selftest.testbranch',
325
'bzrlib.selftest.testremotebranch',
326
'bzrlib.selftest.testrevision',
327
'bzrlib.selftest.test_merge_core',
328
'bzrlib.selftest.test_smart_add',
329
'bzrlib.selftest.testdiff',
330
'bzrlib.selftest.test_xml',
332
'bzrlib.selftest.teststore',
333
'bzrlib.selftest.testgraph',
336
47
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
337
48
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
338
49
if m not in MODULES_TO_DOCTEST:
339
50
MODULES_TO_DOCTEST.append(m)
341
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
342
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
53
for m in (bzrlib.selftest.whitebox,
54
bzrlib.selftest.versioning,
55
bzrlib.selftest.testinv,
56
bzrlib.selftest.testmerge3,
57
bzrlib.selftest.testhashcache,
58
bzrlib.selftest.teststatus,
59
bzrlib.selftest.blackbox,
60
bzrlib.selftest.testhashcache,
61
bzrlib.selftest.testrevisionnamespaces,
62
bzrlib.selftest.testbranch,
63
bzrlib.selftest.testdiff,
65
if m not in MODULES_TO_TEST:
66
MODULES_TO_TEST.append(m)
69
TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
70
print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
344
74
suite = TestSuite()
345
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
346
76
for m in MODULES_TO_TEST:
347
77
suite.addTest(TestLoader().loadTestsFromModule(m))
348
79
for m in (MODULES_TO_DOCTEST):
349
80
suite.addTest(DocTestSuite(m))
350
82
for p in bzrlib.plugin.all_plugins:
351
83
if hasattr(p, 'test_suite'):
352
84
suite.addTest(p.test_suite())
86
suite.addTest(unittest.makeSuite(bzrlib.merge_core.MergeTest, 'test_'))
88
return run_suite(suite, 'testbzr', verbose=verbose)