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

neil_a_wilson
13.58.2006 a1c112904474d02711e22f3be1e208ba1543a0ac
Add additional test cases for add, delete, and modify operations.
14 files modified
986 ■■■■■ changed files
opends/src/server/org/opends/server/core/AbandonOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/AddOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/BindOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/CompareOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DeleteOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/ExtendedOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/ModifyDNOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/ModifyOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/Operation.java 16 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SearchOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/UnbindOperation.java 15 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java 358 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java 122 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java 340 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/AbandonOperation.java
@@ -417,6 +417,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    // Abandon operations cannot be canceled.
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/AddOperation.java
@@ -2466,6 +2466,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/BindOperation.java
@@ -2299,6 +2299,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    // Bind operations cannot be canceled.
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/CompareOperation.java
@@ -1153,6 +1153,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/DeleteOperation.java
@@ -1318,6 +1318,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/ExtendedOperation.java
@@ -771,6 +771,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -2116,6 +2116,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -2808,6 +2808,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/Operation.java
@@ -928,6 +928,22 @@
  /**
   * Sets the cancel request for this operation, if applicable.  This should
   * only be used for testing purposes (e.g., for ensuring a cancel request is
   * submitted before processing begins on an operation, or to allow for
   * cancelling an internal operation).
   *
   * @param  cancelRequest  The cancel request to set for this operation.
   *
   * @return  <CODE>true</CODE> if the cancel request was set, or
   *          <CODE>false</CODE> if it was not for some reason (e.g., the
   *          specified operation cannot be cancelled).
   */
  abstract boolean setCancelRequest(CancelRequest cancelRequest);
  /**
   * Retrieves the cancel request that has been issued for this operation, if
   * there is one.  This method should not be called by post-operation or
   * post-response plugins.
opends/src/server/org/opends/server/core/SearchOperation.java
@@ -2179,6 +2179,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/src/server/org/opends/server/core/UnbindOperation.java
@@ -306,6 +306,21 @@
   * {@inheritDoc}
   */
  @Override()
  boolean setCancelRequest(CancelRequest cancelRequest)
  {
    assert debugEnter(CLASS_NAME, "setCancelRequest",
                      String.valueOf(cancelRequest));
    // Unbind operations cannot be canceled.
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
@@ -31,13 +31,16 @@
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.Backend;
import org.opends.server.plugins.DisconnectClientPlugin;
import org.opends.server.plugins.UpdatePreOpPlugin;
import org.opends.server.protocols.asn1.ASN1Element;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Sequence;
@@ -53,15 +56,18 @@
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LockManager;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.ResultCode;
import org.opends.server.types.WritabilityMode;
import static org.testng.Assert.*;
import static org.opends.server.protocols.ldap.LDAPConstants.*;
import static org.opends.server.util.ServerConstants.*;
@@ -1885,5 +1891,357 @@
    assertEquals(changeListener.getAddCount(), 0);
    DirectoryServer.deregisterChangeNotificationListener(changeListener);
  }
  /**
   * Tests an add operation that gets canceled before startup.
   *
   * @throws  Exception  If an unexpected probem occurs.
   */
  @Test()
  public void testCancelBeforeStartup()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry entry = TestCaseUtils.makeEntry(
         "dn: ou=People,o=test",
         "objectClass: top",
         "objectClass: organizationalUnit",
         "ou: People");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    AddOperation addOperation =
         new AddOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                          null, entry.getDN(), entry.getObjectClasses(),
                          entry.getUserAttributes(),
                          entry.getOperationalAttributes());
    CancelRequest cancelRequest = new CancelRequest(false,
                                                    "testCancelBeforeStartup");
    addOperation.setCancelRequest(cancelRequest);
    addOperation.run();
    assertEquals(addOperation.getResultCode(), ResultCode.CANCELED);
  }
  /**
   * Tests an add operation in which the server cannot obtain a lock on the
   * target entry because there is already a read lock held on it.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups = { "slow" })
  public void testCannotLockEntry()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Lock entryLock = LockManager.lockRead(DN.decode("ou=People,o=test"));
    try
    {
      Entry entry = TestCaseUtils.makeEntry(
           "dn: ou=People,o=test",
           "objectClass: top",
           "objectClass: organizationalUnit",
           "ou: People");
      InternalClientConnection conn =
           InternalClientConnection.getRootConnection();
      AddOperation addOperation =
           conn.processAdd(entry.getDN(), entry.getObjectClasses(),
                           entry.getUserAttributes(),
                           entry.getOperationalAttributes());
      assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
    }
    finally
    {
      LockManager.unlock(DN.decode("ou=People,o=test"), entryLock);
    }
  }
  /**
   * Tests an add operation that should be disconnected in a pre-parse plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPreParseAdd()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<LDAPAttribute> attrs = new ArrayList<LDAPAttribute>();
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("top"));
    values.add(new ASN1OctetString("organizationalUnit"));
    attrs.add(new LDAPAttribute("objectClass", values));
    values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("People"));
    attrs.add(new LDAPAttribute("ou", values));
    AddRequestProtocolOp addRequest =
         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
                                  attrs);
    message = new LDAPMessage(2, addRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
    w.writeElement(message.encode());
    ASN1Element element = r.readElement();
    if (element != null)
    {
      // If we got an element back, then it must be a notice of disconnect
      // unsolicited notification.
      message = LDAPMessage.decode(element.decodeAsSequence());
      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests an add operation that should be disconnected in a pre-operation
   * plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPreOperationAdd()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<LDAPAttribute> attrs = new ArrayList<LDAPAttribute>();
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("top"));
    values.add(new ASN1OctetString("organizationalUnit"));
    attrs.add(new LDAPAttribute("objectClass", values));
    values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("People"));
    attrs.add(new LDAPAttribute("ou", values));
    AddRequestProtocolOp addRequest =
         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
                                  attrs);
    message = new LDAPMessage(2, addRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList(
              "PreOperation"));
    w.writeElement(message.encode());
    ASN1Element element = r.readElement();
    if (element != null)
    {
      // If we got an element back, then it must be a notice of disconnect
      // unsolicited notification.
      message = LDAPMessage.decode(element.decodeAsSequence());
      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests an add operation that should be disconnected in a post-operation
   * plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPostOperationAdd()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<LDAPAttribute> attrs = new ArrayList<LDAPAttribute>();
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("top"));
    values.add(new ASN1OctetString("organizationalUnit"));
    attrs.add(new LDAPAttribute("objectClass", values));
    values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("People"));
    attrs.add(new LDAPAttribute("ou", values));
    AddRequestProtocolOp addRequest =
         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
                                  attrs);
    message = new LDAPMessage(2, addRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList(
              "PostOperation"));
    w.writeElement(message.encode());
    ASN1Element element = r.readElement();
    if (element != null)
    {
      // If we got an element back, then it must be a notice of disconnect
      // unsolicited notification.
      message = LDAPMessage.decode(element.decodeAsSequence());
      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests an add operation that should be disconnected in a post-response
   * plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPostResponseAdd()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<LDAPAttribute> attrs = new ArrayList<LDAPAttribute>();
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("top"));
    values.add(new ASN1OctetString("organizationalUnit"));
    attrs.add(new LDAPAttribute("objectClass", values));
    values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("People"));
    attrs.add(new LDAPAttribute("ou", values));
    AddRequestProtocolOp addRequest =
         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
                                  attrs);
    message = new LDAPMessage(2, addRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList(
              "PostResponse"));
    w.writeElement(message.encode());
responseLoop:
    while (true)
    {
      ASN1Element element = r.readElement();
      if (element == null)
      {
        // The connection has been closed.
        break responseLoop;
      }
      message = LDAPMessage.decode(element.decodeAsSequence());
      switch (message.getProtocolOpType())
      {
        case OP_TYPE_ADD_RESPONSE:
          // This was expected.  The disconnect didn't happen until after the
          // response was sent.
          break;
        case OP_TYPE_EXTENDED_RESPONSE:
          // The server is notifying us that it will be closing the connection.
          break responseLoop;
        default:
          // This is a problem.  It's an unexpected response.
          try
          {
            s.close();
          } catch (Exception e) {}
          throw new Exception("Unexpected response message " + message +
                              " encountered in " +
                              "testDisconnectInPostResponseAdd");
      }
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
@@ -30,6 +30,7 @@
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -50,9 +51,11 @@
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.tools.LDAPDelete;
import org.opends.server.types.ByteString;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LockManager;
import org.opends.server.types.ResultCode;
import org.opends.server.types.WritabilityMode;
@@ -767,6 +770,64 @@
  /**
   * Tests a delete operation that gets canceled before startup.
   *
   * @throws  Exception  If an unexpected probem occurs.
   */
  @Test()
  public void testCancelBeforeStartup()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation deleteOperation =
         new DeleteOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                             null, new ASN1OctetString("o=test"));
    CancelRequest cancelRequest = new CancelRequest(false,
                                                    "testCancelBeforeStartup");
    deleteOperation.setCancelRequest(cancelRequest);
    deleteOperation.run();
    assertEquals(deleteOperation.getResultCode(), ResultCode.CANCELED);
  }
  /**
   * Tests a delete operation in which the server cannot obtain a lock on the
   * target entry because there is already a read lock held on it.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups = { "slow" })
  public void testCannotLockEntry()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Lock entryLock = LockManager.lockRead(DN.decode("o=test"));
    try
    {
      InternalClientConnection conn =
           InternalClientConnection.getRootConnection();
      DeleteOperation deleteOperation =
           conn.processDelete(new ASN1OctetString("o=test"));
      assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
    }
    finally
    {
      LockManager.unlock(DN.decode("o=test"), entryLock);
    }
  }
  /**
   * Tests a delete operation that should be disconnected in a pre-parse plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
@@ -997,5 +1058,66 @@
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests to ensure that any registered notification listeners are invoked for
   * a successful delete operation.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSuccessWithNotificationListener()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestChangeNotificationListener changeListener =
         new TestChangeNotificationListener();
    DirectoryServer.registerChangeNotificationListener(changeListener);
    assertEquals(changeListener.getAddCount(), 0);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation deleteOperation =
         conn.processDelete(new ASN1OctetString("o=test"));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    retrieveCompletedOperationElements(deleteOperation);
    assertEquals(changeListener.getDeleteCount(), 1);
    DirectoryServer.deregisterChangeNotificationListener(changeListener);
  }
  /**
   * Tests to ensure that any registered notification listeners are not invoked
   * for a failed delete operation.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testFailureWithNotificationListener()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestChangeNotificationListener changeListener =
         new TestChangeNotificationListener();
    DirectoryServer.registerChangeNotificationListener(changeListener);
    assertEquals(changeListener.getAddCount(), 0);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation deleteOperation =
         conn.processDelete(new ASN1OctetString("cn=nonexistent,o=test"));
    assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
    assertEquals(changeListener.getDeleteCount(), 0);
    DirectoryServer.deregisterChangeNotificationListener(changeListener);
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
@@ -31,13 +31,16 @@
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.Backend;
import org.opends.server.plugins.DisconnectClientPlugin;
import org.opends.server.plugins.UpdatePreOpPlugin;
import org.opends.server.protocols.asn1.ASN1Element;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Sequence;
@@ -54,9 +57,11 @@
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LockManager;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ObjectClass;
@@ -65,6 +70,7 @@
import static org.testng.Assert.*;
import static org.opends.server.protocols.ldap.LDAPConstants.*;
import static org.opends.server.util.ServerConstants.*;
@@ -3643,5 +3649,339 @@
    assertEquals(changeListener.getModifyCount(), 0);
    DirectoryServer.deregisterChangeNotificationListener(changeListener);
  }
  /**
   * Tests a modify operation that gets canceled before startup.
   *
   * @throws  Exception  If an unexpected probem occurs.
   */
  @Test()
  public void testCancelBeforeStartup()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("foo"));
    LDAPAttribute attr = new LDAPAttribute("description", values);
    ArrayList<LDAPModification> mods = new ArrayList<LDAPModification>();
    mods.add(new LDAPModification(ModificationType.REPLACE, attr));
    ModifyOperation modifyOperation =
         new ModifyOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                             null, new ASN1OctetString("o=test"), mods);
    CancelRequest cancelRequest = new CancelRequest(false,
                                                    "testCancelBeforeStartup");
    modifyOperation.setCancelRequest(cancelRequest);
    modifyOperation.run();
    assertEquals(modifyOperation.getResultCode(), ResultCode.CANCELED);
  }
  /**
   * Tests a modify operation in which the server cannot obtain a lock on the
   * target entry because there is already a read lock held on it.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups = { "slow" })
  public void testCannotLockEntry()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Lock entryLock = LockManager.lockRead(DN.decode("o=test"));
    try
    {
      InternalClientConnection conn =
           InternalClientConnection.getRootConnection();
      ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
      values.add(new ASN1OctetString("foo"));
      LDAPAttribute attr = new LDAPAttribute("description", values);
      ArrayList<LDAPModification> mods = new ArrayList<LDAPModification>();
      mods.add(new LDAPModification(ModificationType.REPLACE, attr));
      ModifyOperation modifyOperation =
           conn.processModify(new ASN1OctetString("o=test"), mods);
      assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
    }
    finally
    {
      LockManager.unlock(DN.decode("o=test"), entryLock);
    }
  }
  /**
   * Tests a modify operation that should be disconnected in a pre-parse plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPreParseModify()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("foo"));
    LDAPAttribute attr = new LDAPAttribute("description", values);
    ArrayList<LDAPModification> mods = new ArrayList<LDAPModification>();
    mods.add(new LDAPModification(ModificationType.REPLACE, attr));
    ModifyRequestProtocolOp modifyRequest =
         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
    message = new LDAPMessage(2, modifyRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
    w.writeElement(message.encode());
    ASN1Element element = r.readElement();
    if (element != null)
    {
      // If we got an element back, then it must be a notice of disconnect
      // unsolicited notification.
      message = LDAPMessage.decode(element.decodeAsSequence());
      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests a modify operation that should be disconnected in a pre-operation
   * plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPreOperationModify()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("foo"));
    LDAPAttribute attr = new LDAPAttribute("description", values);
    ArrayList<LDAPModification> mods = new ArrayList<LDAPModification>();
    mods.add(new LDAPModification(ModificationType.REPLACE, attr));
    ModifyRequestProtocolOp modifyRequest =
         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
    message = new LDAPMessage(2, modifyRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList(
              "PreOperation"));
    w.writeElement(message.encode());
    ASN1Element element = r.readElement();
    if (element != null)
    {
      // If we got an element back, then it must be a notice of disconnect
      // unsolicited notification.
      message = LDAPMessage.decode(element.decodeAsSequence());
      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests a modify operation that should be disconnected in a post-operation
   * plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPostOperationModify()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("foo"));
    LDAPAttribute attr = new LDAPAttribute("description", values);
    ArrayList<LDAPModification> mods = new ArrayList<LDAPModification>();
    mods.add(new LDAPModification(ModificationType.REPLACE, attr));
    ModifyRequestProtocolOp modifyRequest =
         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
    message = new LDAPMessage(2, modifyRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList(
              "PostOperation"));
    w.writeElement(message.encode());
    ASN1Element element = r.readElement();
    if (element != null)
    {
      // If we got an element back, then it must be a notice of disconnect
      // unsolicited notification.
      message = LDAPMessage.decode(element.decodeAsSequence());
      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
  /**
   * Tests a modify operation that should be disconnected in a post-response
   * plugin.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPostResponseModify()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    ASN1Reader r = new ASN1Reader(s);
    ASN1Writer w = new ASN1Writer(s);
    r.setIOTimeout(5000);
    BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
                                   3, new ASN1OctetString("password"));
    LDAPMessage message = new LDAPMessage(1, bindRequest);
    w.writeElement(message.encode());
    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
    BindResponseProtocolOp bindResponse =
         message.getBindResponseProtocolOp();
    assertEquals(bindResponse.getResultCode(), 0);
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    values.add(new ASN1OctetString("foo"));
    LDAPAttribute attr = new LDAPAttribute("description", values);
    ArrayList<LDAPModification> mods = new ArrayList<LDAPModification>();
    mods.add(new LDAPModification(ModificationType.REPLACE, attr));
    ModifyRequestProtocolOp modifyRequest =
         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
    message = new LDAPMessage(2, modifyRequest,
         DisconnectClientPlugin.createDisconnectLDAPControlList(
              "PostResponse"));
    w.writeElement(message.encode());
responseLoop:
    while (true)
    {
      ASN1Element element = r.readElement();
      if (element == null)
      {
        // The connection has been closed.
        break responseLoop;
      }
      message = LDAPMessage.decode(element.decodeAsSequence());
      switch (message.getProtocolOpType())
      {
        case OP_TYPE_MODIFY_RESPONSE:
          // This was expected.  The disconnect didn't happen until after the
          // response was sent.
          break;
        case OP_TYPE_EXTENDED_RESPONSE:
          // The server is notifying us that it will be closing the connection.
          break responseLoop;
        default:
          // This is a problem.  It's an unexpected response.
          try
          {
            s.close();
          } catch (Exception e) {}
          throw new Exception("Unexpected response message " + message +
                              " encountered in " +
                              "testDisconnectInPostResponseModify");
      }
    }
    try
    {
      s.close();
    } catch (Exception e) {}
  }
}