blob: 12654617dff43bc21f03fbdf2b66de28b829fe13 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildFileRule;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.input.DefaultInputHandler;
import org.apache.tools.ant.taskdefs.condition.JavaVersion;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.TeeOutputStream;
import org.junit.Assume;
import org.junit.AssumptionViolatedException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
/**
* stress out java task
* */
public class JavaTest {
@Rule
public BuildFileRule buildRule = new BuildFileRule();
@Rule
public ExpectedException thrown = ExpectedException.none();
private static final int TIME_TO_WAIT = 1;
// wait 1 second extra to allow for java to start ...
// this time was OK on a Win NT machine and on nagoya
private static final int SECURITY_MARGIN = 2000;
/** Utilities used for file operations */
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
private boolean runFatalTests = false;
/**
* configure the project.
* if the property junit.run.fatal.tests is set we run
* the fatal tests
*/
@Before
public void setUp() {
buildRule.configureProject("src/etc/testcases/taskdefs/java.xml");
buildRule.executeTarget("setUp");
//final String propname="tests-classpath.value";
//String testClasspath=System.getProperty(propname);
//System.out.println("Test cp=" + testClasspath);
String runFatal = System.getProperty("junit.run.fatal.tests");
if (runFatal != null) {
runFatalTests = true;
}
}
@Test
public void testNoJarNoClassname() {
thrown.expect(BuildException.class);
thrown.expectMessage("Classname must not be null.");
buildRule.executeTarget("testNoJarNoClassname");
}
@Test
public void testJarNoFork() {
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot execute a jar in non-forked mode. Please set fork='true'. ");
buildRule.executeTarget("testJarNoFork");
}
@Test
public void testJarAndClassName() {
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use combination of ");
buildRule.executeTarget("testJarAndClassName");
}
@Test
public void testClassnameAndJar() {
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use combination of ");
buildRule.executeTarget("testClassnameAndJar");
}
@Test
public void testJarAndModule() {
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use combination of ");
buildRule.executeTarget("testJarAndModule");
}
@Test
public void testModuleAndJar() {
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use combination of ");
buildRule.executeTarget("testModuleAndJar");
}
@Test
public void testClassnameAndModule() {
buildRule.executeTarget("testClassnameAndModule");
}
@Test
public void testModuleAndClassname() {
buildRule.executeTarget("testModuleAndClassname");
}
@Test
public void testModule() {
buildRule.executeTarget("testModule");
}
@Test
public void testModuleCommandLine() {
final String moduleName = "TestModule"; //NOI18N
final String arg = "appArg"; //NOI18N
final Java java = new Java();
java.setFork(true);
java.setModule(moduleName);
java.setJvmargs("-Xmx128M");
java.setArgs(arg);
final String[] cmdLine = java.getCommandLine().getCommandline();
assertNotNull("Has command line.", cmdLine);
assertEquals("Command line should have 5 elements", 5, cmdLine.length);
assertEquals("Last command line element should be java argument: " + arg,
arg,
cmdLine[cmdLine.length - 1]);
assertEquals("The command line element at index 3 should be module name: " + moduleName,
moduleName,
cmdLine[cmdLine.length - 2]);
assertEquals("The command line element at index 2 should be -m",
"-m",
cmdLine[cmdLine.length - 3]);
}
@Test
public void testModuleAndClassnameCommandLine() {
final String moduleName = "TestModule"; //NOI18N
final String className = "org.apache.Test"; //NOI18N
final String moduleClassPair = String.format("%s/%s", moduleName, className);
final String arg = "appArg"; //NOI18N
final Java java = new Java();
java.setFork(true);
java.setModule(moduleName);
java.setClassname(className);
java.setJvmargs("-Xmx128M"); //NOI18N
java.setArgs(arg);
final String[] cmdLine = java.getCommandLine().getCommandline();
assertNotNull("Has command line.", cmdLine);
assertEquals("Command line should have 5 elements", 5, cmdLine.length);
assertEquals("Last command line element should be java argument: " + arg,
arg,
cmdLine[cmdLine.length - 1]);
assertEquals("The command line element at index 3 should be module class pair: " + moduleClassPair,
moduleClassPair,
cmdLine[cmdLine.length - 2]);
assertEquals("The command line element at index 2 should be -m",
"-m",
cmdLine[cmdLine.length - 3]);
}
@Test
public void testRun() {
buildRule.executeTarget("testRun");
}
/** this test fails but we ignore the return value;
* we verify that failure only matters when failonerror is set
*/
@Test
public void testRunFail() {
assumeTrue("Fatal tests have not been set to run", runFatalTests);
buildRule.executeTarget("testRunFail");
}
@Test
public void testRunFailFoe() {
assumeTrue("Fatal tests have not been set to run", runFatalTests);
thrown.expect(BuildException.class);
thrown.expectMessage("Java returned:");
buildRule.executeTarget("testRunFailFoe");
}
@Test
public void testRunFailFoeFork() {
thrown.expect(BuildException.class);
thrown.expectMessage("Java returned:");
buildRule.executeTarget("testRunFailFoeFork");
}
@Test
public void testExcepting() {
buildRule.executeTarget("testExcepting");
assertThat(buildRule.getLog(), containsString("Exception raised inside called program"));
}
@Test
public void testExceptingFork() {
buildRule.executeTarget("testExceptingFork");
assertThat(buildRule.getLog(), containsString("Java Result:"));
}
@Test
public void testExceptingFoe() {
thrown.expect(BuildException.class);
thrown.expectMessage("Exception raised inside called program");
buildRule.executeTarget("testExceptingFoe");
}
@Test
public void testExceptingFoeFork() {
thrown.expect(BuildException.class);
thrown.expectMessage("Java returned:");
buildRule.executeTarget("testExceptingFoeFork");
}
@Test
public void testResultPropertyZero() {
buildRule.executeTarget("testResultPropertyZero");
assertEquals("0", buildRule.getProject().getProperty("exitcode"));
}
@Test
public void testResultPropertyNonZero() {
buildRule.executeTarget("testResultPropertyNonZero");
assertEquals("2", buildRule.getProject().getProperty("exitcode"));
}
@Test
public void testResultPropertyZeroNoFork() {
buildRule.executeTarget("testResultPropertyZeroNoFork");
assertEquals("0", buildRule.getProject().getProperty("exitcode"));
}
@Test
public void testResultPropertyNonZeroNoFork() {
buildRule.executeTarget("testResultPropertyNonZeroNoFork");
assertEquals("-1", buildRule.getProject().getProperty("exitcode"));
}
@Test
public void testRunFailWithFailOnError() {
thrown.expect(BuildException.class);
thrown.expectMessage("Java returned:");
buildRule.executeTarget("testRunFailWithFailOnError");
}
@Test
public void testRunSuccessWithFailOnError() {
buildRule.executeTarget("testRunSuccessWithFailOnError");
}
@Test
public void testSpawn() throws InterruptedException {
File logFile = FILE_UTILS.createTempFile("spawn", "log",
new File(buildRule.getProject().getProperty("output")), false, false);
// this is guaranteed by FileUtils#createTempFile
assertFalse("log file not existing", logFile.exists());
buildRule.getProject().setProperty("logFile", logFile.getAbsolutePath());
buildRule.getProject().setProperty("timeToWait", Long.toString(TIME_TO_WAIT));
buildRule.getProject().executeTarget("testSpawn");
Thread.sleep(TIME_TO_WAIT * 1000 + SECURITY_MARGIN);
// let's be nice with the next generation of developers
if (!logFile.exists()) {
System.out.println("suggestion: increase the constant"
+ " SECURITY_MARGIN to give more time for java to start.");
}
assertTrue("log file exists", logFile.exists());
}
@Test
public void testRedirect1() {
buildRule.executeTarget("redirect1");
}
@Test
public void testRedirect2() {
buildRule.executeTarget("redirect2");
}
@Test
public void testRedirect3() {
buildRule.executeTarget("redirect3");
}
@Test
public void testRedirector1() {
buildRule.executeTarget("redirector1");
}
@Test
public void testRedirector2() {
buildRule.executeTarget("redirector2");
}
@Test
public void testReleasedInput() throws Exception {
PipedOutputStream out = new PipedOutputStream();
final PipedInputStream in = new PipedInputStream(out);
buildRule.getProject().setInputHandler(new DefaultInputHandler() {
protected InputStream getInputStream() {
return in;
}
});
buildRule.getProject().setDefaultInputStream(in);
Java java = new Java();
java.setProject(buildRule.getProject());
java.setClassname(MagicNames.ANT_CORE_PACKAGE + ".Main");
java.setArgs("-version");
java.setFork(true);
// note: due to the missing classpath it will fail, but the input stream
// reader will be read
java.execute();
Thread inputThread = new Thread(() -> {
Input input = new Input();
input.setProject(buildRule.getProject());
input.setAddproperty("input.value");
input.execute();
});
inputThread.start();
// wait a little bit for the task to wait for input
Thread.sleep(100);
// write some stuff in the input stream to be caught by the input task
out.write("foo\n".getBytes());
out.flush();
try {
out.write("bar\n".getBytes());
out.flush();
} catch (IOException x) {
// "Pipe closed" on XP; ignore?
}
inputThread.join(2000);
assertEquals("foo", buildRule.getProject().getProperty("input.value"));
}
@Test
public void testFlushedInput() throws Exception {
final PipedOutputStream out = new PipedOutputStream();
final PipedInputStream in = new PipedInputStream(out);
buildRule.getProject().setInputHandler(new DefaultInputHandler() {
protected InputStream getInputStream() {
return in;
}
});
buildRule.getProject().setDefaultInputStream(in);
final boolean[] timeout = new boolean[1];
timeout[0] = false;
Thread writingThread = new Thread(() -> {
try {
// wait a little bit to have the target executed
Thread.sleep(500);
} catch (InterruptedException e) {
throw new AssumptionViolatedException("Thread interrupted", e);
}
try {
out.write("foo-FlushedInput\n".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
writingThread.setDaemon(true);
writingThread.start();
buildRule.executeTarget("flushedInput");
}
/**
* Test that the Java single file source program feature introduced in Java 11 works fine
*
* @throws Exception
*/
@Test
public void testSimpleSourceFile() {
requireJava11();
buildRule.executeTarget("simpleSourceFile");
}
/**
* Test that the sourcefile option of the Java task can only be run when fork attribute is set
*
* @throws Exception
*/
@Test
public void testSourceFileRequiresFork() {
requireJava11();
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot execute sourcefile in non-forked mode. Please set fork='true'");
buildRule.executeTarget("sourceFileRequiresFork");
}
/**
* Tests that the sourcefile attribute and the classname attribute of the Java task cannot be used
* together
*
* @throws Exception
*/
@Test
public void testSourceFileCantUseClassname() {
requireJava11();
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use 'sourcefile' in combination with");
buildRule.executeTarget("sourceFileCantUseClassname");
}
/**
* Tests that the sourcefile attribute and the jar attribute of the Java task cannot be used
* together
*
* @throws Exception
*/
@Test
public void testSourceFileCantUseJar() {
requireJava11();
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use 'sourcefile' in combination with");
buildRule.executeTarget("sourceFileCantUseJar");
}
/**
* Tests that the sourcefile attribute and the module attribute of the Java task cannot be used
* together
*
* @throws Exception
*/
@Test
public void testSourceFileCantUseModule() {
requireJava11();
thrown.expect(BuildException.class);
thrown.expectMessage("Cannot use 'sourcefile' in combination with");
buildRule.executeTarget("sourceFileCantUseModule");
}
private static void requireJava11() {
final JavaVersion javaVersion = new JavaVersion();
javaVersion.setAtLeast("11");
Assume.assumeTrue("Skipping test which requires a minimum of Java 11 runtime", javaVersion.eval());
}
/**
* entry point class with no dependencies other
* than normal JRE runtime
*/
public static class EntryPoint {
/**
* this entry point is used by the java.xml tests to
* generate failure strings to handle
* argv[0] = exit code (optional)
* argv[1] = string to print to System.out (optional)
* argv[1] = string to print to System.err (optional)
*/
public static void main(String[] argv) {
int exitCode = 0;
if (argv.length > 0) {
try {
exitCode = Integer.parseInt(argv[0]);
} catch (NumberFormatException nfe) {
exitCode = -1;
}
}
if (argv.length > 1) {
System.out.println(argv[1]);
}
if (argv.length > 2) {
System.err.println(argv[2]);
}
if (exitCode != 0) {
System.exit(exitCode);
}
}
}
/**
* entry point class with no dependencies other
* than normal JRE runtime
*/
public static class ExceptingEntryPoint {
/**
* throw a run time exception which does not need
* to be in the signature of the entry point
*/
public static void main(String[] argv) {
throw new NullPointerException("Exception raised inside called program");
}
}
/**
* test class for spawn
*/
public static class SpawnEntryPoint {
public static void main(String[] argv) throws InterruptedException {
int sleepTime = 10;
String logFile = "spawn.log";
if (argv.length >= 1) {
sleepTime = Integer.parseInt(argv[0]);
}
if (argv.length >= 2) {
logFile = argv[1];
}
Thread.sleep(sleepTime * 1000);
File dest = new File(logFile);
try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(dest))) {
out.write("bye bye\n");
} catch (Exception ex) {
}
}
}
/**
* entry point class to pipe System.in to the specified stream:
* "out", "err", or "both". If none specified, swallow the input.
*/
public static class PipeEntryPoint {
/**
* pipe input to specified output
*/
public static void main(String[] args) throws InterruptedException {
OutputStream os = null;
if (args.length > 0) {
if ("out".equalsIgnoreCase(args[0])) {
os = System.out;
} else if ("err".equalsIgnoreCase(args[0])) {
os = System.err;
} else if ("both".equalsIgnoreCase(args[0])) {
os = new TeeOutputStream(System.out, System.err);
}
}
if (os != null) {
Thread t = new Thread(new StreamPumper(System.in, os, true));
t.setName("PipeEntryPoint " + args[0]);
t.start();
t.join();
}
}
}
public static class ReadPoint {
public static void main(String[] args) throws IOException {
String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
System.out.println(line);
}
}
}