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
23
from testsweet import run_suite
25
import bzrlib.commands
29
MODULES_TO_DOCTEST = []
31
from logging import debug, warning, error
34
class TestCase(unittest.TestCase):
35
"""Base class for bzr unit tests.
37
Tests that need access to disk resources should subclass
38
FunctionalTestCase not TestCase.
40
Error and debug log messages are redirected from their usual
41
location into a temporary file, the contents of which can be
42
retrieved by _get_log().
44
There are also convenience functions to invoke bzr's command-line
45
routine, and to build and check bzr trees."""
50
# this replaces the default testsweet.TestCase; we don't want logging changed
51
unittest.TestCase.setUp(self)
52
bzrlib.trace.disable_default_logging()
53
self._enable_file_logging()
56
def _enable_file_logging(self):
57
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
59
self._log_file = os.fdopen(fileno, 'w+')
61
hdlr = logging.StreamHandler(self._log_file)
62
hdlr.setLevel(logging.DEBUG)
63
hdlr.setFormatter(logging.Formatter('%(levelname)4.4s %(message)s'))
64
logging.getLogger('').addHandler(hdlr)
65
logging.getLogger('').setLevel(logging.DEBUG)
67
debug('opened log file %s', name)
69
self._log_file_name = name
73
logging.getLogger('').removeHandler(self._log_hdlr)
74
bzrlib.trace.enable_default_logging()
75
logging.debug('%s teardown', self.id())
76
self._log_file.close()
77
unittest.TestCase.tearDown(self)
84
"""Return as a string the log for this test"""
85
return open(self._log_file_name).read()
87
def run_bzr(self, *args, **kwargs):
88
"""Invoke bzr, as if it were run from the command line.
90
This should be the main method for tests that want to exercise the
91
overall behavior of the bzr application (rather than a unit test
92
or a functional test of the library.)
94
Much of the old code runs bzr by forking a new copy of Python, but
95
that is slower, harder to debug, and generally not necessary.
97
retcode = kwargs.get('retcode', 0)
98
self.assertEquals(bzrlib.commands.run_bzr(args), retcode)
100
def check_inventory_shape(self, inv, shape):
102
Compare an inventory to a list of expected names.
104
Fail if they are not precisely equal.
107
shape = list(shape) # copy
108
for path, ie in inv.entries():
109
name = path.replace('\\', '/')
117
self.fail("expected paths not found in inventory: %r" % shape)
119
self.fail("unexpected paths found in inventory: %r" % extras)
121
BzrTestBase = TestCase
124
class FunctionalTestCase(TestCase):
125
"""Base class for tests that perform function testing - running bzr,
126
using files on disk, and similar activities.
128
InTempDir is an old alias for FunctionalTestCase.
133
OVERRIDE_PYTHON = 'python'
135
def check_file_contents(self, filename, expect):
136
self.log("check contents of file %s" % filename)
137
contents = file(filename, 'r').read()
138
if contents != expect:
139
self.log("expected: %r" % expect)
140
self.log("actually: %r" % contents)
141
self.fail("contents of %s not as expected")
143
def _make_test_root(self):
148
if FunctionalTestCase.TEST_ROOT is not None:
150
FunctionalTestCase.TEST_ROOT = os.path.abspath(
151
tempfile.mkdtemp(suffix='.tmp',
152
prefix=self._TEST_NAME + '-',
155
# make a fake bzr directory there to prevent any tests propagating
156
# up onto the source directory's real branch
157
os.mkdir(os.path.join(FunctionalTestCase.TEST_ROOT, '.bzr'))
160
super(FunctionalTestCase, self).setUp()
162
self._make_test_root()
163
self._currentdir = os.getcwdu()
164
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
165
os.mkdir(self.test_dir)
166
os.chdir(self.test_dir)
170
os.chdir(self._currentdir)
171
super(FunctionalTestCase, self).tearDown()
173
def _formcmd(self, cmd):
174
if isinstance(cmd, basestring):
177
cmd[0] = self.BZRPATH
178
if self.OVERRIDE_PYTHON:
179
cmd.insert(0, self.OVERRIDE_PYTHON)
180
self.log('$ %r' % cmd)
183
def runcmd(self, cmd, retcode=0):
184
"""Run one command and check the return code.
186
Returns a tuple of (stdout,stderr) strings.
188
If a single string is based, it is split into words.
189
For commands that are not simple space-separated words, please
190
pass a list instead."""
193
from subprocess import call
194
except ImportError, e:
197
cmd = self._formcmd(cmd)
198
self.log('$ ' + ' '.join(cmd))
199
actual_retcode = call(cmd, stdout=self._log_file, stderr=self._log_file)
200
if retcode != actual_retcode:
201
raise CommandFailed("test failed: %r returned %d, expected %d"
202
% (cmd, actual_retcode, retcode))
204
def backtick(self, cmd, retcode=0):
205
"""Run a command and return its output"""
208
from subprocess import Popen, PIPE
209
except ImportError, e:
213
cmd = self._formcmd(cmd)
214
child = Popen(cmd, stdout=PIPE, stderr=self._log_file)
215
outd, errd = child.communicate()
217
actual_retcode = child.wait()
219
outd = outd.replace('\r', '')
221
if retcode != actual_retcode:
222
raise CommandFailed("test failed: %r returned %d, expected %d"
223
% (cmd, actual_retcode, retcode))
229
def build_tree(self, shape):
230
"""Build a test tree according to a pattern.
232
shape is a sequence of file specifications. If the final
233
character is '/', a directory is created.
235
This doesn't add anything to a branch.
237
# XXX: It's OK to just create them using forward slashes on windows?
240
assert isinstance(name, basestring)
245
print >>f, "contents of", name
250
class MetaTestLog(TestCase):
251
def test_logging(self):
252
"""Test logs are captured when a test fails."""
253
logging.info('an info message')
254
warning('something looks dodgy...')
255
logging.debug('hello, test is running')
259
InTempDir = FunctionalTestCase
262
def selftest(verbose=False):
263
from unittest import TestLoader, TestSuite
264
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
265
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
266
from doctest import DocTestSuite
272
global MODULES_TO_TEST, MODULES_TO_DOCTEST
275
['bzrlib.selftest.MetaTestLog',
276
'bzrlib.selftest.testinv',
277
'bzrlib.selftest.testfetch',
278
'bzrlib.selftest.versioning',
279
'bzrlib.selftest.whitebox',
280
'bzrlib.selftest.testmerge3',
281
'bzrlib.selftest.testhashcache',
282
'bzrlib.selftest.teststatus',
283
'bzrlib.selftest.testlog',
284
'bzrlib.selftest.blackbox',
285
'bzrlib.selftest.testrevisionnamespaces',
286
'bzrlib.selftest.testbranch',
287
'bzrlib.selftest.testrevision',
289
'bzrlib.selftest.testdiff',
292
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
293
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
294
if m not in MODULES_TO_DOCTEST:
295
MODULES_TO_DOCTEST.append(m)
297
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
298
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
304
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
306
for m in MODULES_TO_TEST:
307
suite.addTest(TestLoader().loadTestsFromModule(m))
309
for m in (MODULES_TO_DOCTEST):
310
suite.addTest(DocTestSuite(m))
312
for p in bzrlib.plugin.all_plugins:
313
if hasattr(p, 'test_suite'):
314
suite.addTest(p.test_suite())
316
import bzrlib.merge_core
317
suite.addTest(unittest.makeSuite(bzrlib.merge_core.MergeTest, 'test_'))
319
return run_suite(suite, 'testbzr', verbose=verbose)