1 /*
  2  * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @summary Test to stress directory listings
 27  * @library /test/lib
 28  * @run testng/othervm/timeout=180 StressDirListings
 29  */
 30 
 31 import java.io.IOException;
 32 import java.net.InetAddress;
 33 import java.net.InetSocketAddress;
 34 import java.net.URI;
 35 import java.net.http.HttpClient;
 36 import java.net.http.HttpRequest;
 37 import java.net.http.HttpResponse.BodyHandlers;
 38 import java.nio.file.Path;
 39 import java.util.logging.ConsoleHandler;
 40 import java.util.logging.Level;
 41 import java.util.logging.Logger;
 42 import com.sun.net.httpserver.HttpServer;
 43 import com.sun.net.httpserver.SimpleFileServer;
 44 import com.sun.net.httpserver.SimpleFileServer.OutputLevel;
 45 import jdk.test.lib.net.URIBuilder;
 46 import org.testng.annotations.AfterTest;
 47 import org.testng.annotations.BeforeTest;
 48 import org.testng.annotations.Test;
 49 import static java.lang.System.out;
 50 import static java.net.http.HttpClient.Builder.NO_PROXY;
 51 import static org.testng.Assert.assertEquals;
 52 
 53 public class StressDirListings {
 54 
 55     static final Path CWD = Path.of(".").toAbsolutePath();
 56     static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
 57 
 58     static final boolean ENABLE_LOGGING = false;
 59     static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver");
 60     static final long start = System.nanoTime();
 61     public static String now() {
 62         long now = System.nanoTime() - start;
 63         long secs = now / 1000_000_000;
 64         long mill = (now % 1000_000_000) / 1000_000;
 65         long nan = now % 1000_000;
 66         return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
 67     }
 68 
 69     HttpServer simpleFileServer;
 70 
 71     @BeforeTest
 72     public void setup() throws IOException {
 73         out.println(now() + " creating server");
 74         if (ENABLE_LOGGING) {
 75             ConsoleHandler ch = new ConsoleHandler();
 76             LOGGER.setLevel(Level.ALL);
 77             ch.setLevel(Level.ALL);
 78             LOGGER.addHandler(ch);
 79         }
 80         simpleFileServer = SimpleFileServer.createFileServer(LOOPBACK_ADDR, CWD, OutputLevel.VERBOSE);
 81         simpleFileServer.start();
 82         out.println(now() + " server started");
 83     }
 84 
 85     @AfterTest
 86     public void teardown() {
 87         out.println(now() + " stopping server");
 88         simpleFileServer.stop(0);
 89         out.println(now() + " server stopped");
 90     }
 91 
 92     // Enough to trigger FileSystemException: Too many open files (machine dependent)
 93     static final int TIMES = 11_000;
 94 
 95     /**
 96      * Issues a large number of identical GET requests sequentially, each of
 97      * which returns the root directory listing. An IOException will be thrown
 98      * if the server does not issue a valid reply, e.g. the server logic that
 99      * enumerates the directory files fails to close the stream from Files::list.
100      */
101     @Test
102     public void testDirListings() throws Exception {
103         out.println(now() + " starting test");
104         var client = HttpClient.newBuilder().proxy(NO_PROXY).build();
105         var request = HttpRequest.newBuilder(uri(simpleFileServer)).build();
106         for (int i=0; i<TIMES; i++) {
107             var response = client.send(request, BodyHandlers.ofString());
108             assertEquals(response.statusCode(), 200);
109             if (i % 100 == 0) {
110                 out.print(" " + i + " ");
111             }
112             if (i % 1000 == 0) {
113                 out.println(now());
114             }
115         }
116         out.println(now() + " test finished");
117     }
118 
119     static URI uri(HttpServer server) {
120         return URIBuilder.newBuilder()
121                 .host("localhost")
122                 .port(server.getAddress().getPort())
123                 .scheme("http")
124                 .path("/")
125                 .buildUnchecked();
126     }
127 }