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

Jean-Noel Rouvignac
19.10.2015 77d37889d8e3b08055a7639db5b3c01465ab2750
OPENDJ-1192 Modify request replay failures

Added unit tests for AttrHistoricalSingleT and AttrHistoricalMultiple.
Renamed AttrInfoTest to AttrHistoricalMultipleTest.
1 files deleted
2 files added
884 ■■■■ changed files
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/AttrHistoricalMultipleTest.java 436 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/AttrHistoricalSingleTest.java 327 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/AttrInfoTest.java 121 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/AttrHistoricalMultipleTest.java
New file
@@ -0,0 +1,436 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2013-2015 ForgeRock AS.
 */
package org.opends.server.replication.plugin;
import static org.assertj.core.api.Assertions.*;
import static org.forgerock.opendj.ldap.ModificationType.*;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ModificationType;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.util.TimeThread;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/** Test AttrHistoricalMultiple. */
@SuppressWarnings("javadoc")
public class AttrHistoricalMultipleTest extends ReplicationTestCase
{
  private static enum E
  {
    CONFLICT(true), CONFLICT_BUT_SHOULD_NOT_BE(true), NO_CONFLICT(false);
    private final boolean expectedConflictStatus;
    private E(boolean expectedResultForReplay)
    {
      this.expectedConflictStatus = expectedResultForReplay;
    }
    private boolean getExpectedResult()
    {
      return this.expectedConflictStatus;
    }
  }
  private CSNGenerator csnGen = new CSNGenerator(1025, System.currentTimeMillis());
  private AttrHistoricalMultiple attrHist;
  private CSN csn;
  private Entry entry;
  /** Avoids declaring the variable in the tests. */
  private Modification mod;
  @BeforeMethod
  public void localSetUp() throws Exception
  {
    attrHist = new AttrHistoricalMultiple();
    csn = csnGen.newCSN();
    entry = new Entry(null, null, null, null);
  }
  @AfterMethod
  public void localTearDown() throws Exception
  {
    attrHist = null;
    csn = null;
  }
  /** Build some data for the AttrInfo test below. */
  @DataProvider(name = "attrInfo")
  public Object[][] createData()
  {
    ByteString att1 = ByteString.valueOf("string");
    ByteString att2 = ByteString.valueOf("value");
    ByteString att3 = ByteString.valueOf("again");
    CSN del1 = new CSN(1,  0,  1);
    CSN del2 = new CSN(1,  1,  1);
    CSN del3 = new CSN(1,  0,  2);
    CSN upd1 = new CSN(TimeThread.getTime(), 123, 45);
    CSN upd2 = new CSN(TimeThread.getTime() + 1000, 123,  45);
    CSN upd3 = new CSN(TimeThread.getTime(), 321, 54);
    return new Object[][]
    {
    { att1, del1, upd1 },
    { att2, del2, upd2 },
    { att3, del3, upd3 },
    { att3, upd3, upd3 } };
  }
  /** Create a AttrInfo and check the methods. */
  @Test(dataProvider = "attrInfo")
  public void attrInfo(ByteString att, CSN deleteTime, CSN updateTime) throws Exception
  {
    // Create an empty AttrInfo
    AttrHistoricalMultiple attrInfo1 = new AttrHistoricalMultiple();
    // Check
    attrInfo1.add(att, updateTime);
    Set<AttrValueHistorical> values1 = attrInfo1.getValuesHistorical();
    assertEquals(values1.size(), 1);
    AttrValueHistorical valueInfo1 = new AttrValueHistorical(att, updateTime, null);
    assertTrue(values1.contains(valueInfo1));
    // Check constructor with parameter
    AttrValueHistorical valueInfo2 = new AttrValueHistorical(att, updateTime, deleteTime);
    AttrHistoricalMultiple attrInfo2 = new AttrHistoricalMultiple(
        deleteTime, updateTime, Collections.singletonMap(valueInfo2, valueInfo2));
    // Check equality
    //assertTrue(attrInfo1.getDeleteTime().compareTo(attrInfo2.getDeleteTime())==0);
    //  Check constructor with time parameter and not Value
    AttrHistoricalMultiple attrInfo3 = new AttrHistoricalMultiple(deleteTime, updateTime, null);
    attrInfo3.add(att, updateTime);
    Set<AttrValueHistorical> values3 = attrInfo3.getValuesHistorical();
    assertEquals(values3.size(), 1);
    valueInfo1 = new AttrValueHistorical(att, updateTime, null);
    assertTrue(values3.contains(valueInfo1));
    // Check duplicate
    AttrHistoricalMultiple attrInfo4 = attrInfo3.duplicate();
    Set<AttrValueHistorical> values4 = attrInfo4.getValuesHistorical();
    assertEquals(attrInfo4.getDeleteTime().compareTo(attrInfo3.getDeleteTime()), 0);
    assertEquals(values4.size(), values3.size());
    // Check
    attrInfo4.delete(att, updateTime);
    assertEquals(attrInfo4.getValuesHistorical().size(), 1);
    // Check
    AttributeType type = DirectoryServer.getAttributeType("description");
    attrInfo3.delete(Attributes.create(type, att), updateTime) ;
    assertEquals(attrInfo3.getValuesHistorical().size(), 1);
    // Check
    attrInfo2.delete(updateTime);
    assertEquals(attrInfo2.getValuesHistorical().size(), 0);
  }
  @Test
  public void replay_addDeleteSameTime() throws Exception
  {
    mod = newModification(ADD, "X");
    replayOperation(csn, entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(DELETE, "X");
    replayOperation(csn, entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addThenAddThenOlderDelete() throws Exception
  {
    CSN[] t = newCSNs(3);
    mod = newModification(ADD, "X");
    replayOperation(t[0], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(ADD, "Y");
    replayOperation(t[2], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(DELETE, "Y");
    replayOperationSuppressMod(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addThenDeleteNoValueThenOlderAdd() throws Exception
  {
    CSN[] t = newCSNs(3);
    replay_addDeleteNoValue(t[0], t[2]);
    mod = newModification(ADD, "Y");
    replayOperationSuppressMod(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addThenDeleteWithValueThenOlderAdd() throws Exception
  {
    CSN[] t = newCSNs(3);
    mod = newModification(ADD, "X");
    replayOperation(t[0], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(DELETE, "X");
    replayOperation(t[2], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(ADD, "X");
    replayOperationSuppressMod(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addThenAdd() throws Exception
  {
    CSN[] t = newCSNs(2);
    mod = newModification(ADD, "X");
    replayOperation(t[0], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(ADD, "X");
    replayOperationSuppressMod(t[1], entry, mod, E.CONFLICT);
  }
  @Test
  public void replay_addThenDeleteThenAdd() throws Exception
  {
    CSN[] t = newCSNs(3);
    mod = newModification(ADD, "X");
    replayOperation(t[0], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(DELETE, "X");
    replayOperation(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(ADD, "X");
    replayOperation(t[1], entry, mod, E.CONFLICT);
  }
  @Test
  public void replay_deleteNoPreviousHistory() throws Exception
  {
    mod = newModification(DELETE, "Y");
    replayOperationSuppressMod(csn, entry, mod, E.CONFLICT);
  }
  @Test
  public void replay_addThenDelete() throws Exception
  {
    CSN[] t = newCSNs(2);
    mod = newModification(ADD, "X");
    replayOperation(t[0], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(DELETE, "X");
    replayOperation(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addThenDeleteThenOlderDelete() throws Exception
  {
    CSN[] t = newCSNs(3);
    replay_addDeleteNoValue(t[0], t[2]);
    mod = newModification(DELETE, "X");
    replayOperationSuppressMod(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addDeleteNoValueSameTimeNotConflict() throws Exception
  {
    replay_addDeleteNoValue(csn, csn);
  }
  @Test
  public void replay_addThenDeleteNoValue() throws Exception
  {
    CSN[] t = newCSNs(2);
    replay_addDeleteNoValue(t[0], t[1]);
  }
  private void replay_addDeleteNoValue(CSN tAdd, CSN tDel) throws Exception
  {
    mod = newModification(ADD, "X");
    replayOperation(tAdd, entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(DELETE);
    replayOperation(tDel, entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_replace() throws Exception
  {
    mod = newModification(REPLACE, "X");
    replayOperation(csn, entry, mod, E.NO_CONFLICT);
  }
  @Test
  public void replay_addThenOlderReplace() throws Exception
  {
    CSN[] t = newCSNs(2);
    mod = newModification(ADD, "X");
    replayOperation(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
    mod = newModification(REPLACE, "Y");
    replayOperation(t[0], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  @Test
  public void replay_addThenDeleteThenOlderReplace() throws Exception
  {
    CSN[] t = newCSNs(3);
    replay_addDeleteNoValue(t[0], t[2]);
    mod = newModification(REPLACE, "Y");
    replayOperationSuppressMod(t[1], entry, mod, E.CONFLICT_BUT_SHOULD_NOT_BE);
  }
  private CSN[] newCSNs(int nb)
  {
    CSN[] results = new CSN[nb];
    for (int i = 0; i < nb; i++)
    {
      results[i] = csnGen.newCSN();
    }
    return results;
  }
  private Modification newModification(ModificationType modType, String attrValue)
  {
    return new Modification(modType, Attributes.create("description", attrValue));
  }
  private Modification newModification(ModificationType modType)
  {
    return new Modification(modType, Attributes.empty("display"));
  }
  private void replayOperationSuppressMod(CSN csn, Entry entry, Modification mod, E conflictStatus)
      throws Exception
  {
    Iterator<Modification> itMod = mock(Iterator.class);
    replayOperation(itMod, csn, entry, mod, conflictStatus);
    verifyModNotReplayed(itMod);
  }
  private void replayOperation(CSN csn, Entry entry, Modification mod, E conflictStatus) throws Exception
  {
    replayOperation(null, csn, entry, mod, conflictStatus);
  }
  private void replayOperation(Iterator<Modification> modsIterator, CSN csn, Entry entry, Modification mod,
      E conflictStatus) throws Exception
  {
    boolean result = attrHist.replayOperation(modsIterator, csn, entry, mod);
    assertEquals(result, conflictStatus.getExpectedResult(),
        "Expected " + (conflictStatus == E.CONFLICT ? "a" : "no") + " conflict when applying " + mod + " to " + entry);
    if (entry != null && conflictStatus != E.CONFLICT)
    {
      entry.applyModification(mod);
      assertAttributeValues(entry, mod);
    }
  }
  private void assertAttributeValues(Entry entry, Modification mod)
  {
    List<ByteString> actualValues = getValues(entry, mod);
    List<ByteString> expectedValues = getValues(mod.getAttribute());
    switch (mod.getModificationType().asEnum())
    {
    case ADD:
      assertThat(actualValues).containsAll(expectedValues);
      return;
    case REPLACE:
      assertThat(actualValues).isEqualTo(expectedValues);
      return;
    case DELETE:
      if (expectedValues.isEmpty())
      {
        assertThat(actualValues).isEmpty();
      }
      else
      {
        assertThat(actualValues).doesNotContainAnyElementsOf(expectedValues);
      }
      return;
    case INCREMENT:
      return;
    }
  }
  private List<ByteString> getValues(Entry entry, Modification mod)
  {
    List<Attribute> attributes = entry.getAttribute(mod.getAttribute().getAttributeType());
    if (attributes != null)
    {
      assertThat(attributes).hasSize(1);
      return getValues(attributes.get(0));
    }
    return Collections.emptyList();
  }
  private List<ByteString> getValues(Attribute attribute)
  {
    List<ByteString> results = new ArrayList<>();
    for (ByteString value : attribute)
    {
      results.add(value);
    }
    return results;
  }
  private void verifyModNotReplayed(Iterator<Modification> it)
  {
    verify(it, times(1)).remove();
    verify(it, only()).remove();
  }
}
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/AttrHistoricalSingleTest.java
New file
@@ -0,0 +1,327 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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
 *
 *      Copyright 2015 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import static org.assertj.core.api.Assertions.*;
import static org.forgerock.opendj.ldap.ModificationType.*;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;
import java.util.Iterator;
import java.util.List;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ModificationType;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.common.CSNGenerator;
import org.opends.server.types.Attribute;
import org.opends.server.types.Attributes;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@SuppressWarnings("javadoc")
public class AttrHistoricalSingleTest extends ReplicationTestCase
{
  private static final boolean CONFLICT = true;
  private static final boolean NO_CONFLICT = false;
  private CSNGenerator csnGen = new CSNGenerator(1025, System.currentTimeMillis());
  private AttrHistoricalSingle attrHist;
  private CSN csn;
  private Entry entry;
  /** Avoids declaring the variable in the tests */
  private Modification mod;
  @BeforeMethod
  public void localSetUp() throws Exception
  {
    attrHist = new AttrHistoricalSingle();
    csn = csnGen.newCSN();
    entry = new Entry(null, null, null, null);
  }
  @AfterMethod
  public void localTearDown() throws Exception
  {
    attrHist = null;
    csn = null;
  }
  @Test
  public void replay_addDeleteSameTime() throws Exception
  {
    mod = newModification(ADD, "X");
    replayOperationSuccess(csn, entry, mod, NO_CONFLICT);
    mod = newModification(DELETE, "X");
    replayOperationSuccess(csn, entry, mod, NO_CONFLICT);
  }
  @Test
  public void replay_addThenDeleteThenOlderAdd() throws Exception
  {
    CSN[] t = newCSNs(3);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[0], entry, mod, NO_CONFLICT);
    mod = newModification(DELETE, "X");
    replayOperationSuccess(t[2], entry, mod, NO_CONFLICT);
    mod = newModification(ADD, "X");
    replayOperationFailure(t[1], entry, mod, CONFLICT);
  }
  @Test
  public void replay_addThenDeleteThenAddThenOlderAdd() throws Exception
  {
    CSN[] t = newCSNs(4);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[0], entry, mod, NO_CONFLICT);
    mod = newModification(DELETE, "X");
    replayOperationSuccess(t[1], entry, mod, NO_CONFLICT);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[3], entry, mod, NO_CONFLICT);
    mod = newModification(ADD, "Y");
    replayOperationSuccess(t[2], entry, mod, CONFLICT);
  }
  @Test
  public void replay_addThenDeleteThenDelete() throws Exception
  {
    CSN[] t = newCSNs(3);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[0], entry, mod, NO_CONFLICT);
    mod = newModification(DELETE, "X");
    replayOperationSuccess(t[1], entry, mod, NO_CONFLICT);
    mod = newModification(DELETE, "X");
    replayOperationFailure(t[2], entry, mod, CONFLICT);
  }
  @Test
  public void replay_addThenOlderDelete() throws Exception
  {
    CSN[] t = newCSNs(2);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[1], null, mod, NO_CONFLICT);
    mod = newModification(DELETE, "X");
    replayOperationFailure(t[0], entry, mod, CONFLICT);
  }
  @Test
  public void replay_deleteMissingAttribute() throws Exception
  {
    mod = newModification(DELETE, "X");
    replayOperationFailure(csn, entry, mod, CONFLICT);
  }
  @Test
  public void replay_deleteMissingAttributeValue() throws Exception
  {
    CSN[] t = newCSNs(2);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[0], entry, mod, NO_CONFLICT);
    Iterator<Modification> it = mock(Iterator.class);
    mod = newModification(DELETE, "Y");
    replayOperationFailure(t[1], entry, mod, CONFLICT);
    verifyModNotReplayed(it);
  }
  /**
   * TODO JNR this looks dubious, is it ever possible in the server?
   * <p>
   * Could multi-threading make this scenario possible?
   * <p>
   * Or is it due to {@link AttrHistoricalSingle#assign(HistAttrModificationKey, ByteString, CSN)} ?
   */
  @Test
  public void replay_deleteValueThatDoesNotExistOnEntry() throws Exception
  {
    CSN[] t = newCSNs(2);
    mod = newModification(ADD, "X");
    entry.applyModification(mod);
    mod = newModification(DELETE, "Y");
    replayOperationFailure(t[1], entry, mod, CONFLICT);
  }
  /**
   * TODO JNR this looks dubious, is it ever possible in the server?
   * <p>
   * Could multi-threading make this scenario possible?
   * <p>
   * Or is it due to {@link AttrHistoricalSingle#assign(HistAttrModificationKey, ByteString, CSN)} ?
   */
  @Test
  public void replay_deleteDubious() throws Exception
  {
    HistoricalAttributeValue histAttrVal = new HistoricalAttributeValue("display:" + csn + ":add:X");
    attrHist.assign(histAttrVal.getHistKey(), histAttrVal.getAttributeValue(), csn);
    mod = newModification(ADD, "X");
    entry.applyModification(mod);
    mod = newModification(DELETE, "Y");
    replayOperationFailure(csn, entry, mod, CONFLICT);
  }
  @Test
  public void replay_replaceWithValue() throws Exception
  {
    mod = newModification(REPLACE, "X");
    replayOperationSuccess(csn, null, mod, NO_CONFLICT);
  }
  @Test
  public void replay_replaceNoValue() throws Exception
  {
    mod = newModification(REPLACE);
    replayOperationSuccess(csn, null, mod, NO_CONFLICT);
  }
  @Test
  public void replay_addThenDeleteThenOlderReplace() throws Exception
  {
    CSN[] t = newCSNs(3);
    mod = newModification(ADD, "X");
    replayOperationSuccess(t[0], entry, mod, NO_CONFLICT);
    mod = newModification(DELETE);
    replayOperationSuccess(t[2], entry, mod, NO_CONFLICT);
    mod = newModification(REPLACE);
    replayOperationFailure(t[1], entry, mod, CONFLICT);
  }
  @Test
  public void replay_increment() throws Exception
  {
    mod = newModification(INCREMENT, "X");
    replayOperationSuccess(csn, null, mod, NO_CONFLICT);
  }
  private CSN[] newCSNs(int nb)
  {
    CSN[] results = new CSN[nb];
    for (int i = 0; i < nb; i++)
    {
      results[i] = csnGen.newCSN();
    }
    return results;
  }
  private Modification newModification(ModificationType modType, String attrValue)
  {
    return new Modification(modType, Attributes.create("display", attrValue));
  }
  private Modification newModification(ModificationType modType)
  {
    return new Modification(modType, Attributes.empty("display"));
  }
  private void replayOperationSuccess(CSN csn, Entry entry, Modification mod, boolean shouldConflict) throws Exception
  {
    replayOperation(null, csn, entry, mod, shouldConflict);
  }
  private void replayOperationFailure(CSN csn, Entry entry, Modification mod, boolean shouldConflict) throws Exception
  {
    Iterator<Modification> itMod = mock(Iterator.class);
    replayOperation(itMod, csn, entry, mod, shouldConflict);
    verifyModNotReplayed(itMod);
  }
  private void replayOperation(Iterator<Modification> modsIterator, CSN csn, Entry entry, Modification mod,
      boolean shouldConflict) throws Exception
  {
    boolean result = attrHist.replayOperation(modsIterator, csn, entry, mod);
    assertEquals(result, shouldConflict,
        "Expected " + (shouldConflict ? "a" : "no") + " conflict when applying " + mod + " to " + entry);
    if (entry != null && !shouldConflict)
    {
      entry.applyModification(mod);
      assertAttributeValue(entry, mod);
    }
  }
  private void assertAttributeValue(Entry entry, Modification mod)
  {
    ByteString actualValue = getActualValue(entry, mod);
    switch (mod.getModificationType().asEnum())
    {
    case ADD:
    case REPLACE:
      ByteString expectedValue = uniqueValue(mod.getAttribute());
      assertEquals(actualValue, expectedValue);
      return;
    case DELETE:
      assertNull(actualValue);
      return;
    }
  }
  private ByteString getActualValue(Entry entry, Modification mod)
  {
    List<Attribute> attributes = entry.getAttribute(mod.getAttribute().getAttributeType());
    if (attributes != null)
    {
      assertThat(attributes).hasSize(1);
      return uniqueValue(attributes.get(0));
    }
    return null;
  }
  private ByteString uniqueValue(Attribute attribute)
  {
    assertThat(attribute).hasSize(1);
    ByteString attrValue = attribute.iterator().next();
    return attrValue;
  }
  private void verifyModNotReplayed(Iterator<Modification> it)
  {
    verify(it, times(1)).remove();
    verify(it, only()).remove();
  }
}
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/AttrInfoTest.java
File was deleted