| | |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | |
| | | import org.opends.server.core.AddOperationBasis; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.ModifyOperationBasis; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.replication.ReplicationTestCase; |
| | | import org.opends.server.replication.common.CSN; |
| | | import org.opends.server.replication.protocol.LDAPUpdateMsg; |
| | |
| | | import static org.forgerock.opendj.ldap.ModificationType.*; |
| | | import static org.opends.server.TestCaseUtils.*; |
| | | import static org.opends.server.protocols.internal.InternalClientConnection.*; |
| | | import static org.opends.server.replication.plugin.EntryHistorical.*; |
| | | import static org.opends.server.replication.protocol.OperationContext.*; |
| | | import static org.opends.server.util.CollectionUtils.*; |
| | | import static org.testng.Assert.*; |
| | |
| | | @SuppressWarnings("javadoc") |
| | | public class ModifyConflictTest extends ReplicationTestCase |
| | | { |
| | | |
| | | private static final String ORGANIZATION = "organization"; |
| | | private static final String DISPLAYNAME = "displayname"; |
| | | private static final String EMPLOYEENUMBER = "employeenumber"; |
| | |
| | | public void replaceAndAdd() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute repl = buildSyncHist(DESCRIPTION, |
| | | ":000000000000000a000000000000:repl:init value"); |
| | | |
| | |
| | | public void replaceAndAddSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute repl = buildSyncHist(DISPLAYNAME, |
| | | ":000000000000000a000000000000:repl:init value"); |
| | | |
| | |
| | | public void replaceWithNull() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | |
| | | public void addAndReplace() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a modify-add done at time t10 |
| | |
| | | public void addAndReplaceSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a modify-add done at time 2 |
| | |
| | | public void deleteAndAdd() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DESCRIPTION, |
| | |
| | | @Test |
| | | public void delValueAndAddValue() throws Exception |
| | | { |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create description with values value1 and value2 and add |
| | | // this attribute to the entry. |
| | | AttributeBuilder builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(builder.toAttribute(), duplicateValues); |
| | | |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a delete of the description attribute value "value1" done at time t1 |
| | |
| | | @Test |
| | | public void delValueAndDelValue() throws Exception |
| | | { |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create an attribute with values value1, value2, value3 and value4 and |
| | | // add this attribute to the entry. |
| | | AttributeBuilder builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | builder.add("value3"); |
| | | builder.add("value4"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(builder.toAttribute(), duplicateValues); |
| | | |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2", "value3", "value4")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | assertContainsOnlyValues(entry, DESCRIPTION, "value1"); |
| | | } |
| | | |
| | | private void addAttribute(Entry entry, Attribute builder) |
| | | { |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(builder, duplicateValues); |
| | | } |
| | | |
| | | /** |
| | | * Test that conflict between a delete attribute and a delete |
| | | * value on a single valued attribute works correctly. |
| | |
| | | @Test |
| | | public void delAttributeAndDelValueSingle() throws Exception |
| | | { |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create a single valued attribute with value : "value1" |
| | | // add this attribute to the entry. |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | Attribute attribute = Attributes.create(EMPLOYEENUMBER, "value1"); |
| | | entry.addAttribute(attribute, duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(EMPLOYEENUMBER, "value1")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a delete of attribute employeenumber. |
| | |
| | | @Test |
| | | public void delValueAndDelAttributeSingle() throws Exception |
| | | { |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create a single valued attribute with value : "value1" |
| | | // add this attribute to the entry. |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | Attribute attribute = Attributes.create(EMPLOYEENUMBER, "value1"); |
| | | entry.addAttribute(attribute, duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(EMPLOYEENUMBER, "value1")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // now simulate a delete of value "value1" |
| | |
| | | @Test |
| | | public void delValueAndAddValueDisordered() throws Exception |
| | | { |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create description with values value1 and value2 and add |
| | | // this attribute to the entry. |
| | | AttributeBuilder builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(builder.toAttribute(), duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | public void deleteAndAddSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create a single valued attribute with value : "value1" |
| | | // add this attribute to the entry. |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | Attribute attribute = Attributes.create(DISPLAYNAME, "value1"); |
| | | entry.addAttribute(attribute, duplicateValues); |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000003000000000000:attrDel"); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DISPLAYNAME, "value1")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000003000000000000:attrDel"); |
| | | // simulate a delete of the whole description attribute done at time t2 |
| | | testModify(entry, hist, 3, true, newModification(DELETE, DISPLAYNAME)); |
| | | assertEquals(hist.encodeAndPurge(), attrDel); |
| | |
| | | public void deleteAndReplace() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | Attribute attrDel = buildSyncHist(DESCRIPTION,":0000000000000004000000000000:attrDel"); |
| | | |
| | | Attribute attrDel = buildSyncHist(DESCRIPTION, |
| | | ":0000000000000004000000000000:attrDel"); |
| | | // simulate a delete of the whole description attribute done at time t4 |
| | | testModify(entry, hist, 4, true, newModification(DELETE, DESCRIPTION)); |
| | | assertEquals(hist.encodeAndPurge(), attrDel); |
| | |
| | | @Test |
| | | public void replaceAndDelete() throws Exception |
| | | { |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create description with values value1 and value2 and add |
| | | // this attribute to the entry. |
| | | AttributeBuilder builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | builder.add("value3"); |
| | | builder.add("value4"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(builder.toAttribute(), duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2", "value3", "value4")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a REPLACE of the attribute with values : value1, value2, value3 |
| | | // at time t1. |
| | | builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | builder.add("value3"); |
| | | |
| | | Modification mod = new Modification(REPLACE, builder.toAttribute()); |
| | | // simulate a REPLACE of the attribute with values : value1, value2, value3 at time t1. |
| | | Modification mod = new Modification(REPLACE, Attributes.create(DESCRIPTION, "value1", "value2", "value3")); |
| | | testModify(entry, hist, 1, true, mod); |
| | | |
| | | Attribute attr = buildSyncHist(DESCRIPTION, |
| | |
| | | ":0000000000000001000000000000:add:value3"); |
| | | assertEquals(hist.encodeAndPurge(), attr); |
| | | |
| | | // simulate a DELETE of the attribute values : value3 and value4 |
| | | // at time t2. |
| | | builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value3"); |
| | | builder.add("value4"); |
| | | mod = new Modification(DELETE, builder.toAttribute()); |
| | | // simulate a DELETE of the attribute values : value3 and value4 at time t2. |
| | | mod = new Modification(DELETE, Attributes.create(DESCRIPTION, "value3", "value4")); |
| | | |
| | | List<Modification> mods = replayModify(entry, hist, mod, 2); |
| | | mod = mods.get(0); |
| | | builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value3"); |
| | | assertEquals(mod.getAttribute(), builder.toAttribute()); |
| | | assertEquals(mod.getAttribute(), Attributes.create(DESCRIPTION, "value3")); |
| | | assertEquals(mod.getModificationType(), DELETE); |
| | | |
| | | attr = buildSyncHist(DESCRIPTION, |
| | |
| | | @Test |
| | | public void replaceAndDeleteDisorder() throws Exception |
| | | { |
| | | AttributeType descriptionAttrType = |
| | | DirectoryServer.getSchema().getAttributeType(DESCRIPTION); |
| | | |
| | | // create an entry to use with conflicts tests. |
| | | Entry entry = initializeEntry(); |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2", "value3", "value4")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // We will reuse these attributes a couple of times. |
| | | AttributeBuilder builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value3"); |
| | | builder.add("value4"); |
| | | Attribute values3and4 = builder.toAttribute(); |
| | | builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | Attribute values1and2 = builder.toAttribute(); |
| | | |
| | | // Create description with values value1 and value2 and add |
| | | // this attribute to the entry. |
| | | builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | builder.add("value3"); |
| | | builder.add("value4"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(builder.toAttribute(), duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | Attribute values3and4 = Attributes.create(DESCRIPTION, "value3", "value4"); |
| | | Attribute values1and2 = Attributes.create(DESCRIPTION, "value1", "value2"); |
| | | |
| | | // simulate a DELETE of the attribute values : value3 and value4 at time t2. |
| | | Modification mod = new Modification(DELETE, values3and4); |
| | |
| | | assertEquals(mod.getAttribute(), values3and4); |
| | | |
| | | // check that the entry now contains value1 and value2 and no other values. |
| | | AttributeType descriptionAttrType = getAttributeType(DESCRIPTION); |
| | | Attribute resultEntryAttr = entry.getAttribute(descriptionAttrType).get(0); |
| | | assertEquals(resultEntryAttr, values1and2); |
| | | |
| | |
| | | |
| | | // simulate a REPLACE of the attribute with values : value1, value2, value3 |
| | | // at time t1. |
| | | builder = new AttributeBuilder(DESCRIPTION); |
| | | builder.add("value1"); |
| | | builder.add("value2"); |
| | | builder.add("value3"); |
| | | |
| | | mod = new Modification(REPLACE, builder.toAttribute()); |
| | | mod = new Modification(REPLACE, Attributes.create(DESCRIPTION, "value1", "value2", "value3")); |
| | | mods = replayModify(entry, hist, mod, 1); |
| | | entry.applyModifications(mods); |
| | | mod = mods.get(0); |
| | |
| | | public void deleteAndReplaceSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create a single valued attribute with value : "value1" |
| | | // add this attribute to the entry. |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | Attribute attribute = Attributes.create(DISPLAYNAME, "value1"); |
| | | entry.addAttribute(attribute, duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DISPLAYNAME, "value1")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000004000000000000:attrDel"); |
| | | |
| | |
| | | public void addAndAdd() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a add of the description attribute done at time t10 |
| | |
| | | public void delAndAddSameOp() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a add of the description attribute done at time t10 |
| | |
| | | assertEquals(hist.encodeAndPurge(), attr); |
| | | |
| | | // Now simulate a del and a add in the same operation |
| | | attr = Attributes.create(DESCRIPTION, "Init Value"); |
| | | Modification mod1 = new Modification(DELETE, attr); |
| | | |
| | | attr = Attributes.create(DESCRIPTION, "Init Value"); |
| | | Modification mod2 = new Modification(ADD, attr); |
| | | |
| | | Modification mod1 = newModification(DELETE, DESCRIPTION, "Init Value"); |
| | | Modification mod2 = newModification(ADD, DESCRIPTION, "Init Value"); |
| | | List<Modification> mods = newLinkedList(mod1, mod2); |
| | | |
| | | replayModifies(entry, hist, mods, 11); |
| | |
| | | public void delAndReplaceSameOp() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DESCRIPTION, |
| | | ":000000000000000c000000000000:attrDel"); |
| | | |
| | |
| | | * in the same operation |
| | | */ |
| | | |
| | | attr = Attributes.create(DESCRIPTION, "init value"); |
| | | Modification mod1 = new Modification(DELETE, attr); |
| | | |
| | | attr = Attributes.empty(DESCRIPTION); |
| | | Modification mod2 = new Modification(REPLACE, attr); |
| | | |
| | | Modification mod1 = newModification(DELETE, DESCRIPTION, "init value"); |
| | | Modification mod2 = newModification(REPLACE, DESCRIPTION); |
| | | List<Modification> mods = newLinkedList(mod1, mod2); |
| | | |
| | | List<Modification> mods2 = new LinkedList<>(mods); |
| | |
| | | public void addAndDelSameOp() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // Now simulate a del and a add in the same operation |
| | | Attribute attr = Attributes.create(DESCRIPTION, "Init Value"); |
| | | Modification mod1 = new Modification(ADD, attr); |
| | | |
| | | attr = Attributes.create(DESCRIPTION, "Init Value"); |
| | | Modification mod2 = new Modification(DELETE, attr); |
| | | |
| | | Modification mod1 = newModification(ADD, DESCRIPTION, "Init Value"); |
| | | Modification mod2 = newModification(DELETE, DESCRIPTION, "Init Value"); |
| | | List<Modification> mods = newLinkedList(mod1, mod2); |
| | | |
| | | replayModifies(entry, hist, mods, 11); |
| | | attr = buildSyncHist(DESCRIPTION, |
| | | Attribute attr = buildSyncHist(DESCRIPTION, |
| | | ":000000000000000b000000000000:del:Init Value"); |
| | | assertEquals(hist.encodeAndPurge(), attr); |
| | | assertThat(mods).as("DEL and ADD of the same attribute same value was not correct").containsExactly(mod1, mod2); |
| | |
| | | public void addAndAddSameValues() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | // simulate a add of the description attribute done at time 1 |
| | |
| | | |
| | | // do the same as before but in reverse order |
| | | entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | public void addAndAddSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute olderValue = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000001000000000000:add:older value"); |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Test that conflict between add, delete and add on aingle valued attribute |
| | | * Test that conflict between add, delete and add on single valued attribute |
| | | * are handled correctly. |
| | | */ |
| | | @Test |
| | | public void addDelAddSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000003000000000000:attrDel"); |
| | | |
| | |
| | | public void addAddDelSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute firstValue = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000001000000000000:add:first value"); |
| | | |
| | |
| | | assertEquals(val.toString(), value); |
| | | } |
| | | |
| | | /** |
| | | * Create an initialize an entry that can be used for modify conflict |
| | | * resolution tests. |
| | | */ |
| | | /** Create an initialize an entry that can be used for modify conflict resolution tests. */ |
| | | private Entry initializeEntry() throws DirectoryException |
| | | { |
| | | AttributeType entryuuidAttrType = |
| | | DirectoryServer.getSchema().getAttributeType( |
| | | EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME); |
| | | |
| | | /* |
| | | * Objectclass and DN do not have any impact on the modify conflict |
| | | * resolution for the description attribute. Always use the same values |
| | |
| | | UUID uuid = UUID.randomUUID(); |
| | | |
| | | // Create the att values list |
| | | AttributeType entryuuidAttrType = getAttributeType(ENTRYUUID_ATTRIBUTE_NAME); |
| | | List<Attribute> uuidList = Attributes.createAsList(entryuuidAttrType, uuid.toString()); |
| | | |
| | | // Add the uuid in the entry |
| | |
| | | return entry; |
| | | } |
| | | |
| | | /** |
| | | * Helper function. |
| | | */ |
| | | /** Helper function. */ |
| | | private void testHistoricalAndFake(Entry entry) |
| | | { |
| | | AttributeType entryuuidAttrType = |
| | | DirectoryServer.getSchema().getAttributeType(EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME); |
| | | |
| | | // Get the historical uuid associated to the entry |
| | | // (the one that needs to be tested) |
| | | String uuid = EntryHistorical.getEntryUUID(entry); |
| | | |
| | | // Get the Entry uuid in String format |
| | | AttributeType entryuuidAttrType = getAttributeType(ENTRYUUID_ATTRIBUTE_NAME); |
| | | List<Attribute> uuidAttrs = entry.getOperationalAttribute(entryuuidAttrType); |
| | | String retrievedUuid = uuidAttrs.get(0).iterator().next().toString(); |
| | | assertEquals(retrievedUuid, uuid); |
| | |
| | | { |
| | | CSN t = new CSN(date, 0, 0); |
| | | |
| | | ModifyOperationBasis modOpBasis = |
| | | new ModifyOperationBasis(getRootConnection(), 1, 1, null, entry.getName(), mods); |
| | | LocalBackendModifyOperation modOp = new LocalBackendModifyOperation(modOpBasis); |
| | | ModifyContext ctx = new ModifyContext(t, "uniqueId"); |
| | | modOp.setAttachment(SYNCHROCONTEXT, ctx); |
| | | |
| | | LocalBackendModifyOperation modOp = modifyOperation(entry, t, mods); |
| | | hist.replayOperation(modOp, entry); |
| | | } |
| | | |
| | | private List<Modification> replayModify( |
| | | Entry entry, EntryHistorical hist, Modification mod, int date) |
| | | { |
| | | AttributeType historicalAttrType = |
| | | DirectoryServer.getSchema().getAttributeType( |
| | | EntryHistorical.HISTORICAL_ATTRIBUTE_NAME); |
| | | |
| | | InternalClientConnection aConnection = |
| | | InternalClientConnection.getRootConnection(); |
| | | CSN t = new CSN(date, 0, 0); |
| | | |
| | | List<Modification> mods = new ArrayList<>(); |
| | | mods.add(mod); |
| | | List<Modification> mods = newArrayList(mod); |
| | | |
| | | ModifyOperationBasis modOpBasis = |
| | | new ModifyOperationBasis(aConnection, 1, 1, null, entry.getName(), mods); |
| | | LocalBackendModifyOperation modOp = new LocalBackendModifyOperation(modOpBasis); |
| | | ModifyContext ctx = new ModifyContext(t, "uniqueId"); |
| | | modOp.setAttachment(SYNCHROCONTEXT, ctx); |
| | | |
| | | LocalBackendModifyOperation modOp = modifyOperation(entry, t, mods); |
| | | hist.replayOperation(modOp, entry); |
| | | |
| | | if (mod.getModificationType() == ADD) |
| | | { |
| | | AddOperationBasis addOpBasis = |
| | | new AddOperationBasis(aConnection, 1, 1, null, entry |
| | | .getName(), entry.getObjectClasses(), entry.getUserAttributes(), |
| | | entry.getOperationalAttributes()); |
| | | LocalBackendAddOperation addOp = new LocalBackendAddOperation(addOpBasis); |
| | | testHistorical(addOp); |
| | | testHistorical(addOperation(entry)); |
| | | } |
| | | else |
| | | { |
| | |
| | | * works by encoding decoding and checking that the result is the same |
| | | * as the initial value. |
| | | */ |
| | | entry.removeAttribute(historicalAttrType); |
| | | entry.removeAttribute(getAttributeType(HISTORICAL_ATTRIBUTE_NAME)); |
| | | entry.addAttribute(hist.encodeAndPurge(), null); |
| | | EntryHistorical hist2 = EntryHistorical.newInstanceFromEntry(entry); |
| | | assertEquals(hist2.encodeAndPurge(), hist.encodeAndPurge()); |
| | |
| | | return mods; |
| | | } |
| | | |
| | | private AttributeType getAttributeType(String attrName) |
| | | { |
| | | return DirectoryServer.getSchema().getAttributeType(attrName); |
| | | } |
| | | |
| | | private LocalBackendAddOperation addOperation(Entry entry) |
| | | { |
| | | AddOperationBasis addOpBasis = new AddOperationBasis(getRootConnection(), 1, 1, null, |
| | | entry.getName(), entry.getObjectClasses(), entry.getUserAttributes(), entry.getOperationalAttributes()); |
| | | return new LocalBackendAddOperation(addOpBasis); |
| | | } |
| | | |
| | | private LocalBackendModifyOperation modifyOperation(Entry entry, CSN t, List<Modification> mods) |
| | | { |
| | | ModifyOperationBasis modOpBasis = new ModifyOperationBasis(getRootConnection(), 1, 1, |
| | | null, entry.getName(), mods); |
| | | LocalBackendModifyOperation modOp = new LocalBackendModifyOperation(modOpBasis); |
| | | modOp.setAttachment(SYNCHROCONTEXT, new ModifyContext(t, "uniqueId")); |
| | | return modOp; |
| | | } |
| | | |
| | | private Modification newModification(ModificationType modType, String attrName, String... values) |
| | | { |
| | | return new Modification(modType, Attributes.create(attrName, values)); |
| | |
| | | |
| | | private void testHistorical(LocalBackendAddOperation addOp) |
| | | { |
| | | AttributeType entryuuidAttrType = |
| | | DirectoryServer.getSchema().getAttributeType( |
| | | EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME); |
| | | |
| | | // Get the historical uuid associated to the entry |
| | | // (the one that needs to be tested) |
| | | String uuid = EntryHistorical.getEntryUUID(addOp); |
| | | |
| | | // Get the op uuid in String format |
| | | AttributeType entryuuidAttrType = getAttributeType(ENTRYUUID_ATTRIBUTE_NAME); |
| | | List<Attribute> uuidAttrs = addOp.getOperationalAttributes().get(entryuuidAttrType); |
| | | String retrievedUuid = uuidAttrs.get(0).iterator().next().toString(); |
| | | assertEquals(retrievedUuid, uuid); |
| | |
| | | public void addDeleteSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | assertNull(attrs); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Test that a single replicated modify operation, that contains a |
| | | * modify-add of a value followed by modify-delete of the attribute |
| | |
| | | public void addDeleteAttrSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | public void replayAddDeleteSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000002000000000000:attrDel"); |
| | | |
| | |
| | | public void replayDelAddDifferent() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create description with values value1 and value2 and add |
| | | // this attribute to the entry. |
| | | Attribute attr = Attributes.create(DESCRIPTION, "value1", "value2"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(attr, duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attr; |
| | | // simulate a delete of same value in the same operation done at time t1 |
| | | testModify(entry, hist, 1, true, newModification(DELETE, DESCRIPTION, "value1")); |
| | | attr = buildSyncHist(DESCRIPTION, |
| | |
| | | public void replayDelAddSame() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // Create description with values value1 and value2 and add |
| | | // this attribute to the entry. |
| | | Attribute attr = Attributes.create(DESCRIPTION, "value1", "value2", "value3"); |
| | | |
| | | List<ByteString> duplicateValues = new LinkedList<>(); |
| | | entry.addAttribute(attr, duplicateValues); |
| | | |
| | | // load historical from the entry |
| | | addAttribute(entry, Attributes.create(DESCRIPTION, "value1", "value2", "value3")); |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attr; |
| | | // simulate a delete of a value in the same operation done at time t1 |
| | | testModify(entry, hist, 1, true, newModification(DELETE, DESCRIPTION, "value1")); |
| | | attr = buildSyncHist(DESCRIPTION, |
| | |
| | | public void replayAddDeleteAttrSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000001000000000000:attrDel"); |
| | | |
| | |
| | | assertNull(attrs); |
| | | } |
| | | |
| | | |
| | | /** |
| | | /** |
| | | * Test that a single replicated modify operation, that contains a |
| | | * modify-replace of a value followed by modify-delete of that value |
| | | * is handled properly. |
| | |
| | | public void replaceDeleteSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | assertNull(attrs); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Test that a single replicated modify operation, that contains a |
| | | * modify-replace of a value followed by modify-delete of the attribute |
| | |
| | | public void replaceDeleteAttrSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | public void replayReplaceDeleteSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute repl = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000002000000000000:repl:aValue"); |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | |
| | | public void replayReplaceDeleteAttrSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | Attribute repl = buildSyncHist(DISPLAYNAME, |
| | | ":0000000000000001000000000000:repl:aValue"); |
| | | Attribute attrDel = buildSyncHist(DISPLAYNAME, |
| | |
| | | assertNull(attrs); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Test that a single replicated modify operation, that contains a |
| | | * modify-replace of a value followed by modify-delete of that value, |
| | |
| | | public void replaceDeleteAddSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | public void replaceDeleteAttrAddSameOpSingle() throws Exception |
| | | { |
| | | Entry entry = initializeEntry(); |
| | | |
| | | // load historical from the entry |
| | | EntryHistorical hist = EntryHistorical.newInstanceFromEntry(entry); |
| | | |
| | | /* |
| | |
| | | |
| | | assertContainsOnlyValues(entry, DISPLAYNAME, "NewValue"); |
| | | } |
| | | |
| | | } |