From 848768d0dba4efc0db802d162beac0d0e4a13dc9 Mon Sep 17 00:00:00 2001
From: coulbeck <coulbeck@localhost>
Date: Tue, 10 Oct 2006 22:42:30 +0000
Subject: [PATCH] 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.

---
 opendj-sdk/opends/src/server/org/opends/server/core/PasswordPolicyState.java                             |   24 +-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java |  562 +++++++++++++++++++++++++++++++++++++++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/tools/LDIFSearch.java                                     |    4 
 opendj-sdk/opends/src/server/org/opends/server/types/SearchResultEntry.java                              |    5 
 opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java                                 |   46 +++-
 5 files changed, 615 insertions(+), 26 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/PasswordPolicyState.java b/opendj-sdk/opends/src/server/org/opends/server/core/PasswordPolicyState.java
index c30c17f..43583d2 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/PasswordPolicyState.java
+++ b/opendj-sdk/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)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
index fbc7ff1..37c59cc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
+++ b/opendj-sdk/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);
     }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/LDIFSearch.java b/opendj-sdk/opends/src/server/org/opends/server/tools/LDIFSearch.java
index cfd63b3..77e0c54 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/LDIFSearch.java
+++ b/opendj-sdk/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())
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/SearchResultEntry.java b/opendj-sdk/opends/src/server/org/opends/server/types/SearchResultEntry.java
index 9c2a36a..06d20ee 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/SearchResultEntry.java
+++ b/opendj-sdk/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
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
new file mode 100644
index 0000000..dab723b
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
@@ -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);
+  }
+}

--
Gitblit v1.10.0