| | |
| | | |
| | | 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. |
| | |
| | | * 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() { |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | } |