From ec144f32207385677a45c0eafda8038a1114ca32 Mon Sep 17 00:00:00 2001
From: gbellato <gbellato@localhost>
Date: Wed, 12 Jul 2006 09:26:05 +0000
Subject: [PATCH] Add some unit tests for - synchronization msg serialization/un-serialization (classes that inherit from SynchronizationMsg) - modify conflicts resolution (Historical class)
---
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationMsgTest.java | 278 +++++++++++++++++++++++++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ModifyConflictTest.java | 276 +++++++++++++++++++++++++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java | 37 +++
opendj-sdk/opends/ext/testng/testng.xml | 1
4 files changed, 592 insertions(+), 0 deletions(-)
diff --git a/opendj-sdk/opends/ext/testng/testng.xml b/opendj-sdk/opends/ext/testng/testng.xml
index 6b1c44b..6c21c90 100644
--- a/opendj-sdk/opends/ext/testng/testng.xml
+++ b/opendj-sdk/opends/ext/testng/testng.xml
@@ -4,6 +4,7 @@
<package name="org.opends.server.protocols.asn1"/>
<package name="org.opends.server.core"/>
<package name="org.opends.server.backends.jeb"/>
+ <package name="org.opends.server.synchronization"/>
</packages>
<test name="precommit">
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ModifyConflictTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ModifyConflictTest.java
new file mode 100644
index 0000000..4d05a7a
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ModifyConflictTest.java
@@ -0,0 +1,276 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.synchronization;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.ObjectClass;
+import static org.opends.server.synchronization.SynchMessages.SYNCHRONIZATION;
+
+/*
+ * Test the conflict resolution for modify operations
+ * This is still a work in progress.
+ * currently implemented tests
+ * - check that an replace with a smaller csn is ignored
+ * should test :
+ * - conflict with multi-valued attributes
+ * - conflict with single-valued attributes
+ * - conflict with options
+ * - conflict with binary attributes
+ * - Replace, add, delete attribute, delete attribute value
+ * - conflict on the objectclass attribute
+ */
+
+
+public class ModifyConflictTest extends SynchronizationTestCase
+{
+
+ /**
+ * Test that conflict between a modify-replace and modify-add
+ * for multi-valued attributes are handled correctly.
+ */
+ @Test()
+ public void replaceAndAdd()
+ throws Exception
+ {
+ /*
+ * Objectclass and DN do not have any impact on the modifty conflict
+ * resolution for the description attribute.
+ * Always use the same values for all these tests.
+ */
+ DN dn = DN.decode("dc=com");
+ Map<ObjectClass, String> objectClasses = new HashMap<ObjectClass, String>();
+ ObjectClass org = DirectoryServer.getObjectClass("organization");
+ objectClasses.put(org, "organization");
+
+ /*
+ * start with a new entry with an empty description
+ */
+ Entry entry = new Entry(dn, objectClasses, null, null);
+ Historical hist = Historical.load(entry);
+
+ /*
+ * simulate a modify-replace done at time t10
+ */
+ testModify(entry, hist, "description", ModificationType.REPLACE,
+ "init value", 10, true);
+
+ /*
+ * Now simulate an add at an earlier date that the previous replace
+ * conflict resolution should remove it.
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "older value", 1, false);
+
+ /*
+ * Now simulate an add at an earlier date that the previous replace
+ * conflict resolution should remove it.
+ * (a second time to make sure...)
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "older value", 2, false);
+
+ /*
+ * Now simulate an add at a later date that the previous replace.
+ * conflict resolution should keep it
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "new value", 11, true);
+
+ }
+
+ /**
+ * Test that conflict between a modify-delete-attribute and modify-add
+ * for multi-valued attributes are handled correctly.
+ */
+ @Test()
+ public void deleteAndAdd()
+ throws Exception
+ {
+ /*
+ * Objectclass and DN do not have any impact on the modifty conflict
+ * resolution for the description attribute.
+ * Always use the same values for all these tests.
+ */
+ DN dn = DN.decode("dc=com");
+ Map<ObjectClass, String> objectClasses = new HashMap<ObjectClass, String>();
+ ObjectClass org = DirectoryServer.getObjectClass("organization");
+ objectClasses.put(org, "organization");
+
+ /*
+ * start with a new entry with an empty description
+ */
+ Entry entry = new Entry(dn, objectClasses, null, null);
+ Historical hist = Historical.load(entry);
+
+ /*
+ * simulate a delete of the whole description attribute done at time t10
+ */
+ testModify(entry, hist, "description", ModificationType.DELETE,
+ null, 10, true);
+
+ /*
+ * Now simulate an add at an earlier date that the previous delete.
+ * The conflict resolution should detect that this add must be ignored.
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "older value", 1, false);
+
+ /*
+ * Now simulate an add at an earlier date that the previous delete.
+ * The conflict resolution should detect that this add must be ignored.
+ * (a second time to make sure that historical information is kept...)
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "older value", 2, false);
+
+ /*
+ * Now simulate an add at a later date that the previous delete.
+ * conflict resolution should keep it
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "new value", 11, true);
+
+ }
+
+ /**
+ * Test that conflict between a modify-add and modify-add
+ * for multi-valued attributes are handled correctly.
+ */
+ @Test()
+ public void addAndAdd()
+ throws Exception
+ {
+ /*
+ * Objectclass and DN do not have any impact on the modifty conflict
+ * resolution for the description attribute.
+ * Always use the same values for all these tests.
+ */
+ DN dn = DN.decode("dc=com");
+ Map<ObjectClass, String> objectClasses = new HashMap<ObjectClass, String>();
+ ObjectClass org = DirectoryServer.getObjectClass("organization");
+ objectClasses.put(org, "organization");
+
+ /*
+ * start with a new entry with an empty description
+ */
+ Entry entry = new Entry(dn, objectClasses, null, null);
+ Historical hist = Historical.load(entry);
+
+ /*
+ * simulate a add of the description attribute done at time t10
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "init value", 10, true);
+
+ /*
+ * Now simulate an add at an earlier date that the previous add.
+ * The conflict resolution should detect that this add must be kept.
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "older value", 1, true);
+
+ /*
+ * Now simulate an add at an earlier date that the previous add.
+ * The conflict resolution should detect that this add must be kept.
+ * (a second time to make sure that historical information is kept...)
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "older value", 2, false);
+
+ /*
+ * Now simulate an add at a later date that the previous add.
+ * conflict resolution should keep it
+ */
+ testModify(entry, hist, "description", ModificationType.ADD,
+ "new value", 11, true);
+ }
+
+ /*
+ * helper function.
+ */
+ private static void testModify(Entry entry,
+ Historical hist, String attrName,
+ ModificationType modType, String value,
+ int date, boolean keepChangeResult)
+ {
+ InternalClientConnection connection = new InternalClientConnection();
+ ChangeNumber t = new ChangeNumber(date, (short) 0, (short) 0);
+
+ /* create AttributeType description that will be usedfor this test */
+ AttributeType attrType =
+ DirectoryServer.getAttributeType(attrName, true);
+
+ LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
+ if (value != null)
+ values.add(new AttributeValue(attrType, value));
+ Attribute attr = new Attribute(attrType, attrName, values);
+ List<Modification> mods = new ArrayList<Modification>();
+ Modification mod = new Modification(modType, attr);
+ mods.add(mod);
+
+ ModifyOperation modOp = new ModifyOperation(connection, 1, 1, null,
+ entry.getDN(), mods);
+
+ modOp.setAttachment(SYNCHRONIZATION, t);
+
+ hist.replayOperation(modOp, entry);
+
+ /*
+ * The last older change should have been detected as conflicting
+ * and should be removed by the conflict resolution code.
+ */
+ if (keepChangeResult)
+ {
+ assertTrue(mods.contains(mod));
+ assertEquals(1, mods.size());
+ }
+ else
+ {
+ assertFalse(mods.contains(mod));
+ assertEquals(0, mods.size());
+ }
+ }
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationMsgTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationMsgTest.java
new file mode 100644
index 0000000..73c1be2
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationMsgTest.java
@@ -0,0 +1,278 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.synchronization;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DirectoryException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.Operation;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.synchronization.ModifyMsg;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.DN;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.RDN;
+import org.opends.server.util.TimeThread;
+
+import static org.opends.server.synchronization.SynchMessages.SYNCHRONIZATION;
+
+/**
+ * Test the contructors, encoders and decoders of the synchronization
+ * ModifyMsg, ModifyDnMsg, AddMsg and Delete Msg
+ */
+public class SynchronizationMsgTest extends SynchronizationTestCase
+{
+ /**
+ * Build some data for the ModifyMsg test below.
+ */
+ @DataProvider(name = "modifyEncodeDecode")
+ public Object[][] createData() {
+ ChangeNumber cn1 = new ChangeNumber(1, (short) 0, (short) 1);
+ ChangeNumber cn2 = new ChangeNumber(TimeThread.getTime(),
+ (short) 123, (short) 45);
+
+ AttributeType type = DirectoryServer.getAttributeType("description");
+
+ Attribute attr1 = new Attribute("description", "new value");
+ Modification mod1 = new Modification(ModificationType.REPLACE, attr1);
+ List<Modification> mods1 = new ArrayList<Modification>();
+ mods1.add(mod1);
+
+ Attribute attr2 =
+ new Attribute(DirectoryServer.getAttributeType("description", true));
+ Modification mod2 = new Modification(ModificationType.DELETE, attr2);
+ List<Modification> mods2 = new ArrayList<Modification>();
+ mods2.add(mod1);
+ mods2.add(mod2);
+
+ List<Modification> mods3 = new ArrayList<Modification>();
+ LinkedHashSet<AttributeValue> values3 =
+ new LinkedHashSet<AttributeValue>();
+ values3.add(new AttributeValue(type, "string"));
+ values3.add(new AttributeValue(type, "value"));
+ values3.add(new AttributeValue(type, "again"));
+ Attribute attr3 = new Attribute(type, "description", values3);
+ Modification mod3 = new Modification(ModificationType.ADD, attr3);
+ mods3.add(mod3);
+
+ List<Modification> mods4 = new ArrayList<Modification>();
+ for (int i =0; i< 10; i++)
+ {
+ LinkedHashSet<AttributeValue> values =
+ new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(type, "string" + String.valueOf(i)));
+ Attribute attr = new Attribute(type, "description", values);
+ Modification mod = new Modification(ModificationType.ADD, attr);
+ mods4.add(mod);
+ }
+
+ return new Object[][] {
+ { cn1, "dc=test", mods1},
+ { cn2, "dc=cn2", mods1},
+ { cn2, "dc=test with a much longer dn in case this would "
+ + "make a difference", mods1},
+ { cn2, "dc=test, cn=with a, o=more complex, ou=dn", mods1},
+ { cn2, "cn=use\\, backslash", mods1},
+ { cn2, "dc=test with several mod", mods2},
+ { cn2, "dc=test with several values", mods3},
+ { cn2, "dc=test with long mod", mods4},
+ };
+ }
+
+
+ /**
+ * Create a ModifyMsg from the data provided above.
+ * The call getBytes() to test the encoding of the Msg and
+ * create another ModifyMsg from the encoded byte array.
+ * Finally test that both Msg matches.
+ */
+ @Test(dataProvider = "modifyEncodeDecode")
+ public void modifyEncodeDecode(ChangeNumber changeNumber,
+ String rawdn, List<Modification> mods)
+ throws Exception
+ {
+ DN dn = DN.decode(rawdn);
+ InternalClientConnection connection = new InternalClientConnection();
+ ModifyMsg msg = new ModifyMsg(changeNumber, dn, mods);
+ ModifyMsg generatedMsg = new ModifyMsg(msg.getBytes());
+
+ assertEquals(msg.changeNumber, generatedMsg.changeNumber);
+
+ Operation op = msg.createOperation(connection);
+ Operation generatedOperation = generatedMsg.createOperation(connection);
+
+ assertEquals(op.getClass(), ModifyOperation.class);
+ assertEquals(generatedOperation.getClass(), ModifyOperation.class);
+
+ ModifyOperation mod1 = (ModifyOperation) op;
+ ModifyOperation mod2 = (ModifyOperation) generatedOperation;
+
+ assertEquals(mod1.getRawEntryDN(), mod2.getRawEntryDN());
+
+ /*
+ * TODO : test that the generated mod equals the original mod.
+ */
+ }
+
+ /**
+ * Build some data for the DeleteMsg test below.
+ * @throws DirectoryException
+ */
+ @DataProvider(name = "deleteEncodeDecode")
+ public Object[][] createDelData() {
+ return new Object[][] {
+ {"dc=com"},
+ {"dc=delete,dc=an,dc=entry,dc=with,dc=a,dc=long dn"},
+ };
+ }
+
+ /**
+ * Create a Delete from the data provided above.
+ * The call getBytes() to test the encoding of the Msg and
+ * create another DeleteMsg from the encoded byte array.
+ * Finally test that both Msg matches.
+ */
+ @Test(dataProvider = "deleteEncodeDecode")
+ public void deleteEncodeDecode(String rawDN)
+ throws Exception
+ {
+ InternalClientConnection connection = new InternalClientConnection();
+ DeleteOperation op = new DeleteOperation(connection, 1, 1,null,
+ DN.decode(rawDN));
+ ChangeNumber cn = new ChangeNumber(TimeThread.getTime(),
+ (short) 123, (short) 45);
+ op.setAttachment(SYNCHRONIZATION, cn);
+ DeleteMsg msg = new DeleteMsg(op);
+ DeleteMsg generatedMsg = new DeleteMsg(msg.getBytes());
+
+ assertEquals(msg.changeNumber, generatedMsg.changeNumber);
+
+ Operation generatedOperation = generatedMsg.createOperation(connection);
+
+ assertEquals(generatedOperation.getClass(), DeleteOperation.class);
+
+ DeleteOperation mod2 = (DeleteOperation) generatedOperation;
+
+ assertEquals(op.getRawEntryDN(), mod2.getRawEntryDN());
+ }
+
+ @DataProvider(name = "modifyDnEncodeDecode")
+ public Object[][] createModifyDnData() {
+ return new Object[][] {
+ {"dc=test,dc=com", "dc=new", false, "dc=change"},
+ {"dc=test,dc=com", "dc=new", true, "dc=change"},
+ // testNG does not like null argument so use "" for the newSuperior
+ // instead of null
+ {"dc=test,dc=com", "dc=new", false, ""},
+ {"dc=delete,dc=an,dc=entry,dc=with,dc=a,dc=long dn",
+ "dc=new",true, ""},
+ };
+ }
+
+ @Test(dataProvider = "modifyDnEncodeDecode")
+ public void modifyDnEncodeDecode(String rawDN, String newRdn,
+ boolean deleteOldRdn, String newSuperior)
+ throws Exception
+ {
+ InternalClientConnection connection = new InternalClientConnection();
+ ModifyDNOperation op =
+ new ModifyDNOperation(connection, 1, 1, null,
+ DN.decode(rawDN), RDN.decode(newRdn), deleteOldRdn,
+ (newSuperior.length() != 0 ? DN.decode(newSuperior) : null));
+
+ ChangeNumber cn = new ChangeNumber(TimeThread.getTime(),
+ (short) 123, (short) 45);
+ op.setAttachment(SYNCHRONIZATION, cn);
+ ModifyDNMsg msg = new ModifyDNMsg(op);
+ ModifyDNMsg generatedMsg = new ModifyDNMsg(msg.getBytes());
+ Operation generatedOperation = generatedMsg.createOperation(connection);
+ ModifyDNOperation mod2 = (ModifyDNOperation) generatedOperation;
+
+ assertEquals(msg.changeNumber, generatedMsg.changeNumber);
+ assertEquals(op.getRawEntryDN(), mod2.getRawEntryDN());
+ assertEquals(op.getRawNewRDN(), mod2.getRawNewRDN());
+ assertEquals(op.deleteOldRDN(), mod2.deleteOldRDN());
+ assertEquals(op.getRawNewSuperior(), mod2.getRawNewSuperior());
+ }
+
+ @DataProvider(name = "addEncodeDecode")
+ public Object[][] createAddData() {
+ return new Object[][] {
+ {"dc=test,dc=com"},
+ };
+ }
+
+ @Test(dataProvider = "addEncodeDecode")
+ public void addEncodeDecode(String rawDN)
+ throws Exception
+ {
+ LinkedHashSet<AttributeValue> ocValues =
+ new LinkedHashSet<AttributeValue>();
+ ocValues.add(
+ new AttributeValue(DirectoryServer.getObjectClassAttributeType(),
+ "organization"));
+ Attribute objectClass =
+ new Attribute(DirectoryServer.getObjectClassAttributeType(),
+ "objectClass", ocValues);
+
+ AttributeType org = DirectoryServer.getAttributeType("o", true);
+ ArrayList<Attribute> userAttributes = new ArrayList<Attribute>(1);
+ LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(org, "com"));
+ Attribute attr = new Attribute(org, "o", values);
+ userAttributes.add(attr);
+
+ ArrayList<Attribute> operationalAttributes = new ArrayList<Attribute>(1);
+ org = DirectoryServer.getAttributeType("creatorsname", true);
+ values = new LinkedHashSet<AttributeValue>();
+ values.add(new AttributeValue(org, "dc=creator"));
+ attr = new Attribute(org, "creatorsname", values);
+ operationalAttributes.add(attr);
+
+ ChangeNumber cn = new ChangeNumber(TimeThread.getTime(),
+ (short) 123, (short) 45);
+
+ AddMsg msg = new AddMsg(cn, rawDN, objectClass, userAttributes,
+ operationalAttributes);
+ AddMsg generatedMsg = new AddMsg(msg.getBytes());
+ assertEquals(msg.getBytes(), generatedMsg.getBytes());
+ // TODO : should test that generated attributes match original attributes.
+ }
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
new file mode 100644
index 0000000..75e1dc5
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
@@ -0,0 +1,37 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.synchronization;
+
+import org.opends.server.DirectoryServerTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * An abstract class that all sycnhronization unit test should extend.
+ */
+@Test(groups = { "precommit", "synchronization" })
+public abstract class SynchronizationTestCase extends DirectoryServerTestCase
+{}
--
Gitblit v1.10.0