Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: test wrapper checks if MANIFEST exists #9011

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/test/py/bazel/native_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,24 @@ def _bat_test_impl(ctx):
content = "\r\n".join(ctx.attr.content),
is_executable = True,
)
return [DefaultInfo(executable = out)]
return [
DefaultInfo(
executable = out,
runfiles = ctx.runfiles(
files = [out],
collect_data = True,
collect_default = True,
),
),
]

bat_test = rule(
implementation = _bat_test_impl,
test = True,
attrs = {"content": attr.string_list()},
attrs = {
"content": attr.string_list(),
"data": attr.label_list(allow_files = True),
},
)

def _exe_test_impl(ctx):
Expand Down
8 changes: 5 additions & 3 deletions src/test/py/bazel/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,11 @@ def _EnvMap(self, env_remove=None, env_add=None):
TestBase.GetEnv('BAZEL_SH',
'c:\\tools\\msys64\\usr\\bin\\bash.exe'),
}
java_home = TestBase.GetEnv('JAVA_HOME', '')
if java_home:
env['JAVA_HOME'] = java_home
for k in ['JAVA_HOME', 'BAZEL_VC', 'BAZEL_VS', 'BAZEL_VC_FULL_VERSION',
'BAZEL_WINSDK_FULL_VERSION']:
v = TestBase.GetEnv(k, '')
if v:
env[k] = v
else:
env = {'HOME': os.path.join(self._temp, 'home')}

Expand Down
99 changes: 68 additions & 31 deletions src/test/py/bazel/test_wrapper_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,18 @@ def _CreateMockWorkspace(self):
' "@echo USER=%USER%",',
' ]',
')',
'py_test(',
'bat_test(',
' name = "runfiles_test",',
' srcs = ["runfiles_test.py"],',
' content = [',
' "@echo off",',
' "echo MF=%RUNFILES_MANIFEST_FILE%",',
' "echo ONLY=%RUNFILES_MANIFEST_ONLY%",',
' "echo DIR=%RUNFILES_DIR%",',
' "echo data_path=%1",',
' "if exist %1 (echo data_exists=1) else (echo data_exists=0)",',
' ],',
' data = ["dummy.dat"],',
' args = ["$(location dummy.dat)"],',
')',
'bat_test(',
' name = "sharded_test",',
Expand Down Expand Up @@ -140,16 +148,6 @@ def _CreateMockWorkspace(self):
src_path=self.Rlocation('io_bazel/src/test/py/bazel/native_test.bzl'),
dst_path='foo/native_test.bzl')

self.ScratchFile(
'foo/runfiles_test.py', [
'from __future__ import print_function',
'import os',
'print("MF=%s" % os.environ.get("RUNFILES_MANIFEST_FILE"))',
'print("ONLY=%s" % os.environ.get("RUNFILES_MANIFEST_ONLY"))',
'print("DIR=%s" % os.environ.get("RUNFILES_DIR"))',
],
executable=True)

self.ScratchFile(
'foo/undecl_test.py', [
'from bazel_tools.tools.python.runfiles import runfiles',
Expand Down Expand Up @@ -275,14 +273,18 @@ def _AssertRunfiles(self, flags):
'--enable_runfiles=no',
] + flags)
self.AssertExitCode(exit_code, 0, stderr)
mf = mf_only = rf_dir = None
mf = mf_only = rf_dir = path = exists = None
for line in stderr + stdout:
if line.startswith('MF='):
mf = line[len('MF='):]
elif line.startswith('ONLY='):
mf_only = line[len('ONLY='):]
elif line.startswith('DIR='):
rf_dir = line[len('DIR='):]
elif line.startswith('data_path='):
path = line[len('data_path='):]
elif line.startswith('data_exists='):
exists = line[len('data_exists='):]

if mf_only != '1':
self._FailWithOutput(stderr + stdout)
Expand All @@ -299,6 +301,51 @@ def _AssertRunfiles(self, flags):
if not os.path.isdir(rf_dir):
self._FailWithOutput(stderr + stdout)

if not path:
# Expect the $(location) expansion in 'args' worked
self._FailWithOutput(stderr + stdout)

if exists != '0':
# Runfiles are disabled, expect the runfile symlink to be missing.
self._FailWithOutput(stderr + stdout)

def _AssertRunfilesSymlinks(self, flags):
exit_code, stdout, stderr = self.RunBazel([
'test',
'//foo:runfiles_test',
'-t-',
'--test_output=all',
# Ensure Bazel creates a runfiles tree.
'--enable_runfiles=yes',
] + flags)
self.AssertExitCode(exit_code, 0, stderr)
mf_only = rf_dir = path = exists = None
for line in stderr + stdout:
if line.startswith('ONLY='):
mf_only = line[len('ONLY='):]
if line.startswith('DIR='):
rf_dir = line[len('DIR='):]
elif line.startswith('TEST_SRCDIR='):
srcdir = line[len('TEST_SRCDIR='):]
elif line.startswith('data_path='):
path = line[len('data_path='):]
elif line.startswith('data_exists='):
exists = line[len('data_exists='):]

if mf_only == '1':
self._FailWithOutput(stderr + stdout)

if not rf_dir or not os.path.isdir(rf_dir):
self._FailWithOutput(stderr + stdout)

if not path:
# Expect the $(location) expansion in 'args' worked
self._FailWithOutput(stderr + stdout)

if exists != '1':
# Runfiles are enabled, expect the runfile symlink to exist.
self._FailWithOutput(stderr + stdout)

def _AssertShardedTest(self, flags):
exit_code, stdout, stderr = self.RunBazel([
'test',
Expand Down Expand Up @@ -566,13 +613,14 @@ def testRunningTestFromExternalRepo(self):
exit_code, 0,
['flag=%s' % flag, 'target=%s' % target] + stderr)

def testTestExecutionWithTestSetupSh(self):
def _RunTests(self, flags):
self._CreateMockWorkspace()
flags = ['--noincompatible_windows_native_test_wrapper']
self._AssertPassingTest(flags)
self._AssertFailingTest(flags)
self._AssertPrintingTest(flags)
self._AssertRunfiles(flags)
self._AssertRunfilesSymlinks(flags)
self._AssertShardedTest(flags)
self._AssertUnexportsEnvvars(flags)
self._AssertTestArgs(flags)
Expand All @@ -583,24 +631,13 @@ def testTestExecutionWithTestSetupSh(self):
self._AssertXmlGeneratedByTestIsRetained(flags, split_xml=False)
self._AssertXmlGeneratedByTestIsRetained(flags, split_xml=True)

def testTestExecutionWithTestSetupSh(self):
self._RunTests(['--noincompatible_windows_native_test_wrapper'])

def testTestExecutionWithTestWrapperExe(self):
self._CreateMockWorkspace()
flags = [
'--incompatible_windows_native_test_wrapper', '--shell_executable='
]
self._AssertPassingTest(flags)
self._AssertFailingTest(flags)
self._AssertPrintingTest(flags)
self._AssertRunfiles(flags)
self._AssertShardedTest(flags)
self._AssertUnexportsEnvvars(flags)
self._AssertTestArgs(flags)
self._AssertUndeclaredOutputs(flags)
self._AssertUndeclaredOutputsAnnotations(flags)
self._AssertXmlGeneration(flags, split_xml=False)
self._AssertXmlGeneration(flags, split_xml=True)
self._AssertXmlGeneratedByTestIsRetained(flags, split_xml=False)
self._AssertXmlGeneratedByTestIsRetained(flags, split_xml=True)
self._RunTests([
'--incompatible_windows_native_test_wrapper',
'--shell_executable='])


if __name__ == '__main__':
Expand Down
59 changes: 56 additions & 3 deletions tools/test/windows/tw.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class Path {
Path() {}
Path(const Path& other) : path_(other.path_) {}
Path(Path&& other) : path_(std::move(other.path_)) {}
Path& operator=(const Path& other) = delete;
Path& operator=(const Path& other) = default;
const std::wstring& Get() const { return path_; }
bool Set(const std::wstring& path);

Expand Down Expand Up @@ -319,6 +319,17 @@ std::wstring AsMixedPath(const std::wstring& path) {
return value;
}

bool IsReadableFile(const Path& p) {
HANDLE h = CreateFileW(AddUncPrefixMaybe(p).c_str(), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
return false;
}
CloseHandle(h);
return true;
}

// Gets an environment variable's value.
// Returns:
// - true, if the envvar is defined and successfully fetched, or it's empty or
Expand Down Expand Up @@ -416,6 +427,46 @@ bool GetCwd(Path* result) {
}
}

bool ChdirToRunfiles(const Path& abs_exec_root, const Path& abs_test_srcdir) {
Path dir = abs_test_srcdir;
std::wstring preserve_cwd;
if (!GetEnv(L"RUNTEST_PRESERVE_CWD", &preserve_cwd)) {
return false;
}
if (preserve_cwd.empty()) {
std::wstring workspace;
if (!GetEnv(L"TEST_WORKSPACE", &workspace)) {
return false;
}
if (!workspace.empty()) {
Path joined;
if (!joined.Set(dir.Get() + L"\\" + workspace)) {
LogErrorWithArg2(__LINE__, "Could not join paths", dir.Get(),
workspace);
return false;
}
dir = joined;
}
} else {
dir = abs_exec_root;
}
dir.Absolutize(abs_exec_root);

// Non-sandboxed commands run in the exec_root, where they have access to the
// entire source tree. By chdir'ing to the runfiles root, tests only have
// direct access to their runfiles tree (if it exists), i.e. to their declared
// dependencies.
std::wstring coverage_dir;
if (!GetEnv(L"COVERAGE_DIR", &coverage_dir) || coverage_dir.empty()) {
if (!SetCurrentDirectoryW(dir.Get().c_str())) {
DWORD err = GetLastError();
LogErrorWithArgAndValue(__LINE__, "Could not chdir", dir.Get(), err);
return false;
}
}
return true;
}

// Set USER as required by the Bazel Test Encyclopedia.
bool ExportUserName() {
std::wstring value;
Expand Down Expand Up @@ -524,7 +575,8 @@ bool ExportRunfiles(const Path& cwd, const Path& test_srcdir) {
// manifest file to find their runfiles.
Path runfiles_mf;
if (!runfiles_mf.Set(test_srcdir.Get() + L"\\MANIFEST") ||
!SetPathEnv(L"RUNFILES_MANIFEST_FILE", runfiles_mf)) {
(IsReadableFile(runfiles_mf) &&
!SetPathEnv(L"RUNFILES_MANIFEST_FILE", runfiles_mf))) {
return false;
}
}
Expand Down Expand Up @@ -1121,7 +1173,7 @@ bool FindTestBinary(const Path& argv0, const Path& cwd, std::wstring test_path,
}

std::wstring workspace;
if (!GetWorkspaceName(&workspace)) {
if (!GetEnv(L"TEST_WORKSPACE", &workspace) || workspace.empty()) {
LogError(__LINE__, "Failed to read %TEST_WORKSPACE%");
return false;
}
Expand Down Expand Up @@ -1852,6 +1904,7 @@ int TestWrapperMain(int argc, wchar_t** argv) {
!PrintTestLogStartMarker() || !GetCwd(&exec_root) ||
!FindTestBinary(argv0, exec_root, test_path_arg, &test_path) ||
!ExportUserName() || !ExportSrcPath(exec_root, &srcdir) ||
!ChdirToRunfiles(exec_root, srcdir) ||
!ExportTmpPath(exec_root, &tmpdir) || !ExportHome(tmpdir) ||
!ExportRunfiles(exec_root, srcdir) || !ExportShardStatusFile(exec_root) ||
!ExportGtestVariables(tmpdir) || !ExportMiscEnvvars(exec_root) ||
Expand Down