15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
from testsweet import run_suite
26
import bzrlib.commands
33
MODULES_TO_DOCTEST = []
35
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")
37
29
class CommandFailed(Exception):
40
class TestCase(unittest.TestCase):
41
"""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
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."""
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'
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
79
logging.getLogger('').removeHandler(self._log_hdlr)
80
bzrlib.trace.enable_default_logging()
81
logging.debug('%s teardown', self.id())
82
self._log_file.close()
83
unittest.TestCase.tearDown(self)
90
"""Return as a string the log for this test"""
91
return open(self._log_file_name).read()
93
def run_bzr(self, *args, **kwargs):
94
"""Invoke bzr, as if it were run from the command line.
96
This should be the main method for tests that want to exercise the
97
overall behavior of the bzr application (rather than a unit test
98
or a functional test of the library.)
100
Much of the old code runs bzr by forking a new copy of Python, but
101
that is slower, harder to debug, and generally not necessary.
103
retcode = kwargs.get('retcode', 0)
104
result = self.apply_redirected(None, None, None,
105
bzrlib.commands.run_bzr, args)
106
self.assertEquals(result, retcode)
109
def check_inventory_shape(self, inv, shape):
111
Compare an inventory to a list of expected names.
113
Fail if they are not precisely equal.
116
shape = list(shape) # copy
117
for path, ie in inv.entries():
118
name = path.replace('\\', '/')
126
self.fail("expected paths not found in inventory: %r" % shape)
128
self.fail("unexpected paths found in inventory: %r" % extras)
130
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
131
a_callable=None, *args, **kwargs):
132
"""Call callable with redirected std io pipes.
134
Returns the return code."""
135
from StringIO import StringIO
136
if not callable(a_callable):
137
raise ValueError("a_callable must be callable.")
141
stdout = self._log_file
143
stderr = self._log_file
144
real_stdin = sys.stdin
145
real_stdout = sys.stdout
146
real_stderr = sys.stderr
151
return a_callable(*args, **kwargs)
153
sys.stdout = real_stdout
154
sys.stderr = real_stderr
155
sys.stdin = real_stdin
158
BzrTestBase = TestCase
161
class TestCaseInTempDir(TestCase):
162
"""Derived class that runs a test within a temporary directory.
164
This is useful for tests that need to create a branch, etc.
166
The directory is created in a slightly complex way: for each
167
Python invocation, a new temporary top-level directory is created.
168
All test cases create their own directory within that. If the
169
tests complete successfully, the directory is removed.
171
InTempDir is an old alias for FunctionalTestCase.
176
OVERRIDE_PYTHON = 'python'
178
def check_file_contents(self, filename, expect):
179
self.log("check contents of file %s" % filename)
180
contents = file(filename, 'r').read()
181
if contents != expect:
182
self.log("expected: %r" % expect)
183
self.log("actually: %r" % contents)
184
self.fail("contents of %s not as expected")
186
def _make_test_root(self):
191
if TestCaseInTempDir.TEST_ROOT is not None:
193
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
194
tempfile.mkdtemp(suffix='.tmp',
195
prefix=self._TEST_NAME + '-',
198
# make a fake bzr directory there to prevent any tests propagating
199
# up onto the source directory's real branch
200
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
203
super(TestCaseInTempDir, self).setUp()
205
self._make_test_root()
206
self._currentdir = os.getcwdu()
207
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
208
os.mkdir(self.test_dir)
209
os.chdir(self.test_dir)
213
os.chdir(self._currentdir)
214
super(TestCaseInTempDir, self).tearDown()
216
def _formcmd(self, cmd):
49
def formcmd(self, cmd):
217
50
if isinstance(cmd, basestring):
219
53
if cmd[0] == 'bzr':
220
54
cmd[0] = self.BZRPATH
221
55
if self.OVERRIDE_PYTHON:
222
56
cmd.insert(0, self.OVERRIDE_PYTHON)
223
58
self.log('$ %r' % cmd)
226
63
def runcmd(self, cmd, retcode=0):
227
64
"""Run one command and check the return code.
275
114
f = file(name, 'wt')
276
115
print >>f, "contents of", name
281
class MetaTestLog(TestCase):
282
def test_logging(self):
283
"""Test logs are captured when a test fails."""
284
logging.info('an info message')
285
warning('something looks dodgy...')
286
logging.debug('hello, test is running')
290
def selftest(verbose=False, pattern=".*"):
291
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
295
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
296
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
297
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
298
218
from doctest import DocTestSuite
304
global MODULES_TO_TEST, MODULES_TO_DOCTEST
307
['bzrlib.selftest.MetaTestLog',
308
'bzrlib.selftest.test_parent',
309
'bzrlib.selftest.testinv',
310
'bzrlib.selftest.testfetch',
311
'bzrlib.selftest.versioning',
312
'bzrlib.selftest.whitebox',
313
'bzrlib.selftest.testmerge3',
314
'bzrlib.selftest.testhashcache',
315
'bzrlib.selftest.teststatus',
316
'bzrlib.selftest.testlog',
317
'bzrlib.selftest.blackbox',
318
'bzrlib.selftest.testrevisionnamespaces',
319
'bzrlib.selftest.testbranch',
320
'bzrlib.selftest.testrevision',
321
'bzrlib.selftest.test_merge_core',
322
'bzrlib.selftest.test_smart_add',
323
'bzrlib.selftest.testdiff',
324
'bzrlib.selftest.test_xml',
326
'bzrlib.selftest.teststore',
329
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
330
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
331
if m not in MODULES_TO_DOCTEST:
332
MODULES_TO_DOCTEST.append(m)
334
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
335
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)
337
231
suite = TestSuite()
338
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
339
for m in MODULES_TO_TEST:
340
suite.addTest(TestLoader().loadTestsFromModule(m))
341
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, \
342
243
suite.addTest(DocTestSuite(m))
343
for p in bzrlib.plugin.all_plugins:
344
if hasattr(p, 'test_suite'):
345
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