| /* | |
| * Copyright (c) 2021, 2025, 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 java -m jdk.httpserver command 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 LOCALE_OPT = "-Duser.language=en -Duser.country=US"; | |
| 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, LOCALE_OPT, "-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 - Prints this help message and exits. | |
| -version, --version - Prints version information and exits. | |
| 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; | |
| } | |
| } |