From a5ce1b53bf9304c08bb51639b48bb77085cd62b3 Mon Sep 17 00:00:00 2001
From: davidely <davidely@localhost>
Date: Sun, 02 Sep 2007 04:00:42 +0000
Subject: [PATCH] There are several improvements to the unit test framework in this commit.
---
opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 112 insertions(+), 0 deletions(-)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java
index e67c436..64e92d9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java
+++ b/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();
+ }
+ }
}
--
Gitblit v1.10.0