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

lutoff
08.42.2006 9e87cf54bdad6b73da706a9adc8e31a2b467d224
Add Synchronization unitTest and code coverage
2 files added
3 files modified
832 ■■■■ changed files
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ModifyConflictTest.java 444 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ServerStateTest.java 134 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SyncMessagesTest.java 63 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationMsgTest.java 156 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java 35 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ModifyConflictTest.java
@@ -31,18 +31,17 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import static org.opends.server.synchronization.OperationContext.*;
import org.opends.server.SchemaFixture;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -54,89 +53,206 @@
import org.opends.server.types.ObjectClass;
/*
 * 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
 * Test the conflict resolution for modify operations As a consequence,
 * this will also test the Historical.java Class 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
public class ModifyConflictTest
    extends SynchronizationTestCase
{
  /**
   * Test that conflict between a modify-replace and modify-add
   * for multi-valued attributes are handled correctly.
   * Test that conflict between a modify-replace and modify-add for
   * multi-valued attributes@DataProvider(name = "ackMsg") are handled
   * correctly.
   */
  @Test()
  public void replaceAndAdd()
         throws Exception
  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);
    // Construct a new random UUID. and add it into the entry
    UUID uuid = UUID.randomUUID();
    // Create the att values list of uuid
    LinkedHashSet<AttributeValue> valuesUuid = new LinkedHashSet<AttributeValue>(
        1);
    valuesUuid.add(new AttributeValue(Historical.entryuuidAttrType,
        new ASN1OctetString(uuid.toString())));
    ArrayList<Attribute> uuidList = new ArrayList<Attribute>(1);
    Attribute uuidAttr = new Attribute(Historical.entryuuidAttrType,
        "entryUUID", valuesUuid);
    uuidList.add(uuidAttr);
    /*
     * Add the uuid in the entry
     */
    Map<AttributeType, List<Attribute>> operationalAttributes = entry
        .getOperationalAttributes();
    operationalAttributes.put(Historical.entryuuidAttrType, uuidList);
    // Create the att values list of historicalAttr
    String stringVal =
      "ds-sync-hist:00000108b3a6cbb800000001:repl:00000108b3a6cbb800000002";
  AttributeValue val = new AttributeValue(Historical.historicalAttrType,
      stringVal);
    LinkedHashSet<AttributeValue> valuesHist =
      new LinkedHashSet<AttributeValue>(1);
    valuesHist.add(val);
    ArrayList<Attribute> histList = new ArrayList<Attribute>(1);
    Attribute histAttr = new Attribute(Historical.historicalAttrType,
        "ds-sync-hist", valuesHist);
    histList.add(histAttr);
    //Add the historical att in the entry
    operationalAttributes.put(Historical.historicalAttrType,histList) ;
    // load historical from the entry
    Historical hist = Historical.load(entry);
    /*
     * simulate a modify-replace done at time t10
     */
    testModify(entry, hist, "description", ModificationType.REPLACE,
               "init value", 10, true);
        "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);
        "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...)
     * conflict resolution should remove it. (a second time to make
     * sure...)
     */
    testModify(entry, hist, "description", ModificationType.ADD,
               "older value", 2, false);
        "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);
    testModify(entry, hist, "description", ModificationType.ADD, "new value",
        11, true);
  }
  /*
   * helper function.
   */
  private void testHistoricalAndFake(
      Historical hist, Entry entry)
  {
    // Get the historical uuid associated to the entry
    // (the one that needs to be tested)
    String uuid = hist.getEntryUuid(entry);
    // Get the Entry uuid in String format
    List<Attribute> uuidAttrs = entry
        .getOperationalAttribute(Historical.entryuuidAttrType);
    uuidAttrs.get(0).getValues().iterator().next().toString();
    if (uuidAttrs != null)
    {
      if (uuidAttrs.size() > 0)
      {
        Attribute att = uuidAttrs.get(0);
        String retrievedUuid = (att.getValues().iterator().next()).toString();
        assertTrue(retrievedUuid.equals(uuid));
      }
    }
    try
    {
      Historical dup = hist.duplicate();
      // TODO Check values
    }
    catch (RuntimeException e)
    {
      assertTrue(false) ;
    }
    // Test FakeOperation
    try
    {
      Iterable<FakeOperation> fks = Historical.generateFakeOperations(entry);
      if (fks.iterator().hasNext())
      {
        FakeOperation fk = fks.iterator().next();
        assertTrue(new FakeOperationComparator().compare(fk, fk) == 0);
        assertTrue(new FakeOperationComparator().compare(null , fk) < 0);
        SynchronizationMessage generatedMsg = fk.generateMessage() ;
        if (generatedMsg instanceof UpdateMessage)
        {
          UpdateMessage new_name = (UpdateMessage) generatedMsg;
          assertEquals(new_name.getUniqueId(),uuid);
        }
      }
    }
    catch (RuntimeException e)
    {
      assertTrue(false) ;
    }
  }
  /*
   * helper function.
   */
  private void testHistorical(
      Historical hist, AddOperation addOp)
  {
    // Get the historical uuid associated to the entry
    // (the one that needs to be tested)
    String uuid = hist.getEntryUuid(addOp);
    // Get the op uuid in String format
    List<Attribute> uuidAttrs = addOp.getOperationalAttributes().get(
        Historical.entryuuidAttrType);
    uuidAttrs.get(0).getValues().iterator().next().toString();
    if (uuidAttrs != null)
    {
      if (uuidAttrs.size() > 0)
      {
        Attribute att = uuidAttrs.get(0);
        String retrievedUuid = (att.getValues().iterator().next()).toString();
        assertTrue(retrievedUuid.equals(uuid));
      }
    }
  }
  /**
   * Test that conflict between a modify-delete-attribute and modify-add
   * for multi-valued attributes are handled correctly.
   */
  @Test()
  public void deleteAndAdd()
         throws Exception
  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.
     * 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>();
@@ -147,95 +263,174 @@
     * start with a new entry with an empty description
     */
    Entry entry = new Entry(dn, objectClasses, null, null);
    // Construct a new random UUID. and add it into the entry
    UUID uuid = UUID.randomUUID();
    // Create the att values list
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(
        1);
    values.add(new AttributeValue(Historical.entryuuidAttrType,
        new ASN1OctetString(uuid.toString())));
    ArrayList<Attribute> uuidList = new ArrayList<Attribute>(1);
    Attribute uuidAttr = new Attribute(Historical.entryuuidAttrType,
        "entryUUID", values);
    uuidList.add(uuidAttr);
    /*
     * Add the uuid in the entry
     */
    Map<AttributeType, List<Attribute>> operationalAttributes = entry
        .getOperationalAttributes();
    operationalAttributes.put(Historical.entryuuidAttrType, uuidList);
    // Create the att values list of historicalAttr
    String stringVal =
      "ds-sync-hist:00000108b3a6cbb800000001:del:00000108b3a6cbb800000002";
  AttributeValue val = new AttributeValue(Historical.historicalAttrType,
      stringVal);
    LinkedHashSet<AttributeValue> valuesHist =
      new LinkedHashSet<AttributeValue>(1);
    valuesHist.add(val);
    ArrayList<Attribute> histList = new ArrayList<Attribute>(1);
    Attribute histAttr = new Attribute(Historical.historicalAttrType,
        "ds-sync-hist", valuesHist);
    //Add the historical att in the entry
    entry.putAttribute(Historical.historicalAttrType,histList) ;
    // load historical from the entry
    Historical hist = Historical.load(entry);
    /*
     * simulate a delete of the whole description attribute done at time t10
     * simulate a delete of the whole description attribute done at time
     * t10
     */
    testModify(entry, hist, "description", ModificationType.DELETE,
               null, 10, true);
    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...)
     * 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", 2, false);
        "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);
    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");
   * 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);
    /*
     * start with a new entry with an empty description
     */
    Entry entry = new Entry(dn, objectClasses, null, null);
   /*
    * simulate a add of the description attribute done at time t10
    */
   testModify(entry, hist, "description", ModificationType.ADD,
              "init value", 10, true);
    // Construct a new random UUID. and add it into the entry
    UUID uuid = UUID.randomUUID();
   /*
    * 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);
    // Create the att values list
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(
        1);
    values.add(new AttributeValue(Historical.entryuuidAttrType,
        new ASN1OctetString(uuid.toString())));
    ArrayList<Attribute> uuidList = new ArrayList<Attribute>(1);
    Attribute uuidAttr = new Attribute(Historical.entryuuidAttrType,
        "entryUUID", values);
    uuidList.add(uuidAttr);
   /*
    * 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);
    /*
     * Add the uuid in the entry
     */
    Map<AttributeType, List<Attribute>> operationalAttributes = entry
        .getOperationalAttributes();
   /*
    * 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);
 }
    operationalAttributes.put(Historical.entryuuidAttrType, uuidList);
    // Create the att values list of historicalAttr
    String stringVal =
      "ds-sync-hist:00000108b3a6cbb800000001:add:00000108b3a6cbb800000002";
  AttributeValue val = new AttributeValue(Historical.historicalAttrType,
      stringVal);
    LinkedHashSet<AttributeValue> valuesHist =
      new LinkedHashSet<AttributeValue>(1);
    valuesHist.add(val);
    ArrayList<Attribute> histList = new ArrayList<Attribute>(1);
    Attribute histAttr = new Attribute(Historical.historicalAttrType,
        "ds-sync-hist", valuesHist);
    histList.add(histAttr);
    //Add the historycal att in the entry
    entry.putAttribute(Historical.historicalAttrType,histList) ;
    // load historical from the entry
    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,
  private void testModify(Entry entry,
      Historical hist, String attrName,
      ModificationType modType, String value,
      int date, boolean keepChangeResult)
@@ -254,17 +449,27 @@
    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);
        entry.getDN(), mods);
    ModifyContext ctx = new ModifyContext(t, "uniqueId");
    modOp.setAttachment(SYNCHROCONTEXT, ctx);
    hist.replayOperation(modOp, entry);
    if (modType.intValue() == ModificationType.ADD.intValue())
    {
      AddOperation addOp = new AddOperation(connection, 1, 1, null, entry
          .getDN(), entry.getObjectClasses(), entry.getUserAttributes(),
          entry.getOperationalAttributes());
      testHistorical(hist, addOp);
    }
    else
    {
      testHistoricalAndFake(hist, entry);
    }
    /*
     * The last older change should have been detected as conflicting
     * and should be removed by the conflict resolution code.
     * The last older change should have been detected as conflicting and
     * should be removed by the conflict resolution code.
     */
    if (keepChangeResult)
    {
@@ -277,27 +482,4 @@
      assertEquals(0, mods.size());
    }
  }
  /**
   * Set up the environment for performing the tests in this suite.
   *
   * @throws Exception
   *           If the environment could not be set up.
   */
  @BeforeClass
  public void setUp() throws Exception {
    // This test suite depends on having the schema available.
    SchemaFixture.FACTORY.setUp();
  }
  /**
   * Tears down the environment for performing the tests in this suite.
   *
   * @throws Exception
   *           If the environment could not be finalized.
   */
  @AfterClass
  public void tearDown() throws Exception {
    SchemaFixture.FACTORY.tearDown();
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/ServerStateTest.java
New file
@@ -0,0 +1,134 @@
/*
 * 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.Set;
import java.util.Map;
import java.util.zip.DataFormatException;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import org.opends.server.api.ClientConnection;
import org.opends.server.core.AddOperation;
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.protocols.ldap.LDAPAttribute;
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.Control;
import org.opends.server.types.DN;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.RDN;
import org.opends.server.util.TimeThread;
import static org.opends.server.synchronization.OperationContext.*;
/**
 * Test the ServerState
 */
public class ServerStateTest extends SynchronizationTestCase
{
  /**
   * Create ChangeNumber Data
   */
  @DataProvider(name = "changeNumberData")
  public Object[][] createChangeNumberData() {
    return new Object[][] {
       {new ChangeNumber(1, (short) 0, (short) 1)},
       {new ChangeNumber(TimeThread.getTime(), (short) 123, (short) 45)}
    };
  }
  /**
   * Create a new ServerState object
   */
  @Test(dataProvider = "changeNumberData")
  public void serverStateTest(ChangeNumber cn)
         throws Exception
  {
    // Check constructor
    DN dn = DN.decode("cn=com");
    ServerState serverState = new ServerState(dn) ;
    // Check Load
    // serverState.loadState() ;
    // TODO Check result
    // Check getServerStateDn()
    DN returned_DN = serverState.getServerStateDn();
    // TODO Check the returned DN
    // Check update
    assertFalse(serverState.update(null));
    assertTrue(serverState.update(cn));
    assertFalse(serverState.update(cn));
    ChangeNumber cn1, cn2, cn3;
    cn1 = new ChangeNumber(cn.getTime()+1,cn.getSeqnum(),cn.getServerId());
    cn2 = new ChangeNumber(cn1.getTime(),cn1.getSeqnum()+1,cn1.getServerId());
    cn3 = new ChangeNumber(cn2.getTime(),cn2.getSeqnum(),(short)(cn2.getServerId()+1));
    assertTrue(serverState.update(cn1)) ;
    assertTrue(serverState.update(cn2)) ;
    assertTrue(serverState.update(cn3)) ;
    // Check toStringSet
    ChangeNumber[] cns = {cn2,cn3};
    Set<String> stringSet = serverState.toStringSet();
    assertEquals(cns.length, stringSet.size());
    // TODO Check the value
    // Check getMaxChangeNumber
    assertEquals(cn2.compareTo(serverState.getMaxChangeNumber(cn2.getServerId())),0);
    assertEquals(cn3.compareTo(serverState.getMaxChangeNumber(cn3.getServerId())),0);
    // Check the toString
    String stringRep = serverState.toString() ;
    // TODO Check the value
    // Check getBytes
    byte[] b = serverState.getBytes();
    ServerState generatedServerState = new ServerState(b,0,b.length -1) ;
    assertEquals(b, generatedServerState.getBytes()) ;
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SyncMessagesTest.java
New file
@@ -0,0 +1,63 @@
/*
 * 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.lang.reflect.Field;
import org.opends.server.messages.MessageHandler;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
 * Test of ValueInfo
 */
public class SyncMessagesTest extends SynchronizationTestCase
{
  /**
   * Create a ValueInfo and check the methods
   */
  @Test()
  public void synchroMessagesTest()
         throws Exception
  {
    SynchMessages.registerMessages() ;
    Field fields[] = SynchMessages.class.getFields() ;
    SynchMessages synMsg = new SynchMessages() ;
    for (Field f : fields)
    {
      if (f.getClass().equals(Integer.class))
      {
        // Get the id
        String msg = MessageHandler.getMessage(f.getInt(synMsg));
        assertFalse(msg.startsWith("Unknown message for message ID"));
      }
    }
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationMsgTest.java
@@ -27,6 +27,7 @@
package org.opends.server.synchronization;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.zip.DataFormatException;
@@ -35,6 +36,8 @@
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import org.opends.server.api.ClientConnection;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryException;
import org.opends.server.core.DirectoryServer;
@@ -49,6 +52,7 @@
import org.opends.server.types.DN;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.RDN;
import org.opends.server.util.TimeThread;
@@ -132,7 +136,9 @@
    DN dn = DN.decode(rawdn);
    InternalClientConnection connection = new InternalClientConnection();
    ModifyMsg msg = new ModifyMsg(changeNumber, dn, mods, "fakeuniqueid");
    ModifyMsg generatedMsg = new ModifyMsg(msg.getBytes());
    ModifyMsg generatedMsg = (ModifyMsg) SynchronizationMessage
        .generateMsg(msg.getBytes());
    assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
@@ -141,19 +147,66 @@
    assertEquals(op.getClass(), ModifyOperation.class);
    assertEquals(generatedOperation.getClass(), ModifyOperation.class);
    ModifyOperation mod1 = (ModifyOperation) op;
    ModifyOperation mod2 = (ModifyOperation) generatedOperation;
    assertEquals(mod1.getRawEntryDN(), mod2.getRawEntryDN());
    assertEquals( mod1.getAttachment(SYNCHROCONTEXT),
                  mod2.getAttachment(SYNCHROCONTEXT));
    /*
     * TODO : test that the generated mod equals the original mod.
     */
  }
    // Check pending change
    testPendingChange(changeNumber,op,msg);
  }
  /**
   * Create a Update Message 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 updateMsgTest(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, "fakeuniqueid");;
    // Check uuid
    assertEquals("fakeuniqueid", msg.getUniqueId());
    // Check isAssured
    assertFalse(msg.isAssured());
    msg.setAssured();
    assertTrue(msg.isAssured());
    // Check equals
    ModifyMsg generatedMsg = (ModifyMsg) SynchronizationMessage
        .generateMsg(msg.getBytes());
    assertFalse(msg.equals(null));
    assertFalse(msg.equals(new Object()));
    assertTrue(msg.equals(generatedMsg));
    // Check hashCode
    assertEquals(msg.hashCode(), generatedMsg.hashCode());
    // Check compareTo
    assertEquals(msg.compareTo(generatedMsg), 0);
    // Check Get / Set DN
    assertTrue(dn.equals(DN.decode(msg.getDn())));
    String fakeDN = "cn=fake cn";
    msg.setDn(fakeDN) ;
    assertEquals(msg.getDn(), fakeDN) ;
  }
  /**
   * Build some data for the DeleteMsg test below.
   * @throws DirectoryException
@@ -183,7 +236,10 @@
      (short) 123, (short) 45);
    op.setAttachment(SYNCHROCONTEXT, new DeleteContext(cn, "uniqueid"));
    DeleteMsg msg = new DeleteMsg(op);
    DeleteMsg generatedMsg = new DeleteMsg(msg.getBytes());
    DeleteMsg generatedMsg = (DeleteMsg) SynchronizationMessage
        .generateMsg(msg.getBytes());
    assertEquals(msg.toString(), generatedMsg.toString());
    assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
@@ -194,6 +250,10 @@
    DeleteOperation mod2 = (DeleteOperation) generatedOperation;
    assertEquals(op.getRawEntryDN(), mod2.getRawEntryDN());
    // Create an update message from this op
    DeleteMsg updateMsg = (DeleteMsg) UpdateMessage.generateMsg(op, true);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
  }
  @DataProvider(name = "modifyDnEncodeDecode")
@@ -225,7 +285,8 @@
    op.setAttachment(SYNCHROCONTEXT,
        new ModifyDnContext(cn, "uniqueid", "newparentId"));
    ModifyDNMsg msg = new ModifyDNMsg(op);
    ModifyDNMsg generatedMsg = new ModifyDNMsg(msg.getBytes());
    ModifyDNMsg generatedMsg = (ModifyDNMsg) SynchronizationMessage
        .generateMsg(msg.getBytes());
    Operation generatedOperation = generatedMsg.createOperation(connection);
    ModifyDNOperation mod2 = (ModifyDNOperation) generatedOperation;
@@ -234,6 +295,10 @@
    assertEquals(op.getRawNewRDN(), mod2.getRawNewRDN());
    assertEquals(op.deleteOldRDN(), mod2.deleteOldRDN());
    assertEquals(op.getRawNewSuperior(), mod2.getRawNewSuperior());
    // Create an update message from this op
    ModifyDNMsg updateMsg = (ModifyDNMsg) UpdateMessage.generateMsg(op, true);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
  }
  @DataProvider(name = "addEncodeDecode")
@@ -255,6 +320,10 @@
    Attribute objectClass =
      new Attribute(DirectoryServer.getObjectClassAttributeType(),
        "objectClass", ocValues);
    HashMap<ObjectClass,String> objectClassList=
      new HashMap<ObjectClass,String>();
    objectClassList.put(DirectoryServer.getObjectClass("organization"),
        "organization");
    AttributeType org = DirectoryServer.getAttributeType("o", true);
    ArrayList<Attribute> userAttributes = new ArrayList<Attribute>(1);
@@ -262,6 +331,10 @@
    values.add(new AttributeValue(org, "com"));
    Attribute attr = new Attribute(org, "o", values);
    userAttributes.add(attr);
    HashMap<AttributeType,List<Attribute>> userAttList=
      new HashMap<AttributeType,List<Attribute>>();
    userAttList.put(org,userAttributes);
    ArrayList<Attribute> operationalAttributes = new ArrayList<Attribute>(1);
    org = DirectoryServer.getAttributeType("creatorsname", true);
@@ -269,6 +342,9 @@
    values.add(new AttributeValue(org, "dc=creator"));
    attr = new Attribute(org, "creatorsname", values);
    operationalAttributes.add(attr);
    HashMap<AttributeType,List<Attribute>> opList=
      new HashMap<AttributeType,List<Attribute>>();
    opList.put(org,operationalAttributes);
    ChangeNumber cn = new ChangeNumber(TimeThread.getTime(),
                                      (short) 123, (short) 45);
@@ -276,9 +352,42 @@
    AddMsg msg = new AddMsg(cn, rawDN, "thisIsaUniqueID", "parentUniqueId",
                            objectClass, userAttributes,
                            operationalAttributes);
    AddMsg generatedMsg = new AddMsg(msg.getBytes());
    AddMsg generatedMsg = (AddMsg) SynchronizationMessage.generateMsg(msg
        .getBytes());
    assertEquals(msg.getBytes(), generatedMsg.getBytes());
    assertEquals(msg.toString(), generatedMsg.toString());
    // TODO : should test that generated attributes match original attributes.
    // Create an new Add Operation from the current addMsg
    InternalClientConnection connection = new InternalClientConnection();
    AddOperation addOp = msg.createOperation(connection, rawDN) ;
    // TODO : should test that generated attributes match original attributes.
    // List<LDAPAttribute> rawAtt = addOp.getRawAttributes();
    assertEquals(msg.getBytes(), generatedMsg.getBytes());
    assertEquals(msg.toString(), generatedMsg.toString());
    //Create an Add operation and generate and Add msg from it
    DN dn = DN.decode(rawDN);
    addOp = new AddOperation((ClientConnection) connection,
        (long) 1, 1, null, dn, objectClassList, userAttList, opList);
    OperationContext opCtx = new AddContext(cn, "thisIsaUniqueID",
        "parentUniqueId");
    addOp.setAttachment(SYNCHROCONTEXT, opCtx);
    generatedMsg = new AddMsg(addOp);
    assertEquals(msg.getBytes(), generatedMsg.getBytes());
    assertEquals(msg.toString(), generatedMsg.toString());
    // TODO : should test that generated attributes match original attributes.
    // Create an update message from this op
    AddMsg updateMsg = (AddMsg) UpdateMessage.generateMsg(addOp, true);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
  }
  /**
@@ -328,6 +437,37 @@
    }
    // Check that retrieved CN is OK
    msg2 = new  AckMessage(msg1.getBytes());
    msg2 = (AckMessage) SynchronizationMessage.generateMsg(msg1.getBytes());
  }
  /**
   * Test PendingChange
   */
  private void testPendingChange(ChangeNumber cn, Operation op, SynchronizationMessage msg)
  {
    if (! (msg instanceof UpdateMessage))
    {
      return ;
    }
    UpdateMessage updateMsg = (UpdateMessage) msg;
    PendingChange pendingChange = new PendingChange(cn,null,null);
    pendingChange.setCommitted(false);
    assertFalse(pendingChange.isCommitted()) ;
    pendingChange.setCommitted(true);
    assertTrue(pendingChange.isCommitted()) ;
    assertTrue(cn.compareTo(pendingChange.getChangeNumber()) == 0);
    assertEquals(pendingChange.getMsg(), null) ;
    pendingChange.setMsg(updateMsg);
    assertEquals(updateMsg.getBytes(), pendingChange.getMsg().getBytes());
    assertEquals(pendingChange.getOp(), null) ;
    pendingChange.setOp(op);
    assertEquals(op.getClass(), op.getClass());
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
@@ -27,11 +27,44 @@
package org.opends.server.synchronization;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.SchemaFixture;
import org.testng.annotations.Test;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
/**
 * An abstract class that all synchronization unit test should extend. 
 */
@Test(groups = { "precommit", "synchronization" })
public abstract class SynchronizationTestCase extends DirectoryServerTestCase
{}
{
  /**
   * Tears down the environment for performing the tests in this suite.
   *
   * @throws Exception
   *         If the environment could not be finalized.
   */
  @AfterClass
  public void tearDown() throws Exception
  {
    SchemaFixture.FACTORY.tearDown();
  }
  /**
   * Set up the environment for performing the tests in this suite.
   *
   * @throws Exception
   *         If the environment could not be set up.
   */
  @BeforeClass
  public void setUp() throws Exception
  {
    // This test suite depends on having the schema available.
    SchemaFixture.FACTORY.setUp();
  }
}