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):
47
def formcmd(self, cmd):
217
48
if isinstance(cmd, basestring):
219
51
if cmd[0] == 'bzr':
220
52
cmd[0] = self.BZRPATH
221
53
if self.OVERRIDE_PYTHON:
222
54
cmd.insert(0, self.OVERRIDE_PYTHON)
223
56
self.log('$ %r' % cmd)
226
61
def runcmd(self, cmd, retcode=0):
227
62
"""Run one command and check the return code.
260
def build_tree(self, shape):
261
"""Build a test tree according to a pattern.
263
shape is a sequence of file specifications. If the final
264
character is '/', a directory is created.
266
This doesn't add anything to a branch.
268
# XXX: It's OK to just create them using forward slashes on windows?
271
assert isinstance(name, basestring)
276
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
98
"""Log a message to a progress file"""
99
print >>self.TEST_LOG, msg
102
class InTempDir(TestBase):
103
"""Base class for tests run in a temporary branch."""
106
self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
107
os.mkdir(self.test_dir)
108
os.chdir(self.test_dir)
112
os.chdir(self.TEST_ROOT)
118
class _MyResult(TestResult):
122
No special behaviour for now.
124
def startTest(self, test):
125
print str(test).ljust(60),
126
TestResult.startTest(self, test)
128
def stopTest(self, test):
130
TestResult.stopTest(self, test)
133
def addError(self, test, err):
135
TestResult.addError(self, test, err)
137
def addFailure(self, test, err):
139
TestResult.addFailure(self, test, err)
141
def addSuccess(self, test):
143
TestResult.addSuccess(self, test)
148
from unittest import TestLoader, TestSuite
150
import bzrlib.selftest.whitebox
151
import bzrlib.selftest.blackbox
298
152
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)
337
160
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):
163
for m in bzrlib.selftest.whitebox, :
164
suite.addTest(tl.loadTestsFromModule(m))
166
suite.addTest(bzrlib.selftest.blackbox.suite())
168
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
342
170
suite.addTest(DocTestSuite(m))
343
for p in bzrlib.plugin.all_plugins:
344
if hasattr(p, 'test_suite'):
345
suite.addTest(p.test_suite())
175
_show_results(result)
177
return result.wasSuccessful()
180
def _setup_test_log():
184
log_filename = os.path.abspath('testbzr.log')
185
TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
187
print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
188
print '%-30s %s' % ('test log', log_filename)
191
def _setup_test_dir():
195
TestBase.ORIG_DIR = os.getcwdu()
196
TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
198
print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
200
if os.path.exists(TestBase.TEST_ROOT):
201
shutil.rmtree(TestBase.TEST_ROOT)
202
os.mkdir(TestBase.TEST_ROOT)
203
os.chdir(TestBase.TEST_ROOT)
205
# make a fake bzr directory there to prevent any tests propagating
206
# up onto the source directory's real branch
207
os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
211
def _show_results(result):
212
for case, tb in result.errors:
213
_show_test_failure('ERROR', case, tb)
215
for case, tb in result.failures:
216
_show_test_failure('FAILURE', case, tb)
219
print '%4d tests run' % result.testsRun
220
print '%4d errors' % len(result.errors)
221
print '%4d failures' % len(result.failures)
225
def _show_test_failure(kind, case, tb):
226
print (kind + '! ').ljust(60, '-')
229
print ''.ljust(60, '-')