1 18 19 package org.apache.beehive.netui.tools.testrecorder.client; 20 21 import org.apache.beehive.netui.tools.testrecorder.shared.Logger; 22 import org.apache.beehive.netui.tools.testrecorder.shared.RecordSessionBean; 23 import org.apache.beehive.netui.tools.testrecorder.shared.Constants; 24 import org.apache.beehive.netui.tools.testrecorder.shared.RequestData; 25 import org.apache.beehive.netui.tools.testrecorder.shared.NVPair; 26 import org.apache.beehive.netui.tools.testrecorder.shared.ResponseData; 27 import org.apache.beehive.netui.tools.testrecorder.shared.xmlbeans.XMLHelper; 28 import org.apache.beehive.netui.tools.testrecorder.shared.config.TestDefinition; 29 import org.apache.commons.httpclient.HttpClient; 30 import org.apache.commons.httpclient.HttpMethod; 31 import org.apache.commons.httpclient.NameValuePair; 32 import org.apache.commons.httpclient.HttpRecoverableException; 33 import org.apache.commons.httpclient.Header; 34 import org.apache.commons.httpclient.methods.PostMethod; 35 import org.apache.commons.httpclient.methods.GetMethod; 36 37 import java.text.DecimalFormat ; 38 import java.text.NumberFormat ; 39 import java.util.Locale ; 40 import java.util.List ; 41 import java.io.File ; 42 import java.io.IOException ; 43 44 49 public class PlaybackExecutor { 50 51 private static final Logger log = Logger.getInstance( PlaybackExecutor.class ); 52 53 private static HttpClient controlClient = new HttpClient(); 54 private static HttpClient testClient = new HttpClient(); 55 56 private static final DecimalFormat format = (DecimalFormat ) 57 NumberFormat.getInstance( Locale.US ); 58 59 static { 60 format.setDecimalSeparatorAlwaysShown( false ); 62 format.setGroupingSize( 0 ); 63 } 64 65 private TestDefinition test; 66 private String description; 67 private String testUser; 68 private File recordFile; 69 private File resultsFile; 70 private File diffFile; 71 72 private NameValuePair[] startParams; 73 private NameValuePair[] stopParams; 74 75 private String testId; 76 private RecordSessionBean session; 77 78 79 public PlaybackExecutor( TestDefinition test, 80 String description, String testUser ) { 81 this.test = test; 82 assert test != null : "the test definition name may not be null"; 83 this.description = description; 84 if ( description == null ) { 85 description = "No Description."; 86 } 87 this.testUser = testUser; 88 setControlParams(); 89 } 90 91 protected void setControlParams() { 92 startParams = new NameValuePair[6]; 93 stopParams = new NameValuePair[4]; 94 95 startParams[0] = new NameValuePair( Constants.MODE, Constants.PLAYBACK ); 96 startParams[1] = new NameValuePair( Constants.CMD, Constants.START ); 97 startParams[2] = new NameValuePair( Constants.FILTER_SKIP_PARAM, Boolean.TRUE.toString() ); 98 startParams[3] = new NameValuePair( Constants.TEST_NAME, getTest().getName() ); 99 startParams[4] = new NameValuePair( Constants.DESCRIPTION, getDescription() ); 100 startParams[5] = new NameValuePair( Constants.TEST_USER, getTestUser() ); 101 102 stopParams[0] = new NameValuePair( Constants.MODE, Constants.PLAYBACK ); 103 stopParams[1] = new NameValuePair( Constants.CMD, Constants.STOP ); 104 stopParams[2] = new NameValuePair( Constants.FILTER_SKIP_PARAM, Boolean.TRUE.toString() ); 105 } 106 107 public boolean run() throws PlaybackException { 108 boolean rtnVal = false; 109 Throwable exception = null; 111 try { 112 startPlayback(); 113 executeRequests(); 114 } 115 catch ( Throwable e ) { 116 log.error( "start failure", e ); 117 exception = e; 118 } 119 finally { 120 if ( getTestId() != null ) { 121 try { 123 rtnVal = stopPlayback(); 124 } 125 catch ( Throwable e ) { 126 if ( exception == null ) { 127 exception = e; 128 } 129 else { 130 log.error( "ERROR: possible spurious failure, failed to stop playback, exception( " + 131 e.getMessage() + " )", e ); 132 } 133 } 134 } 135 if ( exception != null ) { 136 String msg = "ERROR: playback failed, exception( " + exception.getMessage() + " )"; 137 log.error( msg, exception ); 138 if ( exception instanceof PlaybackException ) { 139 throw (PlaybackException) exception; 140 } 141 throw new PlaybackException( msg, exception ); 142 } 143 } 144 return rtnVal; 145 } 146 147 protected void startPlayback() throws PlaybackException { 148 HttpMethod method = new GetMethod( RequestData.genUri( "http", 149 getTest().getWebapp().getServer().getHostname(), getTest().getWebapp().getServer().getPort(), 150 getTest().getWebapp().getServletURI() ) ); 151 method.setQueryString( getStartParams() ); 152 ResponseData response = null; 153 try { 154 response = execute( getControlClient(), method ); 155 } 156 catch ( Exception e ) { 157 String msg = "Failed to execute start playback request, exception( " + e.getMessage() + " )"; 158 log.error( msg, e ); 159 if ( e instanceof PlaybackException ) { 160 throw (PlaybackException) e; 161 } 162 throw new PlaybackException( msg, e ); 163 } 164 String outcome = response.getHeader( Constants.OUTCOME_HEADER ); 165 String testId = response.getHeader( Constants.TEST_ID_HEADER ); 166 String testFileName = response.getHeader( Constants.RECORD_FILE_HEADER ); 167 String startMsg = response.getHeader( Constants.MSG_ATTRIBUTE ); 168 setStopParam( 3, new NameValuePair( Constants.TEST_ID_HEADER, testId ) ); 170 setTestId( testId ); 171 if ( log.isInfoEnabled() ) { 172 log.info( "outcome( " + outcome + " )" ); 173 log.info( "testId( " + getTestId() + " )" ); 174 log.info( "testFileName( " + testFileName + " )" ); 175 } 176 if ( outcome == null || !outcome.equals( Constants.PASS ) ) { 178 throw new PlaybackException( 179 "ERROR: failed to start playback, server error message( " + startMsg + " )" ); 180 } 181 this.recordFile = new File ( testFileName ); 182 if ( !getRecordFile().canRead() ) { 183 String msg = "ERROR: failed to start playback, lacking permissions to read record file( " + 184 getRecordFile() + " )"; 185 System.out.println( msg ); 186 log.error( msg ); 187 throw new PlaybackException( msg ); 188 } 189 RecordSessionBean session = createSession(); 190 setSession( session ); 191 if ( log.isInfoEnabled() ) { 192 log.info( "playback started for test( " + getTest().getName() + " )" ); 193 } 194 } 195 196 protected boolean stopPlayback() throws PlaybackException { 197 boolean rtnVal = false; 198 HttpMethod method = new GetMethod( RequestData.genUri( "http", 199 getTest().getWebapp().getServer().getHostname(), getTest().getWebapp().getServer().getPort(), 200 getTest().getWebapp().getServletURI() ) ); 201 method.setQueryString( getStopParams() ); 202 ResponseData response = null; 203 try { 204 response = execute( getControlClient(), method ); 205 } 206 catch ( Exception e ) { 207 String msg = "Failed to execute stop playback request, exception( " + e.getMessage() + " )"; 208 log.error( msg, e ); 209 if ( e instanceof PlaybackException ) { 210 throw (PlaybackException) e; 211 } 212 throw new PlaybackException( msg, e ); 213 } 214 String outcome = response.getHeader( Constants.OUTCOME_HEADER ); 215 String resultsFileName = response.getHeader( Constants.RESULTS_FILE_HEADER ); 216 String diffFileName = response.getHeader( Constants.RESULTS_DIFF_HEADER ); 217 String stopMsg = response.getHeader( Constants.MSG_ATTRIBUTE ); 218 if ( log.isDebugEnabled() ) { 219 log.debug( "stop outcome( " + outcome + " )" ); 220 log.debug( "stopMsg( " + stopMsg + " )" ); 221 } 222 if ( outcome != null && !outcome.equals( Constants.ERROR ) ) { 223 if ( log.isInfoEnabled() ) { 225 log.info( "Results are stored in file( " + resultsFileName + " )" ); 226 } 227 setResultsFile( new File ( resultsFileName ) ); 228 if ( outcome.equals( Constants.FAIL ) ) { 230 if ( log.isInfoEnabled() ) { 231 log.info( "Diff results are stored in file( " + diffFileName + " )" ); 232 } 233 setDiffFile( new File ( diffFileName ) ); 234 rtnVal = false; 235 } 236 else { 237 rtnVal = true; 238 } 239 } 240 else { 241 String msg = "ERROR: error encountered executing test( " + getTest().getName() + " ), server msg( " + 242 stopMsg + " )"; 243 log.error( msg ); 244 throw new PlaybackException( msg ); 245 } 246 return rtnVal; 247 } 248 249 private RecordSessionBean createSession() throws PlaybackException { 250 RecordSessionBean session = null; 251 try { 252 session = XMLHelper.getRecordSessionBean( getRecordFile() ); 253 if ( log.isDebugEnabled() ) { 254 log.debug( "test( " + getTest().getName() + " ), testCount( " + session.getTestCount() + " )" ); 255 } 256 } 257 catch ( Exception e ) { 258 String msg = "ERROR: failed to process session file( " + getRecordFile().getAbsolutePath() + " )"; 259 log.error( msg, e ); 260 throw new PlaybackException( msg, e ); 261 } 262 return session; 263 } 264 265 private void executeRequests() throws PlaybackException { 266 RequestData request = null; 267 int testNumber = 0; 268 try { 269 List requestList = getSession().getRequestData(); 270 if ( log.isDebugEnabled() ) { 271 log.debug( "beginning test execution" ); 272 } 273 for ( testNumber = 0; testNumber < requestList.size(); testNumber++ ) { 274 request = (RequestData) requestList.get( testNumber ); 275 if ( log.isDebugEnabled() ) { 276 log.debug( "beginning execution for test number( " + ( testNumber + 1 ) + " )" ); 277 } 278 HttpMethod method = createPlaybackMethod( request, getTest() ); 279 if ( log.isDebugEnabled() ) { 280 log.debug( "playback URI( " + method.getURI() + " )" ); 281 } 282 ResponseData response = execute( getTestClient(), method ); 283 if ( log.isDebugEnabled() ) { 284 log.debug( "playback response, status code( " + response.getStatusCode() + " )" ); 285 log.debug( "playback response, body(\n" + response.getBody() + " )" ); 286 } 287 String outcome = response.getHeader( Constants.OUTCOME_HEADER ); 288 if ( log.isDebugEnabled() ) { 289 log.debug( "outcome( " + outcome + " )" ); 290 } 291 if ( response.getStatusCode() >= 400 ) { 292 String msg = "WARNING: unable to access URI( " + method.getURI() + 293 " ), status code( " + response.getStatusCode() + " ) returned"; 294 System.out.println( msg ); 295 if ( log.isWarnEnabled() ) { 296 log.warn( msg ); 297 } 298 } 299 } 300 } 301 catch ( Exception e ) { 302 String msg = "ERROR: failed executing request for test( " + getTest().getName() + 303 " ), testNumber( " + testNumber + " ), path( " + request.getPath() + " ), exception( " 304 + e.getMessage() + " )"; 305 log.error( msg, e ); 306 if ( e instanceof PlaybackException ) { 307 throw (PlaybackException) e; 308 } 309 throw new PlaybackException( msg, e ); 310 } 311 } 312 313 protected ResponseData execute( HttpClient client, HttpMethod method ) throws PlaybackException, IOException { 314 ResponseData response = new ResponseData( method.getHostConfiguration().getHost(), 315 method.getHostConfiguration().getPort() ); 316 int statusCode = -1; 317 for ( int attempt = 0; statusCode == -1 && attempt < 3; attempt++ ) { 319 try { 320 statusCode = client.executeMethod( method ); 321 } 322 catch ( HttpRecoverableException e ) { 323 if ( log.isWarnEnabled() ) { 324 String msg = "A recoverable exception occurred calling URI( " + method.getURI() + 325 " ), retrying. exception( " + e.getMessage() + " )"; 326 log.error( msg, e ); 327 } 328 } 329 catch ( IOException e ) { 330 String msg = "Failed executing request( " + method.getURI() + " ), exception( " + e.getMessage() + 331 " )"; 332 log.error( msg, e ); 333 throw e; 334 } 335 } 336 if ( statusCode == -1 ) { 338 String msg = "Failed to execute request( " + method.getURI() + " )"; 339 log.error( msg ); 340 throw new PlaybackException( msg ); 341 } 342 response.setStatusCode( statusCode ); 343 byte[] responseBody = method.getResponseBody(); 344 response.setBody( new String ( responseBody ) ); 345 if ( log.isDebugEnabled() ) { 346 log.debug( "statusCode( " + statusCode + " )" ); 347 } 349 response.setHeaders( convertHeaders( method.getResponseHeaders() ) ); 350 method.releaseConnection(); 351 return response; 352 } 353 354 protected HttpMethod createPlaybackMethod( RequestData request, TestDefinition test ) { 355 HttpMethod method = null; 356 if ( request.getMethod().equalsIgnoreCase( "POST" ) ) { 357 method = new PostMethod( request.getUri( getTest().getWebapp().getServer().getHostname(), 358 getTest().getWebapp().getServer().getPort() ) ); 359 populatePlaybackPostMethod( (PostMethod) method, request ); 360 } 361 else if ( request.getMethod().equalsIgnoreCase( "GET" ) ) { 362 method = new GetMethod( request.getUri( getTest().getWebapp().getServer().getHostname(), 363 getTest().getWebapp().getServer().getPort() ) ); 364 populatePlaybackGetMethod( (GetMethod) method, request ); 365 } 366 else { 367 throw new RuntimeException ( "ERROR: unhandled HTTP method( " + request.getMethod() + " )" ); 368 } 369 return method; 370 } 371 372 protected HttpMethod populatePlaybackPostMethod( final PostMethod method, final RequestData request ) { 373 log.debug( "calling setRequestBody()" ); 374 method.setRequestBody( convertNVPairs( request.getParameters() ) ); 375 populatePlaybackMethod( method, request ); 376 debugNameValuePairs( method.getParameters() ); 377 return method; 378 } 379 380 protected HttpMethod populatePlaybackGetMethod( final GetMethod method, final RequestData request ) { 381 populatePlaybackMethod( method, request ); 382 method.setQueryString( convertNVPairs( request.getParameters() ) ); 383 return method; 384 } 385 386 protected HttpMethod populatePlaybackMethod( final HttpMethod method, RequestData request ) { 387 addRequestHeaders( method, request ); 388 addTestIdHeader( method ); 389 return method; 390 } 391 392 protected HttpMethod addRequestHeaders( HttpMethod method, RequestData request ) { 393 for ( int i = 0; i < request.getHeaderCount(); i++ ) { 394 if ( skipPlaybackHeader( request.getHeaderName( i ) ) ) { 395 continue; 396 } 397 method.addRequestHeader( request.getHeaderName( i ), request.getHeaderValue( i ) ); 398 } 399 return method; 400 } 401 402 409 protected boolean skipPlaybackHeader( String name ) { 410 if ( name.equalsIgnoreCase( "host" ) || 412 name.equalsIgnoreCase( "referer" ) || 413 name.equalsIgnoreCase( "Content-length" ) || 414 name.equalsIgnoreCase( "Host" ) || 415 name.equals( Constants.TEST_ID_HEADER ) || 416 name.equals( Constants.FAIL_MODE_HEADER ) || 417 name.equals( Constants.TEST_NUMBER_HEADER ) ) { 418 return true; 420 } 421 return false; 422 } 423 424 public NameValuePair[] getStartParams() { 425 return startParams; 426 } 427 428 protected void setStartParams( NameValuePair[] startParams ) { 429 this.startParams = startParams; 430 } 431 432 protected void setStartParam( int index, NameValuePair param ) { 433 if ( index >= startParams.length ) { 434 throw new IndexOutOfBoundsException ( "Invalid start parameter index( " + index + 435 " ), start parameter size is (" + startParams.length + ")" ); 436 } 437 stopParams[index] = param; 438 } 439 440 public NameValuePair[] getStopParams() { 441 return stopParams; 442 } 443 444 protected void setStopParams( NameValuePair[] stopParams ) { 445 this.stopParams = stopParams; 446 } 447 448 protected void setStopParam( int index, NameValuePair param ) { 449 if ( index >= stopParams.length ) { 450 throw new IndexOutOfBoundsException ( "Invalid stop parameter index( " + index + 451 " ), stop parameter size is (" + stopParams.length + ")" ); 452 } 453 stopParams[index] = param; 454 } 455 456 protected HttpMethod addTestIdHeader( HttpMethod method ) { 457 if ( getTestId() != null ) { 458 method.setRequestHeader( Constants.TEST_ID_HEADER, getTestId() ); 459 } 460 return method; 461 } 462 463 public RecordSessionBean getSession() { 464 return session; 465 } 466 467 protected void setSession( RecordSessionBean session ) { 468 this.session = session; 469 } 470 471 protected HttpClient getTestClient() { 472 return testClient; 473 } 474 475 protected HttpClient getControlClient() { 476 return controlClient; 477 } 478 479 public TestDefinition getTest() { 480 return test; 481 } 482 483 public String getDescription() { 484 return description; 485 } 486 487 public String getTestUser() { 488 return testUser; 489 } 490 491 public String getTestId() { 492 return testId; 493 } 494 495 protected void setTestId( String testId ) { 496 this.testId = testId; 497 } 498 499 public File getRecordFile() { 500 return recordFile; 501 } 502 503 public File getResultsFile() { 504 return resultsFile; 505 } 506 507 protected void setResultsFile( File resultsFile ) { 508 this.resultsFile = resultsFile; 509 } 510 511 public File getDiffFile() { 512 return diffFile; 513 } 514 515 protected void setDiffFile( File diffFile ) { 516 this.diffFile = diffFile; 517 } 518 519 private static NVPair[] convertHeaders( Header[] headers ) { 520 if ( headers == null ) { 521 return null; 522 } 523 NVPair[] newPairs = new NVPair[headers.length]; 524 NVPair newPair = null; 525 for ( int i = 0; i < headers.length; i++ ) { 526 newPair = convertHeader( headers[i] ); 527 newPairs[i] = newPair; 528 } 529 return newPairs; 530 } 531 532 private static NVPair convertHeader( Header header ) { 533 if ( log.isDebugEnabled() ) { 534 log.debug( "header, name( " + header.getName() + " ), value( " + header.getValue() + " )" ); 535 } 536 return new NVPair( header.getName(), header.getValue() ); 537 } 538 539 private static NameValuePair[] convertNVPairs( NVPair[] pairs ) { 540 if ( pairs == null ) { 541 return null; 542 } 543 NameValuePair[] newPairs = new NameValuePair[pairs.length]; 544 NameValuePair newPair = null; 545 for ( int i = 0; i < pairs.length; i++ ) { 546 newPair = convertNVPair( pairs[i] ); 547 newPairs[i] = newPair; 548 } 549 return newPairs; 550 } 551 552 private static NameValuePair convertNVPair( NVPair pair ) { 553 if ( log.isDebugEnabled() ) { 554 log.debug( "pair, name( " + pair.getName() + " ), value( " + pair.getValue() + " )" ); 555 } 556 return new NameValuePair( pair.getName(), pair.getValue() ); 557 } 558 559 private static void debugNameValuePairs( NameValuePair[] pairs ) { 560 if ( pairs == null ) { 561 log.debug( "pairs( " + pairs + " )" ); 562 return; 563 } 564 for ( int i = 0; i < pairs.length; i++ ) { 565 log.debug( 566 "pair(" + i + ")[ name( " + pairs[i].getName() + " ), value( " + pairs[i].getValue() + " )" ); 567 } 568 return; 569 } 570 571 } 572 | Popular Tags |