/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Robert Collins
  • Date: 2009-05-23 20:57:12 UTC
  • mfrom: (4371 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4441.
  • Revision ID: robertc@robertcollins.net-20090523205712-lcwbfqk6vwavinuv
MergeĀ .dev.

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
36
37
import os
37
38
from pprint import pformat
38
39
import random
39
40
import re
40
41
import shlex
41
42
import stat
42
 
from subprocess import Popen, PIPE
 
43
from subprocess import Popen, PIPE, STDOUT
43
44
import sys
44
45
import tempfile
45
46
import threading
54
55
    debug,
55
56
    errors,
56
57
    hooks,
 
58
    lock as _mod_lock,
57
59
    memorytree,
58
60
    osutils,
59
61
    progress,
77
79
from bzrlib.merge import merge_inner
78
80
import bzrlib.merge3
79
81
import bzrlib.plugin
80
 
from bzrlib.smart import client, server
 
82
from bzrlib.smart import client, request, server
81
83
import bzrlib.store
82
84
from bzrlib import symbol_versioning
83
85
from bzrlib.symbol_versioning import (
132
134
    def __init__(self, stream, descriptions, verbosity,
133
135
                 bench_history=None,
134
136
                 num_tests=None,
 
137
                 strict=False,
135
138
                 ):
136
139
        """Construct new TestResult.
137
140
 
164
167
        self.unsupported = {}
165
168
        self.count = 0
166
169
        self._overall_start_time = time.time()
 
170
        self._strict = strict
 
171
 
 
172
    def done(self):
 
173
        if self._strict:
 
174
            ok = self.wasStrictlySuccessful()
 
175
        else:
 
176
            ok = self.wasSuccessful()
 
177
        if ok:
 
178
            self.stream.write('tests passed\n')
 
179
        else:
 
180
            self.stream.write('tests failed\n')
 
181
        if TestCase._first_thread_leaker_id:
 
182
            self.stream.write(
 
183
                '%s is leaking threads among %d leaking tests.\n' % (
 
184
                TestCase._first_thread_leaker_id,
 
185
                TestCase._leaking_threads_tests))
167
186
 
168
187
    def _extractBenchmarkTime(self, testCase):
169
188
        """Add a benchmark time for the current test case."""
195
214
 
196
215
    def startTest(self, test):
197
216
        unittest.TestResult.startTest(self, test)
 
217
        if self.count == 0:
 
218
            self.startTests()
198
219
        self.report_test_start(test)
199
220
        test.number = self.count
200
221
        self._recordTestStartTime()
201
222
 
 
223
    def startTests(self):
 
224
        self.stream.write(
 
225
            'testing: %s\n' % (osutils.realpath(sys.argv[0]),))
 
226
        self.stream.write(
 
227
            '   %s (%s python%s)\n' % (
 
228
                    bzrlib.__path__[0],
 
229
                    bzrlib.version_string,
 
230
                    bzrlib._format_version_tuple(sys.version_info),
 
231
                    ))
 
232
        self.stream.write('\n')
 
233
 
202
234
    def _recordTestStartTime(self):
203
235
        """Record that a test has started."""
204
236
        self._start_time = time.time()
348
380
                 bench_history=None,
349
381
                 num_tests=None,
350
382
                 pb=None,
 
383
                 strict=None,
351
384
                 ):
352
385
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
353
 
            bench_history, num_tests)
 
386
            bench_history, num_tests, strict)
354
387
        if pb is None:
355
388
            self.pb = self.ui.nested_progress_bar()
356
389
            self._supplied_pb = False
511
544
                 descriptions=0,
512
545
                 verbosity=1,
513
546
                 bench_history=None,
514
 
                 list_only=False
 
547
                 list_only=False,
 
548
                 strict=False,
515
549
                 ):
516
550
        self.stream = unittest._WritelnDecorator(stream)
517
551
        self.descriptions = descriptions
518
552
        self.verbosity = verbosity
519
553
        self._bench_history = bench_history
520
554
        self.list_only = list_only
 
555
        self._strict = strict
521
556
 
522
557
    def run(self, test):
523
558
        "Run the given test case or test suite."
531
566
                              self.verbosity,
532
567
                              bench_history=self._bench_history,
533
568
                              num_tests=test.countTestCases(),
 
569
                              strict=self._strict,
534
570
                              )
535
571
        result.stop_early = self.stop_on_failure
536
572
        result.report_starting()
541
577
            for t in iter_suite_tests(test):
542
578
                self.stream.writeln("%s" % (t.id()))
543
579
                run += 1
544
 
            actionTaken = "Listed"
 
580
            return None
545
581
        else:
546
 
            test.run(result)
 
582
            try:
 
583
                import testtools
 
584
            except ImportError:
 
585
                test.run(result)
 
586
            else:
 
587
                if isinstance(test, testtools.ConcurrentTestSuite):
 
588
                    # We need to catch bzr specific behaviors
 
589
                    test.run(BZRTransformingResult(result))
 
590
                else:
 
591
                    test.run(result)
547
592
            run = result.testsRun
548
593
            actionTaken = "Ran"
549
594
        stopTime = time.time()
589
634
    if isinstance(suite, unittest.TestCase):
590
635
        yield suite
591
636
    elif isinstance(suite, unittest.TestSuite):
592
 
        for item in suite._tests:
 
637
        for item in suite:
593
638
            for r in iter_suite_tests(item):
594
639
                yield r
595
640
    else:
665
710
    Allows get_password to be tested without real tty attached.
666
711
    """
667
712
 
668
 
    def __init__(self,
669
 
                 stdout=None,
670
 
                 stderr=None,
671
 
                 stdin=None):
672
 
        super(TestUIFactory, self).__init__()
 
713
    def __init__(self, stdout=None, stderr=None, stdin=None):
673
714
        if stdin is not None:
674
715
            # We use a StringIOWrapper to be able to test various
675
716
            # encodings, but the user is still responsible to
676
717
            # encode the string and to set the encoding attribute
677
718
            # of StringIOWrapper.
678
 
            self.stdin = StringIOWrapper(stdin)
679
 
        if stdout is None:
680
 
            self.stdout = sys.stdout
681
 
        else:
682
 
            self.stdout = stdout
683
 
        if stderr is None:
684
 
            self.stderr = sys.stderr
685
 
        else:
686
 
            self.stderr = stderr
 
719
            stdin = StringIOWrapper(stdin)
 
720
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
687
721
 
688
722
    def clear(self):
689
723
        """See progress.ProgressBar.clear()."""
691
725
    def clear_term(self):
692
726
        """See progress.ProgressBar.clear_term()."""
693
727
 
694
 
    def clear_term(self):
695
 
        """See progress.ProgressBar.clear_term()."""
696
 
 
697
728
    def finished(self):
698
729
        """See progress.ProgressBar.finished()."""
699
730
 
710
741
    def update(self, message, count=None, total=None):
711
742
        """See progress.ProgressBar.update()."""
712
743
 
713
 
    def get_non_echoed_password(self, prompt):
 
744
    def get_non_echoed_password(self):
714
745
        """Get password from stdin without trying to handle the echo mode"""
715
 
        if prompt:
716
 
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
717
746
        password = self.stdin.readline()
718
747
        if not password:
719
748
            raise EOFError
722
751
        return password
723
752
 
724
753
 
725
 
def _report_leaked_threads():
726
 
    bzrlib.trace.warning('%s is leaking threads among %d leaking tests',
727
 
                         TestCase._first_thread_leaker_id,
728
 
                         TestCase._leaking_threads_tests)
729
 
 
730
 
 
731
754
class TestCase(unittest.TestCase):
732
755
    """Base class for bzr unit tests.
733
756
 
759
782
    _gather_lsprof_in_benchmarks = False
760
783
    attrs_to_keep = ('id', '_testMethodName', '_testMethodDoc',
761
784
                     '_log_contents', '_log_file_name', '_benchtime',
762
 
                     '_TestCase__testMethodName')
 
785
                     '_TestCase__testMethodName', '_TestCase__testMethodDoc',)
763
786
 
764
787
    def __init__(self, methodName='testMethod'):
765
788
        super(TestCase, self).__init__(methodName)
766
789
        self._cleanups = []
 
790
        self._bzr_test_setUp_run = False
 
791
        self._bzr_test_tearDown_run = False
767
792
 
768
793
    def setUp(self):
769
794
        unittest.TestCase.setUp(self)
 
795
        self._bzr_test_setUp_run = True
770
796
        self._cleanEnvironment()
771
797
        self._silenceUI()
772
798
        self._startLogFile()
773
799
        self._benchcalls = []
774
800
        self._benchtime = None
775
801
        self._clear_hooks()
 
802
        # Track locks - needs to be called before _clear_debug_flags.
 
803
        self._track_locks()
776
804
        self._clear_debug_flags()
777
805
        TestCase._active_threads = threading.activeCount()
778
806
        self.addCleanup(self._check_leaked_threads)
782
810
        import pdb
783
811
        pdb.Pdb().set_trace(sys._getframe().f_back)
784
812
 
785
 
    def exc_info(self):
786
 
        absent_attr = object()
787
 
        exc_info = getattr(self, '_exc_info', absent_attr)
788
 
        if exc_info is absent_attr:
789
 
            exc_info = getattr(self, '_TestCase__exc_info')
790
 
        return exc_info()
791
 
 
792
813
    def _check_leaked_threads(self):
793
814
        active = threading.activeCount()
794
815
        leaked_threads = active - TestCase._active_threads
797
818
            TestCase._leaking_threads_tests += 1
798
819
            if TestCase._first_thread_leaker_id is None:
799
820
                TestCase._first_thread_leaker_id = self.id()
800
 
                # we're not specifically told when all tests are finished.
801
 
                # This will do. We use a function to avoid keeping a reference
802
 
                # to a TestCase object.
803
 
                atexit.register(_report_leaked_threads)
804
821
 
805
822
    def _clear_debug_flags(self):
806
823
        """Prevent externally set debug flags affecting tests.
824
841
        for key, factory in hooks.known_hooks.items():
825
842
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
826
843
            setattr(parent, name, factory())
 
844
        # this hook should always be installed
 
845
        request._install_hook()
827
846
 
828
847
    def _silenceUI(self):
829
848
        """Turn off UI for duration of test"""
834
853
        ui.ui_factory = ui.SilentUIFactory()
835
854
        self.addCleanup(_restore)
836
855
 
 
856
    def _check_locks(self):
 
857
        """Check that all lock take/release actions have been paired."""
 
858
        # once we have fixed all the current lock problems, we can change the
 
859
        # following code to always check for mismatched locks, but only do
 
860
        # traceback showing with -Dlock (self._lock_check_thorough is True).
 
861
        # For now, because the test suite will fail, we only assert that lock
 
862
        # matching has occured with -Dlock.
 
863
        # unhook:
 
864
        acquired_locks = [lock for action, lock in self._lock_actions
 
865
                          if action == 'acquired']
 
866
        released_locks = [lock for action, lock in self._lock_actions
 
867
                          if action == 'released']
 
868
        broken_locks = [lock for action, lock in self._lock_actions
 
869
                        if action == 'broken']
 
870
        # trivially, given the tests for lock acquistion and release, if we
 
871
        # have as many in each list, it should be ok. Some lock tests also
 
872
        # break some locks on purpose and should be taken into account by
 
873
        # considering that breaking a lock is just a dirty way of releasing it.
 
874
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
 
875
            message = ('Different number of acquired and '
 
876
                       'released or broken locks. (%s, %s + %s)' %
 
877
                       (acquired_locks, released_locks, broken_locks))
 
878
            if not self._lock_check_thorough:
 
879
                # Rather than fail, just warn
 
880
                print "Broken test %s: %s" % (self, message)
 
881
                return
 
882
            self.fail(message)
 
883
 
 
884
    def _track_locks(self):
 
885
        """Track lock activity during tests."""
 
886
        self._lock_actions = []
 
887
        self._lock_check_thorough = 'lock' not in debug.debug_flags
 
888
        self.addCleanup(self._check_locks)
 
889
        _mod_lock.Lock.hooks.install_named_hook('lock_acquired',
 
890
                                                self._lock_acquired, None)
 
891
        _mod_lock.Lock.hooks.install_named_hook('lock_released',
 
892
                                                self._lock_released, None)
 
893
        _mod_lock.Lock.hooks.install_named_hook('lock_broken',
 
894
                                                self._lock_broken, None)
 
895
 
 
896
    def _lock_acquired(self, result):
 
897
        self._lock_actions.append(('acquired', result))
 
898
 
 
899
    def _lock_released(self, result):
 
900
        self._lock_actions.append(('released', result))
 
901
 
 
902
    def _lock_broken(self, result):
 
903
        self._lock_actions.append(('broken', result))
 
904
 
837
905
    def _ndiff_strings(self, a, b):
838
906
        """Return ndiff between two strings containing lines.
839
907
 
902
970
        self.assertEqual(expected.st_ino, actual.st_ino)
903
971
        self.assertEqual(expected.st_mode, actual.st_mode)
904
972
 
 
973
    def assertLength(self, length, obj_with_len):
 
974
        """Assert that obj_with_len is of length length."""
 
975
        if len(obj_with_len) != length:
 
976
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
 
977
                length, len(obj_with_len), obj_with_len))
 
978
 
905
979
    def assertPositive(self, val):
906
980
        """Assert that val is greater than 0."""
907
981
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
999
1073
                raise AssertionError("%r is %r." % (left, right))
1000
1074
 
1001
1075
    def assertTransportMode(self, transport, path, mode):
1002
 
        """Fail if a path does not have mode mode.
 
1076
        """Fail if a path does not have mode "mode".
1003
1077
 
1004
1078
        If modes are not supported on this transport, the assertion is ignored.
1005
1079
        """
1008
1082
        path_stat = transport.stat(path)
1009
1083
        actual_mode = stat.S_IMODE(path_stat.st_mode)
1010
1084
        self.assertEqual(mode, actual_mode,
1011
 
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
 
1085
                         'mode of %r incorrect (%s != %s)'
 
1086
                         % (path, oct(mode), oct(actual_mode)))
1012
1087
 
1013
1088
    def assertIsSameRealPath(self, path1, path2):
1014
1089
        """Fail if path1 and path2 points to different files"""
1240
1315
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1241
1316
            # tests do check our impls match APPDATA
1242
1317
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1318
            'VISUAL': None,
 
1319
            'EDITOR': None,
1243
1320
            'BZR_EMAIL': None,
1244
1321
            'BZREMAIL': None, # may still be present in the environment
1245
1322
            'EMAIL': None,
1257
1334
            'NO_PROXY': None,
1258
1335
            'all_proxy': None,
1259
1336
            'ALL_PROXY': None,
1260
 
            # Nobody cares about these ones AFAIK. So far at
 
1337
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1261
1338
            # least. If you do (care), please update this comment
1262
 
            # -- vila 20061212
 
1339
            # -- vila 20080401
1263
1340
            'ftp_proxy': None,
1264
1341
            'FTP_PROXY': None,
1265
1342
            'BZR_REMOTE_PATH': None,
1292
1369
    def _do_skip(self, result, reason):
1293
1370
        addSkip = getattr(result, 'addSkip', None)
1294
1371
        if not callable(addSkip):
1295
 
            result.addError(self, self.exc_info())
 
1372
            result.addError(self, sys.exc_info())
1296
1373
        else:
1297
1374
            addSkip(self, reason)
1298
1375
 
1306
1383
                else:
1307
1384
                    result.addSuccess(self)
1308
1385
                result.stopTest(self)
1309
 
                return
 
1386
                return result
1310
1387
        try:
1311
1388
            try:
1312
1389
                result.startTest(self)
1320
1397
                try:
1321
1398
                    try:
1322
1399
                        self.setUp()
 
1400
                        if not self._bzr_test_setUp_run:
 
1401
                            self.fail(
 
1402
                                "test setUp did not invoke "
 
1403
                                "bzrlib.tests.TestCase's setUp")
1323
1404
                    except KeyboardInterrupt:
 
1405
                        self._runCleanups()
1324
1406
                        raise
1325
1407
                    except TestSkipped, e:
1326
1408
                        self._do_skip(result, e.args[0])
1327
1409
                        self.tearDown()
1328
 
                        return
 
1410
                        return result
1329
1411
                    except:
1330
 
                        result.addError(self, self.exc_info())
1331
 
                        return
 
1412
                        result.addError(self, sys.exc_info())
 
1413
                        self._runCleanups()
 
1414
                        return result
1332
1415
 
1333
1416
                    ok = False
1334
1417
                    try:
1335
1418
                        testMethod()
1336
1419
                        ok = True
1337
1420
                    except self.failureException:
1338
 
                        result.addFailure(self, self.exc_info())
 
1421
                        result.addFailure(self, sys.exc_info())
1339
1422
                    except TestSkipped, e:
1340
1423
                        if not e.args:
1341
1424
                            reason = "No reason given."
1343
1426
                            reason = e.args[0]
1344
1427
                        self._do_skip(result, reason)
1345
1428
                    except KeyboardInterrupt:
 
1429
                        self._runCleanups()
1346
1430
                        raise
1347
1431
                    except:
1348
 
                        result.addError(self, self.exc_info())
 
1432
                        result.addError(self, sys.exc_info())
1349
1433
 
1350
1434
                    try:
1351
1435
                        self.tearDown()
 
1436
                        if not self._bzr_test_tearDown_run:
 
1437
                            self.fail(
 
1438
                                "test tearDown did not invoke "
 
1439
                                "bzrlib.tests.TestCase's tearDown")
1352
1440
                    except KeyboardInterrupt:
 
1441
                        self._runCleanups()
1353
1442
                        raise
1354
1443
                    except:
1355
 
                        result.addError(self, self.exc_info())
 
1444
                        result.addError(self, sys.exc_info())
 
1445
                        self._runCleanups()
1356
1446
                        ok = False
1357
1447
                    if ok: result.addSuccess(self)
1358
1448
                finally:
1359
1449
                    result.stopTest(self)
1360
 
                return
 
1450
                return result
1361
1451
            except TestNotApplicable:
1362
1452
                # Not moved from the result [yet].
 
1453
                self._runCleanups()
1363
1454
                raise
1364
1455
            except KeyboardInterrupt:
 
1456
                self._runCleanups()
1365
1457
                raise
1366
1458
        finally:
1367
1459
            saved_attrs = {}
1368
 
            absent_attr = object()
1369
1460
            for attr_name in self.attrs_to_keep:
1370
 
                attr = getattr(self, attr_name, absent_attr)
1371
 
                if attr is not absent_attr:
1372
 
                    saved_attrs[attr_name] = attr
 
1461
                if attr_name in self.__dict__:
 
1462
                    saved_attrs[attr_name] = self.__dict__[attr_name]
1373
1463
            self.__dict__ = saved_attrs
1374
1464
 
1375
1465
    def tearDown(self):
1376
1466
        self._runCleanups()
1377
1467
        self._log_contents = ''
 
1468
        self._bzr_test_tearDown_run = True
1378
1469
        unittest.TestCase.tearDown(self)
1379
1470
 
1380
1471
    def time(self, callable, *args, **kwargs):
1557
1648
            stdin=stdin,
1558
1649
            working_dir=working_dir,
1559
1650
            )
 
1651
        self.assertIsInstance(error_regexes, (list, tuple))
1560
1652
        for regex in error_regexes:
1561
1653
            self.assertContainsRe(err, regex)
1562
1654
        return out, err
2107
2199
        made_control = self.make_bzrdir(relpath, format=format)
2108
2200
        return made_control.create_repository(shared=shared)
2109
2201
 
 
2202
    def make_smart_server(self, path):
 
2203
        smart_server = server.SmartTCPServer_for_testing()
 
2204
        smart_server.setUp(self.get_server())
 
2205
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2206
        self.addCleanup(smart_server.tearDown)
 
2207
        return remote_transport
 
2208
 
2110
2209
    def make_branch_and_memory_tree(self, relpath, format=None):
2111
2210
        """Create a branch on the default transport and a MemoryTree for it."""
2112
2211
        b = self.make_branch(relpath, format=format)
2113
2212
        return memorytree.MemoryTree.create_on_branch(b)
2114
2213
 
2115
2214
    def make_branch_builder(self, relpath, format=None):
2116
 
        return branchbuilder.BranchBuilder(self.get_transport(relpath),
2117
 
            format=format)
 
2215
        branch = self.make_branch(relpath, format=format)
 
2216
        return branchbuilder.BranchBuilder(branch=branch)
2118
2217
 
2119
2218
    def overrideEnvironmentForTesting(self):
2120
2219
        os.environ['HOME'] = self.test_home_dir
2197
2296
        For TestCaseInTempDir we create a temporary directory based on the test
2198
2297
        name and then create two subdirs - test and home under it.
2199
2298
        """
2200
 
        name_prefix = osutils.pathjoin(self.TEST_ROOT, self._getTestDirPrefix())
 
2299
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
 
2300
            self._getTestDirPrefix())
2201
2301
        name = name_prefix
2202
2302
        for i in range(100):
2203
2303
            if os.path.exists(name):
2221
2321
        self.addCleanup(self.deleteTestDir)
2222
2322
 
2223
2323
    def deleteTestDir(self):
2224
 
        os.chdir(self.TEST_ROOT)
 
2324
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2225
2325
        _rmtree_temp_dir(self.test_base_dir)
2226
2326
 
2227
2327
    def build_tree(self, shape, line_endings='binary', transport=None):
2406
2506
    :param pattern: A regular expression string.
2407
2507
    :return: A callable that returns True if the re matches.
2408
2508
    """
2409
 
    filter_re = re.compile(pattern)
 
2509
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2510
        'test filter')
2410
2511
    def condition(test):
2411
2512
        test_id = test.id()
2412
2513
        return filter_re.search(test_id)
2597
2698
              random_seed=None,
2598
2699
              exclude_pattern=None,
2599
2700
              strict=False,
2600
 
              runner_class=None):
 
2701
              runner_class=None,
 
2702
              suite_decorators=None,
 
2703
              stream=None):
2601
2704
    """Run a test suite for bzr selftest.
2602
2705
 
2603
2706
    :param runner_class: The class of runner to use. Must support the
2612
2715
        verbosity = 1
2613
2716
    if runner_class is None:
2614
2717
        runner_class = TextTestRunner
2615
 
    runner = runner_class(stream=sys.stdout,
 
2718
    if stream is None:
 
2719
        stream = sys.stdout
 
2720
    runner = runner_class(stream=stream,
2616
2721
                            descriptions=0,
2617
2722
                            verbosity=verbosity,
2618
2723
                            bench_history=bench_history,
2619
2724
                            list_only=list_only,
 
2725
                            strict=strict,
2620
2726
                            )
2621
2727
    runner.stop_on_failure=stop_on_failure
2622
 
    # Initialise the random number generator and display the seed used.
2623
 
    # We convert the seed to a long to make it reuseable across invocations.
2624
 
    random_order = False
2625
 
    if random_seed is not None:
2626
 
        random_order = True
2627
 
        if random_seed == "now":
2628
 
            random_seed = long(time.time())
 
2728
    # built in decorator factories:
 
2729
    decorators = [
 
2730
        random_order(random_seed, runner),
 
2731
        exclude_tests(exclude_pattern),
 
2732
        ]
 
2733
    if matching_tests_first:
 
2734
        decorators.append(tests_first(pattern))
 
2735
    else:
 
2736
        decorators.append(filter_tests(pattern))
 
2737
    if suite_decorators:
 
2738
        decorators.extend(suite_decorators)
 
2739
    for decorator in decorators:
 
2740
        suite = decorator(suite)
 
2741
    result = runner.run(suite)
 
2742
    if list_only:
 
2743
        return True
 
2744
    result.done()
 
2745
    if strict:
 
2746
        return result.wasStrictlySuccessful()
 
2747
    else:
 
2748
        return result.wasSuccessful()
 
2749
 
 
2750
 
 
2751
# A registry where get() returns a suite decorator.
 
2752
parallel_registry = registry.Registry()
 
2753
 
 
2754
 
 
2755
def fork_decorator(suite):
 
2756
    concurrency = local_concurrency()
 
2757
    if concurrency == 1:
 
2758
        return suite
 
2759
    from testtools import ConcurrentTestSuite
 
2760
    return ConcurrentTestSuite(suite, fork_for_tests)
 
2761
parallel_registry.register('fork', fork_decorator)
 
2762
 
 
2763
 
 
2764
def subprocess_decorator(suite):
 
2765
    concurrency = local_concurrency()
 
2766
    if concurrency == 1:
 
2767
        return suite
 
2768
    from testtools import ConcurrentTestSuite
 
2769
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
 
2770
parallel_registry.register('subprocess', subprocess_decorator)
 
2771
 
 
2772
 
 
2773
def exclude_tests(exclude_pattern):
 
2774
    """Return a test suite decorator that excludes tests."""
 
2775
    if exclude_pattern is None:
 
2776
        return identity_decorator
 
2777
    def decorator(suite):
 
2778
        return ExcludeDecorator(suite, exclude_pattern)
 
2779
    return decorator
 
2780
 
 
2781
 
 
2782
def filter_tests(pattern):
 
2783
    if pattern == '.*':
 
2784
        return identity_decorator
 
2785
    def decorator(suite):
 
2786
        return FilterTestsDecorator(suite, pattern)
 
2787
    return decorator
 
2788
 
 
2789
 
 
2790
def random_order(random_seed, runner):
 
2791
    """Return a test suite decorator factory for randomising tests order.
 
2792
    
 
2793
    :param random_seed: now, a string which casts to a long, or a long.
 
2794
    :param runner: A test runner with a stream attribute to report on.
 
2795
    """
 
2796
    if random_seed is None:
 
2797
        return identity_decorator
 
2798
    def decorator(suite):
 
2799
        return RandomDecorator(suite, random_seed, runner.stream)
 
2800
    return decorator
 
2801
 
 
2802
 
 
2803
def tests_first(pattern):
 
2804
    if pattern == '.*':
 
2805
        return identity_decorator
 
2806
    def decorator(suite):
 
2807
        return TestFirstDecorator(suite, pattern)
 
2808
    return decorator
 
2809
 
 
2810
 
 
2811
def identity_decorator(suite):
 
2812
    """Return suite."""
 
2813
    return suite
 
2814
 
 
2815
 
 
2816
class TestDecorator(TestSuite):
 
2817
    """A decorator for TestCase/TestSuite objects.
 
2818
    
 
2819
    Usually, subclasses should override __iter__(used when flattening test
 
2820
    suites), which we do to filter, reorder, parallelise and so on, run() and
 
2821
    debug().
 
2822
    """
 
2823
 
 
2824
    def __init__(self, suite):
 
2825
        TestSuite.__init__(self)
 
2826
        self.addTest(suite)
 
2827
 
 
2828
    def countTestCases(self):
 
2829
        cases = 0
 
2830
        for test in self:
 
2831
            cases += test.countTestCases()
 
2832
        return cases
 
2833
 
 
2834
    def debug(self):
 
2835
        for test in self:
 
2836
            test.debug()
 
2837
 
 
2838
    def run(self, result):
 
2839
        # Use iteration on self, not self._tests, to allow subclasses to hook
 
2840
        # into __iter__.
 
2841
        for test in self:
 
2842
            if result.shouldStop:
 
2843
                break
 
2844
            test.run(result)
 
2845
        return result
 
2846
 
 
2847
 
 
2848
class ExcludeDecorator(TestDecorator):
 
2849
    """A decorator which excludes test matching an exclude pattern."""
 
2850
 
 
2851
    def __init__(self, suite, exclude_pattern):
 
2852
        TestDecorator.__init__(self, suite)
 
2853
        self.exclude_pattern = exclude_pattern
 
2854
        self.excluded = False
 
2855
 
 
2856
    def __iter__(self):
 
2857
        if self.excluded:
 
2858
            return iter(self._tests)
 
2859
        self.excluded = True
 
2860
        suite = exclude_tests_by_re(self, self.exclude_pattern)
 
2861
        del self._tests[:]
 
2862
        self.addTests(suite)
 
2863
        return iter(self._tests)
 
2864
 
 
2865
 
 
2866
class FilterTestsDecorator(TestDecorator):
 
2867
    """A decorator which filters tests to those matching a pattern."""
 
2868
 
 
2869
    def __init__(self, suite, pattern):
 
2870
        TestDecorator.__init__(self, suite)
 
2871
        self.pattern = pattern
 
2872
        self.filtered = False
 
2873
 
 
2874
    def __iter__(self):
 
2875
        if self.filtered:
 
2876
            return iter(self._tests)
 
2877
        self.filtered = True
 
2878
        suite = filter_suite_by_re(self, self.pattern)
 
2879
        del self._tests[:]
 
2880
        self.addTests(suite)
 
2881
        return iter(self._tests)
 
2882
 
 
2883
 
 
2884
class RandomDecorator(TestDecorator):
 
2885
    """A decorator which randomises the order of its tests."""
 
2886
 
 
2887
    def __init__(self, suite, random_seed, stream):
 
2888
        TestDecorator.__init__(self, suite)
 
2889
        self.random_seed = random_seed
 
2890
        self.randomised = False
 
2891
        self.stream = stream
 
2892
 
 
2893
    def __iter__(self):
 
2894
        if self.randomised:
 
2895
            return iter(self._tests)
 
2896
        self.randomised = True
 
2897
        self.stream.writeln("Randomizing test order using seed %s\n" %
 
2898
            (self.actual_seed()))
 
2899
        # Initialise the random number generator.
 
2900
        random.seed(self.actual_seed())
 
2901
        suite = randomize_suite(self)
 
2902
        del self._tests[:]
 
2903
        self.addTests(suite)
 
2904
        return iter(self._tests)
 
2905
 
 
2906
    def actual_seed(self):
 
2907
        if self.random_seed == "now":
 
2908
            # We convert the seed to a long to make it reuseable across
 
2909
            # invocations (because the user can reenter it).
 
2910
            self.random_seed = long(time.time())
2629
2911
        else:
2630
2912
            # Convert the seed to a long if we can
2631
2913
            try:
2632
 
                random_seed = long(random_seed)
 
2914
                self.random_seed = long(self.random_seed)
2633
2915
            except:
2634
2916
                pass
2635
 
        runner.stream.writeln("Randomizing test order using seed %s\n" %
2636
 
            (random_seed))
2637
 
        random.seed(random_seed)
2638
 
    # Customise the list of tests if requested
2639
 
    if exclude_pattern is not None:
2640
 
        suite = exclude_tests_by_re(suite, exclude_pattern)
2641
 
    if random_order:
2642
 
        order_changer = randomize_suite
2643
 
    else:
2644
 
        order_changer = preserve_input
2645
 
    if pattern != '.*' or random_order:
2646
 
        if matching_tests_first:
2647
 
            suites = map(order_changer, split_suite_by_re(suite, pattern))
2648
 
            suite = TestUtil.TestSuite(suites)
2649
 
        else:
2650
 
            suite = order_changer(filter_suite_by_re(suite, pattern))
2651
 
 
2652
 
    result = runner.run(suite)
2653
 
 
2654
 
    if strict:
2655
 
        return result.wasStrictlySuccessful()
2656
 
 
2657
 
    return result.wasSuccessful()
 
2917
        return self.random_seed
 
2918
 
 
2919
 
 
2920
class TestFirstDecorator(TestDecorator):
 
2921
    """A decorator which moves named tests to the front."""
 
2922
 
 
2923
    def __init__(self, suite, pattern):
 
2924
        TestDecorator.__init__(self, suite)
 
2925
        self.pattern = pattern
 
2926
        self.filtered = False
 
2927
 
 
2928
    def __iter__(self):
 
2929
        if self.filtered:
 
2930
            return iter(self._tests)
 
2931
        self.filtered = True
 
2932
        suites = split_suite_by_re(self, self.pattern)
 
2933
        del self._tests[:]
 
2934
        self.addTests(suites)
 
2935
        return iter(self._tests)
 
2936
 
 
2937
 
 
2938
def partition_tests(suite, count):
 
2939
    """Partition suite into count lists of tests."""
 
2940
    result = []
 
2941
    tests = list(iter_suite_tests(suite))
 
2942
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
2943
    for block in range(count):
 
2944
        low_test = block * tests_per_process
 
2945
        high_test = low_test + tests_per_process
 
2946
        process_tests = tests[low_test:high_test]
 
2947
        result.append(process_tests)
 
2948
    return result
 
2949
 
 
2950
 
 
2951
def fork_for_tests(suite):
 
2952
    """Take suite and start up one runner per CPU by forking()
 
2953
 
 
2954
    :return: An iterable of TestCase-like objects which can each have
 
2955
        run(result) called on them to feed tests to result.
 
2956
    """
 
2957
    concurrency = local_concurrency()
 
2958
    result = []
 
2959
    from subunit import TestProtocolClient, ProtocolTestCase
 
2960
    class TestInOtherProcess(ProtocolTestCase):
 
2961
        # Should be in subunit, I think. RBC.
 
2962
        def __init__(self, stream, pid):
 
2963
            ProtocolTestCase.__init__(self, stream)
 
2964
            self.pid = pid
 
2965
 
 
2966
        def run(self, result):
 
2967
            try:
 
2968
                ProtocolTestCase.run(self, result)
 
2969
            finally:
 
2970
                os.waitpid(self.pid, os.WNOHANG)
 
2971
 
 
2972
    test_blocks = partition_tests(suite, concurrency)
 
2973
    for process_tests in test_blocks:
 
2974
        process_suite = TestSuite()
 
2975
        process_suite.addTests(process_tests)
 
2976
        c2pread, c2pwrite = os.pipe()
 
2977
        pid = os.fork()
 
2978
        if pid == 0:
 
2979
            try:
 
2980
                os.close(c2pread)
 
2981
                # Leave stderr and stdout open so we can see test noise
 
2982
                # Close stdin so that the child goes away if it decides to
 
2983
                # read from stdin (otherwise its a roulette to see what
 
2984
                # child actually gets keystrokes for pdb etc).
 
2985
                sys.stdin.close()
 
2986
                sys.stdin = None
 
2987
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
2988
                subunit_result = TestProtocolClient(stream)
 
2989
                process_suite.run(subunit_result)
 
2990
            finally:
 
2991
                os._exit(0)
 
2992
        else:
 
2993
            os.close(c2pwrite)
 
2994
            stream = os.fdopen(c2pread, 'rb', 1)
 
2995
            test = TestInOtherProcess(stream, pid)
 
2996
            result.append(test)
 
2997
    return result
 
2998
 
 
2999
 
 
3000
def reinvoke_for_tests(suite):
 
3001
    """Take suite and start up one runner per CPU using subprocess().
 
3002
 
 
3003
    :return: An iterable of TestCase-like objects which can each have
 
3004
        run(result) called on them to feed tests to result.
 
3005
    """
 
3006
    concurrency = local_concurrency()
 
3007
    result = []
 
3008
    from subunit import TestProtocolClient, ProtocolTestCase
 
3009
    class TestInSubprocess(ProtocolTestCase):
 
3010
        def __init__(self, process, name):
 
3011
            ProtocolTestCase.__init__(self, process.stdout)
 
3012
            self.process = process
 
3013
            self.process.stdin.close()
 
3014
            self.name = name
 
3015
 
 
3016
        def run(self, result):
 
3017
            try:
 
3018
                ProtocolTestCase.run(self, result)
 
3019
            finally:
 
3020
                self.process.wait()
 
3021
                os.unlink(self.name)
 
3022
            # print "pid %d finished" % finished_process
 
3023
    test_blocks = partition_tests(suite, concurrency)
 
3024
    for process_tests in test_blocks:
 
3025
        # ugly; currently reimplement rather than reuses TestCase methods.
 
3026
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
3027
        if not os.path.isfile(bzr_path):
 
3028
            # We are probably installed. Assume sys.argv is the right file
 
3029
            bzr_path = sys.argv[0]
 
3030
        fd, test_list_file_name = tempfile.mkstemp()
 
3031
        test_list_file = os.fdopen(fd, 'wb', 1)
 
3032
        for test in process_tests:
 
3033
            test_list_file.write(test.id() + '\n')
 
3034
        test_list_file.close()
 
3035
        try:
 
3036
            argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
 
3037
                '--subunit']
 
3038
            if '--no-plugins' in sys.argv:
 
3039
                argv.append('--no-plugins')
 
3040
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
3041
            # stderr it can interrupt the subunit protocol.
 
3042
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
3043
                bufsize=1)
 
3044
            test = TestInSubprocess(process, test_list_file_name)
 
3045
            result.append(test)
 
3046
        except:
 
3047
            os.unlink(test_list_file_name)
 
3048
            raise
 
3049
    return result
 
3050
 
 
3051
 
 
3052
def cpucount(content):
 
3053
    lines = content.splitlines()
 
3054
    prefix = 'processor'
 
3055
    for line in lines:
 
3056
        if line.startswith(prefix):
 
3057
            concurrency = int(line[line.find(':')+1:]) + 1
 
3058
    return concurrency
 
3059
 
 
3060
 
 
3061
def local_concurrency():
 
3062
    try:
 
3063
        content = file('/proc/cpuinfo', 'rb').read()
 
3064
        concurrency = cpucount(content)
 
3065
    except Exception, e:
 
3066
        concurrency = 1
 
3067
    return concurrency
 
3068
 
 
3069
 
 
3070
class BZRTransformingResult(unittest.TestResult):
 
3071
 
 
3072
    def __init__(self, target):
 
3073
        unittest.TestResult.__init__(self)
 
3074
        self.result = target
 
3075
 
 
3076
    def startTest(self, test):
 
3077
        self.result.startTest(test)
 
3078
 
 
3079
    def stopTest(self, test):
 
3080
        self.result.stopTest(test)
 
3081
 
 
3082
    def addError(self, test, err):
 
3083
        feature = self._error_looks_like('UnavailableFeature: ', err)
 
3084
        if feature is not None:
 
3085
            self.result.addNotSupported(test, feature)
 
3086
        else:
 
3087
            self.result.addError(test, err)
 
3088
 
 
3089
    def addFailure(self, test, err):
 
3090
        known = self._error_looks_like('KnownFailure: ', err)
 
3091
        if known is not None:
 
3092
            self.result._addKnownFailure(test, [KnownFailure,
 
3093
                                                KnownFailure(known), None])
 
3094
        else:
 
3095
            self.result.addFailure(test, err)
 
3096
 
 
3097
    def addSkip(self, test, reason):
 
3098
        self.result.addSkip(test, reason)
 
3099
 
 
3100
    def addSuccess(self, test):
 
3101
        self.result.addSuccess(test)
 
3102
 
 
3103
    def _error_looks_like(self, prefix, err):
 
3104
        """Deserialize exception and returns the stringify value."""
 
3105
        import subunit
 
3106
        value = None
 
3107
        typ, exc, _ = err
 
3108
        if isinstance(exc, subunit.RemoteException):
 
3109
            # stringify the exception gives access to the remote traceback
 
3110
            # We search the last line for 'prefix'
 
3111
            lines = str(exc).split('\n')
 
3112
            while lines and not lines[-1]:
 
3113
                lines.pop(-1)
 
3114
            if lines:
 
3115
                if lines[-1].startswith(prefix):
 
3116
                    value = lines[-1][len(prefix):]
 
3117
        return value
2658
3118
 
2659
3119
 
2660
3120
# Controlled by "bzr selftest -E=..." option
2675
3135
             debug_flags=None,
2676
3136
             starting_with=None,
2677
3137
             runner_class=None,
 
3138
             suite_decorators=None,
2678
3139
             ):
2679
3140
    """Run the whole test suite under the enhanced runner"""
2680
3141
    # XXX: Very ugly way to do this...
2712
3173
                     exclude_pattern=exclude_pattern,
2713
3174
                     strict=strict,
2714
3175
                     runner_class=runner_class,
 
3176
                     suite_decorators=suite_decorators,
2715
3177
                     )
2716
3178
    finally:
2717
3179
        default_transport = old_transport
2896
3358
                   'bzrlib.tests.per_interbranch',
2897
3359
                   'bzrlib.tests.per_lock',
2898
3360
                   'bzrlib.tests.per_repository',
 
3361
                   'bzrlib.tests.per_repository_chk',
2899
3362
                   'bzrlib.tests.per_repository_reference',
 
3363
                   'bzrlib.tests.test__chk_map',
2900
3364
                   'bzrlib.tests.test__dirstate_helpers',
 
3365
                   'bzrlib.tests.test__groupcompress',
 
3366
                   'bzrlib.tests.test__rio',
2901
3367
                   'bzrlib.tests.test__walkdirs_win32',
2902
3368
                   'bzrlib.tests.test_ancestry',
2903
3369
                   'bzrlib.tests.test_annotate',
2911
3377
                   'bzrlib.tests.test_bugtracker',
2912
3378
                   'bzrlib.tests.test_bundle',
2913
3379
                   'bzrlib.tests.test_bzrdir',
 
3380
                   'bzrlib.tests.test__chunks_to_lines',
2914
3381
                   'bzrlib.tests.test_cache_utf8',
 
3382
                   'bzrlib.tests.test_chk_map',
 
3383
                   'bzrlib.tests.test_chunk_writer',
2915
3384
                   'bzrlib.tests.test_clean_tree',
2916
 
                   'bzrlib.tests.test_chunk_writer',
2917
 
                   'bzrlib.tests.test__chunks_to_lines',
2918
3385
                   'bzrlib.tests.test_commands',
2919
3386
                   'bzrlib.tests.test_commit',
2920
3387
                   'bzrlib.tests.test_commit_merge',
2929
3396
                   'bzrlib.tests.test_directory_service',
2930
3397
                   'bzrlib.tests.test_dirstate',
2931
3398
                   'bzrlib.tests.test_email_message',
 
3399
                   'bzrlib.tests.test_eol_filters',
2932
3400
                   'bzrlib.tests.test_errors',
2933
3401
                   'bzrlib.tests.test_export',
2934
3402
                   'bzrlib.tests.test_extract',
2935
3403
                   'bzrlib.tests.test_fetch',
2936
3404
                   'bzrlib.tests.test_fifo_cache',
 
3405
                   'bzrlib.tests.test_filters',
2937
3406
                   'bzrlib.tests.test_ftp_transport',
2938
3407
                   'bzrlib.tests.test_foreign',
2939
3408
                   'bzrlib.tests.test_generate_docs',
2941
3410
                   'bzrlib.tests.test_globbing',
2942
3411
                   'bzrlib.tests.test_gpg',
2943
3412
                   'bzrlib.tests.test_graph',
 
3413
                   'bzrlib.tests.test_groupcompress',
2944
3414
                   'bzrlib.tests.test_hashcache',
2945
3415
                   'bzrlib.tests.test_help',
2946
3416
                   'bzrlib.tests.test_hooks',
2947
3417
                   'bzrlib.tests.test_http',
2948
 
                   'bzrlib.tests.test_http_implementations',
2949
3418
                   'bzrlib.tests.test_http_response',
2950
3419
                   'bzrlib.tests.test_https_ca_bundle',
2951
3420
                   'bzrlib.tests.test_identitymap',
2953
3422
                   'bzrlib.tests.test_index',
2954
3423
                   'bzrlib.tests.test_info',
2955
3424
                   'bzrlib.tests.test_inv',
 
3425
                   'bzrlib.tests.test_inventory_delta',
2956
3426
                   'bzrlib.tests.test_knit',
2957
3427
                   'bzrlib.tests.test_lazy_import',
2958
3428
                   'bzrlib.tests.test_lazy_regex',
2987
3457
                   'bzrlib.tests.test_reconfigure',
2988
3458
                   'bzrlib.tests.test_registry',
2989
3459
                   'bzrlib.tests.test_remote',
 
3460
                   'bzrlib.tests.test_rename_map',
2990
3461
                   'bzrlib.tests.test_repository',
2991
3462
                   'bzrlib.tests.test_revert',
2992
3463
                   'bzrlib.tests.test_revision',
2996
3467
                   'bzrlib.tests.test_rules',
2997
3468
                   'bzrlib.tests.test_sampler',
2998
3469
                   'bzrlib.tests.test_selftest',
 
3470
                   'bzrlib.tests.test_serializer',
2999
3471
                   'bzrlib.tests.test_setup',
3000
3472
                   'bzrlib.tests.test_sftp_transport',
3001
3473
                   'bzrlib.tests.test_shelf',
3191
3663
    the scenario name at the end of its id(), and updating the test object's
3192
3664
    __dict__ with the scenario_param_dict.
3193
3665
 
 
3666
    >>> import bzrlib.tests.test_sampler
3194
3667
    >>> r = multiply_tests(
3195
3668
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3196
3669
    ...     [('one', dict(param=1)),
3270
3743
        osutils.rmtree(dirname)
3271
3744
    except OSError, e:
3272
3745
        if sys.platform == 'win32' and e.errno == errno.EACCES:
3273
 
            sys.stderr.write(('Permission denied: '
3274
 
                                 'unable to remove testing dir '
3275
 
                                 '%s\n' % os.path.basename(dirname)))
 
3746
            sys.stderr.write('Permission denied: '
 
3747
                             'unable to remove testing dir '
 
3748
                             '%s\n%s'
 
3749
                             % (os.path.basename(dirname), e))
3276
3750
        else:
3277
3751
            raise
3278
3752
 
3395
3869
    return None
3396
3870
 
3397
3871
 
3398
 
class _FTPServerFeature(Feature):
3399
 
    """Some tests want an FTP Server, check if one is available.
3400
 
 
3401
 
    Right now, the only way this is available is if 'medusa' is installed.
3402
 
    http://www.amk.ca/python/code/medusa.html
3403
 
    """
3404
 
 
3405
 
    def _probe(self):
3406
 
        try:
3407
 
            import bzrlib.tests.ftp_server
3408
 
            return True
3409
 
        except ImportError:
3410
 
            return False
3411
 
 
3412
 
    def feature_name(self):
3413
 
        return 'FTPServer'
3414
 
 
3415
 
 
3416
 
FTPServerFeature = _FTPServerFeature()
3417
 
 
3418
 
 
3419
3872
class _HTTPSServerFeature(Feature):
3420
3873
    """Some tests want an https Server, check if one is available.
3421
3874
 
3521
3974
        return 'case-insensitive filesystem'
3522
3975
 
3523
3976
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
3977
 
 
3978
 
 
3979
class _SubUnitFeature(Feature):
 
3980
    """Check if subunit is available."""
 
3981
 
 
3982
    def _probe(self):
 
3983
        try:
 
3984
            import subunit
 
3985
            return True
 
3986
        except ImportError:
 
3987
            return False
 
3988
 
 
3989
    def feature_name(self):
 
3990
        return 'subunit'
 
3991
 
 
3992
SubUnitFeature = _SubUnitFeature()
 
3993
# Only define SubUnitBzrRunner if subunit is available.
 
3994
try:
 
3995
    from subunit import TestProtocolClient
 
3996
    class SubUnitBzrRunner(TextTestRunner):
 
3997
        def run(self, test):
 
3998
            result = TestProtocolClient(self.stream)
 
3999
            test.run(result)
 
4000
            return result
 
4001
except ImportError:
 
4002
    pass