diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java new file mode 100644 index 0000000000000..9e53d1008e4e3 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2021, 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. + */ + +/* + * @test + * @bug 8276848 + * @summary Tests the command-line tool with port not specified + * @modules jdk.httpserver + * @library /test/lib + * @run testng/othervm/manual CommandLinePortNotSpecifiedTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.lang.System.out; + +public class CommandLinePortNotSpecifiedTest { + + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JAVA = getJava(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("CommandLinePortNotSpecifiedTest"); + static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); + static final String TEST_DIR_STR = TEST_DIR.toString(); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + Files.createFile(TEST_FILE); + } + + static final int SIGTERM = 15; + static final int NORMAL_EXIT_CODE = normalExitCode(); + + static int normalExitCode() { + if (Platform.isWindows()) { + return 1; // expected process destroy exit code + } else { + // signal terminated exit code on Unix is 128 + signal value + return 128 + SIGTERM; + } + } + + /** + * This is a manual test to confirm the command-line tool starts successfully + * in the case where the port is not specified. In this case the server uses + * the default port 8000. The test is manual to avoid a BindException in the + * unlikely but not impossible case that the port is already in use. + */ + @Test + public void testPortNotSpecified() throws Throwable { + out.println("\n--- testPortNotSpecified"); + simpleserver(JAVA, "-m", "jdk.httpserver") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJava(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java"); + if (Files.notExists(java)) + throw new RuntimeException(java + " not found"); + return java.toAbsolutePath().toString(); + } + + static final String REGULAR_STARTUP_LINE1_STRING = "Serving"; + static final String REGULAR_STARTUP_LINE2_STRING = "URL http://"; + + static final String OPTIONS_TEXT = """ + Options: + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::". + -d, --directory - Directory to serve. Default: current directory. + -o, --output - Output format. none|info|verbose. Default: info. + -p, --port - Port to listen on. Default: 8000. + -h, -?, --help - Print this help message. + To stop the server, press Ctrl + C.""".formatted(LOOPBACK_ADDR); + + // The stdout/stderr output line to wait for when starting the simpleserver + enum WaitForLine { + REGULAR_STARTUP_LINE (REGULAR_STARTUP_LINE2_STRING) , + HELP_STARTUP_LINE (OPTIONS_TEXT.lines().reduce((first, second) -> second).orElseThrow()); + + final String value; + WaitForLine(String value) { this.value = value; } + } + + static OutputAnalyzer simpleserver(String... args) throws Throwable { + return simpleserver(WaitForLine.REGULAR_STARTUP_LINE, true, args); + } + + static OutputAnalyzer simpleserver(WaitForLine waitForLine, boolean destroy, String... args) throws Throwable { + StringBuffer sb = new StringBuffer(); // stdout & stderr + // start the process and await the waitForLine before returning + var p = ProcessTools.startProcess("simpleserver", + new ProcessBuilder(args).directory(TEST_DIR.toFile()), + line -> sb.append(line + "\n"), + line -> line.startsWith(waitForLine.value), + 30, // suitably high default timeout, not expected to timeout + TimeUnit.SECONDS); + if (destroy) { + p.destroy(); // SIGTERM on Unix + } + int ec = p.waitFor(); + var outputAnalyser = new OutputAnalyzer(sb.toString(), "", ec); + return outputAnalyser; + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java index a5e636c354d4b..c17b9e1b9732d 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java @@ -134,8 +134,8 @@ public void testHelp(String opt) throws Throwable { @Test(dataProvider = "bindOptions") public void testBindAllInterfaces(String opt) throws Throwable { - out.println("\n--- testPort, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, "0.0.0.0") + out.println("\n--- testBindAllInterfaces, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, "0.0.0.0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress());