blob: ad709a9ffeab6c382d91f56f5305153e2be25604 [file] [log] [blame]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2022 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tests for rustc_remote_wrapper."""
import contextlib
import io
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
import rustc_remote_wrapper
import rustc
import cl_utils
import fuchsia
import remote_action
from typing import Any, Iterable, Sequence
class ImmediateExit(Exception):
"""For mocking functions that do not return."""
pass
def _write_file_contents(path: Path, contents: str):
with open(path, 'w') as f:
f.write(contents)
def _read_file_contents(path: Path) -> str:
with open(path, 'r') as f:
return f.read()
def _strs(items: Sequence[Any]) -> Sequence[str]:
return [str(i) for i in items]
def _paths(items: Sequence[Any]) -> Sequence[Path]:
if isinstance(items, list):
return [Path(i) for i in items]
elif isinstance(items, set):
return {Path(i) for i in items}
elif isinstance(items, tuple):
return tuple(Path(i) for i in items)
t = type(items)
raise TypeError(f"Unhandled sequence type: {t}")
class DepfileInputsByLineTests(unittest.TestCase):
def test_no_phony_deps(self):
lines = [
'a: b c',
'd: e f g',
]
self.assertEqual(
list(rustc_remote_wrapper.depfile_inputs_by_line(lines)), [])
def test_phony_deps(self):
lines = [
'a:',
'b: c',
'd:',
'z: e f g',
]
self.assertEqual(
list(rustc_remote_wrapper.depfile_inputs_by_line(lines)),
_paths(['a', 'd']))
class TestAccompanyRlibWithSo(unittest.TestCase):
def test_not_rlib(self):
deps = Path('../path/to/foo.rs')
self.assertEqual(
list(rustc_remote_wrapper.accompany_rlib_with_so([deps])), [deps])
def test_rlib_without_so(self):
deps = Path('obj/build/foo.rlib')
with mock.patch.object(Path, 'is_file',
return_value=False) as mock_isfile:
self.assertEqual(
list(rustc_remote_wrapper.accompany_rlib_with_so([deps])),
[deps])
mock_isfile.assert_called_once()
def test_rlib_with_so(self):
deps = Path('obj/build/foo.rlib')
with mock.patch.object(Path, 'is_file',
return_value=True) as mock_isfile:
self.assertEqual(
list(rustc_remote_wrapper.accompany_rlib_with_so([deps])),
[deps, Path('obj/build/foo.so')])
mock_isfile.assert_called_once()
class RustRemoteActionPrepareTests(unittest.TestCase):
def generate_prepare_mocks(
self,
depfile_contents: Sequence[str] = None,
compiler_shlibs: Sequence[Path] = None,
clang_rt_libdir: Path = None,
libcxx_static: Path = None,
) -> Iterable[mock.patch.object]:
"""common mocks needed for RustRemoteAction.prepare()"""
# depfile only command
yield mock.patch.object(
rustc_remote_wrapper, '_make_local_depfile', return_value=0)
if depfile_contents:
yield mock.patch.object(
rustc_remote_wrapper,
'_readlines_from_file',
return_value=depfile_contents)
# check compiler is executable
yield mock.patch.object(
rustc_remote_wrapper, '_tool_is_executable', return_value=True)
if compiler_shlibs:
yield mock.patch.object(
rustc_remote_wrapper.RustRemoteAction,
'_remote_rustc_shlibs',
return_value=iter(compiler_shlibs))
yield mock.patch.object(
rustc_remote_wrapper, '_libcxx_isfile', return_value=True)
if clang_rt_libdir:
yield mock.patch.object(
fuchsia,
'remote_clang_runtime_libdirs',
return_value=[clang_rt_libdir])
if libcxx_static:
yield mock.patch.object(
fuchsia,
'remote_clang_libcxx_static',
return_value=libcxx_static or '')
# expected to be called through _rust_stdlib_libunwind_inputs()
# when --sysroot is unspecified.
yield mock.patch.object(
rustc.RustAction,
'default_rust_sysroot',
return_value=Path('../some/random/sysroot'))
def test_prepare_basic(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
command = _strs([compiler, source, '-o', rlib])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs, set([compiler, shlib_rel, source] + deps))
self.assertEqual(remote_output_files, {rlib})
def test_prepare_depfile(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_path = Path('obj/foo.rlib.d')
depfile_contents = [str(d) + ':' for d in deps]
command = _strs(
[compiler, source, '-o', rlib, f'--emit=dep-info={depfile_path}'])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs, set([compiler, shlib_rel, source] + deps))
self.assertEqual(remote_output_files, {rlib, depfile_path})
self.assertEqual(set(a.always_download), set([depfile_path]))
def test_prepare_depfile_failure(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
depfile_path = Path('obj/foo.rlib.d')
# mocking failure, no need for actual depfile contents
command = _strs(
[compiler, source, '-o', rlib, f'--emit=dep-info={depfile_path}'])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
# Make sure internal RuntimeError gets handled.
with mock.patch.object(rustc_remote_wrapper, '_make_local_depfile',
return_value=1) as mock_deps:
prepare_status = r.prepare()
self.assertEqual(prepare_status, 1) # failure
def test_prepare_externs(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
externs = _paths([
'obj/path/to/this.rlib',
'obj/path/to/that.rlib',
])
extern_flags = [
'--extern',
f'this={externs[0]}',
'--extern',
f'that={externs[1]}',
]
command = _strs([compiler, source, '-o', rlib]) + extern_flags
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs, set([compiler, shlib_rel, source] + deps + externs))
self.assertEqual(remote_output_files, {rlib})
def test_prepare_link_arg_files(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
link_arg = Path('obj/some/random.a')
command = _strs(
[compiler, source, '-o', rlib, f'-Clink-arg={link_arg}'])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs,
set([compiler, shlib_rel, source] + deps + [link_arg]))
self.assertEqual(remote_output_files, {rlib})
def test_prepare_needs_linker(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
exec_root_rel = cl_utils.relpath(exec_root, start=working_dir)
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
linker = Path('../tools/bin/linker')
lld = Path('../tools/bin/ld.lld')
clang_rt_libdir = Path('../fake/lib/clang/x86_64-unknown-linux')
libcxx = Path('fake/clang/libc++.a')
source = Path('../foo/src/lib.rs')
target = 'x86_64-unknown-linux-gnu'
exe = Path('obj/foo.exe')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
command = _strs(
[
compiler, source, '-o', exe, '--crate-type', 'bin',
f'-Clinker={linker}', f'--target={target}',
f'-Clink-arg=-fuse-ld=lld'
])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
self.assertEqual(r.linker, linker)
self.assertEqual(r.remote_ld_path, lld)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
clang_rt_libdir=clang_rt_libdir,
libcxx_static=libcxx,
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs,
set(
_paths(
[compiler, shlib_rel, source] + deps +
[linker, lld, clang_rt_libdir, exec_root_rel / libcxx])))
self.assertEqual(remote_output_files, {exe})
def test_prepare_remote_option_forwarding(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
remote_flag = '--some_forwarded_rewrapper_flag=value' # not real
command = _strs(
[compiler, source, '-o', rlib, f'--remote-flag={remote_flag}'])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs, set([compiler, shlib_rel, source] + deps))
self.assertEqual(remote_output_files, {rlib})
# Position matters, not just presence.
# Could override the set of standard options.
self.assertEqual(r.remote_options[-1], remote_flag)
def test_prepare_environment_names_input_file(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
env_file = Path('../path/to/config.json')
command = _strs(
[
f'CONFIGURE_THINGY={env_file}', compiler, source, '-o', rlib,
f'--remote-inputs={env_file}'
])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
# We are not scanning the environment variables automatically.
# Users should follow the above example command and
# explicitly pass --remote-inputs.
with mock.patch.object(rustc_remote_wrapper, '_env_file_exists',
return_value=True) as mock_exists:
prepare_status = r.prepare()
mock_exists.assert_not_called()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs,
set(_paths([compiler, shlib_rel, source, env_file] + deps)))
self.assertEqual(remote_output_files, {rlib})
def test_native_compile(self):
host_platform = fuchsia.REMOTE_PLATFORM
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path(f'../tools/{host_platform}/bin/rustc')
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
command = _strs([compiler, source, '-o', rlib])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
host_platform=host_platform,
auto_reproxy=False,
)
self.assertTrue(r.host_matches_remote)
def test_target_linker_prefix(self):
for target, ld in [
('arm64-unknown-linux-gnu', 'ld'),
('x86_64-unknown-linux-gnu', 'ld'),
('x86_64-unknown-freebsd', 'ld'),
('x86_64-apple-darwin', 'ld64'),
('ppc64-apple-darwin', 'ld64'),
]:
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/host-platform/bin/rustc')
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
command = _strs(
[compiler, source, '-o', rlib, f'--target={target}'])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
self.assertEqual(r.target_linker_prefix, ld)
def test_remote_mode_ok_with_relative_c_sysroot(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/host-platform/bin/rustc')
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
c_sysroot = Path('generated/sys/root') # relative
target = 'aarch64-unknown-linux-gnu'
command = _strs(
[
compiler, source, '-o', rlib, '--crate-type=bin',
f'--target={target}', f'-Clink-arg=--sysroot={c_sysroot}'
])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
self.assertEqual(r.c_sysroot, c_sysroot)
self.assertFalse(r._c_sysroot_is_outside_exec_root)
self.assertTrue(r.needs_linker)
self.assertFalse(r._remote_disqualified())
self.assertFalse(r.local_only)
sysroot_files = list(r._c_sysroot_files())
self.assertNotEqual(sysroot_files, [])
def test_forced_local_mode_ok_with_external_absolute_c_sysroot(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/host-platform/bin/rustc')
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
c_sysroot = Path('/fancy/pants/local/SDK') # absolute, external
target = 'aarch64-unknown-linux-gnu'
command = _strs(
[
compiler, source, '-o', rlib, '--crate-type=bin',
f'--target={target}', f'-Clink-arg=--sysroot={c_sysroot}'
])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
self.assertEqual(r.c_sysroot, c_sysroot)
self.assertTrue(r._c_sysroot_is_outside_exec_root)
self.assertTrue(r.needs_linker)
self.assertTrue(r._remote_disqualified())
self.assertTrue(r.local_only)
with mock.patch.object(fuchsia, 'c_sysroot_files') as mock_files:
sysroot_files = list(r._c_sysroot_files())
self.assertEqual(sysroot_files, [])
mock_files.assert_not_called()
def test_cdylib_rust_lld(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/mac-x64/bin/rustc')
remote_compiler = Path('../tools/linux-x64/bin/rustc')
remote_rust_lld = remote_compiler.parent / fuchsia._REMOTE_RUST_LLD_RELPATH
source = Path('../foo/src/lib.rs')
dylib = Path('obj/foo.dylib')
command = _strs(
[compiler, source, '--crate-type', 'cdylib', '-o', dylib])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
mocks = self.generate_prepare_mocks()
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
with mock.patch.object(rustc_remote_wrapper.RustRemoteAction,
'_local_depfile_inputs') as mock_deps:
with mock.patch.object(rustc_remote_wrapper.RustRemoteAction,
'_remote_rustc_shlibs') as mock_shlibs:
prepare_status = r.prepare()
mock_deps.assert_called_once()
mock_shlibs.assert_called_once()
a = r.remote_action
remote_inputs = set(a.inputs_relative_to_working_dir)
self.assertIn(remote_compiler, remote_inputs)
self.assertIn(remote_rust_lld, remote_inputs)
def test_prepare_remote_cross_compile(self):
host_platform = 'mac-arm64'
remote_platform = fuchsia.REMOTE_PLATFORM
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path(f'../tools/{host_platform}/bin/rustc')
remote_compiler = Path(f'../tools/{remote_platform}/bin/rustc')
linker = Path(f'../tools/{host_platform}/bin/linker')
remote_linker = Path(f'../tools/{remote_platform}/bin/linker')
remote_ld_path = Path(f'../tools/{remote_platform}/bin/ld.lld')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
libcxx = Path('../std/tools/bin/../lib/libc++.a')
libcxx_norm = Path('../std/tools/lib/libc++.a')
target = 'powerpc-unknown-freebsd'
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_contents = [str(d) + ':' for d in deps]
command = _strs(
[
compiler, source, '-o', rlib, f'--target={target}',
f'-Clinker={linker}', f'-Clink-arg={libcxx}',
f'-Clink-arg=-fuse-ld=lld'
])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
host_platform=host_platform,
auto_reproxy=False,
)
self.assertEqual(r.working_dir, working_dir)
self.assertFalse(r.host_matches_remote)
self.assertEqual(r.original_command, command)
self.assertEqual(r.linker, linker)
self.assertEqual(r.remote_linker, remote_linker)
self.assertEqual(r.remote_ld_path, remote_ld_path)
mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in mocks:
stack.enter_context(m)
prepare_status = r.prepare()
remote_command = list(r.remote_compile_command())
self.assertEqual(prepare_status, 0) # success
self.assertEqual(r.remote_compiler, remote_compiler)
a = r.remote_action
self.assertEqual(
remote_command,
_strs(
[
remote_compiler,
source,
'-o',
rlib,
f'--target={target}',
f'-Clinker={remote_linker}',
f'-Clink-arg={libcxx_norm}', # normalized
f'-Clink-arg=-fuse-ld=lld',
f'-Clink-arg=--ld-path={remote_ld_path}', # added by wrapper
f'--sysroot=../some/random/sysroot',
]))
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs,
set([remote_compiler, shlib_rel, libcxx, source] + deps))
self.assertEqual(remote_output_files, {rlib})
def test_post_run_actions(self):
exec_root = Path('/home/project')
working_dir = exec_root / 'build-here'
compiler = Path('../tools/bin/rustc')
shlib = Path('tools/lib/librusteze.so')
shlib_abs = exec_root / shlib
shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
deps = [Path('../foo/src/other.rs')]
depfile_path = Path('obj/foo.rlib.d')
depfile_contents = [str(d) + ':' for d in deps]
command = _strs(
[compiler, source, '-o', rlib, f'--emit=dep-info={depfile_path}'])
r = rustc_remote_wrapper.RustRemoteAction(
['--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
prepare_mocks = self.generate_prepare_mocks(
depfile_contents=depfile_contents,
compiler_shlibs=[shlib_rel],
)
with contextlib.ExitStack() as stack:
for m in prepare_mocks:
stack.enter_context(m)
prepare_status = r.prepare()
self.assertEqual(prepare_status, 0) # success
a = r.remote_action
self.assertIsNotNone(a._post_remote_run_success_action)
remote_inputs = set(a.inputs_relative_to_working_dir)
remote_output_files = set(a.output_files_relative_to_working_dir)
self.assertEqual(
remote_inputs, set([compiler, shlib_rel, source] + deps))
self.assertEqual(remote_output_files, {rlib, depfile_path})
run_mocks = [
mock.patch.object(
remote_action.RemoteAction,
'_run_maybe_remotely',
return_value=cl_utils.SubprocessResult(0)),
mock.patch.object(
rustc_remote_wrapper.RustRemoteAction,
'_depfile_exists',
return_value=True),
mock.patch.object(
rustc_remote_wrapper.RustRemoteAction, '_cleanup'),
]
with contextlib.ExitStack() as stack:
for m in run_mocks:
stack.enter_context(m)
with mock.patch.object(rustc_remote_wrapper.RustRemoteAction,
'_rewrite_remote_depfile') as mock_rewrite:
run_status = r.run()
mock_rewrite.assert_called_with()
def test_rewrite_remote_depfile(self):
compiler = Path('../tools/bin/rustc')
source = Path('../foo/src/lib.rs')
rlib = Path('obj/foo.rlib')
depfile_path = Path('obj/foo.rlib.d')
with tempfile.TemporaryDirectory() as td:
exec_root = Path(td)
working_dir = exec_root / 'build-here'
command = _strs(
[
compiler, source, '-o', rlib,
f'--emit=dep-info={depfile_path}'
])
r = rustc_remote_wrapper.RustRemoteAction(
['--canonicalize_working_dir=true', '--'] + command,
exec_root=exec_root,
working_dir=working_dir,
auto_reproxy=False,
)
prepare_mocks = self.generate_prepare_mocks()
with contextlib.ExitStack() as stack:
for m in prepare_mocks:
stack.enter_context(m)
with mock.patch.object(rustc_remote_wrapper.RustRemoteAction,
'_remote_inputs',
return_value=iter([])) as mock_inputs:
prepare_status = r.prepare()
mock_inputs.assert_called_with()
self.assertEqual(prepare_status, 0) # success
remote_cwd = r.remote_action.remote_working_dir
depfile_abspath = working_dir / depfile_path
depfile_abspath.parent.mkdir(parents=True, exist_ok=True)
_write_file_contents(
depfile_abspath,
f'{remote_cwd}/obj/foo.rlib: {remote_cwd}/src/lib.rs\n')
r._rewrite_remote_depfile()
new_deps = _read_file_contents(depfile_abspath)
self.assertEqual(new_deps, 'obj/foo.rlib: src/lib.rs\n')
class MainTests(unittest.TestCase):
def test_help_implicit(self):
# Just make sure help exits successfully, without any exceptions
# due to argument parsing.
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
with mock.patch.object(sys, 'exit',
side_effect=ImmediateExit) as mock_exit:
with self.assertRaises(ImmediateExit):
rustc_remote_wrapper.main([])
mock_exit.assert_called_with(0)
def test_help_flag(self):
# Just make sure help exits successfully, without any exceptions
# due to argument parsing.
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
with mock.patch.object(sys, 'exit',
side_effect=ImmediateExit) as mock_exit:
with self.assertRaises(ImmediateExit):
rustc_remote_wrapper.main(['--help'])
mock_exit.assert_called_with(0)
def test_auto_relaunched_with_reproxy(self):
argv = ['--', 'rustc', 'foo.rs', '-o', 'foo.rlib']
with mock.patch.object(os.environ, 'get',
return_value=None) as mock_env:
with mock.patch.object(cl_utils, 'exec_relaunch',
side_effect=ImmediateExit) as mock_relaunch:
with self.assertRaises(ImmediateExit):
rustc_remote_wrapper.main(argv)
mock_env.assert_called()
mock_relaunch.assert_called_once()
args, kwargs = mock_relaunch.call_args_list[0]
relaunch_cmd = args[0]
self.assertEqual(relaunch_cmd[0], fuchsia.REPROXY_WRAP)
cmd_slices = cl_utils.split_into_subsequences(relaunch_cmd[1:], '--')
reproxy_args, self_script, wrapped_command = cmd_slices
self.assertEqual(reproxy_args, [])
self.assertIn('python', self_script[0])
self.assertTrue(self_script[-1].endswith('rustc_remote_wrapper.py'))
self.assertEqual(wrapped_command, argv[1:])
if __name__ == '__main__':
unittest.main()