1
# Copyright (C) 2005 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
from testsweet import run_suite
26
import bzrlib.commands
32
MODULES_TO_DOCTEST = []
34
from logging import debug, warning, error
37
class TestCase(unittest.TestCase):
38
"""Base class for bzr unit tests.
40
Tests that need access to disk resources should subclass
41
TestCaseInTempDir not TestCase.
43
Error and debug log messages are redirected from their usual
44
location into a temporary file, the contents of which can be
45
retrieved by _get_log().
47
There are also convenience functions to invoke bzr's command-line
48
routine, and to build and check bzr trees."""
53
# this replaces the default testsweet.TestCase; we don't want logging changed
54
unittest.TestCase.setUp(self)
55
bzrlib.trace.disable_default_logging()
56
self._enable_file_logging()
59
def _enable_file_logging(self):
60
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
62
self._log_file = os.fdopen(fileno, 'w+')
64
hdlr = logging.StreamHandler(self._log_file)
65
hdlr.setLevel(logging.DEBUG)
66
hdlr.setFormatter(logging.Formatter('%(levelname)4.4s %(message)s'))
67
logging.getLogger('').addHandler(hdlr)
68
logging.getLogger('').setLevel(logging.DEBUG)
70
debug('opened log file %s', name)
72
self._log_file_name = name
76
logging.getLogger('').removeHandler(self._log_hdlr)
77
bzrlib.trace.enable_default_logging()
78
logging.debug('%s teardown', self.id())
79
self._log_file.close()
80
unittest.TestCase.tearDown(self)
87
"""Return as a string the log for this test"""
88
return open(self._log_file_name).read()
90
def run_bzr(self, *args, **kwargs):
91
"""Invoke bzr, as if it were run from the command line.
93
This should be the main method for tests that want to exercise the
94
overall behavior of the bzr application (rather than a unit test
95
or a functional test of the library.)
97
Much of the old code runs bzr by forking a new copy of Python, but
98
that is slower, harder to debug, and generally not necessary.
100
retcode = kwargs.get('retcode', 0)
101
result = self.apply_redirected(None, None, None,
102
bzrlib.commands.run_bzr, args)
103
self.assertEquals(result, retcode)
105
def check_inventory_shape(self, inv, shape):
107
Compare an inventory to a list of expected names.
109
Fail if they are not precisely equal.
112
shape = list(shape) # copy
113
for path, ie in inv.entries():
114
name = path.replace('\\', '/')
122
self.fail("expected paths not found in inventory: %r" % shape)
124
self.fail("unexpected paths found in inventory: %r" % extras)
126
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
127
a_callable=None, *args, **kwargs):
128
"""Call callable with redirected std io pipes.
130
Returns the return code."""
131
from StringIO import StringIO
132
if not callable(a_callable):
133
raise ValueError("a_callable must be callable.")
137
stdout = self._log_file
139
stderr = self._log_file
140
real_stdin = sys.stdin
141
real_stdout = sys.stdout
142
real_stderr = sys.stderr
148
result = a_callable(*args, **kwargs)
150
sys.stdout = real_stdout
151
sys.stderr = real_stderr
152
sys.stdin = real_stdin
156
BzrTestBase = TestCase
159
class TestCaseInTempDir(TestCase):
160
"""Derived class that runs a test within a temporary directory.
162
This is useful for tests that need to create a branch, etc.
164
The directory is created in a slightly complex way: for each
165
Python invocation, a new temporary top-level directory is created.
166
All test cases create their own directory within that. If the
167
tests complete successfully, the directory is removed.
169
InTempDir is an old alias for FunctionalTestCase.
174
OVERRIDE_PYTHON = 'python'
176
def check_file_contents(self, filename, expect):
177
self.log("check contents of file %s" % filename)
178
contents = file(filename, 'r').read()
179
if contents != expect:
180
self.log("expected: %r" % expect)
181
self.log("actually: %r" % contents)
182
self.fail("contents of %s not as expected")
184
def _make_test_root(self):
189
if TestCaseInTempDir.TEST_ROOT is not None:
191
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
192
tempfile.mkdtemp(suffix='.tmp',
193
prefix=self._TEST_NAME + '-',
196
# make a fake bzr directory there to prevent any tests propagating
197
# up onto the source directory's real branch
198
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
201
super(TestCaseInTempDir, self).setUp()
203
self._make_test_root()
204
self._currentdir = os.getcwdu()
205
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
206
os.mkdir(self.test_dir)
207
os.chdir(self.test_dir)
211
os.chdir(self._currentdir)
212
super(TestCaseInTempDir, self).tearDown()
214
def _formcmd(self, cmd):
215
if isinstance(cmd, basestring):
218
cmd[0] = self.BZRPATH
219
if self.OVERRIDE_PYTHON:
220
cmd.insert(0, self.OVERRIDE_PYTHON)
221
self.log('$ %r' % cmd)
224
def runcmd(self, cmd, retcode=0):
225
"""Run one command and check the return code.
227
Returns a tuple of (stdout,stderr) strings.
229
If a single string is based, it is split into words.
230
For commands that are not simple space-separated words, please
231
pass a list instead."""
232
cmd = self._formcmd(cmd)
233
self.log('$ ' + ' '.join(cmd))
234
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
235
stderr=self._log_file)
236
if retcode != actual_retcode:
237
raise CommandFailed("test failed: %r returned %d, expected %d"
238
% (cmd, actual_retcode, retcode))
240
def backtick(self, cmd, retcode=0):
241
"""Run a command and return its output"""
242
cmd = self._formcmd(cmd)
243
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
244
outd, errd = child.communicate()
246
actual_retcode = child.wait()
248
outd = outd.replace('\r', '')
250
if retcode != actual_retcode:
251
raise CommandFailed("test failed: %r returned %d, expected %d"
252
% (cmd, actual_retcode, retcode))
258
def build_tree(self, shape):
259
"""Build a test tree according to a pattern.
261
shape is a sequence of file specifications. If the final
262
character is '/', a directory is created.
264
This doesn't add anything to a branch.
266
# XXX: It's OK to just create them using forward slashes on windows?
269
assert isinstance(name, basestring)
274
print >>f, "contents of", name
279
class MetaTestLog(TestCase):
280
def test_logging(self):
281
"""Test logs are captured when a test fails."""
282
logging.info('an info message')
283
warning('something looks dodgy...')
284
logging.debug('hello, test is running')
288
def selftest(verbose=False, pattern=".*"):
289
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
293
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
294
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
295
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
296
from doctest import DocTestSuite
302
global MODULES_TO_TEST, MODULES_TO_DOCTEST
305
['bzrlib.selftest.MetaTestLog',
306
'bzrlib.selftest.testinv',
307
'bzrlib.selftest.testfetch',
308
'bzrlib.selftest.versioning',
309
'bzrlib.selftest.whitebox',
310
'bzrlib.selftest.testmerge3',
311
'bzrlib.selftest.testhashcache',
312
'bzrlib.selftest.teststatus',
313
'bzrlib.selftest.testlog',
314
'bzrlib.selftest.blackbox',
315
'bzrlib.selftest.testrevisionnamespaces',
316
'bzrlib.selftest.testbranch',
317
'bzrlib.selftest.testrevision',
318
'bzrlib.selftest.test_merge_core',
319
'bzrlib.selftest.test_smart_add',
320
'bzrlib.selftest.testdiff',
324
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
325
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
326
if m not in MODULES_TO_DOCTEST:
327
MODULES_TO_DOCTEST.append(m)
329
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
330
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
333
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
334
for m in MODULES_TO_TEST:
335
suite.addTest(TestLoader().loadTestsFromModule(m))
336
for m in (MODULES_TO_DOCTEST):
337
suite.addTest(DocTestSuite(m))
338
for p in bzrlib.plugin.all_plugins:
339
if hasattr(p, 'test_suite'):
340
suite.addTest(p.test_suite())