Disable runfiles on Windows.
This adds a new configuration option that allows disabling the creation of symlink forest for runfiles.
On Windows, symlink forest is disabled by default; only the runfiles manifest is created.
For shell tests, a function 'rlocation' is provided that converts from runfiles location to a real location.
Work towards #1212.
--
MOS_MIGRATED_REVID=125439553
diff --git a/scripts/bootstrap/compile.sh b/scripts/bootstrap/compile.sh
index a241213..f0a797e 100755
--- a/scripts/bootstrap/compile.sh
+++ b/scripts/bootstrap/compile.sh
@@ -208,7 +208,12 @@
cat <<'EOF' >${ARCHIVE_DIR}/_embedded_binaries/build-runfiles${EXE_EXT}
#!/bin/sh
win_arg='--windows_compatible'
-if [ $1 == $win_arg ];
+manifest_arg='--manifest_only'
+if [ $1 == $win_arg ] || [ $1 == $manifest_arg ];
+then
+ shift
+fi
+if [ $1 == $win_arg ] || [ $1 == $manifest_arg ];
then
shift
fi
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
index 98540d2..61ac369 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
@@ -312,7 +312,8 @@
outputManifest,
/*filesetTree=*/ false,
config.getShExecutable(),
- config.getLocalShellEnvironment()));
+ config.getLocalShellEnvironment(),
+ config.runfilesEnabled()));
return outputManifest;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java
index 5ebe26f..ef2fde9 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java
@@ -43,11 +43,11 @@
private final boolean filesetTree;
private final PathFragment shExecutable;
private final ImmutableMap<String, String> shellEnviroment;
+ private final boolean enableRunfiles;
/**
* Creates SymlinkTreeAction instance.
- *
- * @param owner action owner
+ * @param owner action owner
* @param inputManifest the input runfiles manifest
* @param artifactMiddleman the middleman artifact representing all the files the symlinks
* point to (on Windows we need to know if the target of a "symlink" is
@@ -56,7 +56,7 @@
* (must have "MANIFEST" base name). Symlink tree root
* will be set to the artifact's parent directory.
* @param filesetTree true if this is fileset symlink tree,
- * false if this is a runfiles symlink tree.
+ * @param enableRunfiles true is the actual symlink tree needs to be created.
*/
public SymlinkTreeAction(
ActionOwner owner,
@@ -65,7 +65,8 @@
Artifact outputManifest,
boolean filesetTree,
PathFragment shExecutable,
- ImmutableMap<String, String> shellEnvironment) {
+ ImmutableMap<String, String> shellEnvironment,
+ boolean enableRunfiles) {
super(owner, computeInputs(inputManifest, artifactMiddleman), ImmutableList.of(outputManifest));
Preconditions.checkArgument(outputManifest.getPath().getBaseName().equals("MANIFEST"));
this.inputManifest = inputManifest;
@@ -73,6 +74,7 @@
this.filesetTree = filesetTree;
this.shExecutable = shExecutable;
this.shellEnviroment = shellEnvironment;
+ this.enableRunfiles = enableRunfiles;
}
private static ImmutableList<Artifact> computeInputs(
@@ -129,6 +131,7 @@
actionExecutionContext
.getExecutor()
.getContext(SymlinkTreeActionContext.class)
- .createSymlinks(this, actionExecutionContext, shExecutable, shellEnviroment);
+ .createSymlinks(
+ this, actionExecutionContext, shExecutable, shellEnviroment, enableRunfiles);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java
index fa9182a..11c1417 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java
@@ -31,6 +31,7 @@
SymlinkTreeAction action,
ActionExecutionContext actionExecutionContext,
PathFragment shExecutable,
- ImmutableMap<String, String> shellEnvironment)
+ ImmutableMap<String, String> shellEnvironment,
+ boolean enableRunfiles)
throws ActionExecutionException, InterruptedException;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index c37bac4..0499743 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -855,6 +855,14 @@
+ "static globally defined ones")
public boolean useDynamicConfigurations;
+ @Option(
+ name = "experimental_enable_runfiles",
+ defaultValue = "auto",
+ category = "undocumented",
+ help = "Enable runfiles; off on Windows, on on other platforms"
+ )
+ public TriState enableRunfiles;
+
@Override
public FragmentOptions getHost(boolean fallback) {
Options host = (Options) getDefault();
@@ -2350,6 +2358,17 @@
return options.cpu;
}
+ public boolean runfilesEnabled() {
+ switch (options.enableRunfiles) {
+ case YES:
+ return true;
+ case NO:
+ return false;
+ default:
+ return OS.getCurrent() != OS.WINDOWS;
+ }
+ }
+
/**
* Returns true if the configuration performs static linking.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
index 0e47c2b..6a53d7d 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
@@ -89,7 +89,9 @@
*/
public void createSymlinksUsingCommand(Path execRoot,
BuildConfiguration config, BinTools binTools) throws CommandException {
- List<String> argv = getSpawnArgumentList(execRoot, binTools, config.getShExecutable());
+ List<String> argv =
+ getSpawnArgumentList(
+ execRoot, binTools, config.getShExecutable(), config.runfilesEnabled());
CommandBuilder builder = new CommandBuilder();
builder.addArgs(argv);
@@ -105,19 +107,25 @@
* block for undetermined period of time. If it is interrupted during
* that wait, ExecException will be thrown but interrupted bit will be
* preserved.
- * @param action action instance that requested symlink tree creation
+ * @param action action instance that requested symlink tree creation
* @param actionExecutionContext Services that are in the scope of the action.
* @param shExecutable
+ * @param enableRunfiles
*/
public void createSymlinks(
AbstractAction action,
ActionExecutionContext actionExecutionContext,
BinTools binTools,
PathFragment shExecutable,
- ImmutableMap<String, String> shellEnvironment)
+ ImmutableMap<String, String> shellEnvironment,
+ boolean enableRunfiles)
throws ExecException, InterruptedException {
- List<String> args = getSpawnArgumentList(
- actionExecutionContext.getExecutor().getExecRoot(), binTools, shExecutable);
+ List<String> args =
+ getSpawnArgumentList(
+ actionExecutionContext.getExecutor().getExecRoot(),
+ binTools,
+ shExecutable,
+ enableRunfiles);
try (ResourceHandle handle =
ResourceManager.instance().acquireResources(action, RESOURCE_SET)) {
actionExecutionContext.getExecutor().getSpawnActionContext(action.getMnemonic()).exec(
@@ -130,7 +138,7 @@
* Returns the complete argument list build-runfiles has to be called with.
*/
private List<String> getSpawnArgumentList(
- Path execRoot, BinTools binTools, PathFragment shExecutable) {
+ Path execRoot, BinTools binTools, PathFragment shExecutable, boolean enableRunfiles) {
PathFragment path = binTools.getExecPath(BUILD_RUNFILES);
Preconditions.checkNotNull(path, BUILD_RUNFILES + " not found in embedded tools");
@@ -156,6 +164,10 @@
args.add("--windows_compatible");
}
+ if (!enableRunfiles) {
+ args.add("--manifest_only");
+ }
+
args.add(inputManifest.getPathString());
args.add(symlinkTreeRoot.getPathString());
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
index e34a6b4..dc54714 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
@@ -48,7 +48,8 @@
SymlinkTreeAction action,
ActionExecutionContext actionExecutionContext,
PathFragment shExecutable,
- ImmutableMap<String, String> shellEnvironment)
+ ImmutableMap<String, String> shellEnvironment,
+ boolean enableRunfiles)
throws ActionExecutionException, InterruptedException {
Executor executor = actionExecutionContext.getExecutor();
try (AutoProfiler p =
@@ -64,7 +65,12 @@
action.isFilesetTree(), helper.getSymlinkTreeRoot());
} else {
helper.createSymlinks(
- action, actionExecutionContext, binTools, shExecutable, shellEnvironment);
+ action,
+ actionExecutionContext,
+ binTools,
+ shExecutable,
+ shellEnvironment,
+ enableRunfiles);
}
} catch (ExecException e) {
throw e.toActionExecutionException(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java b/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
index 3790799..fc736ae 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
@@ -169,7 +169,8 @@
outputManifest,
false,
ruleContext.getConfiguration().getShExecutable(),
- ruleContext.getConfiguration().getLocalShellEnvironment()));
+ ruleContext.getConfiguration().getLocalShellEnvironment(),
+ ruleContext.getConfiguration().runfilesEnabled()));
return outputManifest;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
index 72ff4e8..2dd01c3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
@@ -71,8 +71,14 @@
throws ExecException, InterruptedException {
Path runfilesDir = null;
try {
- runfilesDir = TestStrategy.getLocalRunfilesDirectory(action, actionExecutionContext, binTools,
- action.getShExecutable(), action.getLocalShellEnvironment());
+ runfilesDir =
+ TestStrategy.getLocalRunfilesDirectory(
+ action,
+ actionExecutionContext,
+ binTools,
+ action.getShExecutable(),
+ action.getLocalShellEnvironment(),
+ action.isEnableRunfiles());
} catch (ExecException e) {
throw new TestExecException(e.getMessage());
}
@@ -161,6 +167,9 @@
vars.put("TEST_TMPDIR", tmpDir.getPathString());
vars.put("TEST_WORKSPACE", action.getRunfilesPrefix());
vars.put("XML_OUTPUT_FILE", resolvedPaths.getXmlOutputPath().getPathString());
+ if (!action.isEnableRunfiles()) {
+ vars.put("RUNFILES_MANIFEST_ONLY", "1");
+ }
return vars;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestRunnerAction.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestRunnerAction.java
index 687d622..473ec92 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestRunnerAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestRunnerAction.java
@@ -562,6 +562,10 @@
return configuration.getLocalShellEnvironment();
}
+ public boolean isEnableRunfiles() {
+ return configuration.runfilesEnabled();
+ }
+
/**
* The same set of paths as the parent test action, resolved against a given exec root.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
index e1bd9de..68cefe1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
@@ -357,7 +357,8 @@
ActionExecutionContext actionExecutionContext,
BinTools binTools,
PathFragment shExecutable,
- ImmutableMap<String, String> shellEnvironment)
+ ImmutableMap<String, String> shellEnvironment,
+ boolean enableRunfiles)
throws ExecException, InterruptedException {
TestTargetExecutionSettings execSettings = testAction.getExecutionSettings();
@@ -380,8 +381,14 @@
long startTime = Profiler.nanoTimeMaybe();
synchronized (execSettings.getInputManifest()) {
Profiler.instance().logSimpleTask(startTime, ProfilerTask.WAIT, testAction);
- updateLocalRunfilesDirectory(testAction, runfilesDir, actionExecutionContext, binTools,
- shExecutable, shellEnvironment);
+ updateLocalRunfilesDirectory(
+ testAction,
+ runfilesDir,
+ actionExecutionContext,
+ binTools,
+ shExecutable,
+ shellEnvironment,
+ enableRunfiles);
}
return runfilesDir;
@@ -399,7 +406,8 @@
ActionExecutionContext actionExecutionContext,
BinTools binTools,
PathFragment shExecutable,
- ImmutableMap<String, String> shellEnvironment)
+ ImmutableMap<String, String> shellEnvironment,
+ boolean enableRunfiles)
throws ExecException, InterruptedException {
Executor executor = actionExecutionContext.getExecutor();
@@ -423,7 +431,12 @@
runfilesDir.relativeTo(executor.getExecRoot()), /* filesetTree= */
false)
.createSymlinks(
- testAction, actionExecutionContext, binTools, shExecutable, shellEnvironment);
+ testAction,
+ actionExecutionContext,
+ binTools,
+ shExecutable,
+ shellEnvironment,
+ enableRunfiles);
executor.getEventHandler().handle(Event.progress(testAction.getProgressMessage()));
}
diff --git a/src/main/tools/build-runfiles.cc b/src/main/tools/build-runfiles.cc
index ae45200..d48df3c 100644
--- a/src/main/tools/build-runfiles.cc
+++ b/src/main/tools/build-runfiles.cc
@@ -111,9 +111,11 @@
class RunfilesCreator {
public:
- explicit RunfilesCreator(const std::string &output_base, bool windows_compatible)
+ explicit RunfilesCreator(const std::string &output_base,
+ bool windows_compatible, bool manifest_only)
: output_base_(output_base),
windows_compatible_(windows_compatible),
+ manifest_only_(manifest_only),
output_filename_("MANIFEST"),
temp_filename_(output_filename_ + ".tmp") {
SetupOutputBase();
@@ -207,8 +209,10 @@
output_filename_.c_str());
}
- ScanTreeAndPrune(".");
- CreateFiles();
+ if (!manifest_only_) {
+ ScanTreeAndPrune(".");
+ CreateFiles();
+ }
// rename output file into place
if (rename(temp_filename_.c_str(), output_filename_.c_str()) != 0) {
@@ -428,6 +432,7 @@
private:
std::string output_base_;
bool windows_compatible_;
+ bool manifest_only_;
std::string output_filename_;
std::string temp_filename_;
@@ -441,6 +446,7 @@
bool allow_relative = false;
bool use_metadata = false;
bool windows_compatible = false;
+ bool manifest_only = false;
while (argc >= 1) {
if (strcmp(argv[0], "--allow_relative") == 0) {
@@ -452,6 +458,10 @@
} else if (strcmp(argv[0], "--windows_compatible") == 0) {
windows_compatible = true;
argc--; argv++;
+ } else if (strcmp(argv[0], "--manifest_only") == 0) {
+ manifest_only = true;
+ argc--;
+ argv++;
} else {
break;
}
@@ -477,7 +487,8 @@
manifest_file = std::string(cwd_buf) + '/' + manifest_file;
}
- RunfilesCreator runfiles_creator(output_base_dir, windows_compatible);
+ RunfilesCreator runfiles_creator(output_base_dir, windows_compatible,
+ manifest_only);
runfiles_creator.ReadManifest(manifest_file, allow_relative, use_metadata);
runfiles_creator.CreateRunfiles();
diff --git a/src/test/shell/bazel/bazel_windows_cpp_test.sh b/src/test/shell/bazel/bazel_windows_cpp_test.sh
index 2a523cc..4bff4c7 100755
--- a/src/test/shell/bazel/bazel_windows_cpp_test.sh
+++ b/src/test/shell/bazel/bazel_windows_cpp_test.sh
@@ -18,7 +18,7 @@
#
# Load test environment
-source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/test-setup.sh \
+source $(rlocation io_bazel/src/test/shell/bazel/test-setup.sh) \
|| { echo "test-setup.sh not found!" >&2; exit 1; }
if ! is_windows; then
diff --git a/src/test/shell/bazel/test-setup.sh b/src/test/shell/bazel/test-setup.sh
index 05f265f..77b23bb 100755
--- a/src/test/shell/bazel/test-setup.sh
+++ b/src/test/shell/bazel/test-setup.sh
@@ -32,15 +32,6 @@
# Here we unset variable that were set by the invoking Blaze instance
unset JAVA_RUNFILES
-function is_windows() {
- # On windows, the shell test actually running on msys
- if [ "${PLATFORM}" == "msys_nt-6.1" ]; then
- true
- else
- false
- fi
-}
-
function setup_bazelrc() {
# enable batch mode when running on windows
if is_windows; then
diff --git a/src/test/shell/bazel/testenv.sh b/src/test/shell/bazel/testenv.sh
index 8733ead..43c14fd 100755
--- a/src/test/shell/bazel/testenv.sh
+++ b/src/test/shell/bazel/testenv.sh
@@ -21,24 +21,39 @@
BAZEL_RUNFILES="$TEST_SRCDIR/io_bazel"
# Load the unit-testing framework
-source "${BAZEL_RUNFILES}/src/test/shell/unittest.bash" || \
+source "$(rlocation io_bazel/src/test/shell/unittest.bash)" || \
{ echo "Failed to source unittest.bash" >&2; exit 1; }
# WORKSPACE file
workspace_file="${BAZEL_RUNFILES}/WORKSPACE"
# Bazel
-bazel_tree="${BAZEL_RUNFILES}/src/test/shell/bazel/doc-srcs.zip"
-bazel="${BAZEL_RUNFILES}/src/bazel"
+bazel_tree="$(rlocation io_bazel/src/test/shell/bazel/doc-srcs.zip)"
+bazel="$(rlocation io_bazel/src/bazel)"
bazel_data="${BAZEL_RUNFILES}"
+# Windows
+PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
+function is_windows() {
+ # On windows, the shell test actually running on msys
+ if [ "${PLATFORM}" == "msys_nt-6.1" ]; then
+ true
+ else
+ false
+ fi
+}
+
# Java
-jdk_dir="${TEST_SRCDIR}/local_jdk"
-langtools="${BAZEL_RUNFILES}/src/test/shell/bazel/langtools.jar"
+if is_windows; then
+ jdk_dir="$(cygpath -m $(cd $(rlocation local_jdk/bin/java.exe)/../..; pwd))"
+else
+ jdk_dir="${TEST_SRCDIR}/local_jdk"
+fi
+langtools="$(rlocation io_bazel/src/test/shell/bazel/langtools.jar)"
# Tools directory location
-tools_dir="${BAZEL_RUNFILES}/tools"
-langtools_dir="${BAZEL_RUNFILES}/third_party/java/jdk/langtools"
+tools_dir="$(dirname $(rlocation io_bazel/tools/BUILD))"
+langtools_dir="$(dirname $(rlocation io_bazel/third_party/java/jdk/langtools/BUILD))"
EXTRA_BAZELRC="build --ios_sdk_version=8.4"
# Java tooling
@@ -80,7 +95,6 @@
python_server="${BAZEL_RUNFILES}/src/test/shell/bazel/testing_server.py"
# Third-party
-PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
MACHINE_TYPE="$(uname -m)"
MACHINE_IS_64BIT='no'
if [ "${MACHINE_TYPE}" = 'amd64' -o "${MACHINE_TYPE}" = 'x86_64' ]; then
@@ -152,7 +166,7 @@
# Copy the examples of the base workspace
function copy_examples() {
- EXAMPLE="$BAZEL_RUNFILES/examples"
+ EXAMPLE="$(cd $(dirname $(rlocation io_bazel/examples/cpp/BUILD))/..; pwd)"
cp -RL ${EXAMPLE} .
chmod -R +w .
}
diff --git a/src/test/shell/unittest.bash b/src/test/shell/unittest.bash
index c7ff53f..70e311f 100644
--- a/src/test/shell/unittest.bash
+++ b/src/test/shell/unittest.bash
@@ -525,7 +525,8 @@
}
# Multi-platform timestamp function
-if [ "$(uname -s | tr 'A-Z' 'a-z')" = "linux" ]; then
+UNAME=$(uname -s | tr 'A-Z' 'a-z')
+if [ "$UNAME" = "linux" ] || [ "$UNAME" = "msys_nt-6.1" ]; then
function timestamp() {
echo $(($(date +%s%N)/1000000))
}
diff --git a/tools/test/test-setup.sh b/tools/test/test-setup.sh
index 6fa814a..150b9fa 100755
--- a/tools/test/test-setup.sh
+++ b/tools/test/test-setup.sh
@@ -28,12 +28,36 @@
export GTEST_TMP_DIR="${TEST_TMPDIR}"
DIR="$TEST_SRCDIR"
+RUNFILES_MANIFEST_FILE=$DIR/MANIFEST
+
+if [ -z "$RUNFILES_MANIFEST_ONLY" ]; then
+ function rlocation() {
+ if [[ "$1" = /* ]]; then
+ echo $1
+ else
+ echo "$(dirname $RUNFILES_MANIFEST_FILE)/$1"
+ fi
+ }
+else
+ function rlocation() {
+ if [[ "$1" = /* ]]; then
+ echo $1
+ else
+ echo $(grep "^$1 " $MANIFEST_FILE | awk '{ print $2 }')
+ fi
+ }
+fi
+
+export -f rlocation
+export RUNFILES_MANIFEST_FILE
if [ ! -z "$TEST_WORKSPACE" ]
then
DIR="$DIR"/"$TEST_WORKSPACE"
fi
+
+
# normal commands are 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 declared dependencies.
@@ -48,8 +72,18 @@
# If the test is at the top of the tree, we have to add '.' to $PATH,
PATH=".:$PATH"
+
+TEST_NAME=$1
+shift
+
+if [[ "$TEST_NAME" = /* ]]; then
+ EXE="${TEST_NAME}"
+else
+ EXE="$(rlocation $TEST_WORKSPACE/$TEST_NAME)"
+fi
+
exitCode=0
-"$@" || exitCode=$?
+"${EXE}" "$@" || exitCode=$?
if [ -n "${XML_OUTPUT_FILE-}" -a ! -f "${XML_OUTPUT_FILE-}" ]; then
# Create a default XML output file if the test runner hasn't generated it
@@ -63,8 +97,8 @@
cat <<EOF >${XML_OUTPUT_FILE}
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
- <testsuite name="$1" tests="1" failures="0" errors="$errors">
- <testcase name="$1" status="run">$error_msg</testcase>
+ <testsuite name="$TEST_NAME" tests="1" failures="0" errors="$errors">
+ <testcase name="$TEST_NAME" status="run">$error_msg</testcase>
</testsuite>
</testsuites>
EOF