~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/__init__.py

Change the use of run_bzr to run_bzr_captured in blackbox tests - inspired by David Clymers patch to change run_bzr usage to runbzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
 
18
from cStringIO import StringIO
18
19
import logging
19
20
import unittest
20
21
import tempfile
21
22
import os
22
23
import sys
 
24
import errno
 
25
import subprocess
 
26
import shutil
 
27
import testsweet
23
28
 
24
 
from testsweet import run_suite
25
29
import bzrlib.commands
26
 
 
27
30
import bzrlib.trace
28
31
import bzrlib.fetch
29
32
 
 
33
 
30
34
MODULES_TO_TEST = []
31
35
MODULES_TO_DOCTEST = []
32
36
 
33
37
from logging import debug, warning, error
34
38
 
 
39
class CommandFailed(Exception):
 
40
    pass
35
41
 
36
42
class TestCase(unittest.TestCase):
37
43
    """Base class for bzr unit tests.
70
76
        
71
77
        self._log_file_name = name
72
78
 
73
 
        
74
79
    def tearDown(self):
75
80
        logging.getLogger('').removeHandler(self._log_hdlr)
76
81
        bzrlib.trace.enable_default_logging()
78
83
        self._log_file.close()
79
84
        unittest.TestCase.tearDown(self)
80
85
 
81
 
 
82
86
    def log(self, *args):
83
87
        logging.debug(*args)
84
88
 
86
90
        """Return as a string the log for this test"""
87
91
        return open(self._log_file_name).read()
88
92
 
 
93
 
 
94
    def capture(self, cmd):
 
95
        """Shortcut that splits cmd into words, runs, and returns stdout"""
 
96
        return self.run_bzr_captured(cmd.split())[0]
 
97
 
 
98
    def run_bzr_captured(self, argv, retcode=0):
 
99
        """Invoke bzr and return (result, stdout, stderr).
 
100
 
 
101
        Useful for code that wants to check the contents of the
 
102
        output, the way error messages are presented, etc.
 
103
 
 
104
        This should be the main method for tests that want to exercise the
 
105
        overall behavior of the bzr application (rather than a unit test
 
106
        or a functional test of the library.)
 
107
 
 
108
        Much of the old code runs bzr by forking a new copy of Python, but
 
109
        that is slower, harder to debug, and generally not necessary.
 
110
 
 
111
        This runs bzr through the interface that catches and reports
 
112
        errors, and with logging set to something approximating the
 
113
        default, so that error reporting can be checked.
 
114
 
 
115
        argv -- arguments to invoke bzr
 
116
        retcode -- expected return code, or None for don't-care.
 
117
        """
 
118
        stdout = StringIO()
 
119
        stderr = StringIO()
 
120
        self.log('run bzr: %s', ' '.join(argv))
 
121
        handler = logging.StreamHandler(stderr)
 
122
        handler.setFormatter(bzrlib.trace.QuietFormatter())
 
123
        handler.setLevel(logging.INFO)
 
124
        logger = logging.getLogger('')
 
125
        logger.addHandler(handler)
 
126
        try:
 
127
            result = self.apply_redirected(None, stdout, stderr,
 
128
                                           bzrlib.commands.run_bzr_catch_errors,
 
129
                                           argv)
 
130
        finally:
 
131
            logger.removeHandler(handler)
 
132
        out = stdout.getvalue()
 
133
        err = stderr.getvalue()
 
134
        if out:
 
135
            self.log('output:\n%s', out)
 
136
        if err:
 
137
            self.log('errors:\n%s', err)
 
138
        if retcode is not None:
 
139
            self.assertEquals(result, retcode)
 
140
        return out, err
 
141
 
89
142
    def run_bzr(self, *args, **kwargs):
90
143
        """Invoke bzr, as if it were run from the command line.
91
144
 
93
146
        overall behavior of the bzr application (rather than a unit test
94
147
        or a functional test of the library.)
95
148
 
96
 
        Much of the old code runs bzr by forking a new copy of Python, but
97
 
        that is slower, harder to debug, and generally not necessary.
 
149
        This sends the stdout/stderr results into the test's log,
 
150
        where it may be useful for debugging.  See also run_captured.
98
151
        """
99
 
        retcode = kwargs.get('retcode', 0)
100
 
        result = self.apply_redirected(None, None, None,
101
 
                                       bzrlib.commands.run_bzr, args)
102
 
        self.assertEquals(result, retcode)
103
 
        
 
152
        retcode = kwargs.pop('retcode', 0)
 
153
        return self.run_bzr_captured(args, retcode)
 
154
 
104
155
    def check_inventory_shape(self, inv, shape):
105
156
        """
106
157
        Compare an inventory to a list of expected names.
127
178
        """Call callable with redirected std io pipes.
128
179
 
129
180
        Returns the return code."""
130
 
        from StringIO import StringIO
131
181
        if not callable(a_callable):
132
182
            raise ValueError("a_callable must be callable.")
133
183
        if stdin is None:
134
184
            stdin = StringIO("")
135
185
        if stdout is None:
136
 
            stdout = self._log_file
 
186
            if hasattr(self, "_log_file"):
 
187
                stdout = self._log_file
 
188
            else:
 
189
                stdout = StringIO()
137
190
        if stderr is None:
138
 
            stderr = self._log_file
 
191
            if hasattr(self, "_log_file"):
 
192
                stderr = self._log_file
 
193
            else:
 
194
                stderr = StringIO()
139
195
        real_stdin = sys.stdin
140
196
        real_stdout = sys.stdout
141
197
        real_stderr = sys.stderr
142
 
        result = None
143
198
        try:
144
199
            sys.stdout = stdout
145
200
            sys.stderr = stderr
146
201
            sys.stdin = stdin
147
 
            result = a_callable(*args, **kwargs)
 
202
            return a_callable(*args, **kwargs)
148
203
        finally:
149
204
            sys.stdout = real_stdout
150
205
            sys.stderr = real_stderr
151
206
            sys.stdin = real_stdin
152
 
        return result
153
207
 
154
208
 
155
209
BzrTestBase = TestCase
181
235
            self.fail("contents of %s not as expected")
182
236
 
183
237
    def _make_test_root(self):
184
 
        import os
185
 
        import shutil
186
 
        import tempfile
187
 
        
188
238
        if TestCaseInTempDir.TEST_ROOT is not None:
189
239
            return
190
 
        TestCaseInTempDir.TEST_ROOT = os.path.abspath(
191
 
                                 tempfile.mkdtemp(suffix='.tmp',
192
 
                                                  prefix=self._TEST_NAME + '-',
193
 
                                                  dir=os.curdir))
194
 
    
 
240
        i = 0
 
241
        while True:
 
242
            root = 'test%04d.tmp' % i
 
243
            try:
 
244
                os.mkdir(root)
 
245
            except OSError, e:
 
246
                if e.errno == errno.EEXIST:
 
247
                    i += 1
 
248
                    continue
 
249
                else:
 
250
                    raise
 
251
            # successfully created
 
252
            TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
 
253
            break
195
254
        # make a fake bzr directory there to prevent any tests propagating
196
255
        # up onto the source directory's real branch
197
256
        os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
198
257
 
199
258
    def setUp(self):
200
259
        super(TestCaseInTempDir, self).setUp()
201
 
        import os
202
260
        self._make_test_root()
203
261
        self._currentdir = os.getcwdu()
204
262
        self.test_dir = os.path.join(self.TEST_ROOT, self.id())
206
264
        os.chdir(self.test_dir)
207
265
        
208
266
    def tearDown(self):
209
 
        import os
210
267
        os.chdir(self._currentdir)
211
268
        super(TestCaseInTempDir, self).tearDown()
212
269
 
213
 
    def _formcmd(self, cmd):
214
 
        if isinstance(cmd, basestring):
215
 
            cmd = cmd.split()
216
 
        if cmd[0] == 'bzr':
217
 
            cmd[0] = self.BZRPATH
218
 
            if self.OVERRIDE_PYTHON:
219
 
                cmd.insert(0, self.OVERRIDE_PYTHON)
220
 
        self.log('$ %r' % cmd)
221
 
        return cmd
222
 
 
223
 
    def runcmd(self, cmd, retcode=0):
224
 
        """Run one command and check the return code.
225
 
 
226
 
        Returns a tuple of (stdout,stderr) strings.
227
 
 
228
 
        If a single string is based, it is split into words.
229
 
        For commands that are not simple space-separated words, please
230
 
        pass a list instead."""
231
 
        try:
232
 
            import shutil
233
 
            from subprocess import call
234
 
        except ImportError, e:
235
 
            _need_subprocess()
236
 
            raise
237
 
        cmd = self._formcmd(cmd)
238
 
        self.log('$ ' + ' '.join(cmd))
239
 
        actual_retcode = call(cmd, stdout=self._log_file, stderr=self._log_file)
240
 
        if retcode != actual_retcode:
241
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
242
 
                                % (cmd, actual_retcode, retcode))
243
 
 
244
 
    def backtick(self, cmd, retcode=0):
245
 
        """Run a command and return its output"""
246
 
        try:
247
 
            import shutil
248
 
            from subprocess import Popen, PIPE
249
 
        except ImportError, e:
250
 
            _need_subprocess()
251
 
            raise
252
 
 
253
 
        cmd = self._formcmd(cmd)
254
 
        child = Popen(cmd, stdout=PIPE, stderr=self._log_file)
255
 
        outd, errd = child.communicate()
256
 
        self.log(outd)
257
 
        actual_retcode = child.wait()
258
 
 
259
 
        outd = outd.replace('\r', '')
260
 
 
261
 
        if retcode != actual_retcode:
262
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
263
 
                                % (cmd, actual_retcode, retcode))
264
 
 
265
 
        return outd
266
 
 
267
 
 
268
 
 
269
270
    def build_tree(self, shape):
270
271
        """Build a test tree according to a pattern.
271
272
 
275
276
        This doesn't add anything to a branch.
276
277
        """
277
278
        # XXX: It's OK to just create them using forward slashes on windows?
278
 
        import os
279
279
        for name in shape:
280
280
            assert isinstance(name, basestring)
281
281
            if name[-1] == '/':
284
284
                f = file(name, 'wt')
285
285
                print >>f, "contents of", name
286
286
                f.close()
287
 
                
288
287
 
289
288
 
290
289
class MetaTestLog(TestCase):
297
296
 
298
297
 
299
298
def selftest(verbose=False, pattern=".*"):
300
 
    return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
 
299
    return testsweet.run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
301
300
 
302
301
 
303
302
def test_suite():
305
304
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
306
305
    import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
307
306
    from doctest import DocTestSuite
308
 
    import os
309
 
    import shutil
310
 
    import time
311
 
    import sys
312
307
 
313
308
    global MODULES_TO_TEST, MODULES_TO_DOCTEST
314
309
 
315
310
    testmod_names = \
316
311
                  ['bzrlib.selftest.MetaTestLog',
 
312
                   'bzrlib.selftest.test_parent',
317
313
                   'bzrlib.selftest.testinv',
318
314
                   'bzrlib.selftest.testfetch',
319
315
                   'bzrlib.selftest.versioning',
320
316
                   'bzrlib.selftest.whitebox',
321
317
                   'bzrlib.selftest.testmerge3',
 
318
                   'bzrlib.selftest.testmerge',
322
319
                   'bzrlib.selftest.testhashcache',
323
320
                   'bzrlib.selftest.teststatus',
324
321
                   'bzrlib.selftest.testlog',
325
322
                   'bzrlib.selftest.blackbox',
326
323
                   'bzrlib.selftest.testrevisionnamespaces',
327
324
                   'bzrlib.selftest.testbranch',
 
325
                   'bzrlib.selftest.testremotebranch',
328
326
                   'bzrlib.selftest.testrevision',
 
327
                   'bzrlib.selftest.test_revision_info',
329
328
                   'bzrlib.selftest.test_merge_core',
330
329
                   'bzrlib.selftest.test_smart_add',
331
330
                   'bzrlib.selftest.testdiff',
332
 
                   'bzrlib.fetch'
 
331
                   'bzrlib.selftest.test_xml',
 
332
                   'bzrlib.fetch',
 
333
                   'bzrlib.selftest.teststore',
 
334
                   'bzrlib.selftest.testgraph',
333
335
                   ]
334
336
 
335
337
    for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,