~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-03-06 06:48:25 UTC
  • mfrom: (4070.8.6 debug-config)
  • Revision ID: pqm@pqm.ubuntu.com-20090306064825-kbpwggw21dygeix6
(mbp) debug_flags configuration option

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
18
# TODO: Perhaps there should be an API to find out if bzr running under the
33
33
import doctest
34
34
import errno
35
35
import logging
36
 
import math
37
36
import os
38
37
from pprint import pformat
39
38
import random
40
39
import re
41
40
import shlex
42
41
import stat
43
 
from subprocess import Popen, PIPE, STDOUT
 
42
from subprocess import Popen, PIPE
44
43
import sys
45
44
import tempfile
46
45
import threading
54
53
    bzrdir,
55
54
    debug,
56
55
    errors,
57
 
    hooks,
58
56
    memorytree,
59
57
    osutils,
60
58
    progress,
78
76
from bzrlib.merge import merge_inner
79
77
import bzrlib.merge3
80
78
import bzrlib.plugin
81
 
from bzrlib.smart import client, request, server
 
79
from bzrlib.smart import client, server
82
80
import bzrlib.store
83
81
from bzrlib import symbol_versioning
84
82
from bzrlib.symbol_versioning import (
365
363
        self.pb.show_bar = False
366
364
 
367
365
    def report_starting(self):
368
 
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
 
366
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
369
367
 
370
368
    def _progress_prefix_text(self):
371
369
        # the longer this text, the less space we have to show the test
430
428
        """test cannot be run because feature is missing."""
431
429
 
432
430
    def report_cleaning_up(self):
433
 
        self.pb.update('Cleaning up')
 
431
        self.pb.update('cleaning up...')
434
432
 
435
433
    def finished(self):
436
434
        if not self._supplied_pb:
544
542
                run += 1
545
543
            actionTaken = "Listed"
546
544
        else:
547
 
            try:
548
 
                import testtools
549
 
            except ImportError:
550
 
                test.run(result)
551
 
            else:
552
 
                if isinstance(test, testtools.ConcurrentTestSuite):
553
 
                    # We need to catch bzr specific behaviors
554
 
                    test.run(BZRTransformingResult(result))
555
 
                else:
556
 
                    test.run(result)
 
545
            test.run(result)
557
546
            run = result.testsRun
558
547
            actionTaken = "Ran"
559
548
        stopTime = time.time()
596
585
 
597
586
def iter_suite_tests(suite):
598
587
    """Return all tests in a suite, recursing through nested suites"""
599
 
    if isinstance(suite, unittest.TestCase):
600
 
        yield suite
601
 
    elif isinstance(suite, unittest.TestSuite):
602
 
        for item in suite:
 
588
    for item in suite._tests:
 
589
        if isinstance(item, unittest.TestCase):
 
590
            yield item
 
591
        elif isinstance(item, unittest.TestSuite):
603
592
            for r in iter_suite_tests(item):
604
593
                yield r
605
 
    else:
606
 
        raise Exception('unknown type %r for object %r'
607
 
                        % (type(suite), suite))
 
594
        else:
 
595
            raise Exception('unknown object %r inside test suite %r'
 
596
                            % (item, suite))
608
597
 
609
598
 
610
599
class TestSkipped(Exception):
675
664
    Allows get_password to be tested without real tty attached.
676
665
    """
677
666
 
678
 
    def __init__(self, stdout=None, stderr=None, stdin=None):
 
667
    def __init__(self,
 
668
                 stdout=None,
 
669
                 stderr=None,
 
670
                 stdin=None):
 
671
        super(TestUIFactory, self).__init__()
679
672
        if stdin is not None:
680
673
            # We use a StringIOWrapper to be able to test various
681
674
            # encodings, but the user is still responsible to
682
675
            # encode the string and to set the encoding attribute
683
676
            # of StringIOWrapper.
684
 
            stdin = StringIOWrapper(stdin)
685
 
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
 
677
            self.stdin = StringIOWrapper(stdin)
 
678
        if stdout is None:
 
679
            self.stdout = sys.stdout
 
680
        else:
 
681
            self.stdout = stdout
 
682
        if stderr is None:
 
683
            self.stderr = sys.stderr
 
684
        else:
 
685
            self.stderr = stderr
686
686
 
687
687
    def clear(self):
688
688
        """See progress.ProgressBar.clear()."""
690
690
    def clear_term(self):
691
691
        """See progress.ProgressBar.clear_term()."""
692
692
 
 
693
    def clear_term(self):
 
694
        """See progress.ProgressBar.clear_term()."""
 
695
 
693
696
    def finished(self):
694
697
        """See progress.ProgressBar.finished()."""
695
698
 
706
709
    def update(self, message, count=None, total=None):
707
710
        """See progress.ProgressBar.update()."""
708
711
 
709
 
    def get_non_echoed_password(self):
 
712
    def get_non_echoed_password(self, prompt):
710
713
        """Get password from stdin without trying to handle the echo mode"""
 
714
        if prompt:
 
715
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
711
716
        password = self.stdin.readline()
712
717
        if not password:
713
718
            raise EOFError
758
763
    def __init__(self, methodName='testMethod'):
759
764
        super(TestCase, self).__init__(methodName)
760
765
        self._cleanups = []
761
 
        self._bzr_test_setUp_run = False
762
 
        self._bzr_test_tearDown_run = False
763
766
 
764
767
    def setUp(self):
765
768
        unittest.TestCase.setUp(self)
766
 
        self._bzr_test_setUp_run = True
767
769
        self._cleanEnvironment()
768
770
        self._silenceUI()
769
771
        self._startLogFile()
774
776
        TestCase._active_threads = threading.activeCount()
775
777
        self.addCleanup(self._check_leaked_threads)
776
778
 
777
 
    def debug(self):
778
 
        # debug a frame up.
779
 
        import pdb
780
 
        pdb.Pdb().set_trace(sys._getframe().f_back)
 
779
    def exc_info(self):
 
780
        absent_attr = object()
 
781
        exc_info = getattr(self, '_exc_info', absent_attr)
 
782
        if exc_info is absent_attr:
 
783
            exc_info = getattr(self, '_TestCase__exc_info')
 
784
        return exc_info()
781
785
 
782
786
    def _check_leaked_threads(self):
783
787
        active = threading.activeCount()
805
809
 
806
810
    def _clear_hooks(self):
807
811
        # prevent hooks affecting tests
808
 
        self._preserved_hooks = {}
809
 
        for key, factory in hooks.known_hooks.items():
810
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
811
 
            current_hooks = hooks.known_hooks_key_to_object(key)
812
 
            self._preserved_hooks[parent] = (name, current_hooks)
 
812
        import bzrlib.branch
 
813
        import bzrlib.smart.client
 
814
        import bzrlib.smart.server
 
815
        self._preserved_hooks = {
 
816
            bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
 
817
            bzrlib.mutabletree.MutableTree: bzrlib.mutabletree.MutableTree.hooks,
 
818
            bzrlib.smart.client._SmartClient: bzrlib.smart.client._SmartClient.hooks,
 
819
            bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
 
820
            bzrlib.commands.Command: bzrlib.commands.Command.hooks,
 
821
            }
813
822
        self.addCleanup(self._restoreHooks)
814
 
        for key, factory in hooks.known_hooks.items():
815
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
816
 
            setattr(parent, name, factory())
817
 
        # this hook should always be installed
818
 
        request._install_hook()
 
823
        # reset all hooks to an empty instance of the appropriate type
 
824
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
 
825
        bzrlib.smart.client._SmartClient.hooks = bzrlib.smart.client.SmartClientHooks()
 
826
        bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
 
827
        bzrlib.commands.Command.hooks = bzrlib.commands.CommandHooks()
819
828
 
820
829
    def _silenceUI(self):
821
830
        """Turn off UI for duration of test"""
894
903
        self.assertEqual(expected.st_ino, actual.st_ino)
895
904
        self.assertEqual(expected.st_mode, actual.st_mode)
896
905
 
897
 
    def assertLength(self, length, obj_with_len):
898
 
        """Assert that obj_with_len is of length length."""
899
 
        if len(obj_with_len) != length:
900
 
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
901
 
                length, len(obj_with_len), obj_with_len))
902
 
 
903
906
    def assertPositive(self, val):
904
907
        """Assert that val is greater than 0."""
905
908
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
997
1000
                raise AssertionError("%r is %r." % (left, right))
998
1001
 
999
1002
    def assertTransportMode(self, transport, path, mode):
1000
 
        """Fail if a path does not have mode "mode".
 
1003
        """Fail if a path does not have mode mode.
1001
1004
 
1002
1005
        If modes are not supported on this transport, the assertion is ignored.
1003
1006
        """
1006
1009
        path_stat = transport.stat(path)
1007
1010
        actual_mode = stat.S_IMODE(path_stat.st_mode)
1008
1011
        self.assertEqual(mode, actual_mode,
1009
 
                         'mode of %r incorrect (%s != %s)'
1010
 
                         % (path, oct(mode), oct(actual_mode)))
 
1012
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
1011
1013
 
1012
1014
    def assertIsSameRealPath(self, path1, path2):
1013
1015
        """Fail if path1 and path2 points to different files"""
1239
1241
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1240
1242
            # tests do check our impls match APPDATA
1241
1243
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1242
 
            'VISUAL': None,
1243
 
            'EDITOR': None,
1244
1244
            'BZR_EMAIL': None,
1245
1245
            'BZREMAIL': None, # may still be present in the environment
1246
1246
            'EMAIL': None,
1258
1258
            'NO_PROXY': None,
1259
1259
            'all_proxy': None,
1260
1260
            'ALL_PROXY': None,
1261
 
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1261
            # Nobody cares about these ones AFAIK. So far at
1262
1262
            # least. If you do (care), please update this comment
1263
 
            # -- vila 20080401
 
1263
            # -- vila 20061212
1264
1264
            'ftp_proxy': None,
1265
1265
            'FTP_PROXY': None,
1266
1266
            'BZR_REMOTE_PATH': None,
1283
1283
            osutils.set_or_unset_env(name, value)
1284
1284
 
1285
1285
    def _restoreHooks(self):
1286
 
        for klass, (name, hooks) in self._preserved_hooks.items():
1287
 
            setattr(klass, name, hooks)
 
1286
        for klass, hooks in self._preserved_hooks.items():
 
1287
            setattr(klass, 'hooks', hooks)
1288
1288
 
1289
1289
    def knownFailure(self, reason):
1290
1290
        """This test has failed for some known reason."""
1293
1293
    def _do_skip(self, result, reason):
1294
1294
        addSkip = getattr(result, 'addSkip', None)
1295
1295
        if not callable(addSkip):
1296
 
            result.addError(self, sys.exc_info())
 
1296
            result.addError(self, self.exc_info())
1297
1297
        else:
1298
1298
            addSkip(self, reason)
1299
1299
 
1321
1321
                try:
1322
1322
                    try:
1323
1323
                        self.setUp()
1324
 
                        if not self._bzr_test_setUp_run:
1325
 
                            self.fail(
1326
 
                                "test setUp did not invoke "
1327
 
                                "bzrlib.tests.TestCase's setUp")
1328
1324
                    except KeyboardInterrupt:
1329
1325
                        raise
1330
1326
                    except TestSkipped, e:
1332
1328
                        self.tearDown()
1333
1329
                        return
1334
1330
                    except:
1335
 
                        result.addError(self, sys.exc_info())
 
1331
                        result.addError(self, self.exc_info())
1336
1332
                        return
1337
1333
 
1338
1334
                    ok = False
1340
1336
                        testMethod()
1341
1337
                        ok = True
1342
1338
                    except self.failureException:
1343
 
                        result.addFailure(self, sys.exc_info())
 
1339
                        result.addFailure(self, self.exc_info())
1344
1340
                    except TestSkipped, e:
1345
1341
                        if not e.args:
1346
1342
                            reason = "No reason given."
1350
1346
                    except KeyboardInterrupt:
1351
1347
                        raise
1352
1348
                    except:
1353
 
                        result.addError(self, sys.exc_info())
 
1349
                        result.addError(self, self.exc_info())
1354
1350
 
1355
1351
                    try:
1356
1352
                        self.tearDown()
1357
 
                        if not self._bzr_test_tearDown_run:
1358
 
                            self.fail(
1359
 
                                "test tearDown did not invoke "
1360
 
                                "bzrlib.tests.TestCase's tearDown")
1361
1353
                    except KeyboardInterrupt:
1362
1354
                        raise
1363
1355
                    except:
1364
 
                        result.addError(self, sys.exc_info())
 
1356
                        result.addError(self, self.exc_info())
1365
1357
                        ok = False
1366
1358
                    if ok: result.addSuccess(self)
1367
1359
                finally:
1382
1374
            self.__dict__ = saved_attrs
1383
1375
 
1384
1376
    def tearDown(self):
1385
 
        self._bzr_test_tearDown_run = True
1386
1377
        self._runCleanups()
1387
1378
        self._log_contents = ''
1388
1379
        unittest.TestCase.tearDown(self)
2117
2108
        made_control = self.make_bzrdir(relpath, format=format)
2118
2109
        return made_control.create_repository(shared=shared)
2119
2110
 
2120
 
    def make_smart_server(self, path):
2121
 
        smart_server = server.SmartTCPServer_for_testing()
2122
 
        smart_server.setUp(self.get_server())
2123
 
        remote_transport = get_transport(smart_server.get_url()).clone(path)
2124
 
        self.addCleanup(smart_server.tearDown)
2125
 
        return remote_transport
2126
 
 
2127
2111
    def make_branch_and_memory_tree(self, relpath, format=None):
2128
2112
        """Create a branch on the default transport and a MemoryTree for it."""
2129
2113
        b = self.make_branch(relpath, format=format)
2214
2198
        For TestCaseInTempDir we create a temporary directory based on the test
2215
2199
        name and then create two subdirs - test and home under it.
2216
2200
        """
2217
 
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
2218
 
            self._getTestDirPrefix())
 
2201
        name_prefix = osutils.pathjoin(self.TEST_ROOT, self._getTestDirPrefix())
2219
2202
        name = name_prefix
2220
2203
        for i in range(100):
2221
2204
            if os.path.exists(name):
2239
2222
        self.addCleanup(self.deleteTestDir)
2240
2223
 
2241
2224
    def deleteTestDir(self):
2242
 
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
2225
        os.chdir(self.TEST_ROOT)
2243
2226
        _rmtree_temp_dir(self.test_base_dir)
2244
2227
 
2245
2228
    def build_tree(self, shape, line_endings='binary', transport=None):
2424
2407
    :param pattern: A regular expression string.
2425
2408
    :return: A callable that returns True if the re matches.
2426
2409
    """
2427
 
    filter_re = osutils.re_compile_checked(pattern, 0,
2428
 
        'test filter')
 
2410
    filter_re = re.compile(pattern)
2429
2411
    def condition(test):
2430
2412
        test_id = test.id()
2431
2413
        return filter_re.search(test_id)
2616
2598
              random_seed=None,
2617
2599
              exclude_pattern=None,
2618
2600
              strict=False,
2619
 
              runner_class=None,
2620
 
              suite_decorators=None):
 
2601
              runner_class=None):
2621
2602
    """Run a test suite for bzr selftest.
2622
2603
 
2623
2604
    :param runner_class: The class of runner to use. Must support the
2639
2620
                            list_only=list_only,
2640
2621
                            )
2641
2622
    runner.stop_on_failure=stop_on_failure
2642
 
    # built in decorator factories:
2643
 
    decorators = [
2644
 
        random_order(random_seed, runner),
2645
 
        exclude_tests(exclude_pattern),
2646
 
        ]
2647
 
    if matching_tests_first:
2648
 
        decorators.append(tests_first(pattern))
 
2623
    # Initialise the random number generator and display the seed used.
 
2624
    # We convert the seed to a long to make it reuseable across invocations.
 
2625
    random_order = False
 
2626
    if random_seed is not None:
 
2627
        random_order = True
 
2628
        if random_seed == "now":
 
2629
            random_seed = long(time.time())
 
2630
        else:
 
2631
            # Convert the seed to a long if we can
 
2632
            try:
 
2633
                random_seed = long(random_seed)
 
2634
            except:
 
2635
                pass
 
2636
        runner.stream.writeln("Randomizing test order using seed %s\n" %
 
2637
            (random_seed))
 
2638
        random.seed(random_seed)
 
2639
    # Customise the list of tests if requested
 
2640
    if exclude_pattern is not None:
 
2641
        suite = exclude_tests_by_re(suite, exclude_pattern)
 
2642
    if random_order:
 
2643
        order_changer = randomize_suite
2649
2644
    else:
2650
 
        decorators.append(filter_tests(pattern))
2651
 
    if suite_decorators:
2652
 
        decorators.extend(suite_decorators)
2653
 
    for decorator in decorators:
2654
 
        suite = decorator(suite)
 
2645
        order_changer = preserve_input
 
2646
    if pattern != '.*' or random_order:
 
2647
        if matching_tests_first:
 
2648
            suites = map(order_changer, split_suite_by_re(suite, pattern))
 
2649
            suite = TestUtil.TestSuite(suites)
 
2650
        else:
 
2651
            suite = order_changer(filter_suite_by_re(suite, pattern))
 
2652
 
2655
2653
    result = runner.run(suite)
 
2654
 
2656
2655
    if strict:
2657
2656
        return result.wasStrictlySuccessful()
2658
 
    else:
2659
 
        return result.wasSuccessful()
2660
 
 
2661
 
 
2662
 
# A registry where get() returns a suite decorator.
2663
 
parallel_registry = registry.Registry()
2664
 
 
2665
 
 
2666
 
def fork_decorator(suite):
2667
 
    concurrency = local_concurrency()
2668
 
    if concurrency == 1:
2669
 
        return suite
2670
 
    from testtools import ConcurrentTestSuite
2671
 
    return ConcurrentTestSuite(suite, fork_for_tests)
2672
 
parallel_registry.register('fork', fork_decorator)
2673
 
 
2674
 
 
2675
 
def subprocess_decorator(suite):
2676
 
    concurrency = local_concurrency()
2677
 
    if concurrency == 1:
2678
 
        return suite
2679
 
    from testtools import ConcurrentTestSuite
2680
 
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
2681
 
parallel_registry.register('subprocess', subprocess_decorator)
2682
 
 
2683
 
 
2684
 
def exclude_tests(exclude_pattern):
2685
 
    """Return a test suite decorator that excludes tests."""
2686
 
    if exclude_pattern is None:
2687
 
        return identity_decorator
2688
 
    def decorator(suite):
2689
 
        return ExcludeDecorator(suite, exclude_pattern)
2690
 
    return decorator
2691
 
 
2692
 
 
2693
 
def filter_tests(pattern):
2694
 
    if pattern == '.*':
2695
 
        return identity_decorator
2696
 
    def decorator(suite):
2697
 
        return FilterTestsDecorator(suite, pattern)
2698
 
    return decorator
2699
 
 
2700
 
 
2701
 
def random_order(random_seed, runner):
2702
 
    """Return a test suite decorator factory for randomising tests order.
2703
 
    
2704
 
    :param random_seed: now, a string which casts to a long, or a long.
2705
 
    :param runner: A test runner with a stream attribute to report on.
2706
 
    """
2707
 
    if random_seed is None:
2708
 
        return identity_decorator
2709
 
    def decorator(suite):
2710
 
        return RandomDecorator(suite, random_seed, runner.stream)
2711
 
    return decorator
2712
 
 
2713
 
 
2714
 
def tests_first(pattern):
2715
 
    if pattern == '.*':
2716
 
        return identity_decorator
2717
 
    def decorator(suite):
2718
 
        return TestFirstDecorator(suite, pattern)
2719
 
    return decorator
2720
 
 
2721
 
 
2722
 
def identity_decorator(suite):
2723
 
    """Return suite."""
2724
 
    return suite
2725
 
 
2726
 
 
2727
 
class TestDecorator(TestSuite):
2728
 
    """A decorator for TestCase/TestSuite objects.
2729
 
    
2730
 
    Usually, subclasses should override __iter__(used when flattening test
2731
 
    suites), which we do to filter, reorder, parallelise and so on, run() and
2732
 
    debug().
2733
 
    """
2734
 
 
2735
 
    def __init__(self, suite):
2736
 
        TestSuite.__init__(self)
2737
 
        self.addTest(suite)
2738
 
 
2739
 
    def countTestCases(self):
2740
 
        cases = 0
2741
 
        for test in self:
2742
 
            cases += test.countTestCases()
2743
 
        return cases
2744
 
 
2745
 
    def debug(self):
2746
 
        for test in self:
2747
 
            test.debug()
2748
 
 
2749
 
    def run(self, result):
2750
 
        # Use iteration on self, not self._tests, to allow subclasses to hook
2751
 
        # into __iter__.
2752
 
        for test in self:
2753
 
            if result.shouldStop:
2754
 
                break
2755
 
            test.run(result)
2756
 
        return result
2757
 
 
2758
 
 
2759
 
class ExcludeDecorator(TestDecorator):
2760
 
    """A decorator which excludes test matching an exclude pattern."""
2761
 
 
2762
 
    def __init__(self, suite, exclude_pattern):
2763
 
        TestDecorator.__init__(self, suite)
2764
 
        self.exclude_pattern = exclude_pattern
2765
 
        self.excluded = False
2766
 
 
2767
 
    def __iter__(self):
2768
 
        if self.excluded:
2769
 
            return iter(self._tests)
2770
 
        self.excluded = True
2771
 
        suite = exclude_tests_by_re(self, self.exclude_pattern)
2772
 
        del self._tests[:]
2773
 
        self.addTests(suite)
2774
 
        return iter(self._tests)
2775
 
 
2776
 
 
2777
 
class FilterTestsDecorator(TestDecorator):
2778
 
    """A decorator which filters tests to those matching a pattern."""
2779
 
 
2780
 
    def __init__(self, suite, pattern):
2781
 
        TestDecorator.__init__(self, suite)
2782
 
        self.pattern = pattern
2783
 
        self.filtered = False
2784
 
 
2785
 
    def __iter__(self):
2786
 
        if self.filtered:
2787
 
            return iter(self._tests)
2788
 
        self.filtered = True
2789
 
        suite = filter_suite_by_re(self, self.pattern)
2790
 
        del self._tests[:]
2791
 
        self.addTests(suite)
2792
 
        return iter(self._tests)
2793
 
 
2794
 
 
2795
 
class RandomDecorator(TestDecorator):
2796
 
    """A decorator which randomises the order of its tests."""
2797
 
 
2798
 
    def __init__(self, suite, random_seed, stream):
2799
 
        TestDecorator.__init__(self, suite)
2800
 
        self.random_seed = random_seed
2801
 
        self.randomised = False
2802
 
        self.stream = stream
2803
 
 
2804
 
    def __iter__(self):
2805
 
        if self.randomised:
2806
 
            return iter(self._tests)
2807
 
        self.randomised = True
2808
 
        self.stream.writeln("Randomizing test order using seed %s\n" %
2809
 
            (self.actual_seed()))
2810
 
        # Initialise the random number generator.
2811
 
        random.seed(self.actual_seed())
2812
 
        suite = randomize_suite(self)
2813
 
        del self._tests[:]
2814
 
        self.addTests(suite)
2815
 
        return iter(self._tests)
2816
 
 
2817
 
    def actual_seed(self):
2818
 
        if self.random_seed == "now":
2819
 
            # We convert the seed to a long to make it reuseable across
2820
 
            # invocations (because the user can reenter it).
2821
 
            self.random_seed = long(time.time())
2822
 
        else:
2823
 
            # Convert the seed to a long if we can
2824
 
            try:
2825
 
                self.random_seed = long(self.random_seed)
2826
 
            except:
2827
 
                pass
2828
 
        return self.random_seed
2829
 
 
2830
 
 
2831
 
class TestFirstDecorator(TestDecorator):
2832
 
    """A decorator which moves named tests to the front."""
2833
 
 
2834
 
    def __init__(self, suite, pattern):
2835
 
        TestDecorator.__init__(self, suite)
2836
 
        self.pattern = pattern
2837
 
        self.filtered = False
2838
 
 
2839
 
    def __iter__(self):
2840
 
        if self.filtered:
2841
 
            return iter(self._tests)
2842
 
        self.filtered = True
2843
 
        suites = split_suite_by_re(self, self.pattern)
2844
 
        del self._tests[:]
2845
 
        self.addTests(suites)
2846
 
        return iter(self._tests)
2847
 
 
2848
 
 
2849
 
def partition_tests(suite, count):
2850
 
    """Partition suite into count lists of tests."""
2851
 
    result = []
2852
 
    tests = list(iter_suite_tests(suite))
2853
 
    tests_per_process = int(math.ceil(float(len(tests)) / count))
2854
 
    for block in range(count):
2855
 
        low_test = block * tests_per_process
2856
 
        high_test = low_test + tests_per_process
2857
 
        process_tests = tests[low_test:high_test]
2858
 
        result.append(process_tests)
2859
 
    return result
2860
 
 
2861
 
 
2862
 
def fork_for_tests(suite):
2863
 
    """Take suite and start up one runner per CPU by forking()
2864
 
 
2865
 
    :return: An iterable of TestCase-like objects which can each have
2866
 
        run(result) called on them to feed tests to result.
2867
 
    """
2868
 
    concurrency = local_concurrency()
2869
 
    result = []
2870
 
    from subunit import TestProtocolClient, ProtocolTestCase
2871
 
    class TestInOtherProcess(ProtocolTestCase):
2872
 
        # Should be in subunit, I think. RBC.
2873
 
        def __init__(self, stream, pid):
2874
 
            ProtocolTestCase.__init__(self, stream)
2875
 
            self.pid = pid
2876
 
 
2877
 
        def run(self, result):
2878
 
            try:
2879
 
                ProtocolTestCase.run(self, result)
2880
 
            finally:
2881
 
                os.waitpid(self.pid, os.WNOHANG)
2882
 
 
2883
 
    test_blocks = partition_tests(suite, concurrency)
2884
 
    for process_tests in test_blocks:
2885
 
        process_suite = TestSuite()
2886
 
        process_suite.addTests(process_tests)
2887
 
        c2pread, c2pwrite = os.pipe()
2888
 
        pid = os.fork()
2889
 
        if pid == 0:
2890
 
            try:
2891
 
                os.close(c2pread)
2892
 
                # Leave stderr and stdout open so we can see test noise
2893
 
                # Close stdin so that the child goes away if it decides to
2894
 
                # read from stdin (otherwise its a roulette to see what
2895
 
                # child actually gets keystrokes for pdb etc).
2896
 
                sys.stdin.close()
2897
 
                sys.stdin = None
2898
 
                stream = os.fdopen(c2pwrite, 'wb', 1)
2899
 
                subunit_result = TestProtocolClient(stream)
2900
 
                process_suite.run(subunit_result)
2901
 
            finally:
2902
 
                os._exit(0)
2903
 
        else:
2904
 
            os.close(c2pwrite)
2905
 
            stream = os.fdopen(c2pread, 'rb', 1)
2906
 
            test = TestInOtherProcess(stream, pid)
2907
 
            result.append(test)
2908
 
    return result
2909
 
 
2910
 
 
2911
 
def reinvoke_for_tests(suite):
2912
 
    """Take suite and start up one runner per CPU using subprocess().
2913
 
 
2914
 
    :return: An iterable of TestCase-like objects which can each have
2915
 
        run(result) called on them to feed tests to result.
2916
 
    """
2917
 
    concurrency = local_concurrency()
2918
 
    result = []
2919
 
    from subunit import TestProtocolClient, ProtocolTestCase
2920
 
    class TestInSubprocess(ProtocolTestCase):
2921
 
        def __init__(self, process, name):
2922
 
            ProtocolTestCase.__init__(self, process.stdout)
2923
 
            self.process = process
2924
 
            self.process.stdin.close()
2925
 
            self.name = name
2926
 
 
2927
 
        def run(self, result):
2928
 
            try:
2929
 
                ProtocolTestCase.run(self, result)
2930
 
            finally:
2931
 
                self.process.wait()
2932
 
                os.unlink(self.name)
2933
 
            # print "pid %d finished" % finished_process
2934
 
    test_blocks = partition_tests(suite, concurrency)
2935
 
    for process_tests in test_blocks:
2936
 
        # ugly; currently reimplement rather than reuses TestCase methods.
2937
 
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
2938
 
        if not os.path.isfile(bzr_path):
2939
 
            # We are probably installed. Assume sys.argv is the right file
2940
 
            bzr_path = sys.argv[0]
2941
 
        fd, test_list_file_name = tempfile.mkstemp()
2942
 
        test_list_file = os.fdopen(fd, 'wb', 1)
2943
 
        for test in process_tests:
2944
 
            test_list_file.write(test.id() + '\n')
2945
 
        test_list_file.close()
2946
 
        try:
2947
 
            argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
2948
 
                '--subunit']
2949
 
            if '--no-plugins' in sys.argv:
2950
 
                argv.append('--no-plugins')
2951
 
            # stderr=STDOUT would be ideal, but until we prevent noise on
2952
 
            # stderr it can interrupt the subunit protocol.
2953
 
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
2954
 
                bufsize=1)
2955
 
            test = TestInSubprocess(process, test_list_file_name)
2956
 
            result.append(test)
2957
 
        except:
2958
 
            os.unlink(test_list_file_name)
2959
 
            raise
2960
 
    return result
2961
 
 
2962
 
 
2963
 
def cpucount(content):
2964
 
    lines = content.splitlines()
2965
 
    prefix = 'processor'
2966
 
    for line in lines:
2967
 
        if line.startswith(prefix):
2968
 
            concurrency = int(line[line.find(':')+1:]) + 1
2969
 
    return concurrency
2970
 
 
2971
 
 
2972
 
def local_concurrency():
2973
 
    try:
2974
 
        content = file('/proc/cpuinfo', 'rb').read()
2975
 
        concurrency = cpucount(content)
2976
 
    except Exception, e:
2977
 
        concurrency = 1
2978
 
    return concurrency
2979
 
 
2980
 
 
2981
 
class BZRTransformingResult(unittest.TestResult):
2982
 
 
2983
 
    def __init__(self, target):
2984
 
        unittest.TestResult.__init__(self)
2985
 
        self.result = target
2986
 
 
2987
 
    def startTest(self, test):
2988
 
        self.result.startTest(test)
2989
 
 
2990
 
    def stopTest(self, test):
2991
 
        self.result.stopTest(test)
2992
 
 
2993
 
    def addError(self, test, err):
2994
 
        feature = self._error_looks_like('UnavailableFeature: ', err)
2995
 
        if feature is not None:
2996
 
            self.result.addNotSupported(test, feature)
2997
 
        else:
2998
 
            self.result.addError(test, err)
2999
 
 
3000
 
    def addFailure(self, test, err):
3001
 
        known = self._error_looks_like('KnownFailure: ', err)
3002
 
        if known is not None:
3003
 
            self.result._addKnownFailure(test, [KnownFailure,
3004
 
                                                KnownFailure(known), None])
3005
 
        else:
3006
 
            self.result.addFailure(test, err)
3007
 
 
3008
 
    def addSkip(self, test, reason):
3009
 
        self.result.addSkip(test, reason)
3010
 
 
3011
 
    def addSuccess(self, test):
3012
 
        self.result.addSuccess(test)
3013
 
 
3014
 
    def _error_looks_like(self, prefix, err):
3015
 
        """Deserialize exception and returns the stringify value."""
3016
 
        import subunit
3017
 
        value = None
3018
 
        typ, exc, _ = err
3019
 
        if isinstance(exc, subunit.RemoteException):
3020
 
            # stringify the exception gives access to the remote traceback
3021
 
            # We search the last line for 'prefix'
3022
 
            lines = str(exc).split('\n')
3023
 
            if len(lines) > 1:
3024
 
                last = lines[-2] # -1 is empty, final \n
3025
 
            else:
3026
 
                last = lines[-1]
3027
 
            if last.startswith(prefix):
3028
 
                value = last[len(prefix):]
3029
 
        return value
 
2657
 
 
2658
    return result.wasSuccessful()
3030
2659
 
3031
2660
 
3032
2661
# Controlled by "bzr selftest -E=..." option
3047
2676
             debug_flags=None,
3048
2677
             starting_with=None,
3049
2678
             runner_class=None,
3050
 
             suite_decorators=None,
3051
2679
             ):
3052
2680
    """Run the whole test suite under the enhanced runner"""
3053
2681
    # XXX: Very ugly way to do this...
3085
2713
                     exclude_pattern=exclude_pattern,
3086
2714
                     strict=strict,
3087
2715
                     runner_class=runner_class,
3088
 
                     suite_decorators=suite_decorators,
3089
2716
                     )
3090
2717
    finally:
3091
2718
        default_transport = old_transport
3271
2898
                   'bzrlib.tests.per_lock',
3272
2899
                   'bzrlib.tests.per_repository',
3273
2900
                   'bzrlib.tests.per_repository_reference',
3274
 
                   'bzrlib.tests.test__chk_map',
3275
2901
                   'bzrlib.tests.test__dirstate_helpers',
3276
 
                   'bzrlib.tests.test__groupcompress',
3277
2902
                   'bzrlib.tests.test__walkdirs_win32',
3278
2903
                   'bzrlib.tests.test_ancestry',
3279
2904
                   'bzrlib.tests.test_annotate',
3287
2912
                   'bzrlib.tests.test_bugtracker',
3288
2913
                   'bzrlib.tests.test_bundle',
3289
2914
                   'bzrlib.tests.test_bzrdir',
3290
 
                   'bzrlib.tests.test__chunks_to_lines',
3291
2915
                   'bzrlib.tests.test_cache_utf8',
3292
 
                   # These need to be excluded until the development5 format
3293
 
                   # lands. (That's waiting on the dependent inventory and
3294
 
                   # repository changes to land.)
3295
 
                   #'bzrlib.tests.test_chk_map',
3296
2916
                   'bzrlib.tests.test_chunk_writer',
3297
 
                   'bzrlib.tests.test_clean_tree',
 
2917
                   'bzrlib.tests.test__chunks_to_lines',
3298
2918
                   'bzrlib.tests.test_commands',
3299
2919
                   'bzrlib.tests.test_commit',
3300
2920
                   'bzrlib.tests.test_commit_merge',
3309
2929
                   'bzrlib.tests.test_directory_service',
3310
2930
                   'bzrlib.tests.test_dirstate',
3311
2931
                   'bzrlib.tests.test_email_message',
3312
 
                   'bzrlib.tests.test_eol_filters',
3313
2932
                   'bzrlib.tests.test_errors',
3314
2933
                   'bzrlib.tests.test_export',
3315
2934
                   'bzrlib.tests.test_extract',
3316
2935
                   'bzrlib.tests.test_fetch',
3317
2936
                   'bzrlib.tests.test_fifo_cache',
3318
 
                   'bzrlib.tests.test_filters',
3319
2937
                   'bzrlib.tests.test_ftp_transport',
3320
2938
                   'bzrlib.tests.test_foreign',
3321
2939
                   'bzrlib.tests.test_generate_docs',
3323
2941
                   'bzrlib.tests.test_globbing',
3324
2942
                   'bzrlib.tests.test_gpg',
3325
2943
                   'bzrlib.tests.test_graph',
3326
 
                   'bzrlib.tests.test_groupcompress',
3327
2944
                   'bzrlib.tests.test_hashcache',
3328
2945
                   'bzrlib.tests.test_help',
3329
2946
                   'bzrlib.tests.test_hooks',
3336
2953
                   'bzrlib.tests.test_index',
3337
2954
                   'bzrlib.tests.test_info',
3338
2955
                   'bzrlib.tests.test_inv',
3339
 
                   'bzrlib.tests.test_inventory_delta',
3340
2956
                   'bzrlib.tests.test_knit',
3341
2957
                   'bzrlib.tests.test_lazy_import',
3342
2958
                   'bzrlib.tests.test_lazy_regex',
3371
2987
                   'bzrlib.tests.test_reconfigure',
3372
2988
                   'bzrlib.tests.test_registry',
3373
2989
                   'bzrlib.tests.test_remote',
3374
 
                   'bzrlib.tests.test_rename_map',
3375
2990
                   'bzrlib.tests.test_repository',
3376
2991
                   'bzrlib.tests.test_revert',
3377
2992
                   'bzrlib.tests.test_revision',
3381
2996
                   'bzrlib.tests.test_rules',
3382
2997
                   'bzrlib.tests.test_sampler',
3383
2998
                   'bzrlib.tests.test_selftest',
3384
 
                   'bzrlib.tests.test_serializer',
3385
2999
                   'bzrlib.tests.test_setup',
3386
3000
                   'bzrlib.tests.test_sftp_transport',
3387
3001
                   'bzrlib.tests.test_shelf',
3545
3159
    return suite
3546
3160
 
3547
3161
 
 
3162
def multiply_tests_from_modules(module_name_list, scenario_iter, loader=None):
 
3163
    """Adapt all tests in some given modules to given scenarios.
 
3164
 
 
3165
    This is the recommended public interface for test parameterization.
 
3166
    Typically the test_suite() method for a per-implementation test
 
3167
    suite will call multiply_tests_from_modules and return the
 
3168
    result.
 
3169
 
 
3170
    :param module_name_list: List of fully-qualified names of test
 
3171
        modules.
 
3172
    :param scenario_iter: Iterable of pairs of (scenario_name,
 
3173
        scenario_param_dict).
 
3174
    :param loader: If provided, will be used instead of a new
 
3175
        bzrlib.tests.TestLoader() instance.
 
3176
 
 
3177
    This returns a new TestSuite containing the cross product of
 
3178
    all the tests in all the modules, each repeated for each scenario.
 
3179
    Each test is adapted by adding the scenario name at the end
 
3180
    of its name, and updating the test object's __dict__ with the
 
3181
    scenario_param_dict.
 
3182
 
 
3183
    >>> r = multiply_tests_from_modules(
 
3184
    ...     ['bzrlib.tests.test_sampler'],
 
3185
    ...     [('one', dict(param=1)),
 
3186
    ...      ('two', dict(param=2))])
 
3187
    >>> tests = list(iter_suite_tests(r))
 
3188
    >>> len(tests)
 
3189
    2
 
3190
    >>> tests[0].id()
 
3191
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
 
3192
    >>> tests[0].param
 
3193
    1
 
3194
    >>> tests[1].param
 
3195
    2
 
3196
    """
 
3197
    # XXX: Isn't load_tests() a better way to provide the same functionality
 
3198
    # without forcing a predefined TestScenarioApplier ? --vila 080215
 
3199
    if loader is None:
 
3200
        loader = TestUtil.TestLoader()
 
3201
 
 
3202
    suite = loader.suiteClass()
 
3203
 
 
3204
    adapter = TestScenarioApplier()
 
3205
    adapter.scenarios = list(scenario_iter)
 
3206
    adapt_modules(module_name_list, adapter, loader, suite)
 
3207
    return suite
 
3208
 
 
3209
 
3548
3210
def multiply_scenarios(scenarios_left, scenarios_right):
3549
3211
    """Multiply two sets of scenarios.
3550
3212
 
3559
3221
        for right_name, right_dict in scenarios_right]
3560
3222
 
3561
3223
 
3562
 
def multiply_tests(tests, scenarios, result):
3563
 
    """Multiply tests_list by scenarios into result.
3564
 
 
3565
 
    This is the core workhorse for test parameterisation.
3566
 
 
3567
 
    Typically the load_tests() method for a per-implementation test suite will
3568
 
    call multiply_tests and return the result.
3569
 
 
3570
 
    :param tests: The tests to parameterise.
3571
 
    :param scenarios: The scenarios to apply: pairs of (scenario_name,
3572
 
        scenario_param_dict).
3573
 
    :param result: A TestSuite to add created tests to.
3574
 
 
3575
 
    This returns the passed in result TestSuite with the cross product of all
3576
 
    the tests repeated once for each scenario.  Each test is adapted by adding
3577
 
    the scenario name at the end of its id(), and updating the test object's
3578
 
    __dict__ with the scenario_param_dict.
3579
 
 
3580
 
    >>> import bzrlib.tests.test_sampler
3581
 
    >>> r = multiply_tests(
3582
 
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3583
 
    ...     [('one', dict(param=1)),
3584
 
    ...      ('two', dict(param=2))],
3585
 
    ...     TestSuite())
3586
 
    >>> tests = list(iter_suite_tests(r))
3587
 
    >>> len(tests)
3588
 
    2
3589
 
    >>> tests[0].id()
3590
 
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
3591
 
    >>> tests[0].param
3592
 
    1
3593
 
    >>> tests[1].param
3594
 
    2
3595
 
    """
3596
 
    for test in iter_suite_tests(tests):
3597
 
        apply_scenarios(test, scenarios, result)
3598
 
    return result
3599
 
 
3600
 
 
3601
 
def apply_scenarios(test, scenarios, result):
3602
 
    """Apply the scenarios in scenarios to test and add to result.
3603
 
 
3604
 
    :param test: The test to apply scenarios to.
3605
 
    :param scenarios: An iterable of scenarios to apply to test.
3606
 
    :return: result
3607
 
    :seealso: apply_scenario
3608
 
    """
3609
 
    for scenario in scenarios:
3610
 
        result.addTest(apply_scenario(test, scenario))
3611
 
    return result
3612
 
 
3613
 
 
3614
 
def apply_scenario(test, scenario):
3615
 
    """Copy test and apply scenario to it.
3616
 
 
3617
 
    :param test: A test to adapt.
3618
 
    :param scenario: A tuple describing the scenarion.
3619
 
        The first element of the tuple is the new test id.
3620
 
        The second element is a dict containing attributes to set on the
3621
 
        test.
3622
 
    :return: The adapted test.
3623
 
    """
3624
 
    new_id = "%s(%s)" % (test.id(), scenario[0])
3625
 
    new_test = clone_test(test, new_id)
3626
 
    for name, value in scenario[1].items():
3627
 
        setattr(new_test, name, value)
3628
 
    return new_test
3629
 
 
3630
 
 
3631
 
def clone_test(test, new_id):
3632
 
    """Clone a test giving it a new id.
3633
 
 
3634
 
    :param test: The test to clone.
3635
 
    :param new_id: The id to assign to it.
3636
 
    :return: The new test.
3637
 
    """
3638
 
    from copy import deepcopy
3639
 
    new_test = deepcopy(test)
3640
 
    new_test.id = lambda: new_id
3641
 
    return new_test
 
3224
 
 
3225
def adapt_modules(mods_list, adapter, loader, suite):
 
3226
    """Adapt the modules in mods_list using adapter and add to suite."""
 
3227
    tests = loader.loadTestsFromModuleNames(mods_list)
 
3228
    adapt_tests(tests, adapter, suite)
 
3229
 
 
3230
 
 
3231
def adapt_tests(tests_list, adapter, suite):
 
3232
    """Adapt the tests in tests_list using adapter and add to suite."""
 
3233
    for test in iter_suite_tests(tests_list):
 
3234
        suite.addTests(adapter.adapt(test))
3642
3235
 
3643
3236
 
3644
3237
def _rmtree_temp_dir(dirname):
3657
3250
        osutils.rmtree(dirname)
3658
3251
    except OSError, e:
3659
3252
        if sys.platform == 'win32' and e.errno == errno.EACCES:
3660
 
            sys.stderr.write('Permission denied: '
3661
 
                             'unable to remove testing dir '
3662
 
                             '%s\n%s'
3663
 
                             % (os.path.basename(dirname), e))
 
3253
            sys.stderr.write(('Permission denied: '
 
3254
                                 'unable to remove testing dir '
 
3255
                                 '%s\n' % os.path.basename(dirname)))
3664
3256
        else:
3665
3257
            raise
3666
3258
 
3750
3342
UnicodeFilenameFeature = _UnicodeFilenameFeature()
3751
3343
 
3752
3344
 
 
3345
class TestScenarioApplier(object):
 
3346
    """A tool to apply scenarios to tests."""
 
3347
 
 
3348
    def adapt(self, test):
 
3349
        """Return a TestSuite containing a copy of test for each scenario."""
 
3350
        result = unittest.TestSuite()
 
3351
        for scenario in self.scenarios:
 
3352
            result.addTest(self.adapt_test_to_scenario(test, scenario))
 
3353
        return result
 
3354
 
 
3355
    def adapt_test_to_scenario(self, test, scenario):
 
3356
        """Copy test and apply scenario to it.
 
3357
 
 
3358
        :param test: A test to adapt.
 
3359
        :param scenario: A tuple describing the scenarion.
 
3360
            The first element of the tuple is the new test id.
 
3361
            The second element is a dict containing attributes to set on the
 
3362
            test.
 
3363
        :return: The adapted test.
 
3364
        """
 
3365
        from copy import deepcopy
 
3366
        new_test = deepcopy(test)
 
3367
        for name, value in scenario[1].items():
 
3368
            setattr(new_test, name, value)
 
3369
        new_id = "%s(%s)" % (new_test.id(), scenario[0])
 
3370
        new_test.id = lambda: new_id
 
3371
        return new_test
 
3372
 
 
3373
 
3753
3374
def probe_unicode_in_user_encoding():
3754
3375
    """Try to encode several unicode strings to use in unicode-aware tests.
3755
3376
    Return first successfull match.
3783
3404
    return None
3784
3405
 
3785
3406
 
 
3407
class _FTPServerFeature(Feature):
 
3408
    """Some tests want an FTP Server, check if one is available.
 
3409
 
 
3410
    Right now, the only way this is available is if 'medusa' is installed.
 
3411
    http://www.amk.ca/python/code/medusa.html
 
3412
    """
 
3413
 
 
3414
    def _probe(self):
 
3415
        try:
 
3416
            import bzrlib.tests.ftp_server
 
3417
            return True
 
3418
        except ImportError:
 
3419
            return False
 
3420
 
 
3421
    def feature_name(self):
 
3422
        return 'FTPServer'
 
3423
 
 
3424
 
 
3425
FTPServerFeature = _FTPServerFeature()
 
3426
 
 
3427
 
3786
3428
class _HTTPSServerFeature(Feature):
3787
3429
    """Some tests want an https Server, check if one is available.
3788
3430
 
3888
3530
        return 'case-insensitive filesystem'
3889
3531
 
3890
3532
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
3891
 
 
3892
 
 
3893
 
class _SubUnitFeature(Feature):
3894
 
    """Check if subunit is available."""
3895
 
 
3896
 
    def _probe(self):
3897
 
        try:
3898
 
            import subunit
3899
 
            return True
3900
 
        except ImportError:
3901
 
            return False
3902
 
 
3903
 
    def feature_name(self):
3904
 
        return 'subunit'
3905
 
 
3906
 
SubUnitFeature = _SubUnitFeature()
3907
 
# Only define SubUnitBzrRunner if subunit is available.
3908
 
try:
3909
 
    from subunit import TestProtocolClient
3910
 
    class SubUnitBzrRunner(TextTestRunner):
3911
 
        def run(self, test):
3912
 
            # undo out claim for testing which looks like a test start to subunit
3913
 
            self.stream.write("success: %s\n" % (osutils.realpath(sys.argv[0]),))
3914
 
            result = TestProtocolClient(self.stream)
3915
 
            test.run(result)
3916
 
            return result
3917
 
except ImportError:
3918
 
    pass