opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
@@ -29,7 +29,9 @@ import static com.forgerock.opendj.ldap.CoreMessages.ERR_NO_SEARCH_RESULT_ENTRIES; import static com.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES; import static com.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES_NO_COUNT; import static com.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES; import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; import java.util.Collection; @@ -67,11 +69,7 @@ SearchResultHandler { private final ResultHandler<? super SearchResultEntry> handler; private volatile SearchResultEntry firstEntry = null; private volatile SearchResultReference firstReference = null; private volatile int entryCount = 0; private final SingleEntryHandler singleEntryHandler = new SingleEntryHandler(); private volatile FutureResult<Result> future = null; @@ -86,14 +84,22 @@ @Override public SearchResultEntry get() throws ErrorResultException, InterruptedException { future.get(); try { future.get(); } catch (ErrorResultException e) { throw singleEntryHandler.filterError(e); } return get0(); } @Override public SearchResultEntry get(final long timeout, final TimeUnit unit) throws ErrorResultException, TimeoutException, InterruptedException { future.get(timeout, unit); public SearchResultEntry get(final long timeout, final TimeUnit unit) throws ErrorResultException, TimeoutException, InterruptedException { try { future.get(timeout, unit); } catch (ErrorResultException e) { throw singleEntryHandler.filterError(e); } return get0(); } @@ -104,26 +110,20 @@ @Override public boolean handleEntry(final SearchResultEntry entry) { if (firstEntry == null) { firstEntry = entry; } entryCount++; return true; return singleEntryHandler.handleEntry(entry); } @Override public void handleErrorResult(final ErrorResultException error) { if (handler != null) { handler.handleErrorResult(error); ErrorResultException finalError = singleEntryHandler.filterError(error); handler.handleErrorResult(finalError); } } @Override public boolean handleReference(final SearchResultReference reference) { if (firstReference == null) { firstReference = reference; } return true; return singleEntryHandler.handleReference(reference); } @Override @@ -148,21 +148,11 @@ } private SearchResultEntry get0() throws ErrorResultException { if (entryCount == 0) { // Did not find any entries. throw newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, ERR_NO_SEARCH_RESULT_ENTRIES.get().toString()); } else if (entryCount > 1) { // Got more entries than expected. throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount).toString()); } else if (firstReference != null) { // Got an unexpected search result reference. throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get( firstReference.getURIs().iterator().next()).toString()); ErrorResultException exception = singleEntryHandler.checkForClientSideError(); if (exception == null) { return singleEntryHandler.firstEntry; } else { return firstEntry; throw exception; } } @@ -192,7 +182,7 @@ */ @Override public void handleErrorResult(final ErrorResultException error) { // Ignore. // Ignore } @Override @@ -211,6 +201,50 @@ // Ignore. } /** * Filter the provided error in order to transform size limit exceeded error to a client side error, * or leave it as is for any other error. * * @param error to filter * @return provided error in most case, or <code>ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED</code> * error if provided error is <code>ResultCode.SIZE_LIMIT_EXCEEDED</code> */ public ErrorResultException filterError(final ErrorResultException error) { if (error.getResult().getResultCode().equals(ResultCode.SIZE_LIMIT_EXCEEDED)) { return newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES_NO_COUNT.get().toString()); } else { return error; } } /** * Check for any error related to number of search result at client-side level: no result, * too many result, search result reference. * * This method should be called only after search operation is finished. * * @return an <code>ErrorResultException</code> if an error is detected, <code>null</code> otherwise */ public ErrorResultException checkForClientSideError() { ErrorResultException exception = null; if (entryCount == 0) { // Did not find any entries. exception = newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, ERR_NO_SEARCH_RESULT_ENTRIES .get().toString()); } else if (entryCount > 1) { // Got more entries than expected. exception = newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount).toString()); } else if (firstReference != null) { // Got an unexpected search result reference. exception = newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(firstReference.getURIs().iterator().next()) .toString()); } return exception; } } // Visitor used for processing synchronous change requests. @@ -410,7 +444,7 @@ public SearchResultEntry readEntry(final DN baseObject, final String... attributeDescriptions) throws ErrorResultException { final SearchRequest request = Requests.newSearchRequest(baseObject, SearchScope.BASE_OBJECT, Filter Requests.newSingleEntrySearchRequest(baseObject, SearchScope.BASE_OBJECT, Filter .objectClassPresent(), attributeDescriptions); return searchSingleEntry(request); } @@ -432,8 +466,9 @@ final Collection<String> attributeDescriptions, final ResultHandler<? super SearchResultEntry> handler) { final SearchRequest request = Requests.newSearchRequest(name, SearchScope.BASE_OBJECT, Filter .objectClassPresent()); Requests.newSingleEntrySearchRequest( name, SearchScope.BASE_OBJECT, Filter.objectClassPresent()); if (attributeDescriptions != null) { request.getAttributes().addAll(attributeDescriptions); } @@ -521,23 +556,16 @@ public SearchResultEntry searchSingleEntry(final SearchRequest request) throws ErrorResultException { final SingleEntryHandler handler = new SingleEntryHandler(); search(request, handler); if (handler.entryCount == 0) { // Did not find any entries. throw newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, ERR_NO_SEARCH_RESULT_ENTRIES.get().toString()); } else if (handler.entryCount > 1) { // Got more entries than expected. throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(handler.entryCount).toString()); } else if (handler.firstReference != null) { // Got an unexpected search result reference. throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get( handler.firstReference.getURIs().iterator().next()).toString()); } else { try { search(enforceSingleEntrySearchRequest(request), handler); } catch (ErrorResultException e) { throw handler.filterError(e); } ErrorResultException error = handler.checkForClientSideError(); if (error == null) { return handler.firstEntry; } else { throw error; } } @@ -548,7 +576,7 @@ public SearchResultEntry searchSingleEntry(final String baseObject, final SearchScope scope, final String filter, final String... attributeDescriptions) throws ErrorResultException { final SearchRequest request = Requests.newSearchRequest(baseObject, scope, filter, attributeDescriptions); Requests.newSingleEntrySearchRequest(baseObject, scope, filter, attributeDescriptions); return searchSingleEntry(request); } @@ -559,12 +587,28 @@ public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request, final ResultHandler<? super SearchResultEntry> handler) { final SingleEntryFuture innerFuture = new SingleEntryFuture(handler); final FutureResult<Result> future = searchAsync(request, null, innerFuture); final FutureResult<Result> future = searchAsync(enforceSingleEntrySearchRequest(request), null, innerFuture); innerFuture.setResultFuture(future); return innerFuture; } /** * Ensure that a single entry search request is returned, based on provided request. * * @param request * to be checked * @return a single entry search request, equal to or based on the provided request */ private SearchRequest enforceSingleEntrySearchRequest(final SearchRequest request) { if (request.isSingleEntrySearch()) { return request; } else { return Requests.copyOfSearchRequest(request).setSizeLimit(1); } } /** * {@inheritDoc} * <p> * Sub-classes should provide an implementation which returns an appropriate opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/Requests.java
@@ -22,7 +22,7 @@ * * * Copyright 2010 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.ldap.requests; @@ -1017,7 +1017,7 @@ /** * Creates a new search request using the provided distinguished name, * scope, and filter, decoded using the default schema. * scope, and filter. * * @param name * The distinguished name of the base entry relative to which the @@ -1079,6 +1079,58 @@ } /** * Creates a new search request for a single entry, using the provided distinguished name, * scope, and filter. * * @param name * The distinguished name of the base entry relative to which the * search is to be performed. * @param scope * The scope of the search. * @param filter * The filter that defines the conditions that must be fulfilled * in order for an entry to be returned. * @param attributeDescriptions * The names of the attributes to be included with each entry. * @return The new search request. * @throws NullPointerException * If the {@code name}, {@code scope}, or {@code filter} were * {@code null}. */ public static SearchRequest newSingleEntrySearchRequest(final DN name, final SearchScope scope, final Filter filter, final String... attributeDescriptions) { return newSearchRequest(name, scope, filter, attributeDescriptions).setSizeLimit(1); } /** * Creates a new search request for a single entry, using the provided distinguished name, * scope, and filter, decoded using the default schema. * * @param name * The distinguished name of the base entry relative to which the * search is to be performed. * @param scope * The scope of the search. * @param filter * The filter that defines the conditions that must be fulfilled * in order for an entry to be returned. * @param attributeDescriptions * The names of the attributes to be included with each entry. * @return The new search request. * @throws LocalizedIllegalArgumentException * If {@code name} could not be decoded using the default * schema, or if {@code filter} is not a valid LDAP string * representation of a filter. * @throws NullPointerException * If the {@code name}, {@code scope}, or {@code filter} were * {@code null}. */ public static SearchRequest newSingleEntrySearchRequest(final String name, final SearchScope scope, final String filter, final String... attributeDescriptions) { return newSearchRequest(name, scope, filter, attributeDescriptions).setSizeLimit(1); } /** * Creates a new simple bind request having an empty name and password * suitable for anonymous authentication. * opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SearchRequest.java
@@ -22,7 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.requests; @@ -147,6 +147,19 @@ int getSizeLimit(); /** * Indicates whether search result is expected to be limited to a single entry. * <p> * It is the case if size limit is equal to 1 or if scope is equal to <code>SearchScope.BASE_OBJECT</code>. * <p> * If search results contain more than one entry, the search operation will throw * a <code>MultipleEntriesFoundException</code>. * * @return {@code true} if the search is limited to a single entry result, * or {@code false} (the default) otherwise. */ boolean isSingleEntrySearch(); /** * Returns the time limit that should be used in order to restrict the * maximum time (in seconds) allowed for the search. * <p> @@ -270,6 +283,8 @@ * A value of zero (the default) in this field indicates that no * client-requested size limit restrictions are in effect. Servers may also * enforce a maximum number of entries to return. * <p> * This method overrides the size limit set using a previous call to {@link #setSingleEntrySearch()}. * * @param limit * The size limit that should be used in order to restrict the opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SearchRequestImpl.java
@@ -22,7 +22,7 @@ * * * Copyright 2010 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.requests; @@ -107,6 +107,11 @@ } @Override public boolean isSingleEntrySearch() { return sizeLimit == 1 || SearchScope.BASE_OBJECT.equals(scope); } @Override public int getTimeLimit() { return timeLimit; } opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableSearchRequestImpl.java
@@ -22,7 +22,7 @@ * * * Copyright 2010 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.requests; @@ -80,6 +80,11 @@ } @Override public boolean isSingleEntrySearch() { return impl.isSingleEntrySearch(); } @Override public int getTimeLimit() { return impl.getTimeLimit(); } opendj3/opendj-ldap-sdk/src/main/resources/com/forgerock/opendj/ldap/core.properties
@@ -844,6 +844,8 @@ but did not return any search result entries when one was expected ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES=The search request succeeded \ but returned %d search result entry when only one was expected ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES_NO_COUNT=The search request succeeded \ but returned more than one search result entry when only one was expected ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES=The search request succeeded \ but returned a search result reference containing the following URI: %s # opendj3/opendj-ldap-sdk/src/main/resources/com/forgerock/opendj/ldap/core_fr.properties
@@ -20,6 +20,7 @@ # CDDL HEADER END # # Copyright 2009 Sun Microsystems, Inc. # Portions copyright 2013 ForgeRock AS # ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=La valeur indiqu\u00e9e "%s" n'est pas une cha\u00eene de pays valide car elle n'a pas une longueur de deux caract\u00e8res exactement ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=La valeur indiqu\u00e9e "%s" n'est pas une m\u00e9thode de distribution valide car elle ne contient aucun \u00e9l\u00e9ment @@ -94,3 +95,6 @@ ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=La r\u00e8gle de contenu DIT "%s" n'est pas valide car elle interdit l'utilisation du type d'attribut %s requis par la classe d'objet structurelle associ\u00e9e %s ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=La r\u00e8gle de contenu DIT "%s" n'est pas valide car elle interdit l'utilisation du type d'attribut %s requis par la classe d'objet structurelle auxiliaire %s ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=Impossible d'analyser la valeur fournie "%s" en tant que nom valide distinctif car la valeur de l'attribut commence avec un caract\u00e8re en position %d qui doit \u00eatre \u00e9vit\u00e9 ERR_NO_SEARCH_RESULT_ENTRIES=La recherche a \u00e9t\u00e9 effectu\u00e9e avec succ\u00e8s mais n'a retourn\u00e9 aucune entr\u00e9e alors qu'une entr\u00e9e \u00e9tait attendue ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES=La recherche a \u00e9t\u00e9 effectu\u00e9e avec succ\u00e8s mais a retourn\u00e9 %s entr\u00e9es alors qu'une seule entr\u00e9e \u00e9tait attendue ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES_NO_COUNT=La recherche a \u00e9t\u00e9 effectu\u00e9e avec succ\u00e8s mais a retourn\u00e9 plusieurs entr\u00e9es alors qu'une seule entr\u00e9e \u00e9tait attendue opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java
@@ -22,7 +22,7 @@ * * * Copyright 2010 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. * Portions copyright 2011-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap; @@ -30,6 +30,7 @@ import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; import static org.mockito.Mockito.*; import java.util.LinkedList; import java.util.List; @@ -65,15 +66,11 @@ private final class MockConnection extends AbstractAsynchronousConnection { private final ResultCode resultCode; private final SearchResultEntry entry; private final SearchResultEntry[] entries; private MockConnection(ResultCode resultCode) { this(resultCode, null); } private MockConnection(ResultCode resultCode, SearchResultEntry entry) { private MockConnection(ResultCode resultCode, SearchResultEntry...entries) { this.resultCode = resultCode; this.entry = entry; this.entries = entries; } /** @@ -222,14 +219,17 @@ public FutureResult<Result> searchAsync(SearchRequest request, IntermediateResponseHandler intermediateResponseHandler, SearchResultHandler resultHandler) { if (entry != null) { for (SearchResultEntry entry : entries) { resultHandler.handleEntry(entry); } if (!resultCode.isExceptional()) { return new CompletedFutureResult<Result>(Responses.newResult(resultCode)); if (resultCode.isExceptional()) { ErrorResultException errorResult = newErrorResult(resultCode); resultHandler.handleErrorResult(errorResult); return new CompletedFutureResult<Result>(errorResult); } else { return new CompletedFutureResult<Result>(newErrorResult(resultCode)); Result result = Responses.newResult(resultCode); resultHandler.handleResult(result); return new CompletedFutureResult<Result>(result); } } @@ -401,10 +401,144 @@ List<SearchResultEntry> entries = new LinkedList<SearchResultEntry>(); try { mockConnection.search(searchRequest, entries); fail(); failWasExpected(ErrorResultException.class); } catch (ErrorResultException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.UNWILLING_TO_PERFORM); assertThat(entries.isEmpty()); } } @Test() public void testSingleEntrySearchRequestSuccess() throws Exception { final SearchResultEntry entry = Responses.newSearchResultEntry("cn=test"); final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, entry); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); assertThat(mockConnection.searchSingleEntry(request)).isEqualTo(entry); } @SuppressWarnings("unchecked") @Test() public void testSingleEntrySearchAsyncRequestSuccess() throws Exception { final SearchResultEntry entry = Responses.newSearchResultEntry("cn=test"); final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, entry); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class); FutureResult<SearchResultEntry> futureResult = mockConnection.searchSingleEntryAsync(request, handler); assertThat(futureResult.get()).isEqualTo(entry); verify(handler).handleResult(any(SearchResultEntry.class)); } @Test() public void testSingleEntrySearchRequestNoEntryReturned() throws Exception { final Connection mockConnection = new MockConnection(ResultCode.SUCCESS); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); try { mockConnection.searchSingleEntry(request); failWasExpected(EntryNotFoundException.class); } catch (EntryNotFoundException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED); } } @Test() public void testSingleEntrySearchRequestMultipleEntriesToReturn() throws Exception { final Connection mockConnection = new MockConnection(ResultCode.SIZE_LIMIT_EXCEEDED, Responses.newSearchResultEntry("cn=test")); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); try { mockConnection.searchSingleEntry(request); failWasExpected(MultipleEntriesFoundException.class); } catch (MultipleEntriesFoundException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED); } } @Test() public void testSingleEntrySearchRequestMultipleEntriesReturnedByServer() throws Exception { // could happen if server does not enforce size limit final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, Responses.newSearchResultEntry("cn=test"), Responses.newSearchResultEntry("cn=test,ou=org")); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.WHOLE_SUBTREE, "(objectClass=*)"); try { mockConnection.searchSingleEntry(request); failWasExpected(MultipleEntriesFoundException.class); } catch (MultipleEntriesFoundException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED); } } @SuppressWarnings("unchecked") @Test() public void testSingleEntrySearchAsyncRequestMultipleEntriesToReturn() throws Exception { final Connection mockConnection = new MockConnection(ResultCode.SIZE_LIMIT_EXCEEDED, Responses.newSearchResultEntry("cn=test")); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class); try { mockConnection.searchSingleEntryAsync(request, handler).get(); failWasExpected(MultipleEntriesFoundException.class); } catch (MultipleEntriesFoundException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED); verify(handler).handleErrorResult(any(ErrorResultException.class)); } } @Test() public void testSingleEntrySearchAsyncRequestMultipleEntriesReturnedByServer() throws Exception { // could happen if server does not enfore size limit final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, Responses.newSearchResultEntry("cn=test"), Responses.newSearchResultEntry("cn=test,ou=org")); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class); try { mockConnection.searchSingleEntryAsync(request, handler).get(); failWasExpected(MultipleEntriesFoundException.class); } catch (MultipleEntriesFoundException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED); verify(handler).handleErrorResult(any(ErrorResultException.class)); } } @Test() public void testSingleEntrySearchRequestFail() throws Exception { final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); try { mockConnection.searchSingleEntry(request); failWasExpected(ErrorResultException.class); } catch (ErrorResultException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.UNWILLING_TO_PERFORM); } } @Test() public void testSingleEntrySearchAsyncRequestFail() throws Exception { final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM); final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)"); ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class); try { mockConnection.searchSingleEntryAsync(request, handler).get(); failWasExpected(ErrorResultException.class); } catch (ErrorResultException e) { assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.UNWILLING_TO_PERFORM); verify(handler).handleErrorResult(any(ErrorResultException.class)); } } } opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/SdkTestCase.java
@@ -22,10 +22,12 @@ * * * Copyright 2010 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldap; import static org.fest.assertions.Fail.*; import org.forgerock.testng.ForgeRockTestCase; import org.testng.annotations.Test; @@ -35,4 +37,13 @@ */ @Test(groups = { "precommit", "types", "sdk" }) public abstract class SdkTestCase extends ForgeRockTestCase { /** * Fail with precise message giving the exception that was expected. * * @param exceptionClass expected exception */ void failWasExpected(Class<? extends Throwable> exceptionClass) { fail("should throw an exception " + exceptionClass.getSimpleName()); } } opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/SearchRequestTestCase.java
New file @@ -0,0 +1,82 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2013 ForgeRock AS. */ package org.forgerock.opendj.ldap.requests; import static org.fest.assertions.Assertions.*; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.Filter; import org.forgerock.opendj.ldap.SearchScope; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @SuppressWarnings("javadoc") public class SearchRequestTestCase extends RequestTestCase { @DataProvider(name = "SearchRequests") public Object[][] getSearchRequests() throws Exception { return getTestRequests(); } @Override protected SearchRequest[] createTestRequests() throws Exception { return new SearchRequest[] { Requests.newSearchRequest( "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT, "(uid=user)", "uid", "ou"), Requests.newSearchRequest("uid=user.0,ou=people,o=test", SearchScope.SINGLE_LEVEL, "(uid=user)", "uid", "ou") }; } @Test public void createRequestForSingleEntrySearch() throws Exception { SearchRequest request = Requests.newSingleEntrySearchRequest( DN.valueOf("uid=user.0,ou=people,o=test"), SearchScope.BASE_OBJECT, Filter.equality("uid", "user"), "uid"); assertThat(request.getSizeLimit()).isEqualTo(1); assertThat(request.isSingleEntrySearch()).isTrue(); } @Test public void createRequestForSingleEntrySearchWithStrings() throws Exception { SearchRequest request = Requests.newSingleEntrySearchRequest( "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT, "(uid=user)", "uid"); assertThat(request.getSizeLimit()).isEqualTo(1); assertThat(request.isSingleEntrySearch()).isTrue(); } @Test public void createRequestWithBaseObjectScope() throws Exception { SearchRequest request = Requests.newSearchRequest( DN.valueOf("uid=user.0,ou=people,o=test"), SearchScope.BASE_OBJECT, Filter.equality("uid", "user"), "uid"); assertThat(request.isSingleEntrySearch()).isTrue(); } }