15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
from testsweet import run_suite
25
import bzrlib.commands
31
MODULES_TO_DOCTEST = []
33
from logging import debug, warning, error
36
class TestCase(unittest.TestCase):
37
"""Base class for bzr unit tests.
18
from unittest import TestResult, TestCase
22
from subprocess import call, Popen, PIPE
23
except ImportError, e:
25
sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
26
"this is shipped with python2.4 and available separately for 2.3\n")
30
class CommandFailed(Exception):
34
class TestBase(TestCase):
35
"""Base class for bzr test cases.
37
Just defines some useful helper functions; doesn't actually test
39
Tests that need access to disk resources should subclass
40
FunctionalTestCase not TestCase.
42
Error and debug log messages are redirected from their usual
43
location into a temporary file, the contents of which can be
44
retrieved by _get_log().
46
There are also convenience functions to invoke bzr's command-line
47
routine, and to build and check bzr trees."""
41
# TODO: Special methods to invoke bzr, so that we can run it
42
# through a specified Python intepreter
44
OVERRIDE_PYTHON = None # to run with alternative python 'python'
52
# this replaces the default testsweet.TestCase; we don't want logging changed
53
unittest.TestCase.setUp(self)
54
bzrlib.trace.disable_default_logging()
55
self._enable_file_logging()
58
def _enable_file_logging(self):
59
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
61
self._log_file = os.fdopen(fileno, 'w+')
63
hdlr = logging.StreamHandler(self._log_file)
64
hdlr.setLevel(logging.DEBUG)
65
hdlr.setFormatter(logging.Formatter('%(levelname)4.4s %(message)s'))
66
logging.getLogger('').addHandler(hdlr)
67
logging.getLogger('').setLevel(logging.DEBUG)
69
debug('opened log file %s', name)
71
self._log_file_name = name
75
logging.getLogger('').removeHandler(self._log_hdlr)
76
bzrlib.trace.enable_default_logging()
77
logging.debug('%s teardown', self.id())
78
self._log_file.close()
79
unittest.TestCase.tearDown(self)
86
"""Return as a string the log for this test"""
87
return open(self._log_file_name).read()
89
def run_bzr(self, *args, **kwargs):
90
"""Invoke bzr, as if it were run from the command line.
92
This should be the main method for tests that want to exercise the
93
overall behavior of the bzr application (rather than a unit test
94
or a functional test of the library.)
96
Much of the old code runs bzr by forking a new copy of Python, but
97
that is slower, harder to debug, and generally not necessary.
99
retcode = kwargs.get('retcode', 0)
100
result = self.apply_redirected(None, None, None,
101
bzrlib.commands.run_bzr, args)
102
self.assertEquals(result, retcode)
104
def check_inventory_shape(self, inv, shape):
106
Compare an inventory to a list of expected names.
108
Fail if they are not precisely equal.
111
shape = list(shape) # copy
112
for path, ie in inv.entries():
113
name = path.replace('\\', '/')
121
self.fail("expected paths not found in inventory: %r" % shape)
123
self.fail("unexpected paths found in inventory: %r" % extras)
125
BzrTestBase = TestCase
128
class FunctionalTestCase(TestCase):
129
"""Base class for tests that perform function testing - running bzr,
130
using files on disk, and similar activities.
132
InTempDir is an old alias for FunctionalTestCase.
137
OVERRIDE_PYTHON = 'python'
139
def check_file_contents(self, filename, expect):
140
self.log("check contents of file %s" % filename)
141
contents = file(filename, 'r').read()
142
if contents != expect:
143
self.log("expected: %r" % expect)
144
self.log("actually: %r" % contents)
145
self.fail("contents of %s not as expected")
147
def _make_test_root(self):
152
if FunctionalTestCase.TEST_ROOT is not None:
154
FunctionalTestCase.TEST_ROOT = os.path.abspath(
155
tempfile.mkdtemp(suffix='.tmp',
156
prefix=self._TEST_NAME + '-',
159
# make a fake bzr directory there to prevent any tests propagating
160
# up onto the source directory's real branch
161
os.mkdir(os.path.join(FunctionalTestCase.TEST_ROOT, '.bzr'))
164
super(FunctionalTestCase, self).setUp()
166
self._make_test_root()
167
self._currentdir = os.getcwdu()
168
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
169
os.mkdir(self.test_dir)
170
os.chdir(self.test_dir)
174
os.chdir(self._currentdir)
175
super(FunctionalTestCase, self).tearDown()
177
def _formcmd(self, cmd):
50
def formcmd(self, cmd):
178
51
if isinstance(cmd, basestring):
180
54
if cmd[0] == 'bzr':
181
55
cmd[0] = self.BZRPATH
182
56
if self.OVERRIDE_PYTHON:
183
57
cmd.insert(0, self.OVERRIDE_PYTHON)
184
59
self.log('$ %r' % cmd)
187
64
def runcmd(self, cmd, retcode=0):
188
65
"""Run one command and check the return code.
248
115
f = file(name, 'wt')
249
116
print >>f, "contents of", name
253
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
254
a_callable=None, *args, **kwargs):
255
"""Call callable with redirected std io pipes.
257
Returns the return code."""
258
from StringIO import StringIO
259
if not callable(a_callable):
260
raise ValueError("a_callable must be callable.")
264
stdout = self._log_file
266
stderr = self._log_file
267
real_stdin = sys.stdin
268
real_stdout = sys.stdout
269
real_stderr = sys.stderr
275
result = a_callable(*args, **kwargs)
277
sys.stdout = real_stdout
278
sys.stderr = real_stderr
279
sys.stdin = real_stdin
283
InTempDir = FunctionalTestCase
286
class MetaTestLog(TestCase):
287
def test_logging(self):
288
"""Test logs are captured when a test fails."""
289
logging.info('an info message')
290
warning('something looks dodgy...')
291
logging.debug('hello, test is running')
295
def selftest(verbose=False, pattern=".*"):
296
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
300
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
301
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
302
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
121
"""Log a message to a progress file"""
122
self._log_buf = self._log_buf + str(msg) + '\n'
123
print >>self.TEST_LOG, msg
126
def check_inventory_shape(self, inv, shape):
128
Compare an inventory to a list of expected names.
130
Fail if they are not precisely equal.
133
shape = list(shape) # copy
134
for path, ie in inv.entries():
135
name = path.replace('\\', '/')
143
self.fail("expected paths not found in inventory: %r" % shape)
145
self.fail("unexpected paths found in inventory: %r" % extras)
148
def check_file_contents(self, filename, expect):
149
self.log("check contents of file %s" % filename)
150
contents = file(filename, 'r').read()
151
if contents != expect:
152
self.log("expected: %r" % expected)
153
self.log("actually: %r" % contents)
154
self.fail("contents of %s not as expected")
158
class InTempDir(TestBase):
159
"""Base class for tests run in a temporary branch."""
162
self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
163
os.mkdir(self.test_dir)
164
os.chdir(self.test_dir)
168
os.chdir(self.TEST_ROOT)
174
class _MyResult(TestResult):
178
No special behaviour for now.
180
def __init__(self, out):
182
TestResult.__init__(self)
184
def startTest(self, test):
185
# TODO: Maybe show test.shortDescription somewhere?
186
print >>self.out, '%-60.60s' % test.id(),
188
TestResult.startTest(self, test)
190
def stopTest(self, test):
192
TestResult.stopTest(self, test)
195
def addError(self, test, err):
196
print >>self.out, 'ERROR'
197
TestResult.addError(self, test, err)
198
_show_test_failure('error', test, err, self.out)
200
def addFailure(self, test, err):
201
print >>self.out, 'FAILURE'
202
TestResult.addFailure(self, test, err)
203
_show_test_failure('failure', test, err, self.out)
205
def addSuccess(self, test):
206
print >>self.out, 'OK'
207
TestResult.addSuccess(self, test)
212
from unittest import TestLoader, TestSuite
213
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, bzrlib.commands
215
import bzrlib.selftest.whitebox
216
import bzrlib.selftest.blackbox
217
import bzrlib.selftest.versioning
218
import bzrlib.selftest.testmerge3
219
import bzrlib.merge_core
303
220
from doctest import DocTestSuite
309
global MODULES_TO_TEST, MODULES_TO_DOCTEST
312
['bzrlib.selftest.MetaTestLog',
313
'bzrlib.selftest.testinv',
314
'bzrlib.selftest.testfetch',
315
'bzrlib.selftest.versioning',
316
'bzrlib.selftest.whitebox',
317
'bzrlib.selftest.testmerge3',
318
'bzrlib.selftest.testhashcache',
319
'bzrlib.selftest.teststatus',
320
'bzrlib.selftest.testlog',
321
'bzrlib.selftest.blackbox',
322
'bzrlib.selftest.testrevisionnamespaces',
323
'bzrlib.selftest.testbranch',
324
'bzrlib.selftest.testrevision',
325
'bzrlib.selftest.test_merge_core',
326
'bzrlib.selftest.test_smart_add',
327
'bzrlib.selftest.testdiff',
331
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
332
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
333
if m not in MODULES_TO_DOCTEST:
334
MODULES_TO_DOCTEST.append(m)
336
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
337
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
226
TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
227
print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
339
233
suite = TestSuite()
340
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
341
for m in MODULES_TO_TEST:
342
suite.addTest(TestLoader().loadTestsFromModule(m))
343
for m in (MODULES_TO_DOCTEST):
236
# should also test bzrlib.merge_core, but they seem to be out of date with
239
for m in bzrlib.selftest.whitebox, \
240
bzrlib.selftest.versioning, \
241
bzrlib.selftest.testmerge3:
242
suite.addTest(tl.loadTestsFromModule(m))
244
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
344
247
suite.addTest(DocTestSuite(m))
345
for p in bzrlib.plugin.all_plugins:
346
if hasattr(p, 'test_suite'):
347
suite.addTest(p.test_suite())
249
suite.addTest(bzrlib.selftest.blackbox.suite())
251
# save stdout & stderr so there's no leakage from code-under-test
252
real_stdout = sys.stdout
253
real_stderr = sys.stderr
254
sys.stdout = sys.stderr = TestBase.TEST_LOG
256
result = _MyResult(real_stdout)
259
sys.stdout = real_stdout
260
sys.stderr = real_stderr
262
_show_results(result)
264
return result.wasSuccessful()
269
def _setup_test_log():
273
log_filename = os.path.abspath('testbzr.log')
274
TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
276
print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
277
print '%-30s %s' % ('test log', log_filename)
280
def _setup_test_dir():
284
TestBase.ORIG_DIR = os.getcwdu()
285
TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
287
print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
289
if os.path.exists(TestBase.TEST_ROOT):
290
shutil.rmtree(TestBase.TEST_ROOT)
291
os.mkdir(TestBase.TEST_ROOT)
292
os.chdir(TestBase.TEST_ROOT)
294
# make a fake bzr directory there to prevent any tests propagating
295
# up onto the source directory's real branch
296
os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
300
def _show_results(result):
302
print '%4d tests run' % result.testsRun
303
print '%4d errors' % len(result.errors)
304
print '%4d failures' % len(result.failures)
308
def _show_test_failure(kind, case, exc_info, out):
309
from traceback import print_exception
311
print >>out, '-' * 60
314
desc = case.shortDescription()
316
print >>out, ' (%s)' % desc
318
print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
320
if isinstance(case, TestBase):
322
print >>out, 'log from this test:'
323
print >>out, case._log_buf
325
print >>out, '-' * 60