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              Random random = new Random( System.nanoTime() );
54  
55              String contextPath = "";
56              String servletMapping = "/server";
57              int port1 = random.nextInt( 50000 ) + 10000;
58              AbstractTestServer server1 = createServer( port1 );
59              server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
60              server1.start();
61              try
62              {
63                  int port2 = random.nextInt( 50000 ) + 10000;
64                  AbstractTestServer server2 = createServer( port2 );
65                  server2.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
66                  server2.start();
67                  try
68                  {
69                      HttpClient client = new HttpClient();
70                      client.setConnectorType( HttpClient.CONNECTOR_SOCKET );
71                      client.start();
72                      try
73                      {
74                          String[] urls = new String[2];
75                          urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
76                          urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
77  
78                          ContentExchange exchange1 = new ContentExchange( true );
79                          exchange1.setMethod( HttpMethods.GET );
80                          exchange1.setURL( urls[0] + "?action=init" );
81                          client.send( exchange1 );
82                          exchange1.waitForDone();
83                          assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
84                          String sessionCookie = exchange1.getResponseFields().getStringField( "Set-Cookie" );
85                          assertTrue(sessionCookie != null);
86                          // Mangle the cookie, replacing Path with $Path, etc.
87                          sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
88  
89                          ExecutorService executor = Executors.newCachedThreadPool();
90                          int clientsCount = 50;
91                          CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
92                          int requestsCount = 100;
93                          Worker[] workers = new Worker[clientsCount];
94                          for ( int i = 0; i < clientsCount; ++i )
95                          {
96                              workers[i] = new Worker( barrier, requestsCount, sessionCookie, urls );
97                              workers[i].start();
98                              executor.execute( workers[i] );
99                          }
100                         // Wait for all workers to be ready
101                         barrier.await();
102                         long start = System.nanoTime();
103 
104                         // Wait for all workers to be done
105                         barrier.await();
106                         long end = System.nanoTime();
107                         long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
108                         System.out.println( "elapsed ms: " + elapsed );
109 
110                         for ( Worker worker : workers )
111                             worker.stop();
112                         executor.shutdownNow();
113 
114                         // Perform one request to get the result
115                         ContentExchange exchange2 = new ContentExchange( true );
116                         exchange2.setMethod( HttpMethods.GET );
117                         exchange2.setURL( urls[0] + "?action=result" );
118                         exchange2.getRequestFields().add( "Cookie", sessionCookie );
119                         client.send( exchange2 );
120                         exchange2.waitForDone();
121                         assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
122                         String response = exchange2.getResponseContent();
123                         System.out.println( "get = " + response );
124                         assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) );
125                     }
126                     finally
127                     {
128                         client.stop();
129                     }
130                 }
131                 finally
132                 {
133                     server2.stop();
134                 }
135             }
136             finally
137             {
138                 server1.stop();
139             }
140         }
141     }
142 
143     public static class Worker
144         implements Runnable
145     {
146         private final HttpClient client;
147 
148         private final CyclicBarrier barrier;
149 
150         private final int requestsCount;
151 
152         private final String sessionCookie;
153 
154         private final String[] urls;
155 
156         public Worker( CyclicBarrier barrier, int requestsCount, String sessionCookie, String[] urls )
157         {
158             this.client = new HttpClient();
159             this.client.setConnectorType( HttpClient.CONNECTOR_SOCKET );
160             this.barrier = barrier;
161             this.requestsCount = requestsCount;
162             this.sessionCookie = sessionCookie;
163             this.urls = urls;
164         }
165 
166         public void start()
167             throws Exception
168         {
169             client.start();
170         }
171 
172         public void stop()
173             throws Exception
174         {
175             client.stop();
176         }
177 
178         public void run()
179         {
180             try
181             {
182                 // Wait for all workers to be ready
183                 barrier.await();
184 
185                 Random random = new Random( System.nanoTime() );
186 
187                 for ( int i = 0; i < requestsCount; ++i )
188                 {
189                     int urlIndex = random.nextInt( urls.length );
190 
191                     ContentExchange exchange = new ContentExchange( true );
192                     exchange.setMethod( HttpMethods.GET );
193                     exchange.setURL( urls[urlIndex] + "?action=increment" );
194                     exchange.getRequestFields().add( "Cookie", sessionCookie );
195                     client.send( exchange );
196                     exchange.waitForDone();
197                     assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
198                 }
199 
200                 // Wait for all workers to be done
201                 barrier.await();
202             }
203             catch ( Exception x )
204             {
205                 throw new RuntimeException( x );
206             }
207         }
208     }
209 
210     public static class TestServlet
211         extends HttpServlet
212     {
213         @Override
214         protected void doGet( HttpServletRequest request, HttpServletResponse response )
215             throws ServletException, IOException
216         {
217             String action = request.getParameter( "action" );
218             if ( "init".equals( action ) )
219             {
220                 HttpSession session = request.getSession( true );
221                 session.setAttribute( "value", 0 );
222             }
223             else if ( "increment".equals( action ) )
224             {
225                 // Without synchronization, because it is taken care by Jetty/Terracotta
226                 HttpSession session = request.getSession( false );
227                 int value = (Integer) session.getAttribute( "value" );
228                 session.setAttribute( "value", value + 1 );
229             }
230             else if ( "result".equals( action ) )
231             {
232                 HttpSession session = request.getSession( false );
233                 int value = (Integer) session.getAttribute( "value" );
234                 PrintWriter writer = response.getWriter();
235                 writer.println( value );
236                 writer.flush();
237             }
238         }
239     }
240 }