mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

davidely
02.00.2007 a5ce1b53bf9304c08bb51639b48bb77085cd62b3
opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java
@@ -28,8 +28,15 @@
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import org.testng.annotations.AfterClass;
import org.opends.messages.Message;
import java.util.IdentityHashMap;
import java.util.Set;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
 * This class defines a base test case that should be subclassed by all
 * unit tests used by the Directory Server.
@@ -37,6 +44,7 @@
 * This class adds the ability to print error messages and automatically
 * have them include the class name.
 */
@Test(sequential=true)
public abstract class DirectoryServerTestCase {
  @BeforeSuite
  public final void suppressOutput() {
@@ -48,4 +56,108 @@
    TestCaseUtils.shutdownServer(Message.raw("The current test suite has finished."));
    TestCaseUtils.unsupressOutput();
  }
  //
  // This is all a HACK to reduce the amount of memory that's consumed.
  //
  // This could be a problem if a subclass references a @DataProvider in
  // a super-class that provides static parameters, i.e. the parameters are
  // not regenerated for each invocation of the DataProvider.
  //
  /** A list of all parameters that were generated by a @DataProvider
   *  and passed to a test method of this class.  TestListener helps us
   *  keep this so that once all of the tests are finished, we can clear
   *  it out in an @AfterClass method.  We can't just clear it out right
   *  away in the TestListener because some methods share a @DataProvider.*/
  private final IdentityHashMap<Object[],Object> successfulTestParams = new IdentityHashMap<Object[],Object>();
  /** These are test parameters from a test that has failed.  We need to
   *  keep these around because the test report expects to find them when
   *  printing out failures. */
  private final IdentityHashMap<Object[],Object> failedTestParams = new IdentityHashMap<Object[],Object>();
  /**
   * Adds testParams to the list of all test parameters, so it can be
   * null'ed out later if it's not part.
   */
  void addParamsFromSuccessfulTests(Object[] testParams) {
    if (testParams != null) {
      successfulTestParams.put(testParams, testParams);
    }
  }
  /**
   * Adds testParams to the list of all failed test parameters, so that we
   * know to NOT null it out later.
   */
  void addParamsFromFailedTest(Object[] testParams) {
    if (testParams != null) {
      failedTestParams.put(testParams, testParams);
    }
  }
  /**
   * null out all test parameters except the ones used in failed tests
   * since we might need these again.
   */
  @AfterClass(alwaysRun = true)
  public void clearSuccessfulTestParams() {
    Set<Object[]> paramsSet = successfulTestParams.keySet();
    if (paramsSet == null) {  // Can this ever happen?
      return;
    }
    for (Object[] params: paramsSet) {
      if (failedTestParams.containsKey(params)) {
        continue;
      }
      for (int i = 0; i < params.length; i++) {
        params[i] = null;
      }
    }
    successfulTestParams.clear();
    failedTestParams.clear();
  }
  /**
   * The member variables of a test class can prevent lots of memory from being
   * reclaimed, so we use reflection to null out all of the member variables
   * after the tests have run.  Since all tests must inherit from
   * DirectoryServerTestCase, TestNG guarantees that this method runs after
   * all of the subclass methods, so this isn't too dangerous.
   */
  @AfterClass(alwaysRun = true)
  public void nullMemberVariablesAfterTest() {
    Class cls = this.getClass();
    // Iterate through all of the fields in all subclasses of
    // DirectoryServerTestCase, but not DirectoryServerTestCase itself.
    while (DirectoryServerTestCase.class.isAssignableFrom(cls) &&
           !DirectoryServerTestCase.class.equals(cls))
    {
      Field fields[] = cls.getDeclaredFields();
      for (int i = 0; i < fields.length; i++) {
        Field field = fields[i];
        int modifiers = field.getModifiers();
        Class fieldClass = field.getType();
        // If it's a non-static non-final non-primitive type, then null it out
        // so that the garbage collector can reclaim it and everything it
        // references.
        if (!fieldClass.isPrimitive() &&
            !fieldClass.isEnum()      &&
            !Modifier.isFinal(modifiers) &&
            !Modifier.isStatic(modifiers))
        {
          field.setAccessible(true);
          try {
            field.set(this, null);
          } catch (IllegalAccessException e) {
            // We're only doing this to save memory, so it's no big deal
            // if we can't set it.
          }
        }
      }
      cls = cls.getSuperclass();
    }
  }
}