8251213: [TESTBUG] CDS tests shouldn't write output files into test.classes directory

Reviewed-by: minqi, ccheung
This commit is contained in:
Ioi Lam 2020-08-09 20:56:04 -07:00
parent ee060c777c
commit c1093dc244
25 changed files with 113 additions and 87 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,7 @@ import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
public class AppendClasspath {
@ -54,11 +55,11 @@ public class AppendClasspath {
.assertNormalExit();
// PASS: 2) runtime has an non-existing jar in the -cp
String classDir = System.getProperty("test.classes");
String outDir = CDSTestUtils.getOutputDir();
String newFile = "non-exist.jar";
String nonExistPath = classDir + File.separator + newFile;
String nonExistPath = outDir + File.separator + newFile;
String classPath = appJar + File.pathSeparator + nonExistPath;
File nonExistJar = new File(classDir, newFile);
File nonExistJar = new File(outDir, newFile);
if (nonExistJar.exists()) {
nonExistJar.delete();
}

View File

@ -237,7 +237,7 @@ public class BootClassPathMismatch {
}
private static void copyHelloToNewDir() throws Exception {
String classDir = System.getProperty("test.classes");
String classDir = CDSTestUtils.getOutputDir();
String dstDir = classDir + File.separator + "newdir";
try {
Files.createDirectory(Paths.get(dstDir));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,7 @@
* @run driver/timeout=240 ClassPathAttr
*/
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import java.io.File;
import java.nio.file.Files;
@ -101,7 +102,7 @@ public class ClassPathAttr {
buildCpAttr("cpattr6", "cpattr6.mf", "CpAttr6", "CpAttr6");
String cp = TestCommon.getTestJar("cpattr6.jar");
String nonExistPath = System.getProperty("test.classes") + File.separator + "cpattrX.jar";
String nonExistPath = CDSTestUtils.getOutputDir() + File.separator + "cpattrX.jar";
(new File(nonExistPath)).delete();
TestCommon.testDump(cp, TestCommon.list("CpAttr6"),
@ -129,7 +130,7 @@ public class ClassPathAttr {
}
private static void buildCpAttr(String jarName, String manifest, String enclosingClassName, String ...testClassNames) throws Exception {
String jarClassesDir = System.getProperty("test.classes") + File.separator + jarName + "_classes";
String jarClassesDir = CDSTestUtils.getOutputDir() + File.separator + jarName + "_classes";
try { Files.createDirectory(Paths.get(jarClassesDir)); } catch (FileAlreadyExistsException e) { }
JarBuilder.compile(jarClassesDir, System.getProperty("test.src") + File.separator +

View File

@ -32,6 +32,7 @@
*/
import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
@ -48,7 +49,7 @@ public class JarBuilder {
.orElseThrow(() -> new RuntimeException("ToolProvider for jar not found"));
public static String getJarFilePath(String jarName) {
return classDir + File.separator + jarName + ".jar";
return CDSTestUtils.getOutputDir() + File.separator + jarName + ".jar";
}
// jar all files under dir, with manifest file man, with an optional versionArgs
@ -59,7 +60,7 @@ public class JarBuilder {
// -C <path to the base classes> .\
// --release 9 -C <path to the versioned classes> .
// the last line begins with "--release" corresponds to the optional versionArgs.
public static void build(String jarName, File dir, String man, String ...versionArgs)
public static String build(String jarName, File dir, String man, String ...versionArgs)
throws Exception {
ArrayList<String> args = new ArrayList<String>();
if (man != null) {
@ -67,7 +68,8 @@ public class JarBuilder {
} else {
args.add("cf");
}
args.add(classDir + File.separator + jarName + ".jar");
String jarFile = getJarFilePath(jarName);
args.add(jarFile);
if (man != null) {
args.add(man);
}
@ -78,6 +80,7 @@ public class JarBuilder {
args.add(verArg);
}
createJar(args);
return jarFile;
}
public static String build(String jarName, String ...classNames)
@ -259,8 +262,6 @@ public class JarBuilder {
public static void signJar() throws Exception {
String keyTool = JDKToolFinder.getJDKTool("keytool");
String jarSigner = JDKToolFinder.getJDKTool("jarsigner");
String classDir = System.getProperty("test.classes");
String FS = File.separator;
executeProcess(keyTool,
"-genkey", "-keystore", "./keystore", "-alias", "mykey",
@ -270,8 +271,8 @@ public class JarBuilder {
executeProcess(jarSigner,
"-keystore", "./keystore", "-storepass", "abc123", "-keypass",
"abc123", "-signedjar", classDir + FS + "signed_hello.jar",
classDir + FS + "hello.jar", "mykey")
"abc123", "-signedjar", getJarFilePath("signed_hello"),
getJarFilePath("hello"), "mykey")
.shouldHaveExitValue(0);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -51,14 +51,14 @@ public class LongClassListPath {
// Create a directory with long path and copy the classlist file to
// the directory.
Path classDir = Paths.get(System.getProperty("test.classes"));
Path classDir = Paths.get(CDSTestUtils.getOutputDir());
Path destDir = classDir;
int subDirLen = MAX_PATH - classDir.toString().length() - 2;
if (subDirLen > 0) {
char[] chars = new char[subDirLen];
Arrays.fill(chars, 'x');
String subPath = new String(chars);
destDir = Paths.get(System.getProperty("test.classes"), subPath);
destDir = Paths.get(CDSTestUtils.getOutputDir(), subPath);
}
File longDir = destDir.toFile();
longDir.mkdir();

View File

@ -41,6 +41,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
public class MoveJDKTest {
@ -178,12 +179,12 @@ public class MoveJDKTest {
}
private static String copyFakeModulesFromHelloJar() throws Exception {
String classDir = System.getProperty("test.classes");
String outDir = CDSTestUtils.getOutputDir();
String newFile = "hello.modules";
String path = classDir + File.separator + newFile;
String path = outDir + File.separator + newFile;
Files.copy(Paths.get(classDir, "hello.jar"),
Paths.get(classDir, newFile),
Files.copy(Paths.get(outDir, "hello.jar"),
Paths.get(outDir, newFile),
StandardCopyOption.REPLACE_EXISTING);
return path;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.IOException;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
public class MultiReleaseJars {
@ -90,7 +91,7 @@ public class MultiReleaseJars {
* META-INF/versions/<major-version>/version/Version.class
*/
static void createClassFilesAndJar() throws Exception {
String tempDir = System.getProperty("test.classes");
String tempDir = CDSTestUtils.getOutputDir();
File baseDir = new File(tempDir + File.separator + "base");
File vDir = new File(tempDir + File.separator + MAJOR_VERSION_STRING);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,7 @@ import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
public class NonExistClasspath {
@ -46,9 +47,9 @@ public class NonExistClasspath {
}
static void doTest(String appJar, boolean bootcp) throws Exception {
String classDir = System.getProperty("test.classes");
String outDir = CDSTestUtils.getOutputDir();
String newFile = "non-exist.jar";
String nonExistPath = classDir + File.separator + newFile;
String nonExistPath = outDir + File.separator + newFile;
final String errorMessage1 = "Unable to use shared archive";
final String errorMessage2 = "shared class paths mismatch";
final String errorMessage3 = (bootcp ? "BOOT" : "APP") + " classpath mismatch";
@ -90,8 +91,8 @@ public class NonExistClasspath {
.assertNormalExit();
// Now make nonExistPath exist. CDS will fail to load.
Files.copy(Paths.get(classDir, "hello.jar"),
Paths.get(classDir, newFile),
Files.copy(Paths.get(outDir, "hello.jar"),
Paths.get(outDir, newFile),
StandardCopyOption.REPLACE_EXISTING);
TestCommon.run(make_args(bootcp,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,10 +45,8 @@ public class OldClassTest implements Opcodes {
public static void main(String[] args) throws Exception {
File jarSrcFile = new File(JarBuilder.getOrCreateHelloJar());
File dir = new File(System.getProperty("test.classes", "."));
File jarFile = new File(dir, "OldClassTest_old.jar");
String jar = jarFile.getPath();
String jar = JarBuilder.getJarFilePath("OldClassTest_old");
File jarFile = new File(jar);
if (!jarFile.exists() || jarFile.lastModified() < jarSrcFile.lastModified()) {
createTestJarFile(jarSrcFile, jarFile);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -321,12 +321,11 @@ public class TestCommon extends CDSTestUtils {
firstJar = firstJar.substring(0, n);
}
String classDir = System.getProperty("test.classes");
String expected1 = classDir + File.separator;
String expected2 = System.getProperty("user.dir") + File.separator;
String expected = getOutputDir() + File.separator;
if (!firstJar.startsWith(expected1) && !firstJar.startsWith(expected2)) {
if (!firstJar.startsWith(expected)) {
throw new RuntimeException("FIXME: jar file not at a supported location ('"
+ expected1 + "', or '" + expected2 + "'): " + firstJar);
+ expected + "'): " + firstJar);
}
String replaceJar = firstJar + ".tmp";

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -62,15 +62,13 @@ public class VerifierTest implements Opcodes {
String jarName_hi = "hi" + "_" + subCaseId;
JarBuilder.build(jarName_verifier_test_tmp, "VerifierTest0", "VerifierTestA",
File jarSrcFile = new File(JarBuilder.build(jarName_verifier_test_tmp, "VerifierTest0", "VerifierTestA",
"VerifierTestB", "VerifierTestC", "VerifierTestD", "VerifierTestE",
"UnverifiableBase", "UnverifiableIntf", "UnverifiableIntfSub");
"UnverifiableBase", "UnverifiableIntf", "UnverifiableIntfSub"));
JarBuilder.build(jarName_greet, "Greet");
JarBuilder.build(jarName_hi, "Hi", "Hi$MyClass");
File dir = new File(System.getProperty("test.classes", "."));
File jarSrcFile = new File(dir, jarName_verifier_test_tmp + ".jar");
File jarFile = new File(dir, jarName_verifier_test + ".jar");
File jarFile = new File(JarBuilder.getJarFilePath(jarName_verifier_test));
String jar = jarFile.getPath();
if (!jarFile.exists() || jarFile.lastModified() < jarSrcFile.lastModified()) {

View File

@ -36,11 +36,8 @@
*/
import org.testng.annotations.Test;
import java.io.File;
import jtreg.SkippedException;
import sun.hotspot.gc.GC;
@Test
@ -58,8 +55,7 @@ public class CDSStreamTestDriver extends DynamicArchiveTestBase {
static void doTest() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("streamapp", new File(classDir), null);
String appJar = classDir + File.separator + "streamapp.jar";
String appJar = JarBuilder.build("streamapp", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String testngJar = null;

View File

@ -47,8 +47,7 @@ public class DoubleSumAverageTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("stream", new File(classDir), null);
String appJar = classDir + File.separator + "stream.jar";
String appJar = JarBuilder.build("stream", new File(classDir), null);
dumpAndRun(topArchiveName, "-Xlog:cds,cds+dynamic=debug,class+load=trace",
"-cp", appJar, mainClass);

View File

@ -36,11 +36,11 @@
*/
import java.io.File;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
public class HelloDynamicCustom extends DynamicArchiveTestBase {
private static final String ARCHIVE_NAME =
System.getProperty("test.classes") + File.separator + "HelloDynamicCustom-top.jsa";
private static final String ARCHIVE_NAME = CDSTestUtils.getOutputFileName("top.jsa");
public static void main(String[] args) throws Exception {
runTest(HelloDynamicCustom::testDefaultBase);

View File

@ -39,10 +39,10 @@
*/
import java.io.File;
import jdk.test.lib.cds.CDSTestUtils;
public class HelloDynamicCustomUnload extends DynamicArchiveTestBase {
private static final String ARCHIVE_NAME =
System.getProperty("test.classes") + File.separator + "HelloDynamicCustomUnload.jsa";
private static final String ARCHIVE_NAME = CDSTestUtils.getOutputFileName("top.jsa");
public static void main(String[] args) throws Exception {
runTest(HelloDynamicCustomUnload::testDefaultBase);

View File

@ -37,12 +37,12 @@
*/
import java.io.File;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class LambdaForClassInBaseArchive extends DynamicArchiveTestBase {
static final String classList = System.getProperty("test.classes") +
File.separator + "LambdaForClassInBaseArchive.list";
static final String classList = CDSTestUtils.getOutputFileName("classlist");
static final String appClass = "SimpleApp";
public static void main(String[] args) throws Exception {

View File

@ -45,14 +45,14 @@
*/
import java.io.File;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class NoClassToArchive extends DynamicArchiveTestBase {
static final String warningMessage =
"There is no class to be included in the dynamic archive";
static final String classList = System.getProperty("test.classes") +
File.separator + "NoClassToArchive.list";
static final String classList = CDSTestUtils.getOutputFileName("classlist");
static final String appClass = "StrConcatApp";
public static void main(String[] args) throws Exception {

View File

@ -30,7 +30,29 @@ for i in "${testnames[@]}"
do
fname="$i$name_suffix"
cat << EOF > $fname
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
// this file is auto-generated by $0. Do not edit manually.
/*
@ -78,8 +100,7 @@ public class $i extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -68,8 +68,7 @@ public class MethodHandlesAsCollectorTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -68,8 +68,7 @@ public class MethodHandlesCastFailureTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -68,8 +68,7 @@ public class MethodHandlesGeneralTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -68,8 +68,7 @@ public class MethodHandlesInvokersTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -68,8 +68,7 @@ public class MethodHandlesPermuteArgumentsTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -68,8 +68,7 @@ public class MethodHandlesSpreadArgumentsTest extends DynamicArchiveTestBase {
static void testImpl() throws Exception {
String topArchiveName = getNewArchiveName();
JarBuilder.build("MH", new File(classDir), null);
String appJar = classDir + File.separator + "MH.jar";
String appJar = JarBuilder.build("MH", new File(classDir), null);
String[] classPaths = javaClassPath.split(File.pathSeparator);
String junitJar = null;

View File

@ -482,11 +482,21 @@ public class CDSTestUtils {
return output;
}
private static final String outputDir;
private static final File outputDirAsFile;
static {
outputDir = System.getProperty("user.dir", ".");
outputDirAsFile = new File(outputDir);
}
public static String getOutputDir() {
return outputDir;
}
// get the file object for the test artifact
public static File getTestArtifact(String name, boolean checkExistence) {
File dir = new File(System.getProperty("test.classes", "."));
File file = new File(dir, name);
File file = new File(outputDirAsFile, name);
if (checkExistence && !file.exists()) {
throw new RuntimeException("Cannot find " + file.getPath());
@ -549,14 +559,16 @@ public class CDSTestUtils {
// ===================== FILE ACCESS convenience methods
public static File getOutputFile(String name) {
File dir = new File(System.getProperty("test.classes", "."));
return new File(dir, testName + "-" + name);
return new File(outputDirAsFile, testName + "-" + name);
}
public static String getOutputFileName(String name) {
return getOutputFile(name).getName();
}
public static File getOutputSourceFile(String name) {
File dir = new File(System.getProperty("test.classes", "."));
return new File(dir, name);
return new File(outputDirAsFile, name);
}
@ -570,14 +582,17 @@ public class CDSTestUtils {
public static OutputAnalyzer executeAndLog(ProcessBuilder pb, String logName) throws Exception {
long started = System.currentTimeMillis();
OutputAnalyzer output = new OutputAnalyzer(pb.start());
String outputFileNamePrefix =
testName + "-" + String.format("%04d", getNextLogCounter()) + "-" + logName;
String logFileNameStem =
String.format("%04d", getNextLogCounter()) + "-" + logName;
writeFile(getOutputFile(outputFileNamePrefix + ".stdout"), output.getStdout());
writeFile(getOutputFile(outputFileNamePrefix + ".stderr"), output.getStderr());
File stdout = getOutputFile(logFileNameStem + ".stdout");
File stderr = getOutputFile(logFileNameStem + ".stderr");
writeFile(stdout, output.getStdout());
writeFile(stderr, output.getStderr());
System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]");
System.out.println("[logging stdout to " + outputFileNamePrefix + ".stdout]");
System.out.println("[logging stderr to " + outputFileNamePrefix + ".stderr]");
System.out.println("[logging stdout to " + stdout + "]");
System.out.println("[logging stderr to " + stderr + "]");
System.out.println("[STDERR]\n" + output.getStderr());
if (copyChildStdoutToMainStdout)