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

coulbeck
11.42.2006 c0144353899d1191c10de1d50e60036e508d5189
Fixes for the following issues, reviewed by neil_a_wilson.
issue 776: Overflow of large values for time limit.
issue 781: search result entries have their object class in the wrong field.

Initial unit tests for SearchOperation.
1 files added
4 files modified
641 ■■■■■ changed files
opends/src/server/org/opends/server/core/PasswordPolicyState.java 24 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SearchOperation.java 46 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDIFSearch.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/SearchResultEntry.java 5 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java 562 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/PasswordPolicyState.java
@@ -1366,7 +1366,7 @@
          LinkedHashSet<AttributeValue> values = null;
          long expirationTime = currentTime -
                    (passwordPolicy.getLockoutFailureExpirationInterval()*1000);
               (passwordPolicy.getLockoutFailureExpirationInterval()*1000L);
          Iterator<Long> iterator = authFailureTimes.iterator();
          while (iterator.hasNext())
          {
@@ -1715,7 +1715,7 @@
    if (passwordPolicy.getLockoutDuration() > 0)
    {
      long unlockTime = failureLockedTime +
                        (1000*passwordPolicy.getLockoutDuration());
           (1000L*passwordPolicy.getLockoutDuration());
      if (unlockTime > currentTime)
      {
        if (debug)
@@ -2141,7 +2141,7 @@
      }
      long lockTime = currentTime -
                      (passwordPolicy.getIdleLockoutInterval()*1000);
                      (passwordPolicy.getIdleLockoutInterval()*1000L);
      long lastLoginTime = getLastLoginTime();
      if (lastLoginTime > 0)
      {
@@ -2488,7 +2488,7 @@
    }
    long maxResetTime = passwordChangedTime +
                        (1000 * passwordPolicy.getMaximumPasswordResetAge());
                        (1000L * passwordPolicy.getMaximumPasswordResetAge());
    boolean locked = (maxResetTime < currentTime);
    if (debug)
@@ -2529,7 +2529,7 @@
      int maxAge = passwordPolicy.getMaximumPasswordAge();
      if (maxAge > 0)
      {
        long expTime = passwordChangedTime + (1000*maxAge);
        long expTime = passwordChangedTime + (1000L*maxAge);
        if (expTime < expirationTime)
        {
          expirationTime = expTime;
@@ -2540,7 +2540,7 @@
      int maxResetAge = passwordPolicy.getMaximumPasswordResetAge();
      if (mustChangePassword() && (maxResetAge > 0))
      {
        long expTime = passwordChangedTime + (1000*maxResetAge);
        long expTime = passwordChangedTime + (1000L*maxResetAge);
        if (expTime < expirationTime)
        {
          expirationTime = expTime;
@@ -2575,7 +2575,7 @@
        int warningInterval = passwordPolicy.getWarningInterval();
        if (warningInterval > 0)
        {
          long shouldWarnTime = expirationTime - (warningInterval*1000);
          long shouldWarnTime = expirationTime - (warningInterval*1000L);
          if (shouldWarnTime > currentTime)
          {
            // The warning time is in the future, so we know the password isn't
@@ -2603,7 +2603,7 @@
                if (! passwordPolicy.expirePasswordsWithoutWarning())
                {
                  expirationTime = currentTime + (warningInterval*1000);
                  expirationTime = currentTime + (warningInterval*1000L);
                }
              }
              else
@@ -2612,7 +2612,7 @@
                if (! passwordPolicy.expirePasswordsWithoutWarning())
                {
                  expirationTime = warnedTime + (warningInterval*1000);
                  expirationTime = warnedTime + (warningInterval*1000L);
                }
              }
            }
@@ -2628,7 +2628,7 @@
              }
              else if (warnedTime > 0)
              {
                expirationTime = warnedTime + (warningInterval*1000);
                expirationTime = warnedTime + (warningInterval*1000L);
                if (expirationTime > currentTime)
                {
                  shouldWarn        = ConditionResult.TRUE;
@@ -2647,7 +2647,7 @@
                shouldWarn        = ConditionResult.TRUE;
                isFirstWarning    = ConditionResult.TRUE;
                isPasswordExpired = ConditionResult.FALSE;
                expirationTime    = currentTime + (warningInterval*1000);
                expirationTime    = currentTime + (warningInterval*1000L);
              }
            }
          }
@@ -2770,7 +2770,7 @@
      return false;
    }
    else if ((passwordChangedTime + (minAge*1000)) < currentTime)
    else if ((passwordChangedTime + (minAge*1000L)) < currentTime)
    {
      // It's been long enough since the user changed their password.
      if (debug)
opends/src/server/org/opends/server/core/SearchOperation.java
@@ -944,9 +944,15 @@
          {
            // First, add the objectclass attribute.
            Attribute ocAttr = entry.getObjectClassAttribute();
            List<Attribute> ocList = new ArrayList<Attribute>(1);
            ocList.add(ocAttr);
            entryToReturn.putAttribute(ocAttr.getAttributeType(), ocList);
            try
            {
              entryToReturn.setObjectClasses(ocAttr.getValues());
            }
            catch (DirectoryException e)
            {
              // We cannot get this exception because the object classes have
              // already been validated in the entry they came from.
            }
            // Next iterate through all the user attributes and include them.
@@ -1125,18 +1131,34 @@
        }
        else
        {
          List<Attribute> attrList = entry.getAttribute(attrType, options);
          if (attrList != null)
          if (attrType.isObjectClassType() && !typesOnly)
          {
            if (typesOnly)
            Attribute ocAttr = entry.getObjectClassAttribute();
            try
            {
              attrList = new ArrayList<Attribute>(1);
              attrList.add(new Attribute(attrType));
              entryToReturn.putAttribute(attrType, attrList);
              entryToReturn.setObjectClasses(ocAttr.getValues());
            }
            else
            catch (DirectoryException e)
            {
              entryToReturn.putAttribute(attrType, attrList);
              // We cannot get this exception because the object classes have
              // already been validated in the entry they came from.
            }
          }
          else
          {
            List<Attribute> attrList = entry.getAttribute(attrType, options);
            if (attrList != null)
            {
              if (typesOnly)
              {
                attrList = new ArrayList<Attribute>(1);
                attrList.add(new Attribute(attrType));
                entryToReturn.putAttribute(attrType, attrList);
              }
              else
              {
                entryToReturn.putAttribute(attrType, attrList);
              }
            }
          }
        }
@@ -1564,7 +1586,7 @@
    else
    {
      // FIXME -- Factor in the user's effective time limit.
      timeLimitExpiration = processingStartTime + (1000 * timeLimit);
      timeLimitExpiration = processingStartTime + (1000L * timeLimit);
    }
opends/src/server/org/opends/server/tools/LDIFSearch.java
@@ -531,7 +531,7 @@
    {
      if (timeLimit.isPresent())
      {
        timeLimitMillis = 1000 * timeLimit.getIntValue();
        timeLimitMillis = 1000L * timeLimit.getIntValue();
      }
      else
      {
@@ -569,7 +569,7 @@
    }
    // Create the LDIF import configuration that will be used to rad the source
    // Create the LDIF import configuration that will be used to read the source
    // data.
    LDIFImportConfig importConfig;
    if (ldifFile.isPresent())
opends/src/server/org/opends/server/types/SearchResultEntry.java
@@ -39,6 +39,11 @@
 * This class defines a data structure for storing information about
 * an entry that matches a given set of search criteria and should be
 * returned to the client.
 * When the search result entry contains attribute types only, the
 * objectclass type (if requested) will be present in the user
 * attributes.  When the search result entry contains both attribute
 * types and values, the objectclass attribute will not be present in
 * the user attributes.
 */
public class SearchResultEntry
       extends Entry
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
New file
@@ -0,0 +1,562 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.protocols.ldap.*;
import org.opends.server.types.*;
import org.opends.server.TestCaseUtils;
import org.opends.server.plugins.InvocationCounterPlugin;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.net.Socket;
import java.io.IOException;
public class SearchOperationTestCase extends OperationTestCase
{
  private Entry entry;
  private int ldapAttrCount;
  @BeforeClass
  public void setUp() throws Exception
  {
    TestCaseUtils.startServer();
    TestCaseUtils.initializeTestBackend(true);
    InternalClientConnection connection =
         InternalClientConnection.getRootConnection();
    // Add a test entry.
    entry = TestCaseUtils.makeEntry(
         "dn: uid=rogasawara,o=test",
         "userpassword: password",
         "objectclass: top",
         "objectclass: person",
         "objectclass: organizationalPerson",
         "objectclass: inetOrgPerson",
         "uid: rogasawara",
         "mail: rogasawara@airius.co.jp",
         "givenname;lang-ja:: 44Ot44OJ44OL44O8",
         "sn;lang-ja:: 5bCP56yg5Y6f",
         "cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==",
         "title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==",
         "preferredlanguage: ja",
         "givenname:: 44Ot44OJ44OL44O8",
         "sn:: 5bCP56yg5Y6f",
         "cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==",
         "title:: 5Za25qWt6YOoIOmDqOmVtw==",
         "givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8",
         "sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ",
         "cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==",
         "title;lang-ja;phonetic:: " +
              "44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==",
         "givenname;lang-en: Rodney",
         "sn;lang-en: Ogasawara",
         "cn;lang-en: Rodney Ogasawara",
         "title;lang-en: Sales, Director"
    );
    // Calculate the total number of LDAP attributes in this entry.
    ldapAttrCount = 1; // For the objectclass attribute.
    for (Attribute a : entry.getAttributes())
    {
      ldapAttrCount += a.getValues().size();
    }
    // The add operation changes the attributes, so let's duplicate the entry.
    Entry duplicateEntry = entry.duplicate();
    AddOperation addOperation =
         connection.processAdd(duplicateEntry.getDN(),
                               duplicateEntry.getObjectClasses(),
                               duplicateEntry.getUserAttributes(),
                               duplicateEntry.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    assertNotNull(DirectoryServer.getEntry(entry.getDN()));
    // Add a test ldapsubentry.
    Entry ldapSubentry = TestCaseUtils.makeEntry(
         "dn: cn=subentry,o=test",
         "objectclass: ldapsubentry");
    addOperation =
         connection.processAdd(ldapSubentry.getDN(),
                               ldapSubentry.getObjectClasses(),
                               ldapSubentry.getUserAttributes(),
                               ldapSubentry.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    assertNotNull(DirectoryServer.getEntry(ldapSubentry.getDN()));
  }
  public Operation[] createTestOperations() throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    return new Operation[]
    {
         new SearchOperation(conn,
                             InternalClientConnection.nextOperationID(),
                             InternalClientConnection.nextMessageID(),
                             new ArrayList<Control>(),
                             new ASN1OctetString("o=test"),
                             SearchScope.WHOLE_SUBTREE,
                             DereferencePolicy.NEVER_DEREF_ALIASES,
                             -1,
                             -1,
                             false,
                             LDAPFilter.decode("(objectclass=*)"),
                             null)
    };
  }
  /**
   * Invokes a number of operation methods on the provided search operation
   * for which all processing has been completed.
   *
   * @param  searchOperation  The operation to be tested.
   */
  private void examineCompletedOperation(SearchOperation searchOperation)
  {
    assertTrue(searchOperation.getProcessingStartTime() > 0);
    assertTrue(searchOperation.getProcessingStopTime() > 0);
    assertTrue(searchOperation.getProcessingTime() >= 0);
    assertNotNull(searchOperation.getResponseLogElements());
    assertEquals(InvocationCounterPlugin.getPreParseCount(), 1);
    assertEquals(InvocationCounterPlugin.getPreOperationCount(), 1);
    assertEquals(InvocationCounterPlugin.getPostOperationCount(), 1);
    assertEquals(InvocationCounterPlugin.getPostResponseCount(), 1);
  }
  private Entry searchInternalForSingleEntry(
       InternalSearchOperation searchOperation)
  {
    InvocationCounterPlugin.resetAllCounters();
    searchOperation.run();
    assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    assertEquals(searchOperation.getEntriesSent(), 1);
    assertEquals(searchOperation.getErrorMessage().length(), 0);
    examineCompletedOperation(searchOperation);
    return searchOperation.getSearchEntries().getFirst();
  }
  private SearchResultEntryProtocolOp searchExternalForSingleEntry(
       SearchRequestProtocolOp searchRequest)
       throws IOException, LDAPException, ASN1Exception, InterruptedException
  {
    // Establish a connection to the server.
    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
    try
    {
      ASN1Reader r = new ASN1Reader(s);
      ASN1Writer w = new ASN1Writer(s);
      r.setIOTimeout(1500000);
      bindAsManager(w, r);
      InvocationCounterPlugin.resetAllCounters();
      LDAPMessage message;
      message = new LDAPMessage(2, searchRequest);
      w.writeElement(message.encode());
      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
      SearchResultEntryProtocolOp searchResultEntry =
           message.getSearchResultEntryProtocolOp();
      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
      SearchResultDoneProtocolOp searchResultDone =
           message.getSearchResultDoneProtocolOp();
      assertEquals(InvocationCounterPlugin.waitForPostResponse(), 1);
      assertEquals(searchResultDone.getResultCode(), LDAPResultCode.SUCCESS);
      return searchResultEntry;
    }
    finally
    {
      s.close();
    }
  }
  private void bindAsManager(ASN1Writer w, ASN1Reader r)
       throws IOException, LDAPException, ASN1Exception, InterruptedException
  {
    InvocationCounterPlugin.resetAllCounters();
    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(InvocationCounterPlugin.waitForPostResponse(), 1);
    assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
  }
  @Test
  public void testSearchInternal() throws Exception
  {
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=*)"),
              null, null);
    searchOperation.run();
    assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    assertEquals(searchOperation.getEntriesSent(), 2);
    assertEquals(searchOperation.getErrorMessage().length(), 0);
    examineCompletedOperation(searchOperation);
  }
  @Test
  public void testSearchInternalUnspecifiedAttributes() throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              null, null);
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses(), entry.getObjectClasses());
    assertEquals(resultEntry.getUserAttributes().size(),
                 entry.getUserAttributes().size());
    assertEquals(resultEntry.getOperationalAttributes().size(), 0);
  }
  @Test
  public void testSearchInternalAllUserAttributesTypesOnly() throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              true,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              null, null);
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses().size(), 0);
    assertEquals(resultEntry.getUserAttributes().size(),
                 entry.getUserAttributes().size() + 1);
    assertEquals(resultEntry.getOperationalAttributes().size(), 0);
  }
  @Test
  public void testSearchInternalAllOperationalAttributes() throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("+");
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes, null);
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses().size(), 0);
    assertEquals(resultEntry.getUserAttributes().size(), 0);
    assertTrue(resultEntry.getOperationalAttributes().size() > 0);
  }
  @Test
  public void testSearchInternalAllUserAndOperationalAttributes()
       throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("*");
    attributes.add("+");
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes, null);
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses(), entry.getObjectClasses());
    assertTrue(resultEntry.getOperationalAttributes().size() > 0);
    assertEquals(resultEntry.getUserAttributes().size(),
                 entry.getUserAttributes().size());
  }
  @Test
  public void testSearchInternalAllUserAttributesPlusSelectedOperational()
       throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("*");
    attributes.add("createtimestamp");
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes, null);
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses(), entry.getObjectClasses());
    assertEquals(resultEntry.getUserAttributes().size(),
                 entry.getUserAttributes().size());
    assertEquals(resultEntry.getOperationalAttributes().size(), 1);
  }
  @Test
  public void testSearchInternalSelectedAttributes()
       throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("uid");
    attributes.add("createtimestamp");
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(
              conn,
              InternalClientConnection.nextOperationID(),
              InternalClientConnection.nextMessageID(),
              new ArrayList<Control>(),
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes, null);
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses().size(), 0);
    assertEquals(resultEntry.getUserAttributes().size(), 1);
    assertEquals(resultEntry.getOperationalAttributes().size(), 1);
  }
  @Test
  public void testSearchExternalUnspecifiedAttributes() throws Exception
  {
    SearchRequestProtocolOp searchRequest =
         new SearchRequestProtocolOp(
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              null);
    SearchResultEntryProtocolOp searchResultEntry =
         searchExternalForSingleEntry(searchRequest);
    assertEquals(searchResultEntry.getAttributes().size(), ldapAttrCount);
  }
  @Test
  public void testSearchExternalAllUserAttributes() throws Exception
  {
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("*");
    SearchRequestProtocolOp searchRequest =
         new SearchRequestProtocolOp(
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes);
    SearchResultEntryProtocolOp searchResultEntry =
         searchExternalForSingleEntry(searchRequest);
    assertEquals(searchResultEntry.getAttributes().size(), ldapAttrCount);
  }
  @Test
  public void testSearchExternalAllUserAttributesTypesOnly() throws Exception
  {
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("*");
    SearchRequestProtocolOp searchRequest =
         new SearchRequestProtocolOp(
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              true,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes);
    SearchResultEntryProtocolOp searchResultEntry =
         searchExternalForSingleEntry(searchRequest);
    // The attributes will include the objectclass type.
    assertEquals(searchResultEntry.getAttributes().size(),
                 entry.getUserAttributes().size() + 1);
  }
  @Test
  public void testSearchExternalObjectClassAttribute() throws Exception
  {
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("objectclass");
    SearchRequestProtocolOp searchRequest =
         new SearchRequestProtocolOp(
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes);
    SearchResultEntryProtocolOp searchResultEntry =
         searchExternalForSingleEntry(searchRequest);
    assertEquals(searchResultEntry.getAttributes().size(), 1);
    assertEquals(searchResultEntry.getAttributes().
         getFirst().getValues().size(), 4);
  }
  @Test
  public void testSearchExternalSelectedAttributes() throws Exception
  {
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    attributes.add("uid");
    attributes.add("createtimestamp");
    SearchRequestProtocolOp searchRequest =
         new SearchRequestProtocolOp(
              new ASN1OctetString("o=test"),
              SearchScope.WHOLE_SUBTREE,
              DereferencePolicy.NEVER_DEREF_ALIASES,
              Integer.MAX_VALUE,
              Integer.MAX_VALUE,
              false,
              LDAPFilter.decode("(objectclass=inetorgperson)"),
              attributes);
    SearchResultEntryProtocolOp searchResultEntry =
         searchExternalForSingleEntry(searchRequest);
    assertEquals(searchResultEntry.getAttributes().size(), 2);
  }
}