15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
from testsweet import run_suite
18
from testsweet import TestCase, run_suite, InTempDir
26
19
import bzrlib.commands
29
20
import bzrlib.fetch
32
22
MODULES_TO_TEST = []
33
23
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)8s %(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()
26
class BzrTestBase(InTempDir):
27
"""bzr-specific test base class"""
93
28
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
29
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
short_id = self.id().replace('bzrlib.selftest.', '')
208
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
209
os.mkdir(self.test_dir)
210
os.chdir(self.test_dir)
214
os.chdir(self._currentdir)
215
super(TestCaseInTempDir, self).tearDown()
217
def _formcmd(self, cmd):
218
if isinstance(cmd, basestring):
221
cmd[0] = self.BZRPATH
222
if self.OVERRIDE_PYTHON:
223
cmd.insert(0, self.OVERRIDE_PYTHON)
224
self.log('$ %r' % cmd)
227
def runcmd(self, cmd, retcode=0):
228
"""Run one command and check the return code.
230
Returns a tuple of (stdout,stderr) strings.
232
If a single string is based, it is split into words.
233
For commands that are not simple space-separated words, please
234
pass a list instead."""
235
cmd = self._formcmd(cmd)
236
self.log('$ ' + ' '.join(cmd))
237
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
238
stderr=self._log_file)
239
if retcode != actual_retcode:
240
raise CommandFailed("test failed: %r returned %d, expected %d"
241
% (cmd, actual_retcode, retcode))
243
def backtick(self, cmd, retcode=0):
244
"""Run a command and return its output"""
245
cmd = self._formcmd(cmd)
246
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
247
outd, errd = child.communicate()
249
actual_retcode = child.wait()
251
outd = outd.replace('\r', '')
253
if retcode != actual_retcode:
254
raise CommandFailed("test failed: %r returned %d, expected %d"
255
% (cmd, actual_retcode, retcode))
261
def build_tree(self, shape):
262
"""Build a test tree according to a pattern.
264
shape is a sequence of file specifications. If the final
265
character is '/', a directory is created.
267
This doesn't add anything to a branch.
269
# XXX: It's OK to just create them using forward slashes on windows?
272
assert isinstance(name, basestring)
277
print >>f, "contents of", name
282
class MetaTestLog(TestCase):
283
def test_logging(self):
284
"""Test logs are captured when a test fails."""
285
logging.info('an info message')
286
warning('something looks dodgy...')
287
logging.debug('hello, test is running')
291
def selftest(verbose=False, pattern=".*"):
292
"""Run the whole test suite under the enhanced runner"""
293
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
297
"""Build and return TestSuite for the whole program."""
298
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
30
self.assertEquals(bzrlib.commands.run_bzr(args), retcode)
33
def selftest(verbose=False):
34
from unittest import TestLoader, TestSuite
299
35
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
300
36
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
301
37
from doctest import DocTestSuite
307
44
global MODULES_TO_TEST, MODULES_TO_DOCTEST
310
['bzrlib.selftest.MetaTestLog',
47
['bzrlib.selftest.whitebox',
48
'bzrlib.selftest.versioning',
311
49
'bzrlib.selftest.testinv',
312
'bzrlib.selftest.versioning',
313
50
'bzrlib.selftest.testmerge3',
314
51
'bzrlib.selftest.testhashcache',
315
52
'bzrlib.selftest.teststatus',
316
53
'bzrlib.selftest.testlog',
54
'bzrlib.selftest.blackbox',
317
55
'bzrlib.selftest.testrevisionnamespaces',
318
56
'bzrlib.selftest.testbranch',
319
57
'bzrlib.selftest.testrevision',
320
'bzrlib.selftest.test_merge_core',
321
'bzrlib.selftest.test_smart_add',
322
59
'bzrlib.selftest.testdiff',
323
'bzrlib.selftest.test_parent',
324
'bzrlib.selftest.test_xml',
325
'bzrlib.selftest.testfetch',
326
'bzrlib.selftest.whitebox',
327
'bzrlib.selftest.teststore',
328
'bzrlib.selftest.blackbox',
331
63
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,