From e674d6cc941b2c9e4af09f4bfcf37b5e4bc24f7c Mon Sep 17 00:00:00 2001 From: Ulrik Sandberg Date: Sun, 24 Aug 2008 06:53:18 +0000 Subject: [PATCH] Moved VLV stuff to mvn-build. Added unit tests. --- ...ewControlAggregateDirContextProcessor.java | 36 +++ ...ualListViewControlDirContextProcessor.java | 16 +- .../control/VirtualListViewResultsCookie.java | 0 .../ldap/control/ControlArrayMatcher.java | 58 ++++ .../ldap/control/PagedResultTest.java | 9 + ...istViewControlDirContextProcessorTest.java | 286 ++++++++++++++++++ sandbox/.springBeans | 69 +++-- .../control/DummyVLVDirContextProcessor.java | 13 - 8 files changed, 437 insertions(+), 50 deletions(-) create mode 100644 mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlAggregateDirContextProcessor.java rename {sandbox => mvn-build/core}/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java (89%) rename {sandbox => mvn-build/core}/src/main/java/org/springframework/ldap/control/VirtualListViewResultsCookie.java (100%) create mode 100644 mvn-build/core/src/test/java/org/springframework/ldap/control/ControlArrayMatcher.java create mode 100644 mvn-build/core/src/test/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessorTest.java delete mode 100644 sandbox/src/main/java/org/springframework/ldap/control/DummyVLVDirContextProcessor.java diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlAggregateDirContextProcessor.java b/mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlAggregateDirContextProcessor.java new file mode 100644 index 00000000..643a4e5d --- /dev/null +++ b/mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlAggregateDirContextProcessor.java @@ -0,0 +1,36 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ldap.control; + +import org.springframework.ldap.core.support.AggregateDirContextProcessor; + +/** + * AggregateDirContextProcessor implementation for managing a virtual list view + * by aggregating DirContextProcessor implementations for a VirtualListViewControl + * and its required companion SortControl. + * + * @author Mattias Arthursson + * @author Ulrik Sandberg + */ +public class VirtualListViewControlAggregateDirContextProcessor extends AggregateDirContextProcessor { + + private VirtualListViewControlDirContextProcessor vlvProcessor; + + private SortControlDirContextProcessor sortControlProcessor; + + public VirtualListViewControlAggregateDirContextProcessor(String sortKey, int pageSize) { + } +} diff --git a/sandbox/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java b/mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java similarity index 89% rename from sandbox/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java rename to mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java index 26070185..34e6cceb 100644 --- a/sandbox/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java +++ b/mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessor.java @@ -146,6 +146,11 @@ public class VirtualListViewControlDirContextProcessor implements this.responseControlClass = responseControlClass; } + /** + * Set whether the targetOffset should be interpreted as + * percentage of the list or an offset into the list. + * @param isPercentage true if targetOffset is a percentage + */ public void setOffsetPercentage(boolean isPercentage) { this.offsetPercentage = isPercentage; } @@ -189,9 +194,16 @@ public class VirtualListViewControlDirContextProcessor implements try { VirtualListViewControl virtualListViewControl; if (offsetPercentage) { + // Request a view of a portion of the list centered around a + // given target entry. The position of the target entry is + // estimated as a percentage of the list. virtualListViewControl = new VirtualListViewControl( targetOffset, pageSize, CRITICAL_CONTROL); } else { + // Request a view of a portion of the list with the specified + // number of entries before and after a given target entry. The + // target entry is identified by means of an offset into the + // list. virtualListViewControl = new VirtualListViewControl( targetOffset, listSize, 0, pageSize - 1, CRITICAL_CONTROL); @@ -244,11 +256,11 @@ public class VirtualListViewControlDirContextProcessor implements } /** - * Check if the given control matches a paged results response control. + * Check if the given control matches a virtual list view response control. * * @param responseControl * the control to check for a match - * @return whether the control is a paged results response control + * @return whether the control is a virtual list view response control */ private boolean isVirtualListViewResponseControl(Control responseControl) { if (responseControl.getClass().isAssignableFrom(responseControlClass)) { diff --git a/sandbox/src/main/java/org/springframework/ldap/control/VirtualListViewResultsCookie.java b/mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewResultsCookie.java similarity index 100% rename from sandbox/src/main/java/org/springframework/ldap/control/VirtualListViewResultsCookie.java rename to mvn-build/core/src/main/java/org/springframework/ldap/control/VirtualListViewResultsCookie.java diff --git a/mvn-build/core/src/test/java/org/springframework/ldap/control/ControlArrayMatcher.java b/mvn-build/core/src/test/java/org/springframework/ldap/control/ControlArrayMatcher.java new file mode 100644 index 00000000..5b89ea16 --- /dev/null +++ b/mvn-build/core/src/test/java/org/springframework/ldap/control/ControlArrayMatcher.java @@ -0,0 +1,58 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ldap.control; + +import java.util.Arrays; + +import javax.naming.ldap.Control; + +import org.easymock.AbstractMatcher; + +public class ControlArrayMatcher extends AbstractMatcher { + protected boolean argumentMatches(Object expected, Object actual) { + Control[] expectedControls = (Control[]) expected; + Control[] actualControls = (Control[]) actual; + if (expectedControls.length != actualControls.length) { + return false; + } + for (int i = 0; i < actualControls.length; i++) { + Control actualControl = actualControls[i]; + Control expectedControl = expectedControls[i]; + if (actualControl == null && expectedControl != null) { + return false; + } + if (actualControl != null && expectedControl == null) { + return false; + } + if (actualControl == null && expectedControl == null) { + continue; + } + if (!actualControl.getClass().equals(expectedControl.getClass())) { + return false; + } + } + + return true; + } + + protected String argumentToString(Object argument) { + if (argument instanceof Control[]) { + Control[] control = (Control[]) argument; + return Arrays.toString(control); + } + return super.argumentToString(argument); + } +} diff --git a/mvn-build/core/src/test/java/org/springframework/ldap/control/PagedResultTest.java b/mvn-build/core/src/test/java/org/springframework/ldap/control/PagedResultTest.java index e42aa115..bdb9757e 100644 --- a/mvn-build/core/src/test/java/org/springframework/ldap/control/PagedResultTest.java +++ b/mvn-build/core/src/test/java/org/springframework/ldap/control/PagedResultTest.java @@ -18,6 +18,8 @@ package org.springframework.ldap.control; import java.util.LinkedList; import java.util.List; +import javax.naming.ldap.PagedResultsControl; + import org.springframework.ldap.control.PagedResult; import org.springframework.ldap.control.PagedResultsCookie; @@ -25,6 +27,13 @@ import com.gargoylesoftware.base.testing.EqualsTester; import junit.framework.TestCase; +/** + * Unit tests for the PagedResult class. + * {@link PagedResultsControl} + * + * @author Mattias Arthursson + * @author Ulrik Sandberg + */ public class PagedResultTest extends TestCase { public void testEquals() throws Exception { List expectedList = new LinkedList(); diff --git a/mvn-build/core/src/test/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessorTest.java b/mvn-build/core/src/test/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessorTest.java new file mode 100644 index 00000000..e8c1cb08 --- /dev/null +++ b/mvn-build/core/src/test/java/org/springframework/ldap/control/VirtualListViewControlDirContextProcessorTest.java @@ -0,0 +1,286 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ldap.control; + +import java.io.IOException; + +import javax.naming.ldap.Control; +import javax.naming.ldap.LdapContext; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.easymock.MockControl; +import org.springframework.ldap.OperationNotSupportedException; + +import com.sun.jndi.ldap.Ber; +import com.sun.jndi.ldap.BerDecoder; +import com.sun.jndi.ldap.BerEncoder; +import com.sun.jndi.ldap.ctl.SortControl; +import com.sun.jndi.ldap.ctl.VirtualListViewControl; +import com.sun.jndi.ldap.ctl.VirtualListViewResponseControl; + +/** + * Unit tests for the VirtualListViewControlDirContextProcessor class. + * + * @author Ulrik Sandberg + */ +public class VirtualListViewControlDirContextProcessorTest extends TestCase { + + private static final String OID_REQUEST = "2.16.840.1.113730.3.4.9"; + + private static final String OID_RESPONSE = "2.16.840.1.113730.3.4.10"; + + private MockControl ldapContextControl; + + private LdapContext ldapContextMock; + + protected void setUp() throws Exception { + super.setUp(); + + // Create ldapContext mock + ldapContextControl = MockControl.createControl(LdapContext.class); + ldapContextMock = (LdapContext) ldapContextControl.getMock(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + + ldapContextControl = null; + ldapContextMock = null; + } + + protected void replay() { + ldapContextControl.replay(); + } + + protected void verify() { + ldapContextControl.verify(); + } + + public void testPreProcess() throws Exception { + final VirtualListViewControl control = new VirtualListViewControl(0, 3, + true); + int pageSize = 5; + VirtualListViewControlDirContextProcessor tested = new VirtualListViewControlDirContextProcessor( + pageSize) { + public Control createRequestControl() { + return control; + } + }; + + ldapContextControl.expectAndReturn( + ldapContextMock.getRequestControls(), new Control[0]); + + SortControl sortControl = new SortControl(new String[] { "cn" }, true); + VirtualListViewControl vlvControl = new VirtualListViewControl(0, 0, 0, + 0, true); + + Control[] controls = new Control[] { sortControl, vlvControl }; + ldapContextMock.setRequestControls(controls); + // just check that class names match + ldapContextControl.setMatcher(new ControlArrayMatcher()); + + replay(); + + tested.preProcess(ldapContextMock); + + verify(); + } + + public void testCreateRequestControlWithTargetAsOffset() throws Exception { + int pageSize = 5; + int targetOffset = 25; + int listSize = 1000; + VirtualListViewControlDirContextProcessor tested = new VirtualListViewControlDirContextProcessor( + pageSize, targetOffset, listSize, + new VirtualListViewResultsCookie(new byte[0], 0, 0)); + VirtualListViewControl result = (VirtualListViewControl) tested + .createRequestControl(); + assertNotNull(result); + assertEquals(OID_REQUEST, result.getID()); + + // verify that the values have been encoded as we expect + int expectedBeforeCount = 0; + int expectedAfterCount = 4; + int expectedOffset = 25; + int expectedContentCount = listSize; + assertEncodedRequest(result.getEncodedValue(), expectedBeforeCount, + expectedAfterCount, expectedOffset, expectedContentCount, + new byte[0]); + } + + public void testCreateRequestControlWithTargetAsPercentage() + throws Exception { + int pageSize = 5; + int targetPercentage = 25; + int listSize = 1000; + VirtualListViewControlDirContextProcessor tested = new VirtualListViewControlDirContextProcessor( + pageSize, targetPercentage, listSize, + new VirtualListViewResultsCookie(new byte[0], 0, 0)); + tested.setOffsetPercentage(true); + VirtualListViewControl result = (VirtualListViewControl) tested + .createRequestControl(); + assertNotNull(result); + assertEquals(OID_REQUEST, result.getID()); + + int expectedBeforeCount = 2; + int expectedAfterCount = 2; + // interestingly, it seems rather than calculate what 25% of 1000 is, + // the VLVControl requests 25 out of an expected 100 + int expectedOffset = 25; + int expectedContentCount = 100; + assertEncodedRequest(result.getEncodedValue(), expectedBeforeCount, + expectedAfterCount, expectedOffset, expectedContentCount, + new byte[0]); + } + + public void testPostProcess() throws Exception { + int pageSize = 5; + int targetOffset = 25; + int listSize = 1000; + VirtualListViewControlDirContextProcessor tested = new VirtualListViewControlDirContextProcessor( + pageSize, targetOffset, listSize, + new VirtualListViewResultsCookie(new byte[0], 0, 0)); + + int virtualListViewResult = 53; // unwilling to perform + byte[] encoded = encodeResponseValue(10, listSize, + virtualListViewResult); + VirtualListViewResponseControl control = new VirtualListViewResponseControl( + OID_RESPONSE, false, encoded); + ldapContextControl.expectAndDefaultReturn(ldapContextMock + .getResponseControls(), new Control[] { control }); + + replay(); + + try { + tested.postProcess(ldapContextMock); + fail("OperationNotSupportedException expected"); + } + catch (OperationNotSupportedException expected) { + Throwable cause = expected.getCause(); + assertEquals(javax.naming.OperationNotSupportedException.class, + cause.getClass()); + assertEquals("[LDAP: error code 53 - Unwilling To Perform]", cause + .getMessage()); + } + verify(); + assertNotNull(tested.getCookie()); + assertEquals(0, tested.getCookie().getCookie().length); + } + + public void testBerDecoding() throws Exception { + int virtualListViewResult = 53; // unwilling to perform + byte[] encoded = encodeResponseValue(10, 1000, virtualListViewResult); + + int expectedLength = 14; + assertEncodedResponse(encoded, expectedLength, 10, 1000, 53, + new byte[0]); + } + + private byte[] encodeResponseValue(int targetPosition, int contentCount, + int virtualListViewResult) throws IOException { + + // build the ASN.1 encoding + BerEncoder ber = new BerEncoder(10); + + ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR); + ber.encodeInt(targetPosition); // list offset for the target entry + ber.encodeInt(contentCount); // server's estimate of the current + // number of entries in the list + ber.encodeInt(virtualListViewResult, Ber.ASN_ENUMERATED); + ber.encodeOctetString(new byte[0], Ber.ASN_OCTET_STR); + ber.endSeq(); + + return ber.getTrimmedBuf(); + } + + private void assertEncodedRequest(byte[] encodedValue, + int expectedBeforeCount, int expectedAfterCount, + int expectedOffset, int expectedContentCount, + byte[] expectedContextId) throws Exception { + dumpEncodedValue("VirtualListViewRequest\n", encodedValue); + BerDecoder ber = new BerDecoder(encodedValue, 0, encodedValue.length); + ber.parseSeq(null); + + int actualBeforeCount = ber.parseInt(); + int actualAfterCount = ber.parseInt(); + byte targetType = (byte) ber.parseByte(); + targetType <<= 3; // skip highest three bits + targetType >>= 3; + ber.parseLength(); // ignore + switch (targetType) { + case 0: // byOffset + int actualOffset = ber.parseInt(); + int actualContentCount = ber.parseInt(); + assertEquals("beforeCount,", expectedBeforeCount, actualBeforeCount); + assertEquals("afterCount,", expectedAfterCount, actualAfterCount); + assertEquals("offset,", expectedOffset, actualOffset); + assertEquals("contentCount,", expectedContentCount, + actualContentCount); + break; + + case 1: // greaterThanOrEqual + throw new AssertionFailedError( + "CHOICE value greaterThanOrEqual not supported"); + + default: + throw new AssertionFailedError("illegal CHOICE value: " + + targetType); + } + byte[] bs = ber.parseOctetString(Ber.ASN_OCTET_STR, null); + assertContextId(expectedContextId, bs); + } + + private void assertContextId(byte[] expectedContextId, + byte[] actualContextId) { + if (expectedContextId == null && actualContextId == null) { + return; + } + if (expectedContextId == null && actualContextId != null) { + fail("expected , got <" + actualContextId + ">"); + } + if (expectedContextId != null && actualContextId == null) { + fail("expected <" + expectedContextId + ">, got "); + } + assertEquals(expectedContextId.length, actualContextId.length); + } + + private void assertEncodedResponse(byte[] encodedValue, + int expectedEncodingLength, int expectedTargetPosition, + int expectedContentCount, int expectedVirtualListViewResult, + byte[] expectedContextId) throws Exception { + dumpEncodedValue("VirtualListViewResponse\n", encodedValue); + assertEquals(expectedEncodingLength, encodedValue.length); + BerDecoder ber = new BerDecoder(encodedValue, 0, encodedValue.length); + ber.parseSeq(null); + + int actualTargetPosition = ber.parseInt(); + int actualContentCount = ber.parseInt(); + int actualVirtualListViewResult = ber.parseEnumeration(); + assertEquals("targetPosition,", expectedTargetPosition, + actualTargetPosition); + assertEquals("contentCount,", expectedContentCount, actualContentCount); + assertEquals("virtualListViewResult,", expectedVirtualListViewResult, + actualVirtualListViewResult); + byte[] bs = ber.parseOctetString(Ber.ASN_OCTET_STR, null); + assertContextId(expectedContextId, bs); + } + + private void dumpEncodedValue(String message, byte[] encodedValue) { + Ber.dumpBER(System.out, message, encodedValue, 0, encodedValue.length); + } +} diff --git a/sandbox/.springBeans b/sandbox/.springBeans index c45e28d1..d5aef395 100644 --- a/sandbox/.springBeans +++ b/sandbox/.springBeans @@ -1,35 +1,34 @@ - - - - xml - - - src/iutest/conf/ldapTemplateBaseSuffixTestContext.xml - src/iutest/conf/ldapTemplateTestContext.xml - - - - iutest with base - false - false - - src/iutest/conf/ldapTemplateBaseSuffixTestContext.xml - - - - iutesttransactions - false - false - - - - - iutest - false - false - - src/iutest/conf/ldapTemplateTestContext.xml - - - - + + + 1 + + + + + + + + + + + false + false + + + + + + false + false + + + + + + false + false + + + + + diff --git a/sandbox/src/main/java/org/springframework/ldap/control/DummyVLVDirContextProcessor.java b/sandbox/src/main/java/org/springframework/ldap/control/DummyVLVDirContextProcessor.java deleted file mode 100644 index 64e9cdcd..00000000 --- a/sandbox/src/main/java/org/springframework/ldap/control/DummyVLVDirContextProcessor.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.springframework.ldap.control; - -import org.springframework.ldap.core.support.AggregateDirContextProcessor; - -public class DummyVLVDirContextProcessor extends AggregateDirContextProcessor { - - private VirtualListViewControlDirContextProcessor vlvProcessor; - - private SortControlDirContextProcessor sortControlProcessor; - - public DummyVLVDirContextProcessor(String sortKey, int pageSize) { - } -}