/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.control.util; import java.util.EnumSet; import java.util.concurrent.BlockingQueue; import org.ldaptive.AbstractTest; import org.ldaptive.AttributeModification; import org.ldaptive.AttributeModificationType; import org.ldaptive.Connection; import org.ldaptive.DnParser; import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; import org.ldaptive.LdapException; import org.ldaptive.ModifyDnOperation; import org.ldaptive.ModifyDnRequest; import org.ldaptive.ModifyOperation; import org.ldaptive.ModifyRequest; import org.ldaptive.ResultCode; import org.ldaptive.SearchEntry; import org.ldaptive.SearchRequest; import org.ldaptive.SearchResult; import org.ldaptive.TestControl; import org.ldaptive.TestUtils; import org.ldaptive.async.AsyncRequest; import org.ldaptive.control.PersistentSearchChangeType; import org.testng.AssertJUnit; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * Unit test for {@link PersistentSearchClient}. * * @author Middleware Services */ public class PersistentSearchClientTest extends AbstractTest { /** Entry created for ldap tests. */ private static LdapEntry testLdapEntry; /** * @param ldifFile to create. * * @throws Exception On test failure. */ @Parameters("createEntry31") @BeforeClass(groups = {"control-util"}) public void createLdapEntry(final String ldifFile) throws Exception { final String ldif = TestUtils.readFileIntoString(ldifFile); testLdapEntry = TestUtils.convertLdifToResult(ldif).getEntry(); super.createLdapEntry(testLdapEntry); } /** @throws Exception On test failure. */ @AfterClass(groups = {"control-util"}) public void deleteLdapEntry() throws Exception { super.deleteLdapEntry(testLdapEntry.getDn()); } /** * @param dn to search on. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "persistentSearchDn", "persistentSearchReturnAttrs", "persistentSearchResults" }) @Test(groups = {"control-util"}) public void persistentSearch(final String dn, final String returnAttrs, final String ldifFile) throws Exception { if (TestControl.isActiveDirectory()) { return; } final String expected = TestUtils.readFileIntoString(ldifFile); final SearchResult expectedResult = TestUtils.convertLdifToResult(expected); try (Connection conn = TestUtils.createConnection()) { conn.open(); final PersistentSearchClient client = new PersistentSearchClient( conn, EnumSet.allOf(PersistentSearchChangeType.class), true, true); final SearchRequest request = SearchRequest.newObjectScopeSearchRequest(dn, returnAttrs.split("\\|")); final BlockingQueue<PersistentSearchItem> results = client.execute(request); // test the async request PersistentSearchItem item = results.take(); if (item.isException()) { throw item.getException(); } AsyncRequest asyncRequest = null; if (item.isAsyncRequest()) { asyncRequest = item.getAsyncRequest(); // some providers don't support the request object AssertJUnit.assertTrue(item.getAsyncRequest().getMessageId() > 0); } checkItem(item); // make a change final LdapAttribute modAttr = new LdapAttribute("initials", "PSC"); final ModifyOperation modify = new ModifyOperation(conn); modify.execute(new ModifyRequest(dn, new AttributeModification(AttributeModificationType.REPLACE, modAttr))); item = results.take(); checkItem(item); AssertJUnit.assertTrue(item.isEntry()); AssertJUnit.assertEquals( PersistentSearchChangeType.MODIFY, item.getEntry().getEntryChangeNotificationControl().getChangeType()); expectedResult.getEntry().addAttribute(modAttr); TestUtils.assertEquals( expectedResult, new SearchResult(createCompareEntry(expectedResult.getEntry(), item.getEntry().getSearchEntry()))); // modify dn final String modDn = "CN=PSC," + DnParser.substring(dn, 1); final LdapAttribute cn = expectedResult.getEntry().getAttribute("cn"); final ModifyDnOperation modifyDn = new ModifyDnOperation(conn); modifyDn.execute(new ModifyDnRequest(dn, modDn)); item = results.take(); AssertJUnit.assertTrue(item.isEntry()); AssertJUnit.assertEquals( PersistentSearchChangeType.MODDN, item.getEntry().getEntryChangeNotificationControl().getChangeType()); expectedResult.getEntry().setDn(modDn); expectedResult.getEntry().addAttribute(new LdapAttribute("CN", "PSC")); TestUtils.assertEquals( expectedResult, new SearchResult(createCompareEntry(expectedResult.getEntry(), item.getEntry().getSearchEntry()))); // modify dn back modifyDn.execute(new ModifyDnRequest(modDn, dn)); item = results.take(); AssertJUnit.assertTrue(item.isEntry()); AssertJUnit.assertEquals( PersistentSearchChangeType.MODDN, item.getEntry().getEntryChangeNotificationControl().getChangeType()); expectedResult.getEntry().setDn(dn); expectedResult.getEntry().addAttribute(cn); TestUtils.assertEquals( expectedResult, new SearchResult(createCompareEntry(expectedResult.getEntry(), item.getEntry().getSearchEntry()))); asyncRequest.abandon(); if (!results.isEmpty()) { item = results.take(); if (item.isResponse()) { AssertJUnit.assertEquals(ResultCode.USER_CANCELLED, item.getResponse().getResultCode()); } else if (item.isException()) { final LdapException e = (LdapException) item.getException(); AssertJUnit.assertEquals(ResultCode.USER_CANCELLED, e.getResultCode()); } else { AssertJUnit.fail("Unknown result type"); } } AssertJUnit.assertTrue(results.isEmpty()); } } /** * Check that the supplied item isn't a response or exception. * * @param item to check * * @throws UnsupportedOperationException if the server doesn't support this control * @throws IllegalStateException if the item is a response or exception */ private void checkItem(final PersistentSearchItem item) { if (item.isResponse()) { if (ResultCode.UNAVAILABLE_CRITICAL_EXTENSION.equals(item.getResponse().getResultCode())) { // ignore this test if not supported by the server throw new UnsupportedOperationException("LDAP server does not support this control"); } else { throw new IllegalStateException("Unexpected response: " + item.getResponse()); } } else if (item.isException()) { final LdapException e = (LdapException) item.getException(); if (ResultCode.UNAVAILABLE_CRITICAL_EXTENSION.equals(e.getResultCode())) { // ignore this test if not supported by the server throw new UnsupportedOperationException("LDAP server does not support this control"); } else { throw new IllegalStateException("Unexpected exception: " + e); } } } /** * Creates an ldap entry to compare with expected results. Removes any extra attributes returned from using the * persistent search control. * * @param expectedEntry to compare with * @param searchEntry returned from a persistent search * * @return sanitized entry to compare with * * @throws Exception if an error occurs */ private LdapEntry createCompareEntry(final LdapEntry expectedEntry, final SearchEntry searchEntry) throws Exception { final LdapEntry compareEntry = new LdapEntry(expectedEntry.getDn()); for (String attr : expectedEntry.getAttributeNames()) { compareEntry.addAttribute(searchEntry.getAttribute(attr)); } return compareEntry; } }