View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server.session;
20  
21  import java.io.IOException;
22  import java.io.PrintWriter;
23  import java.util.Random;
24  import java.util.concurrent.CyclicBarrier;
25  import java.util.concurrent.ExecutorService;
26  import java.util.concurrent.Executors;
27  import java.util.concurrent.TimeUnit;
28  
29  import javax.servlet.ServletException;
30  import javax.servlet.http.HttpServlet;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  import javax.servlet.http.HttpSession;
34  
35  import org.eclipse.jetty.client.ContentExchange;
36  import org.eclipse.jetty.client.HttpClient;
37  import org.eclipse.jetty.http.HttpMethods;
38  import org.junit.Test;
39  import static org.junit.Assert.assertEquals;
40  import static org.junit.Assert.assertTrue;
41  
42  
43  /**
44   * AbstractLightLoadTest
45   */
46  public abstract class AbstractLightLoadTest
47  {
48      protected boolean _stress = Boolean.getBoolean( "STRESS" );
49  
50      public abstract AbstractTestServer createServer(int port);
51  
52      @Test
53      public void testLightLoad()
54          throws Exception
55      {
56          if ( _stress )
57          {
58              String contextPath = "";
59              String servletMapping = "/server";
60              AbstractTestServer server1 = createServer( 0 );
61              server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
62              server1.start();
63              int port1 = server1.getPort();
64              try
65              {
66                  AbstractTestServer server2 = createServer( 0 );
67                  server2.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
68                  server2.start();
69                  int port2=server2.getPort();
70                  try
71                  {
72                      HttpClient client = new HttpClient();
73                      client.setConnectorType( HttpClient.CONNECTOR_SOCKET );
74                      client.start();
75                      try
76                      {
77                          String[] urls = new String[2];
78                          urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
79                          urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
80  
81                          ContentExchange exchange1 = new ContentExchange( true );
82                          exchange1.setMethod( HttpMethods.GET );
83                          exchange1.setURL( urls[0] + "?action=init" );
84                          client.send( exchange1 );
85                          exchange1.waitForDone();
86                          assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
87                          String sessionCookie = exchange1.getResponseFields().getStringField( "Set-Cookie" );
88                          assertTrue(sessionCookie != null);
89                          // Mangle the cookie, replacing Path with $Path, etc.
90                          sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
91  
92                          ExecutorService executor = Executors.newCachedThreadPool();
93                          int clientsCount = 50;
94                          CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
95                          int requestsCount = 100;
96                          Worker[] workers = new Worker[clientsCount];
97                          for ( int i = 0; i < clientsCount; ++i )
98                          {
99                              workers[i] = new Worker( barrier, requestsCount, sessionCookie, urls );
100                             workers[i].start();
101                             executor.execute( workers[i] );
102                         }
103                         // Wait for all workers to be ready
104                         barrier.await();
105                         long start = System.nanoTime();
106 
107                         // Wait for all workers to be done
108                         barrier.await();
109                         long end = System.nanoTime();
110                         long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
111                         System.out.println( "elapsed ms: " + elapsed );
112 
113                         for ( Worker worker : workers )
114                             worker.stop();
115                         executor.shutdownNow();
116 
117                         // Perform one request to get the result
118                         ContentExchange exchange2 = new ContentExchange( true );
119                         exchange2.setMethod( HttpMethods.GET );
120                         exchange2.setURL( urls[0] + "?action=result" );
121                         exchange2.getRequestFields().add( "Cookie", sessionCookie );
122                         client.send( exchange2 );
123                         exchange2.waitForDone();
124                         assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
125                         String response = exchange2.getResponseContent();
126                         System.out.println( "get = " + response );
127                         assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) );
128                     }
129                     finally
130                     {
131                         client.stop();
132                     }
133                 }
134                 finally
135                 {
136                     server2.stop();
137                 }
138             }
139             finally
140             {
141                 server1.stop();
142             }
143         }
144     }
145 
146     public static class Worker
147         implements Runnable
148     {
149         private final HttpClient client;
150 
151         private final CyclicBarrier barrier;
152 
153         private final int requestsCount;
154 
155         private final String sessionCookie;
156 
157         private final String[] urls;
158 
159         public Worker( CyclicBarrier barrier, int requestsCount, String sessionCookie, String[] urls )
160         {
161             this.client = new HttpClient();
162             this.client.setConnectorType( HttpClient.CONNECTOR_SOCKET );
163             this.barrier = barrier;
164             this.requestsCount = requestsCount;
165             this.sessionCookie = sessionCookie;
166             this.urls = urls;
167         }
168 
169         public void start()
170             throws Exception
171         {
172             client.start();
173         }
174 
175         public void stop()
176             throws Exception
177         {
178             client.stop();
179         }
180 
181         public void run()
182         {
183             try
184             {
185                 // Wait for all workers to be ready
186                 barrier.await();
187 
188                 Random random = new Random( System.nanoTime() );
189 
190                 for ( int i = 0; i < requestsCount; ++i )
191                 {
192                     int urlIndex = random.nextInt( urls.length );
193 
194                     ContentExchange exchange = new ContentExchange( true );
195                     exchange.setMethod( HttpMethods.GET );
196                     exchange.setURL( urls[urlIndex] + "?action=increment" );
197                     exchange.getRequestFields().add( "Cookie", sessionCookie );
198                     client.send( exchange );
199                     exchange.waitForDone();
200                     assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
201                 }
202 
203                 // Wait for all workers to be done
204                 barrier.await();
205             }
206             catch ( Exception x )
207             {
208                 throw new RuntimeException( x );
209             }
210         }
211     }
212 
213     public static class TestServlet
214         extends HttpServlet
215     {
216         @Override
217         protected void doGet( HttpServletRequest request, HttpServletResponse response )
218             throws ServletException, IOException
219         {
220             String action = request.getParameter( "action" );
221             if ( "init".equals( action ) )
222             {
223                 HttpSession session = request.getSession( true );
224                 session.setAttribute( "value", 0 );
225             }
226             else if ( "increment".equals( action ) )
227             {
228                 // Without synchronization, because it is taken care by Jetty/Terracotta
229                 HttpSession session = request.getSession( false );
230                 int value = (Integer) session.getAttribute( "value" );
231                 session.setAttribute( "value", value + 1 );
232             }
233             else if ( "result".equals( action ) )
234             {
235                 HttpSession session = request.getSession( false );
236                 int value = (Integer) session.getAttribute( "value" );
237                 PrintWriter writer = response.getWriter();
238                 writer.println( value );
239                 writer.flush();
240             }
241         }
242     }
243 }