212
219
osutils.set_or_unset_env(var, value)
222
def _clear__type_equality_funcs(test):
223
"""Cleanup bound methods stored on TestCase instances
225
Clear the dict breaking a few (mostly) harmless cycles in the affected
226
unittests released with Python 2.6 and initial Python 2.7 versions.
228
For a few revisions between Python 2.7.1 and Python 2.7.2 that annoyingly
229
shipped in Oneiric, an object with no clear method was used, hence the
230
extra complications, see bug 809048 for details.
232
type_equality_funcs = getattr(test, "_type_equality_funcs", None)
233
if type_equality_funcs is not None:
234
tef_clear = getattr(type_equality_funcs, "clear", None)
235
if tef_clear is None:
236
tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
237
if tef_instance_dict is not None:
238
tef_clear = tef_instance_dict.clear
239
if tef_clear is not None:
215
243
class ExtendedTestResult(testtools.TextTestResult):
216
244
"""Accepts, reports and accumulates the results of running tests.
332
360
return float(''.join(details['benchtime'].iter_bytes()))
333
361
return getattr(testCase, "_benchtime", None)
363
def _delta_to_float(self, a_timedelta, precision):
364
# This calls ceiling to ensure that the most pessimistic view of time
365
# taken is shown (rather than leaving it to the Python %f operator
366
# to decide whether to round/floor/ceiling. This was added when we
367
# had pyp3 test failures that suggest a floor was happening.
368
shift = 10 ** precision
369
return math.ceil((a_timedelta.days * 86400.0 + a_timedelta.seconds +
370
a_timedelta.microseconds / 1000000.0) * shift) / shift
335
372
def _elapsedTestTimeString(self):
336
373
"""Return a time string for the overall time the current test has taken."""
337
374
return self._formatTime(self._delta_to_float(
338
self._now() - self._start_datetime))
375
self._now() - self._start_datetime, 3))
340
377
def _testTimeString(self, testCase):
341
378
benchmark_time = self._extractBenchmarkTime(testCase)
385
422
getDetails = getattr(test, "getDetails", None)
386
423
if getDetails is not None:
387
424
getDetails().clear()
388
# Clear _type_equality_funcs to try to stop TestCase instances
389
# from wasting memory. 'clear' is not available in all Python
390
# versions (bug 809048)
391
type_equality_funcs = getattr(test, "_type_equality_funcs", None)
392
if type_equality_funcs is not None:
393
tef_clear = getattr(type_equality_funcs, "clear", None)
394
if tef_clear is None:
395
tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
396
if tef_instance_dict is not None:
397
tef_clear = tef_instance_dict.clear
398
if tef_clear is not None:
425
_clear__type_equality_funcs(test)
400
426
self._traceback_from_test = None
402
428
def startTests(self):
503
529
self.not_applicable_count += 1
504
530
self.report_not_applicable(test, reason)
532
def _count_stored_tests(self):
533
"""Count of tests instances kept alive due to not succeeding"""
534
return self.error_count + self.failure_count + self.known_failure_count
506
536
def _post_mortem(self, tb=None):
507
537
"""Start a PDB post mortem session."""
508
538
if os.environ.get('BZR_TEST_PDB', None):
981
1011
def setUp(self):
982
1012
super(TestCase, self).setUp()
1014
# At this point we're still accessing the config files in $BZR_HOME (as
1015
# set by the user running selftest).
1016
timeout = config.GlobalStack().get('selftest.timeout')
1018
timeout_fixture = fixtures.TimeoutFixture(timeout)
1019
timeout_fixture.setUp()
1020
self.addCleanup(timeout_fixture.cleanUp)
983
1022
for feature in getattr(self, '_test_needs_features', []):
984
1023
self.requireFeature(feature)
985
1024
self._cleanEnvironment()
1026
if bzrlib.global_state is not None:
1027
self.overrideAttr(bzrlib.global_state, 'cmdline_overrides',
1028
config.CommandLineStore())
986
1030
self._silenceUI()
987
1031
self._startLogFile()
988
1032
self._benchcalls = []
995
1039
# between tests. We should get rid of this altogether: bug 656694. --
997
1041
self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
998
# Isolate config option expansion until its default value for bzrlib is
999
# settled on or a the FIXME associated with _get_expand_default_value
1000
# is addressed -- vila 20110219
1001
self.overrideAttr(config, '_expand_default_value', None)
1002
1042
self._log_files = set()
1003
1043
# Each key in the ``_counters`` dict holds a value for a different
1004
1044
# counter. When the test ends, addDetail() should be used to output the
1297
1337
# hook into bzr dir opening. This leaves a small window of error for
1298
1338
# transport tests, but they are well known, and we can improve on this
1300
bzrdir.BzrDir.hooks.install_named_hook("pre_open",
1340
controldir.ControlDir.hooks.install_named_hook("pre_open",
1301
1341
self._preopen_isolate_transport, "Check bzr directories are safe.")
1303
1343
def _ndiff_strings(self, a, b):
1717
1756
self.addCleanup(self._finishLogFile)
1719
1758
def _finishLogFile(self):
1720
"""Finished with the log file.
1722
Close the file and delete it.
1759
"""Flush and dereference the in-memory log for this testcase"""
1724
1760
if trace._trace_file:
1725
1761
# flush the log file, to get all content
1726
1762
trace._trace_file.flush()
1727
1763
trace.pop_log_file(self._log_memento)
1764
# The logging module now tracks references for cleanup so discard ours
1765
del self._log_memento
1729
1767
def thisFailsStrictLockCheck(self):
1730
1768
"""It is known that this test would fail with -Dstrict_locks.
1755
1793
:returns: The actual attr value.
1757
value = getattr(obj, attr_name)
1758
1795
# The actual value is captured by the call below
1759
self.addCleanup(setattr, obj, attr_name, value)
1796
value = getattr(obj, attr_name, _unitialized_attr)
1797
if value is _unitialized_attr:
1798
# When the test completes, the attribute should not exist, but if
1799
# we aren't setting a value, we don't need to do anything.
1800
if new is not _unitialized_attr:
1801
self.addCleanup(delattr, obj, attr_name)
1803
self.addCleanup(setattr, obj, attr_name, value)
1760
1804
if new is not _unitialized_attr:
1761
1805
setattr(obj, attr_name, new)
1966
2010
self.log('run bzr: %r', args)
1967
2011
# FIXME: don't call into logging here
1968
handler = logging.StreamHandler(stderr)
1969
handler.setLevel(logging.INFO)
2012
handler = trace.EncodedStreamHandler(stderr, errors="replace",
1970
2014
logger = logging.getLogger('')
1971
2015
logger.addHandler(handler)
1972
2016
old_ui_factory = ui.ui_factory
2356
2405
from bzrlib.smart import request
2357
2406
request_handlers = request.request_handlers
2358
2407
orig_method = request_handlers.get(verb)
2408
orig_info = request_handlers.get_info(verb)
2359
2409
request_handlers.remove(verb)
2360
self.addCleanup(request_handlers.register, verb, orig_method)
2410
self.addCleanup(request_handlers.register, verb, orig_method,
2363
2414
class CapturedCall(object):
2416
2467
self.transport_readonly_server = None
2417
2468
self.__vfs_server = None
2471
super(TestCaseWithMemoryTransport, self).setUp()
2473
def _add_disconnect_cleanup(transport):
2474
"""Schedule disconnection of given transport at test cleanup
2476
This needs to happen for all connected transports or leaks occur.
2478
Note reconnections may mean we call disconnect multiple times per
2479
transport which is suboptimal but seems harmless.
2481
self.addCleanup(transport.disconnect)
2483
_mod_transport.Transport.hooks.install_named_hook('post_connect',
2484
_add_disconnect_cleanup, None)
2486
self._make_test_root()
2487
self.addCleanup(os.chdir, os.getcwdu())
2488
self.makeAndChdirToTestDir()
2489
self.overrideEnvironmentForTesting()
2490
self.__readonly_server = None
2491
self.__server = None
2492
self.reduceLockdirTimeout()
2493
# Each test may use its own config files even if the local config files
2494
# don't actually exist. They'll rightly fail if they try to create them
2496
self.overrideAttr(config, '_shared_stores', {})
2419
2498
def get_transport(self, relpath=None):
2420
2499
"""Return a writeable transport.
2570
2649
# http://pad.lv/825027).
2571
2650
self.assertIs(None, os.environ.get('BZR_HOME', None))
2572
2651
os.environ['BZR_HOME'] = root
2573
wt = bzrdir.BzrDir.create_standalone_workingtree(root)
2652
wt = controldir.ControlDir.create_standalone_workingtree(root)
2574
2653
del os.environ['BZR_HOME']
2575
2654
except Exception, e:
2576
self.fail("Fail to initialize the safety net: %r\nExiting\n" % (e,))
2655
self.fail("Fail to initialize the safety net: %r\n" % (e,))
2577
2656
# Hack for speed: remember the raw bytes of the dirstate file so that
2578
2657
# we don't need to re-open the wt to check it hasn't changed.
2579
2658
TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2627
2706
self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
2628
2707
self.permit_dir(self.test_dir)
2630
def make_branch(self, relpath, format=None):
2709
def make_branch(self, relpath, format=None, name=None):
2631
2710
"""Create a branch on the transport at relpath."""
2632
2711
repo = self.make_repository(relpath, format=format)
2633
return repo.bzrdir.create_branch(append_revisions_only=False)
2635
def resolve_format(self, format):
2636
"""Resolve an object to a ControlDir format object.
2638
The initial format object can either already be
2639
a ControlDirFormat, None (for the default format),
2640
or a string with the name of the control dir format.
2642
:param format: Object to resolve
2643
:return A ControlDirFormat instance
2647
if isinstance(format, basestring):
2648
format = bzrdir.format_registry.make_bzrdir(format)
2651
def resolve_format(self, format):
2652
"""Resolve an object to a ControlDir format object.
2654
The initial format object can either already be
2655
a ControlDirFormat, None (for the default format),
2656
or a string with the name of the control dir format.
2658
:param format: Object to resolve
2659
:return A ControlDirFormat instance
2663
if isinstance(format, basestring):
2664
format = bzrdir.format_registry.make_bzrdir(format)
2712
return repo.bzrdir.create_branch(append_revisions_only=False,
2715
def get_default_format(self):
2718
def resolve_format(self, format):
2719
"""Resolve an object to a ControlDir format object.
2721
The initial format object can either already be
2722
a ControlDirFormat, None (for the default format),
2723
or a string with the name of the control dir format.
2725
:param format: Object to resolve
2726
:return A ControlDirFormat instance
2729
format = self.get_default_format()
2730
if isinstance(format, basestring):
2731
format = controldir.format_registry.make_bzrdir(format)
2667
2734
def make_bzrdir(self, relpath, format=None):
2714
2781
self.overrideEnv('HOME', test_home_dir)
2715
2782
self.overrideEnv('BZR_HOME', test_home_dir)
2718
super(TestCaseWithMemoryTransport, self).setUp()
2719
# Ensure that ConnectedTransport doesn't leak sockets
2720
def get_transport_from_url_with_cleanup(*args, **kwargs):
2721
t = orig_get_transport_from_url(*args, **kwargs)
2722
if isinstance(t, _mod_transport.ConnectedTransport):
2723
self.addCleanup(t.disconnect)
2726
orig_get_transport_from_url = self.overrideAttr(
2727
_mod_transport, 'get_transport_from_url',
2728
get_transport_from_url_with_cleanup)
2729
self._make_test_root()
2730
self.addCleanup(os.chdir, os.getcwdu())
2731
self.makeAndChdirToTestDir()
2732
self.overrideEnvironmentForTesting()
2733
self.__readonly_server = None
2734
self.__server = None
2735
self.reduceLockdirTimeout()
2737
2784
def setup_smart_server_with_call_log(self):
2738
2785
"""Sets up a smart server as the transport server with a call log."""
2739
2786
self.transport_server = test_server.SmartTCPServer_for_testing
2787
self.hpss_connections = []
2740
2788
self.hpss_calls = []
2741
2789
import traceback
2742
2790
# Skip the current stack down to the caller of
2745
2793
def capture_hpss_call(params):
2746
2794
self.hpss_calls.append(
2747
2795
CapturedCall(params, prefix_length))
2796
def capture_connect(transport):
2797
self.hpss_connections.append(transport)
2748
2798
client._SmartClient.hooks.install_named_hook(
2749
2799
'call', capture_hpss_call, None)
2800
_mod_transport.Transport.hooks.install_named_hook(
2801
'post_connect', capture_connect, None)
2751
2803
def reset_smart_call_log(self):
2752
2804
self.hpss_calls = []
2805
self.hpss_connections = []
2755
2808
class TestCaseInTempDir(TestCaseWithMemoryTransport):
2825
2878
# stacking policy to honour; create a bzr dir with an unshared
2826
2879
# repository (but not a branch - our code would be trying to escape
2827
2880
# then!) to stop them, and permit it to be read.
2828
# control = bzrdir.BzrDir.create(self.test_base_dir)
2881
# control = controldir.ControlDir.create(self.test_base_dir)
2829
2882
# control.create_repository()
2830
2883
self.test_home_dir = self.test_base_dir + '/home'
2831
2884
os.mkdir(self.test_home_dir)
2957
3014
# this obviously requires a format that supports branch references
2958
3015
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
3017
format = self.resolve_format(format=format)
3018
if not format.supports_workingtrees:
3019
b = self.make_branch(relpath+'.branch', format=format)
3020
return b.create_checkout(relpath, lightweight=True)
2960
3021
b = self.make_branch(relpath, format=format)
2962
3023
return b.bzrdir.create_workingtree()
2967
3028
if self.vfs_transport_factory is test_server.LocalURLServer:
2968
3029
# the branch is colocated on disk, we cannot create a checkout.
2969
3030
# hopefully callers will expect this.
2970
local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
3031
local_controldir = controldir.ControlDir.open(
3032
self.get_vfs_only_url(relpath))
2971
3033
wt = local_controldir.create_workingtree()
2972
3034
if wt.branch._format != b._format:
3003
3065
self.assertFalse(differences.has_changed(),
3004
3066
"Trees %r and %r are different: %r" % (left, right, differences))
3007
super(TestCaseWithTransport, self).setUp()
3008
self.__vfs_server = None
3010
3068
def disable_missing_extensions_warning(self):
3011
3069
"""Some tests expect a precise stderr content.
3013
3071
There is no point in forcing them to duplicate the extension related
3016
config.GlobalConfig().set_user_option('ignore_missing_extensions', True)
3074
config.GlobalStack().set('ignore_missing_extensions', True)
3019
3077
class ChrootedTestCase(TestCaseWithTransport):
3261
3319
result_decorators=result_decorators,
3263
3321
runner.stop_on_failure=stop_on_failure
3322
if isinstance(suite, unittest.TestSuite):
3323
# Empty out _tests list of passed suite and populate new TestSuite
3324
suite._tests[:], suite = [], TestSuite(suite)
3264
3325
# built in decorator factories:
3266
3327
random_order(random_seed, runner),
3365
3426
class TestDecorator(TestUtil.TestSuite):
3366
3427
"""A decorator for TestCase/TestSuite objects.
3368
Usually, subclasses should override __iter__(used when flattening test
3369
suites), which we do to filter, reorder, parallelise and so on, run() and
3429
Contains rather than flattening suite passed on construction
3373
def __init__(self, suite):
3374
TestUtil.TestSuite.__init__(self)
3377
def countTestCases(self):
3380
cases += test.countTestCases()
3387
def run(self, result):
3388
# Use iteration on self, not self._tests, to allow subclasses to hook
3391
if result.shouldStop:
3432
def __init__(self, suite=None):
3433
super(TestDecorator, self).__init__()
3434
if suite is not None:
3437
# Don't need subclass run method with suite emptying
3438
run = unittest.TestSuite.run
3397
3441
class CountingDecorator(TestDecorator):
3408
3452
"""A decorator which excludes test matching an exclude pattern."""
3410
3454
def __init__(self, suite, exclude_pattern):
3411
TestDecorator.__init__(self, suite)
3412
self.exclude_pattern = exclude_pattern
3413
self.excluded = False
3417
return iter(self._tests)
3418
self.excluded = True
3419
suite = exclude_tests_by_re(self, self.exclude_pattern)
3421
self.addTests(suite)
3422
return iter(self._tests)
3455
super(ExcludeDecorator, self).__init__(
3456
exclude_tests_by_re(suite, exclude_pattern))
3425
3459
class FilterTestsDecorator(TestDecorator):
3426
3460
"""A decorator which filters tests to those matching a pattern."""
3428
3462
def __init__(self, suite, pattern):
3429
TestDecorator.__init__(self, suite)
3430
self.pattern = pattern
3431
self.filtered = False
3435
return iter(self._tests)
3436
self.filtered = True
3437
suite = filter_suite_by_re(self, self.pattern)
3439
self.addTests(suite)
3440
return iter(self._tests)
3463
super(FilterTestsDecorator, self).__init__(
3464
filter_suite_by_re(suite, pattern))
3443
3467
class RandomDecorator(TestDecorator):
3444
3468
"""A decorator which randomises the order of its tests."""
3446
3470
def __init__(self, suite, random_seed, stream):
3447
TestDecorator.__init__(self, suite)
3448
self.random_seed = random_seed
3449
self.randomised = False
3450
self.stream = stream
3454
return iter(self._tests)
3455
self.randomised = True
3456
self.stream.write("Randomizing test order using seed %s\n\n" %
3457
(self.actual_seed()))
3471
random_seed = self.actual_seed(random_seed)
3472
stream.write("Randomizing test order using seed %s\n\n" %
3458
3474
# Initialise the random number generator.
3459
random.seed(self.actual_seed())
3460
suite = randomize_suite(self)
3462
self.addTests(suite)
3463
return iter(self._tests)
3475
random.seed(random_seed)
3476
super(RandomDecorator, self).__init__(randomize_suite(suite))
3465
def actual_seed(self):
3466
if self.random_seed == "now":
3479
def actual_seed(seed):
3467
3481
# We convert the seed to a long to make it reuseable across
3468
3482
# invocations (because the user can reenter it).
3469
self.random_seed = long(time.time())
3483
return long(time.time())
3471
3485
# Convert the seed to a long if we can
3473
self.random_seed = long(self.random_seed)
3488
except (TypeError, ValueError):
3476
return self.random_seed
3479
3493
class TestFirstDecorator(TestDecorator):
3480
3494
"""A decorator which moves named tests to the front."""
3482
3496
def __init__(self, suite, pattern):
3483
TestDecorator.__init__(self, suite)
3484
self.pattern = pattern
3485
self.filtered = False
3489
return iter(self._tests)
3490
self.filtered = True
3491
suites = split_suite_by_re(self, self.pattern)
3493
self.addTests(suites)
3494
return iter(self._tests)
3497
super(TestFirstDecorator, self).__init__()
3498
self.addTests(split_suite_by_re(suite, pattern))
3497
3501
def partition_tests(suite, count):
3542
3546
ProtocolTestCase.run(self, result)
3544
os.waitpid(self.pid, 0)
3548
pid, status = os.waitpid(self.pid, 0)
3549
# GZ 2011-10-18: If status is nonzero, should report to the result
3550
# that something went wrong.
3546
3552
test_blocks = partition_tests(suite, concurrency)
3553
# Clear the tests from the original suite so it doesn't keep them alive
3554
suite._tests[:] = []
3547
3555
for process_tests in test_blocks:
3548
process_suite = TestUtil.TestSuite()
3549
process_suite.addTests(process_tests)
3556
process_suite = TestUtil.TestSuite(process_tests)
3557
# Also clear each split list so new suite has only reference
3558
process_tests[:] = []
3550
3559
c2pread, c2pwrite = os.pipe()
3551
3560
pid = os.fork()
3553
workaround_zealous_crypto_random()
3563
stream = os.fdopen(c2pwrite, 'wb', 1)
3564
workaround_zealous_crypto_random()
3555
3565
os.close(c2pread)
3556
3566
# Leave stderr and stdout open so we can see test noise
3557
3567
# Close stdin so that the child goes away if it decides to
3558
3568
# read from stdin (otherwise its a roulette to see what
3559
3569
# child actually gets keystrokes for pdb etc).
3560
3570
sys.stdin.close()
3562
stream = os.fdopen(c2pwrite, 'wb', 1)
3563
3571
subunit_result = AutoTimingTestResultDecorator(
3564
TestProtocolClient(stream))
3572
SubUnitBzrProtocolClient(stream))
3565
3573
process_suite.run(subunit_result)
3575
# Try and report traceback on stream, but exit with error even
3576
# if stream couldn't be created or something else goes wrong.
3577
# The traceback is formatted to a string and written in one go
3578
# to avoid interleaving lines from multiple failing children.
3580
stream.write(traceback.format_exc())
3569
3585
os.close(c2pwrite)
3570
3586
stream = os.fdopen(c2pread, 'rb', 1)
3676
3692
# with proper exclusion rules.
3677
3693
# -Ethreads Will display thread ident at creation/join time to
3678
3694
# help track thread leaks
3695
# -Euncollected_cases Display the identity of any test cases that weren't
3696
# deallocated after being completed.
3680
3697
# -Econfig_stats Will collect statistics using addDetail
3681
3698
selftest_debug_flags = set()
3788
3805
:return: (absents, duplicates) absents is a list containing the test found
3789
3806
in id_list but not in test_suite, duplicates is a list containing the
3790
test found multiple times in test_suite.
3807
tests found multiple times in test_suite.
3792
3809
When using a prefined test id list, it may occurs that some tests do not
3793
3810
exist anymore or that some tests use the same id. This function warns the
4011
4027
'bzrlib.tests.test_http',
4012
4028
'bzrlib.tests.test_http_response',
4013
4029
'bzrlib.tests.test_https_ca_bundle',
4030
'bzrlib.tests.test_https_urllib',
4014
4031
'bzrlib.tests.test_i18n',
4015
4032
'bzrlib.tests.test_identitymap',
4016
4033
'bzrlib.tests.test_ignores',
4065
4082
'bzrlib.tests.test_revisiontree',
4066
4083
'bzrlib.tests.test_rio',
4067
4084
'bzrlib.tests.test_rules',
4085
'bzrlib.tests.test_url_policy_open',
4068
4086
'bzrlib.tests.test_sampler',
4069
4087
'bzrlib.tests.test_scenarios',
4070
4088
'bzrlib.tests.test_script',
4114
4132
'bzrlib.tests.test_version',
4115
4133
'bzrlib.tests.test_version_info',
4116
4134
'bzrlib.tests.test_versionedfile',
4135
'bzrlib.tests.test_vf_search',
4117
4136
'bzrlib.tests.test_weave',
4118
4137
'bzrlib.tests.test_whitebox',
4119
4138
'bzrlib.tests.test_win32utils',
4480
4499
from subunit.test_results import AutoTimingTestResultDecorator
4481
4500
class SubUnitBzrProtocolClient(TestProtocolClient):
4502
def stopTest(self, test):
4503
super(SubUnitBzrProtocolClient, self).stopTest(test)
4504
_clear__type_equality_funcs(test)
4483
4506
def addSuccess(self, test, details=None):
4484
4507
# The subunit client always includes the details in the subunit
4485
4508
# stream, but we don't want to include it in ours.
4501
@deprecated_function(deprecated_in((2, 5, 0)))
4502
def ModuleAvailableFeature(name):
4503
from bzrlib.tests import features
4504
return features.ModuleAvailableFeature(name)
4524
# API compatibility for old plugins; see bug 892622.
4527
'HTTPServerFeature',
4528
'ModuleAvailableFeature',
4529
'HTTPSServerFeature', 'SymlinkFeature', 'HardlinkFeature',
4530
'OsFifoFeature', 'UnicodeFilenameFeature',
4531
'ByteStringNamedFilesystem', 'UTF8Filesystem',
4532
'BreakinFeature', 'CaseInsCasePresFilenameFeature',
4533
'CaseInsensitiveFilesystemFeature', 'case_sensitive_filesystem_feature',
4534
'posix_permissions_feature',
4536
globals()[name] = _CompatabilityThunkFeature(
4537
symbol_versioning.deprecated_in((2, 5, 0)),
4538
'bzrlib.tests', name,
4539
name, 'bzrlib.tests.features')
4542
for (old_name, new_name) in [
4543
('UnicodeFilename', 'UnicodeFilenameFeature'),
4545
globals()[name] = _CompatabilityThunkFeature(
4546
symbol_versioning.deprecated_in((2, 5, 0)),
4547
'bzrlib.tests', old_name,
4548
new_name, 'bzrlib.tests.features')