View Javadoc

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