886
887
:param universal_newlines: Convert CRLF => LF
888
889
env_changes = kwargs.get('env_changes', {})
890
process = self.start_bzr_subprocess(args, env_changes=env_changes)
891
# We distinguish between retcode=None and retcode not passed.
892
supplied_retcode = kwargs.get('retcode', 0)
893
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
894
universal_newlines=kwargs.get('universal_newlines', False),
897
def start_bzr_subprocess(self, process_args, env_changes=None,
898
skip_if_plan_to_signal=False):
899
"""Start bzr in a subprocess for testing.
901
This starts a new Python interpreter and runs bzr in there.
902
This should only be used for tests that have a justifiable need for
903
this isolation: e.g. they are testing startup time, or signal
904
handling, or early startup code, etc. Subprocess code can't be
905
profiled or debugged so easily.
907
:param process_args: a list of arguments to pass to the bzr executable,
908
for example `['--version']`.
909
:param env_changes: A dictionary which lists changes to environment
910
variables. A value of None will unset the env variable.
911
The values must be strings. The change will only occur in the
912
child, so you don't need to fix the environment after running.
913
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
916
:returns: Popen object for the started process.
918
if skip_if_plan_to_signal:
919
if not getattr(os, 'kill', None):
920
raise TestSkipped("os.kill not available.")
922
if env_changes is None:
892
926
def cleanup_environment():
898
932
osutils.set_or_unset_env(env_var, value)
900
934
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
935
if not os.path.isfile(bzr_path):
936
# We are probably installed. Assume sys.argv is the right file
937
bzr_path = sys.argv[0]
904
940
# win32 subprocess doesn't support preexec_fn
905
941
# so we will avoid using it on all platforms, just to
906
942
# make sure the code path is used, and we don't break on win32
907
943
cleanup_environment()
908
process = Popen([sys.executable, bzr_path]+args,
909
stdout=PIPE, stderr=PIPE)
944
process = Popen([sys.executable, bzr_path] + list(process_args),
945
stdin=PIPE, stdout=PIPE, stderr=PIPE)
911
947
restore_environment()
913
out = process.stdout.read()
914
err = process.stderr.read()
916
if kwargs.get('universal_newlines', False):
950
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
951
universal_newlines=False, process_args=None):
952
"""Finish the execution of process.
954
:param process: the Popen object returned from start_bzr_subprocess.
955
:param retcode: The status code that is expected. Defaults to 0. If
956
None is supplied, the status code is not checked.
957
:param send_signal: an optional signal to send to the process.
958
:param universal_newlines: Convert CRLF => LF
959
:returns: (stdout, stderr)
961
if send_signal is not None:
962
os.kill(process.pid, send_signal)
963
out, err = process.communicate()
965
if universal_newlines:
917
966
out = out.replace('\r\n', '\n')
918
967
err = err.replace('\r\n', '\n')
920
retcode = process.wait()
921
supplied_retcode = kwargs.get('retcode', 0)
922
if supplied_retcode is not None:
923
assert supplied_retcode == retcode
969
if retcode is not None and retcode != process.returncode:
970
if process_args is None:
971
process_args = "(unknown args)"
972
mutter('Output of bzr %s:\n%s', process_args, out)
973
mutter('Error for bzr %s:\n%s', process_args, err)
974
self.fail('Command bzr %s failed with retcode %s != %s'
975
% (process_args, retcode, process.returncode))
924
976
return [out, err]
926
978
def check_inventory_shape(self, inv, shape):
1213
1265
if relpath is not None and relpath != '.':
1214
1266
if not base.endswith('/'):
1215
1267
base = base + '/'
1216
base = base + urlutils.escape(relpath)
1268
# XXX: Really base should be a url; we did after all call
1269
# get_url()! But sometimes it's just a path (from
1270
# LocalAbspathServer), and it'd be wrong to append urlescaped data
1271
# to a non-escaped local path.
1272
if base.startswith('./') or base.startswith('/'):
1275
base += urlutils.escape(relpath)
1219
1278
def get_transport(self):
1240
1299
def make_bzrdir(self, relpath, format=None):
1242
url = self.get_url(relpath)
1243
mutter('relpath %r => url %r', relpath, url)
1244
segments = url.split('/')
1245
if segments and segments[-1] not in ('', '.'):
1246
parent = '/'.join(segments[:-1])
1247
t = get_transport(parent)
1301
# might be a relative or absolute path
1302
maybe_a_url = self.get_url(relpath)
1303
segments = maybe_a_url.rsplit('/', 1)
1304
t = get_transport(maybe_a_url)
1305
if len(segments) > 1 and segments[-1] not in ('', '.'):
1249
t.mkdir(segments[-1])
1250
1308
except errors.FileExists:
1252
1310
if format is None:
1253
format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
1254
# FIXME: make this use a single transport someday. RBC 20060418
1255
return format.initialize_on_transport(get_transport(relpath))
1311
format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1312
return format.initialize_on_transport(t)
1256
1313
except errors.UninitializableFormat:
1257
1314
raise TestSkipped("Format %s is not initializable." % format)
1264
1321
def make_branch_and_tree(self, relpath, format=None):
1265
1322
"""Create a branch on the transport and a tree locally.
1324
If the transport is not a LocalTransport, the Tree can't be created on
1325
the transport. In that case the working tree is created in the local
1326
directory, and the returned tree's branch and repository will also be
1329
This will fail if the original default transport for this test
1330
case wasn't backed by the working directory, as the branch won't
1331
be on disk for us to open it.
1333
:param format: The BzrDirFormat.
1334
:returns: the WorkingTree.
1269
1336
# TODO: always use the local disk path for the working tree,
1270
1337
# this obviously requires a format that supports branch references
1275
1342
return b.bzrdir.create_workingtree()
1276
1343
except errors.NotLocalUrl:
1277
# new formats - catch No tree error and create
1278
# a branch reference and a checkout.
1279
# old formats at that point - raise TestSkipped.
1280
# TODO: rbc 20060208
1281
return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
1344
# We can only make working trees locally at the moment. If the
1345
# transport can't support them, then reopen the branch on a local
1346
# transport, and create the working tree there.
1348
# Possibly we should instead keep
1349
# the non-disk-backed branch and create a local checkout?
1350
bd = bzrdir.BzrDir.open(relpath)
1351
return bd.create_workingtree()
1283
1353
def assertIsDirectory(self, relpath, transport):
1284
1354
"""Assert that relpath within transport is a directory.
1405
1475
'bzrlib.tests.test_errors',
1406
1476
'bzrlib.tests.test_escaped_store',
1407
1477
'bzrlib.tests.test_fetch',
1478
'bzrlib.tests.test_ftp_transport',
1408
1479
'bzrlib.tests.test_gpg',
1409
1480
'bzrlib.tests.test_graph',
1410
1481
'bzrlib.tests.test_hashcache',
1441
1513
'bzrlib.tests.test_selftest',
1442
1514
'bzrlib.tests.test_setup',
1443
1515
'bzrlib.tests.test_sftp_transport',
1444
'bzrlib.tests.test_ftp_transport',
1445
1516
'bzrlib.tests.test_smart_add',
1517
'bzrlib.tests.test_smart_transport',
1446
1518
'bzrlib.tests.test_source',
1447
1519
'bzrlib.tests.test_status',
1448
1520
'bzrlib.tests.test_store',