1 5 package com.tc.test.server.appserver.unit; 6 7 import org.apache.commons.io.FileUtils; 8 import org.apache.commons.lang.ClassUtils; 9 import org.apache.tools.ant.Project; 10 import org.apache.tools.ant.taskdefs.Zip; 11 12 import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt; 13 14 import com.tc.object.config.schema.Lock; 15 import com.tc.object.config.schema.Root; 16 import com.tc.process.LinkedJavaProcessPollingAgent; 17 import com.tc.properties.TCPropertiesImpl; 18 import com.tc.test.TCTestCase; 19 import com.tc.test.TestConfigObject; 20 import com.tc.test.server.Server; 21 import com.tc.test.server.appserver.AppServer; 22 import com.tc.test.server.appserver.AppServerInstallation; 23 import com.tc.test.server.appserver.AppServerResult; 24 import com.tc.test.server.appserver.NewAppServerFactory; 25 import com.tc.test.server.appserver.StandardAppServerParameters; 26 import com.tc.test.server.appserver.war.AbstractDescriptorXml; 27 import com.tc.test.server.appserver.war.War; 28 import com.tc.test.server.dsoserver.DsoServer; 29 import com.tc.test.server.dsoserver.StandardDsoServer; 30 import com.tc.test.server.dsoserver.StandardDsoServerParameters; 31 import com.tc.test.server.tcconfig.StandardTerracottaAppServerConfig; 32 import com.tc.test.server.tcconfig.TerracottaServerConfigGenerator; 33 import com.tc.test.server.util.HttpUtil; 34 import com.tc.test.server.util.VmStat; 35 import com.tc.text.Banner; 36 import com.tc.util.Assert; 37 import com.tc.util.runtime.Os; 38 import com.tc.util.runtime.ThreadDump; 39 import com.terracotta.session.util.ConfigProperties; 40 41 import java.io.File ; 42 import java.io.IOException ; 43 import java.lang.reflect.Modifier ; 44 import java.net.MalformedURLException ; 45 import java.net.URL ; 46 import java.text.SimpleDateFormat ; 47 import java.util.ArrayList ; 48 import java.util.Date ; 49 import java.util.Iterator ; 50 import java.util.List ; 51 import java.util.Properties ; 52 53 import javax.servlet.http.HttpServlet ; 54 import javax.servlet.http.HttpSessionActivationListener ; 55 import javax.servlet.http.HttpSessionAttributeListener ; 56 import javax.servlet.http.HttpSessionListener ; 57 58 150 public abstract class AbstractAppServerTestCase extends TCTestCase { 151 152 private static final SynchronizedInt nodeCounter = new SynchronizedInt(-1); 153 private static final String NODE = "node-"; 154 private static final String DOMAIN = "localhost"; 155 156 protected final List appservers = new ArrayList (); 157 private final Object workingDirLock = new Object (); 158 private final List dsoServerJvmArgs = new ArrayList (); 159 private final List roots = new ArrayList (); 160 private final List locks = new ArrayList (); 161 private final List includes = new ArrayList (); 162 163 private final TestConfigObject config; 164 165 private File serverInstallDir; 166 private File workingDir; 167 private File tempDir; 168 private File bootJar; 169 private NewAppServerFactory appServerFactory; 170 private AppServerInstallation installation; 171 private File warFile; 172 private DsoServer dsoServer; 173 private TerracottaServerConfigGenerator configGen; 174 175 private boolean isSynchronousWrite = false; 176 177 public AbstractAppServerTestCase() { 178 setDumpThreadsOnTimeout(Os.isWindows() || Os.isMac()); 180 181 try { 182 config = TestConfigObject.getInstance(); 183 } catch (IOException e) { 184 throw new RuntimeException (e); 185 } 186 187 } 188 189 protected int getJMXPort() { 190 if (configGen == null) { throw new AssertionError ( 191 "DSO server is not running so JMX port has not been assigned yet."); } 192 return configGen.getConfig().getJmxPort(); 193 } 194 195 protected void setUp() throws Exception { 196 LinkedJavaProcessPollingAgent.startHeartBeatServer(); 197 tempDir = getTempDirectory(); 198 serverInstallDir = makeDir(config.appserverServerInstallDir()); 199 File workDir = new File (config.appserverWorkingDir()); 200 try { 201 if (workDir.exists()) { 202 if (workDir.isDirectory()) { 203 FileUtils.cleanDirectory(workDir); 204 } else { 205 throw new RuntimeException (workDir + " exists, but is not a directory"); 206 } 207 } 208 } catch (Throwable e) { 209 File prev = workDir; 210 workDir = new File (config.appserverWorkingDir() + "-" 211 + new SimpleDateFormat ("yyyyMMdd-HHmmss").format(new Date ())); 212 Banner.warnBanner("Caught IOException setting up workDir as " + prev + ", using " + workDir + " instead"); 213 } 214 215 workingDir = makeDir(workDir.getAbsolutePath()); 216 bootJar = new File (config.normalBootJar()); 217 appServerFactory = NewAppServerFactory.createFactoryFromProperties(config); 218 219 String appserverURLBase = config.appserverURLBase(); 220 String appserverHome = config.appserverHome(); 221 222 if (appserverHome != null && !appserverHome.trim().equals("")) { 223 File home = new File (appserverHome); 224 installation = appServerFactory.createInstallation(home, workingDir); 225 226 } else if (appserverURLBase != null && !appserverURLBase.trim().equals("")) { 227 URL host = new URL (appserverURLBase); 228 installation = appServerFactory.createInstallation(host, serverInstallDir, workingDir); 229 230 } else { 231 throw new AssertionError ( 232 "No container installation available. You must define one of the following config properties:\n" 233 + TestConfigObject.APP_SERVER_HOME + "\nor\n" 234 + TestConfigObject.APP_SERVER_REPOSITORY_URL_BASE); 235 } 236 } 237 238 protected final boolean cleanTempDir() { 239 return false; 240 } 241 242 protected void beforeTimeout() throws Throwable { 243 threadDumpGroup(); 244 245 archiveSandboxLogs(); 247 } 248 249 private void archiveSandboxLogs() { 250 synchronized (workingDirLock) { 251 if (installation != null) { 252 String src = installation.sandboxDirectory().getParentFile().getAbsolutePath(); 253 String dest = new File (tempDir, "archive-logs-" + System.currentTimeMillis() + ".zip").getAbsolutePath(); 254 255 String msg = "\n"; 256 msg += "*****************************\n"; 257 msg += "* Archiving logs in [" + src + "] to " + dest + "\n"; 258 msg += "*****************************\n"; 259 System.out.println(msg); 260 261 Zip zip = new Zip(); 262 zip.setProject(new Project()); 263 zip.setDestFile(new File (dest)); 264 zip.setBasedir(new File (src)); 265 zip.setIncludes("**/*.log"); 266 zip.setUpdate(false); 267 zip.execute(); 268 } 269 } 270 } 271 272 275 protected final void startDsoServer() throws Exception { 276 Assert.assertNull(dsoServer); 277 dsoServer = new StandardDsoServer(); 278 279 if (dsoServerJvmArgs != null && !dsoServerJvmArgs.isEmpty()) { 280 dsoServer.addJvmArgs(dsoServerJvmArgs); 281 } 282 283 TerracottaServerConfigGenerator generator = configGen(); 284 285 File dsoWorkingDir = installation.dataDirectory(); 286 File outputFile = new File (dsoWorkingDir, "dso-server.log"); 287 288 StandardDsoServerParameters params = new StandardDsoServerParameters(generator, dsoWorkingDir, outputFile, 289 generator.getConfig().getDsoPort(), generator 290 .getConfig().getJmxPort()); 291 292 dsoServer.start(params); 293 } 294 295 298 protected final void addDsoServerJvmArgs(List jvmArgs) { 299 dsoServerJvmArgs.addAll(jvmArgs); 300 } 301 302 305 protected final void setSynchronousWrite(boolean value) { 306 isSynchronousWrite = value; 307 } 308 309 312 protected final void addRoots(List rootsToAdd) { 313 roots.addAll(rootsToAdd); 314 } 315 316 319 protected final void addLocks(List locksToAdd) { 320 locks.addAll(locksToAdd); 321 } 322 323 protected final void addInclude(String expression) { 324 includes.add(expression); 325 } 326 327 334 protected final AppServerResult startAppServer(boolean dsoEnabled) throws Exception { 335 return startAppServer(dsoEnabled, new Properties()); 336 } 337 338 343 protected final AppServerResult startAppServer(boolean dsoEnabled, Properties props) throws Exception { 344 return startAppServer(dsoEnabled, props, null); 345 } 346 347 351 protected final AppServerResult startAppServer(boolean dsoEnabled, Properties props, String [] jvmargs) 352 throws Exception { 353 int nodeNumber = nodeCounter.increment(); 354 try { 355 StandardAppServerParameters params; 356 params = (StandardAppServerParameters) appServerFactory.createParameters(NODE + nodeNumber, props); 357 AppServer appServer = appServerFactory.createAppServer(installation); 358 359 if (dsoEnabled) { 360 params.enableDSO(configGen(), bootJar); 361 } 362 if (jvmargs != null) { 363 for (int i = 0; i < jvmargs.length; i++) { 364 params.appendJvmArgs(jvmargs[i]); 365 } 366 } 367 368 params.appendJvmArgs("-DNODE=" + NODE + nodeNumber); 369 370 372 params.appendJvmArgs("-D" + TCPropertiesImpl.SYSTEM_PROP_PREFIX + "." + ConfigProperties.REQUEST_BENCHES 373 + "=true"); 374 375 params.appendJvmArgs("-verbose:gc"); 376 params.appendJvmArgs("-Xloggc:" + new File (this.workingDir, "node-" + nodeNumber + ".gc.log")); 377 params.appendJvmArgs("-XX:+PrintGCDetails"); 378 379 if (false && nodeNumber == 0) { 380 int debugPort = 8000 + nodeNumber; 381 System.out.println("Waiting for debugger connection on port " + debugPort); 382 params.appendJvmArgs("-Xdebug"); 383 params.appendJvmArgs("-Xrunjdwp:server=y,transport=dt_socket,address=" + debugPort + ",suspend=y"); 384 } 385 386 params.addWar(warFile()); 387 AppServerResult r = (AppServerResult) appServer.start(params); 388 389 appservers.add(appServer); 391 return r; 392 } catch (Exception e) { 393 threadDumpGroup(); 394 throw e; 395 } 396 } 397 398 private void threadDumpGroup() { 399 if (Os.isUnix() && !Os.isMac()) { 402 ThreadDump.dumpProcessGroup(); 403 } 404 } 405 406 409 public URL createUrl(int port, Class servletClass, String query) throws MalformedURLException { 410 if (query != null && query.length() > 0) { 411 query = "?" + query; 412 } 413 414 String [] parts = servletClass.getName().split("\\."); 415 String servletUrl = AbstractDescriptorXml.translateUrl(parts[parts.length - 1]); 416 return new URL ("http://" + DOMAIN + ":" + port + "/" + testName() + "/" + servletUrl + query); 417 } 418 419 public URL createUrl(int port, Class servletClass) throws MalformedURLException { 420 return createUrl(port, servletClass, ""); 421 } 422 423 private boolean awaitShutdown(int timewait) throws Exception { 424 long start = System.currentTimeMillis(); 425 boolean foundAlive = false; 426 do { 427 Thread.sleep(1000); 428 foundAlive = LinkedJavaProcessPollingAgent.isAnyAppServerAlive(); 429 } while (foundAlive && System.currentTimeMillis() - start < timewait); 430 431 return foundAlive; 432 } 433 434 439 protected void tearDown() throws Exception { 440 try { 441 for (Iterator iter = appservers.iterator(); iter.hasNext();) { 442 Server server = (Server) iter.next(); 443 server.stop(); 444 } 445 446 awaitShutdown(10 * 1000); 447 if (dsoServer != null && dsoServer.isRunning()) dsoServer.stop(); 448 System.out.println("Shutdown heartbeat server and its children..."); 449 LinkedJavaProcessPollingAgent.shutdown(); 450 } finally { 451 VmStat.stop(); 452 synchronized (workingDirLock) { 453 File dest = new File (tempDir, getName()); 454 System.err.println("Copying files from " + workingDir + " to " + dest); 455 try { 456 com.tc.util.io.FileUtils.copyFile(workingDir, dest); 457 } catch (IOException ioe) { 458 Banner.warnBanner("IOException caught while copying workingDir files"); 459 ioe.printStackTrace(); 460 } 461 462 System.err.println("Deleting working directory files in " + workingDir); 463 try { 464 FileUtils.forceDelete(workingDir); 465 } catch (IOException ioe) { 466 Banner.warnBanner("IOException caught while deleting workingDir"); 467 ioe.printStackTrace(); 469 } 470 } 471 } 472 } 473 474 protected final void collectVmStats() throws IOException { 475 VmStat.start(workingDir); 476 } 477 478 private synchronized File warFile() throws Exception { 479 if (warFile != null) return warFile; 480 War war = appServerFactory.createWar(testName()); 481 addServletsWebAppClasses(war); 482 File resourceDir = installation.dataDirectory(); 483 warFile = new File (resourceDir + File.separator + war.writeWarFileToDirectory(resourceDir)); 484 return warFile; 485 } 486 487 private void addServletsWebAppClasses(War war) throws InstantiationException , IllegalAccessException { 488 Class [] classes = getClass().getClasses(); 489 for (int i = 0; i < classes.length; i++) { 490 Class clazz = classes[i]; 491 if (!isSafeClass(clazz)) { 492 continue; 493 } 494 if (isServlet(clazz)) { 495 war.addServlet(clazz); 496 } 497 if (isListener(clazz)) { 498 war.addListener(clazz); 499 } 500 if (isFilter(clazz)) { 501 TCServletFilter filterInstance = (TCServletFilter) clazz.newInstance(); 502 war.addFilter(clazz, filterInstance.getPattern(), filterInstance.getInitParams()); 503 } 504 war.addClass(clazz); 506 } 507 } 508 509 private static boolean isSafeClass(Class clazz) { 510 int mod = clazz.getModifiers(); 511 return Modifier.isStatic(mod) && Modifier.isPublic(mod) && !Modifier.isInterface(mod) && !Modifier.isAbstract(mod); 512 } 513 514 private static boolean isServlet(Class clazz) { 515 return clazz.getSuperclass().equals(HttpServlet .class) && clazz.getName().toLowerCase().endsWith("servlet"); 516 } 517 518 private static boolean isFilter(Class clazz) { 519 return TCServletFilter.class.isAssignableFrom(clazz); 520 } 521 522 private static boolean isListener(Class clazz) { 523 return HttpSessionActivationListener .class.isAssignableFrom(clazz) 524 || HttpSessionAttributeListener .class.isAssignableFrom(clazz) 525 || HttpSessionListener .class.isAssignableFrom(clazz); 526 } 527 528 private File makeDir(String dirPath) throws IOException { 529 File dir = new File (dirPath); 530 if (dir.exists()) { 531 if (dir.isDirectory()) { return dir; } 532 throw new IOException (dir + " exists, but is not a directory"); 533 } 534 boolean created = dir.mkdirs(); 535 if (!created) { throw new IOException ("Could not create directory " + dir); } 536 return dir; 537 } 538 539 private String testName() { 540 return ClassUtils.getShortClassName(getClass()); 541 } 542 543 private synchronized TerracottaServerConfigGenerator configGen() throws Exception { 544 if (configGen != null) { return configGen; } 545 StandardTerracottaAppServerConfig configBuilder = appServerFactory.createTcConfig(installation.dataDirectory()); 546 547 if (isSessionTest()) { 548 if (isSynchronousWrite) { 549 configBuilder.addWebApplication(testName(), isSynchronousWrite); 550 } else { 551 configBuilder.addWebApplication(testName()); 552 } 553 } 554 555 configBuilder.addInclude("com.tctest..*"); 556 configBuilder.addInclude("com.tctest..*$*"); 557 558 for (Iterator iter = includes.iterator(); iter.hasNext();) { 559 configBuilder.addInclude((String ) iter.next()); 560 } 561 562 for (Iterator iter = roots.iterator(); iter.hasNext();) { 563 Root root = (Root) iter.next(); 564 configBuilder.addRoot(root.fieldName(), root.rootName()); 565 } 566 567 for (Iterator iter = locks.iterator(); iter.hasNext();) { 568 Lock lock = (Lock) iter.next(); 569 String lockName = null; 570 if (!lock.isAutoLock()) { 571 lockName = lock.lockName(); 572 } 573 configBuilder.addLock(lock.isAutoLock(), lock.methodExpression(), lock.lockLevel().toString(), lockName); 574 } 575 576 return configGen = new TerracottaServerConfigGenerator(installation.dataDirectory(), configBuilder); 577 } 578 579 protected boolean isSessionTest() { 580 return true; 581 } 582 } 583 | Popular Tags |