1515 */ 
1616package  io .fabric8 .kubernetes .client .http ;
1717
18- import  com .sun .net .httpserver .HttpExchange ;
19- import  com .sun .net .httpserver .HttpHandler ;
20- import  com .sun .net .httpserver .HttpServer ;
18+ import  io .fabric8 .kubernetes .client .RequestConfigBuilder ;
2119import  io .fabric8 .mockwebserver .MockWebServer ;
2220import  io .fabric8 .mockwebserver .MockWebServerListener ;
2321import  io .fabric8 .mockwebserver .http .MockResponse ;
2422import  io .fabric8 .mockwebserver .http .RecordedHttpConnection ;
2523import  io .fabric8 .mockwebserver .http .Response ;
2624import  io .fabric8 .mockwebserver .http .WebSocketListener ;
2725import  io .fabric8 .mockwebserver .vertx .Protocol ;
26+ import  io .vertx .core .Vertx ;
27+ import  io .vertx .core .http .HttpServer ;
28+ import  io .vertx .core .http .HttpServerOptions ;
29+ import  io .vertx .core .http .HttpServerRequest ;
30+ import  io .vertx .core .http .HttpVersion ;
31+ import  io .vertx .core .net .NetServerOptions ;
32+ import  org .awaitility .Awaitility ;
2833import  org .junit .jupiter .api .AfterEach ;
2934import  org .junit .jupiter .api .BeforeEach ;
3035import  org .junit .jupiter .api .DisplayName ;
3136import  org .junit .jupiter .api .Test ;
3237import  org .junit .jupiter .api .condition .DisabledOnOs ;
3338import  org .junit .jupiter .api .condition .OS ;
3439
35- import  java .io .IOException ;
36- import  java .net .InetSocketAddress ;
3740import  java .net .URI ;
3841import  java .util .Collection ;
3942import  java .util .Collections ;
4245import  java .util .concurrent .ConcurrentHashMap ;
4346import  java .util .concurrent .CountDownLatch ;
4447import  java .util .concurrent .CyclicBarrier ;
45- import  java .util .concurrent .ExecutorService ;
46- import  java .util .concurrent .Executors ;
4748import  java .util .concurrent .TimeUnit ;
4849import  java .util .stream .IntStream ;
4950
@@ -59,29 +60,24 @@ public abstract class AbstractSimultaneousConnectionsTest {
5960
6061  private  RegisteredConnections  registeredConnections ;
6162  private  MockWebServer  mockWebServer ;
62-   private  ExecutorService  httpExecutor ;
63-   private  HttpServer  httpServer ;
63+   private  Vertx  vertx ;
6464
6565  private  HttpClient .Builder  clientBuilder ;
6666
6767  @ BeforeEach 
68-   void  prepareServerAndBuilder () throws   IOException   {
68+   void  prepareServerAndBuilder () {
6969    registeredConnections  = new  RegisteredConnections ();
7070    mockWebServer  = new  MockWebServer ();
7171    mockWebServer .addListener (registeredConnections );
72-     httpExecutor  = Executors .newCachedThreadPool ();
73-     httpServer  = HttpServer .create (new  InetSocketAddress (0 ), 0 );
74-     httpServer .setExecutor (httpExecutor );
75-     httpServer .start ();
72+     vertx  = Vertx .vertx ();
7673    clientBuilder  = getHttpClientFactory ().newBuilder ()
7774        .connectTimeout (60 , TimeUnit .SECONDS );
7875  }
7976
8077  @ AfterEach 
8178  void  stopServer () {
8279    mockWebServer .shutdown ();
83-     httpServer .stop (0 );
84-     httpExecutor .shutdownNow ();
80+     vertx .close ();
8581  }
8682
8783  protected  abstract  HttpClient .Factory  getHttpClientFactory ();
@@ -95,20 +91,21 @@ private void withHttp1() {
9591  @ DisplayName ("Should be able to make 2048 simultaneous HTTP/1.x connections before processing the response" )
9692  @ DisabledOnOs (OS .WINDOWS )
9793  public  void  http1Connections () throws  Exception  {
98-     final  DelayedResponseHandler  handler  = new  DelayedResponseHandler (MAX_HTTP_1_CONNECTIONS ,
99-         exchange  -> {
100-           exchange .sendResponseHeaders (204 , -1 );
101-           exchange .close ();
102-         });
103-     httpServer .createContext ("/http" , handler );
104-     try  (final  HttpClient  client  = clientBuilder .build ()) {
105-       final  Collection <CompletableFuture <HttpResponse <AsyncBody >>> asyncResponses  = ConcurrentHashMap .newKeySet ();
106-       final  HttpRequest  request  = client .newHttpRequestBuilder ()
107-           .uri (String .format ("http://localhost:%s/http" , httpServer .getAddress ().getPort ()))
108-           .build ();
94+     final  Collection <CompletableFuture <HttpResponse <AsyncBody >>> asyncResponses  = ConcurrentHashMap .newKeySet ();
95+     try  (
96+         var  server  = new  DelayedResponseHttp1Server (vertx , MAX_HTTP_1_CONNECTIONS );
97+         var  client  = clientBuilder .tag (new  RequestConfigBuilder ().withRequestRetryBackoffLimit (0 ).build ()).build ()) {
10998      for  (int  it  = 0 ; it  < MAX_HTTP_1_CONNECTIONS ; it ++) {
99+         final  HttpRequest  request  = client .newHttpRequestBuilder ()
100+             .uri (server .uri () + "?"  + it )
101+             .build ();
110102        asyncResponses .add (client .consumeBytes (request , (value , asyncBody ) -> asyncBody .consume ()));
111-         handler .await ();
103+       }
104+       server .await ();
105+       assertThat (server .requests )
106+           .hasSize (MAX_HTTP_1_CONNECTIONS );
107+       for  (HttpServerRequest  serverRequest  : server .requests ) {
108+         serverRequest .response ().setStatusCode (204 ).end ();
112109      }
113110      CompletableFuture .allOf (asyncResponses .toArray (new  CompletableFuture [0 ])).get (70 , TimeUnit .SECONDS );
114111      assertThat (asyncResponses )
@@ -126,19 +123,18 @@ public void http1Connections() throws Exception {
126123  @ DisplayName ("Should be able to make 1024 simultaneous HTTP connections before upgrading to WebSocket" )
127124  @ DisabledOnOs (OS .WINDOWS )
128125  public  void  http1WebSocketConnectionsBeforeUpgrade () throws  Exception  {
129-     final  DelayedResponseHandler  handler  = new  DelayedResponseHandler (MAX_HTTP_1_WS_CONNECTIONS ,
130-         exchange  -> exchange .sendResponseHeaders (404 , -1 ));
131-     httpServer .createContext ("/http" , handler );
132-     try  (final  HttpClient  client  = clientBuilder .build ()) {
126+     try  (var  server  = new  DelayedResponseHttp1Server (vertx , MAX_HTTP_1_WS_CONNECTIONS ); var  client  = clientBuilder .build ()) {
133127      for  (int  it  = 0 ; it  < MAX_HTTP_1_WS_CONNECTIONS ; it ++) {
134128        client .newWebSocketBuilder ()
135-             .uri (URI .create (String . format ( "http://localhost:%s/http" ,  httpServer . getAddress (). getPort () )))
129+             .uri (URI .create (server . uri ( )))
136130            .buildAsync (new  WebSocket .Listener () {
137131            });
138-         handler .await ();
139132      }
133+       server .await ();
134+       assertThat (server .requests )
135+           .hasSize (MAX_HTTP_1_WS_CONNECTIONS );
136+       server .requests .forEach (request  -> request .response ().setStatusCode (101 ).end ());
140137    }
141-     assertThat (handler .connectionCount .get (60 , TimeUnit .SECONDS )).isEqualTo (MAX_HTTP_1_WS_CONNECTIONS );
142138  }
143139
144140  @ Test 
@@ -192,47 +188,46 @@ public void onMessage(WebSocket webSocket, String text) {
192188    }
193189  }
194190
195-   private  static  class  DelayedResponseHandler  implements  HttpHandler  {
196- 
197-     private  final  int  requestCount ;
198-     private  final  CyclicBarrier  barrier ;
199-     private  final  Set <HttpExchange > exchanges ;
200-     private  final  CompletableFuture <Integer > connectionCount ;
201-     private  final  ExecutorService  executorService ;
202- 
203-     private  DelayedResponseHandler (int  requestCount , HttpHandler  handler ) {
204-       this .requestCount  = requestCount ;
205-       this .barrier  = new  CyclicBarrier (2 );
206-       exchanges  = ConcurrentHashMap .newKeySet ();
207-       connectionCount  = new  CompletableFuture <>();
208-       executorService  = Executors .newFixedThreadPool (1 );
209-       connectionCount .thenRunAsync (() -> {
210-         for  (HttpExchange  exchange  : exchanges ) {
211-           try  {
212-             handler .handle (exchange );
213-           } catch  (IOException  ignore ) {
214-             // NO OP 
215-           }
216-         }
217-       }, executorService )
218-           .whenComplete ((unused , throwable ) -> executorService .shutdownNow ());
191+   private  static  class  DelayedResponseHttp1Server  implements  AutoCloseable  {
192+ 
193+     private  final  int  connections ;
194+     private  final  HttpServer  httpServer ;
195+     private  final  Collection <HttpServerRequest > requests ;
196+     private  final  CountDownLatch  connectionLatch ;
197+ 
198+     private  DelayedResponseHttp1Server (Vertx  vertx , int  connections ) throws  Exception  {
199+       this .connections  = connections ;
200+       requests  = ConcurrentHashMap .newKeySet ();
201+       connectionLatch  = new  CountDownLatch (connections );
202+       httpServer  = vertx .createHttpServer (new  HttpServerOptions ()
203+           .setPort (NetServerOptions .DEFAULT_PORT )
204+           .setAlpnVersions (Collections .singletonList (HttpVersion .HTTP_1_1 )));
205+       httpServer .connectionHandler (event  -> connectionLatch .countDown ());
206+       httpServer .requestHandler (requests ::add );
207+       httpServer .listen ().toCompletionStage ().toCompletableFuture ().get (10 , TimeUnit .SECONDS );
219208    }
220209
221210    @ Override 
222-     public  void  handle (HttpExchange  exchange ) {
223-       exchanges .add (exchange );
224-       await ();
225-       if  (exchanges .size () == requestCount ) {
226-         connectionCount .complete (requestCount );
227-       }
211+     public  void  close () throws  Exception  {
212+       requests .forEach (request  -> request .connection ().close ());
213+       requests .clear ();
214+       httpServer .close ().toCompletionStage ().toCompletableFuture ().get (10 , TimeUnit .SECONDS );
215+     }
228216
217+     private  String  uri () {
218+       return  String .format ("http://localhost:%s/http-1-connections" , httpServer .actualPort ());
229219    }
230220
231-     public   final  void  await () {
221+     private  void  await () {
232222      try  {
233-         barrier .await (5 , TimeUnit .SECONDS );
234-       } catch  (Exception  ex ) {
235-         throw  new  RuntimeException ("Failed to await the barrier" );
223+         if  (!connectionLatch .await (10 , TimeUnit .SECONDS )) {
224+           throw  new  AssertionError (
225+               "Failed to await the connection latch, remaining connections to open: "  + connectionLatch .getCount ());
226+         }
227+         Awaitility .await ().atMost (5 , TimeUnit .SECONDS ).until (() -> requests .size () == connections );
228+       } catch  (InterruptedException  e ) {
229+         Thread .currentThread ().interrupt ();
230+         throw  new  RuntimeException ("Failed to await the connection latch (interrupted)" , e );
236231      }
237232    }
238233  }
0 commit comments