15
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
18
from unittest import TestResult, TestCase
22
from subprocess import call, Popen, PIPE
23
except ImportError, e:
24
sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
25
"this is shipped with python2.4 and available separately for 2.3\n")
39
29
class CommandFailed(Exception):
42
class TestCase(unittest.TestCase):
43
"""Base class for bzr unit tests.
33
class TestBase(TestCase):
34
"""Base class for bzr test cases.
36
Just defines some useful helper functions; doesn't actually test
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."""
40
# TODO: Special methods to invoke bzr, so that we can run it
41
# through a specified Python intepreter
43
OVERRIDE_PYTHON = None # to run with alternative python 'python'
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)8s %(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
81
logging.getLogger('').removeHandler(self._log_hdlr)
82
bzrlib.trace.enable_default_logging()
83
logging.debug('%s teardown', self.id())
84
self._log_file.close()
85
unittest.TestCase.tearDown(self)
92
"""Return as a string the log for this test"""
93
return open(self._log_file_name).read()
95
def run_bzr(self, *args, **kwargs):
96
"""Invoke bzr, as if it were run from the command line.
98
This should be the main method for tests that want to exercise the
99
overall behavior of the bzr application (rather than a unit test
100
or a functional test of the library.)
102
Much of the old code runs bzr by forking a new copy of Python, but
103
that is slower, harder to debug, and generally not necessary.
105
retcode = kwargs.get('retcode', 0)
106
result = self.apply_redirected(None, None, None,
107
bzrlib.commands.run_bzr, args)
108
self.assertEquals(result, retcode)
111
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
stdout = self._log_file
144
stderr = self._log_file
145
real_stdin = sys.stdin
146
real_stdout = sys.stdout
147
real_stderr = sys.stderr
152
return a_callable(*args, **kwargs)
154
sys.stdout = real_stdout
155
sys.stderr = real_stderr
156
sys.stdin = real_stdin
159
BzrTestBase = TestCase
162
class TestCaseInTempDir(TestCase):
163
"""Derived class that runs a test within a temporary directory.
165
This is useful for tests that need to create a branch, etc.
167
The directory is created in a slightly complex way: for each
168
Python invocation, a new temporary top-level directory is created.
169
All test cases create their own directory within that. If the
170
tests complete successfully, the directory is removed.
172
InTempDir is an old alias for FunctionalTestCase.
177
OVERRIDE_PYTHON = 'python'
179
def check_file_contents(self, filename, expect):
180
self.log("check contents of file %s" % filename)
181
contents = file(filename, 'r').read()
182
if contents != expect:
183
self.log("expected: %r" % expect)
184
self.log("actually: %r" % contents)
185
self.fail("contents of %s not as expected")
187
def _make_test_root(self):
188
if TestCaseInTempDir.TEST_ROOT is not None:
192
root = 'test%04d.tmp' % i
196
if e.errno == errno.EEXIST:
201
# successfully created
202
TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
204
# make a fake bzr directory there to prevent any tests propagating
205
# up onto the source directory's real branch
206
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
209
super(TestCaseInTempDir, self).setUp()
211
self._make_test_root()
212
self._currentdir = os.getcwdu()
213
short_id = self.id().replace('bzrlib.selftest.', '') \
214
.replace('__main__.', '')
215
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
216
os.mkdir(self.test_dir)
217
os.chdir(self.test_dir)
221
os.chdir(self._currentdir)
222
super(TestCaseInTempDir, self).tearDown()
224
def _formcmd(self, cmd):
49
def formcmd(self, cmd):
225
50
if isinstance(cmd, basestring):
227
53
if cmd[0] == 'bzr':
228
54
cmd[0] = self.BZRPATH
229
55
if self.OVERRIDE_PYTHON:
230
56
cmd.insert(0, self.OVERRIDE_PYTHON)
231
58
self.log('$ %r' % cmd)
234
63
def runcmd(self, cmd, retcode=0):
235
64
"""Run one command and check the return code.
283
114
f = file(name, 'wt')
284
115
print >>f, "contents of", name
289
class MetaTestLog(TestCase):
290
def test_logging(self):
291
"""Test logs are captured when a test fails."""
292
logging.info('an info message')
293
warning('something looks dodgy...')
294
logging.debug('hello, test is running')
298
def selftest(verbose=False, pattern=".*"):
299
"""Run the whole test suite under the enhanced runner"""
300
return testsweet.run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
304
"""Build and return TestSuite for the whole program."""
305
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
306
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
307
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
120
"""Log a message to a progress file"""
121
self._log_buf = self._log_buf + str(msg) + '\n'
122
print >>self.TEST_LOG, msg
125
def check_inventory_shape(self, inv, shape):
127
Compare an inventory to a list of expected names.
129
Fail if they are not precisely equal.
132
shape = list(shape) # copy
133
for path, ie in inv.entries():
134
name = path.replace('\\', '/')
142
self.fail("expected paths not found in inventory: %r" % shape)
144
self.fail("unexpected paths found in inventory: %r" % extras)
147
def check_file_contents(self, filename, expect):
148
self.log("check contents of file %s" % filename)
149
contents = file(filename, 'r').read()
150
if contents != expect:
151
self.log("expected: %r" % expected)
152
self.log("actually: %r" % contents)
153
self.fail("contents of %s not as expected")
157
class InTempDir(TestBase):
158
"""Base class for tests run in a temporary branch."""
161
self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
162
os.mkdir(self.test_dir)
163
os.chdir(self.test_dir)
167
os.chdir(self.TEST_ROOT)
173
class _MyResult(TestResult):
177
No special behaviour for now.
179
def __init__(self, out):
181
TestResult.__init__(self)
183
def startTest(self, test):
184
# TODO: Maybe show test.shortDescription somewhere?
185
print >>self.out, '%-60.60s' % test.id(),
187
TestResult.startTest(self, test)
189
def stopTest(self, test):
191
TestResult.stopTest(self, test)
194
def addError(self, test, err):
195
print >>self.out, 'ERROR'
196
TestResult.addError(self, test, err)
197
_show_test_failure('error', test, err, self.out)
199
def addFailure(self, test, err):
200
print >>self.out, 'FAILURE'
201
TestResult.addFailure(self, test, err)
202
_show_test_failure('failure', test, err, self.out)
204
def addSuccess(self, test):
205
print >>self.out, 'OK'
206
TestResult.addSuccess(self, test)
211
from unittest import TestLoader, TestSuite
212
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, bzrlib.commands
214
import bzrlib.selftest.whitebox
215
import bzrlib.selftest.blackbox
216
import bzrlib.selftest.versioning
217
import bzrlib.merge_core
308
218
from doctest import DocTestSuite
314
global MODULES_TO_TEST, MODULES_TO_DOCTEST
317
['bzrlib.selftest.MetaTestLog',
318
'bzrlib.selftest.testinv',
319
'bzrlib.selftest.test_commit',
320
'bzrlib.selftest.versioning',
321
'bzrlib.selftest.testmerge3',
322
'bzrlib.selftest.testhashcache',
323
'bzrlib.selftest.teststatus',
324
'bzrlib.selftest.testlog',
325
'bzrlib.selftest.testrevisionnamespaces',
326
'bzrlib.selftest.testbranch',
327
'bzrlib.selftest.testrevision',
328
'bzrlib.selftest.test_merge_core',
329
'bzrlib.selftest.test_smart_add',
330
'bzrlib.selftest.testdiff',
331
'bzrlib.selftest.test_parent',
332
'bzrlib.selftest.test_xml',
333
'bzrlib.selftest.test_weave',
334
'bzrlib.selftest.testfetch',
335
'bzrlib.selftest.whitebox',
336
'bzrlib.selftest.teststore',
337
'bzrlib.selftest.blackbox',
340
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
341
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
342
if m not in MODULES_TO_DOCTEST:
343
MODULES_TO_DOCTEST.append(m)
345
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
346
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
224
TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
225
print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
348
231
suite = TestSuite()
349
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
350
for m in MODULES_TO_TEST:
351
suite.addTest(TestLoader().loadTestsFromModule(m))
352
for m in (MODULES_TO_DOCTEST):
234
# should also test bzrlib.merge_core, but they seem to be out of date with
237
for m in bzrlib.selftest.whitebox, \
238
bzrlib.selftest.versioning:
239
suite.addTest(tl.loadTestsFromModule(m))
241
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
353
243
suite.addTest(DocTestSuite(m))
354
for p in bzrlib.plugin.all_plugins:
355
if hasattr(p, 'test_suite'):
356
suite.addTest(p.test_suite())
245
suite.addTest(bzrlib.selftest.blackbox.suite())
247
# save stdout & stderr so there's no leakage from code-under-test
248
real_stdout = sys.stdout
249
real_stderr = sys.stderr
250
sys.stdout = sys.stderr = TestBase.TEST_LOG
252
result = _MyResult(real_stdout)
255
sys.stdout = real_stdout
256
sys.stderr = real_stderr
258
_show_results(result)
260
return result.wasSuccessful()
265
def _setup_test_log():
269
log_filename = os.path.abspath('testbzr.log')
270
TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
272
print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
273
print '%-30s %s' % ('test log', log_filename)
276
def _setup_test_dir():
280
TestBase.ORIG_DIR = os.getcwdu()
281
TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
283
print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
285
if os.path.exists(TestBase.TEST_ROOT):
286
shutil.rmtree(TestBase.TEST_ROOT)
287
os.mkdir(TestBase.TEST_ROOT)
288
os.chdir(TestBase.TEST_ROOT)
290
# make a fake bzr directory there to prevent any tests propagating
291
# up onto the source directory's real branch
292
os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
296
def _show_results(result):
298
print '%4d tests run' % result.testsRun
299
print '%4d errors' % len(result.errors)
300
print '%4d failures' % len(result.failures)
304
def _show_test_failure(kind, case, exc_info, out):
305
from traceback import print_exception
307
print >>out, '-' * 60
310
desc = case.shortDescription()
312
print >>out, ' (%s)' % desc
314
print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
316
if isinstance(case, TestBase):
318
print >>out, 'log from this test:'
319
print >>out, case._log_buf
321
print >>out, '-' * 60