From 828abccb259536427fd416b73469ab18520406d3 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 11 Apr 2013 16:00:03 +0000
Subject: [PATCH] OPENDJ-861: Etag attribute invalid when used in conjunction with pre- and post- read controls
---
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 220 insertions(+), 10 deletions(-)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
index 3d2ab72..0041577 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
@@ -22,18 +22,26 @@
* CDDL HEADER END
*
*
- * Copyright 2012 ForgeRock AS
+ * Copyright 2012-2013 ForgeRock AS
*/
package org.opends.server.extensions;
+import static java.util.Collections.singleton;
+import static java.util.Collections.singletonList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
@@ -46,6 +54,10 @@
import org.opends.server.admin.std.server.EntityTagVirtualAttributeCfg;
import org.opends.server.admin.std.server.VirtualAttributeCfg;
import org.opends.server.controls.LDAPAssertionRequestControl;
+import org.opends.server.controls.LDAPPostReadRequestControl;
+import org.opends.server.controls.LDAPPostReadResponseControl;
+import org.opends.server.controls.LDAPPreReadRequestControl;
+import org.opends.server.controls.LDAPPreReadResponseControl;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.SearchOperation;
@@ -55,7 +67,23 @@
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.schema.DirectoryStringSyntax;
-import org.opends.server.types.*;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ConditionResult;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DereferencePolicy;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.RawAttribute;
+import org.opends.server.types.RawModification;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SearchScope;
+import org.opends.server.types.VirtualAttributeRule;
import org.opends.server.util.StaticUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -68,11 +96,15 @@
public class EntityTagVirtualAttributeProviderTestCase extends
ExtensionsTestCase
{
+ private static final String DESCRIPTION = "description";
+ private static final String ETAG = "etag";
+
private final AttributeValue dummyValue = AttributeValues.create(
ByteString.valueOf("dummy"), ByteString.valueOf("dummy"));
private final EntityTagVirtualAttributeProvider provider = new EntityTagVirtualAttributeProvider();
private boolean changeListenerRemoved = false;
private boolean changeListenerAdded = false;
+
private final EntityTagVirtualAttributeCfg config = new EntityTagVirtualAttributeCfg()
{
private final TreeSet<AttributeType> excludedAttributes = new TreeSet<AttributeType>();
@@ -554,7 +586,7 @@
};
VirtualAttributeRule rule = new VirtualAttributeRule(
- DirectoryServer.getAttributeType("etag"), provider,
+ DirectoryServer.getAttributeType(ETAG), provider,
Collections.<DN> emptySet(), SearchScope.WHOLE_SUBTREE,
Collections.<DN> emptySet(), Collections.<SearchFilter> emptySet(),
VirtualAttributeCfgDefn.ConflictBehavior.REAL_OVERRIDES_VIRTUAL);
@@ -579,8 +611,8 @@
public void testOptimisticConcurrency() throws Exception
{
// Use an internal connection.
- AttributeType etagType = DirectoryServer.getAttributeType("etag");
- AttributeType descrType = DirectoryServer.getAttributeType("description");
+ AttributeType etagType = DirectoryServer.getAttributeType(ETAG);
+ AttributeType descrType = DirectoryServer.getAttributeType(DESCRIPTION);
String userDN = "uid=test.user,ou=People,o=test";
InternalClientConnection conn = InternalClientConnection
.getRootConnection();
@@ -616,11 +648,11 @@
// Apply a change using the assertion control for optimistic concurrency.
List<RawModification> mods = Collections
.<RawModification> singletonList(new LDAPModification(
- ModificationType.REPLACE, RawAttribute.create("description",
+ ModificationType.REPLACE, RawAttribute.create(DESCRIPTION,
"first modify")));
List<Control> ctrls = Collections
.<Control> singletonList(new LDAPAssertionRequestControl(true,
- LDAPFilter.createEqualityFilter("etag", ByteString.valueOf(etag1))));
+ LDAPFilter.createEqualityFilter(ETAG, ByteString.valueOf(etag1))));
ModifyOperation modifyOperation = conn.processModify(userDN, mods, ctrls);
assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
@@ -640,7 +672,7 @@
// Simulate a concurrent update: perform another update using the old etag.
mods = Collections.<RawModification> singletonList(new LDAPModification(
- ModificationType.REPLACE, RawAttribute.create("description",
+ ModificationType.REPLACE, RawAttribute.create(DESCRIPTION,
"second modify")));
modifyOperation = conn.processModify(userDN, mods, ctrls);
assertEquals(modifyOperation.getResultCode(), ResultCode.ASSERTION_FAILED);
@@ -662,12 +694,190 @@
+ /**
+ * Tests that the etag returned with a pre-read control after a modify
+ * operation is correct. See OPENDJ-861.
+ *
+ * @throws Exception
+ * If an unexpected exception occurred.
+ */
+ @Test(enabled = false)
+ public void testPreReadControl() throws Exception
+ {
+ AttributeType etagType = DirectoryServer.getAttributeType(ETAG);
+ AttributeType descrType = DirectoryServer.getAttributeType(DESCRIPTION);
+ String userDN = "uid=test.user,ou=People,o=test";
+
+ // Use an internal connection.
+ InternalClientConnection conn = InternalClientConnection
+ .getRootConnection();
+
+ // Create a test backend containing the user entry to be modified.
+ TestCaseUtils.initializeTestBackend(true);
+
+ // @formatter:off
+ TestCaseUtils.addEntries(
+ "dn: ou=People,o=test",
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: People",
+ "",
+ "dn: uid=test.user,ou=People,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid: test.user",
+ "givenName: Test",
+ "sn: User",
+ "cn: Test User",
+ "userPassword: password",
+ "description: initial value");
+ // @formatter:on
+
+ // Read the user entry and get the etag.
+ Entry e1 = readEntry(conn, userDN);
+ String etag1 = e1
+ .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
+ assertNotNull(etag1);
+
+ // Apply a change using the pre and post read controls.
+ List<RawModification> mods = Collections
+ .<RawModification> singletonList(new LDAPModification(
+ ModificationType.REPLACE, RawAttribute.create(DESCRIPTION,
+ "modified value")));
+ List<Control> ctrls = singletonList((Control) new LDAPPreReadRequestControl(
+ true, singleton(ETAG)));
+ ModifyOperation modifyOperation = conn.processModify(userDN, mods, ctrls);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+ // Reread the entry and check that the description has been added and that
+ // the etag has changed.
+ Entry e2 = readEntry(conn, userDN);
+
+ String etag2 = e2
+ .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
+ assertNotNull(etag2);
+ assertFalse(etag1.equals(etag2));
+
+ String description2 = e2.getAttributeValue(descrType,
+ DirectoryStringSyntax.DECODER);
+ assertNotNull(description2);
+ assertEquals(description2, "modified value");
+
+ // Now check that the pre-read is the same as the initial etag.
+ LDAPPreReadResponseControl preReadControl = null;
+ for (Control control : modifyOperation.getResponseControls())
+ {
+ if (control instanceof LDAPPreReadResponseControl)
+ {
+ preReadControl = (LDAPPreReadResponseControl) control;
+ break;
+ }
+ }
+ assertNotNull(preReadControl);
+ String etagPreRead = preReadControl.getSearchEntry().getAttributeValue(
+ etagType, DirectoryStringSyntax.DECODER);
+ assertEquals(etagPreRead, etag1);
+ }
+
+
+
+ /**
+ * Tests that the etag returned with a post-read control after a modify
+ * operation is correct. See OPENDJ-861.
+ *
+ * @throws Exception
+ * If an unexpected exception occurred.
+ */
+ @Test(enabled = false)
+ public void testPostReadControl() throws Exception
+ {
+ AttributeType etagType = DirectoryServer.getAttributeType(ETAG);
+ AttributeType descrType = DirectoryServer.getAttributeType(DESCRIPTION);
+ String userDN = "uid=test.user,ou=People,o=test";
+
+ // Use an internal connection.
+ InternalClientConnection conn = InternalClientConnection
+ .getRootConnection();
+
+ // Create a test backend containing the user entry to be modified.
+ TestCaseUtils.initializeTestBackend(true);
+
+ // @formatter:off
+ TestCaseUtils.addEntries(
+ "dn: ou=People,o=test",
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: People",
+ "",
+ "dn: uid=test.user,ou=People,o=test",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid: test.user",
+ "givenName: Test",
+ "sn: User",
+ "cn: Test User",
+ "userPassword: password",
+ "description: initial value");
+ // @formatter:on
+
+ // Read the user entry and get the etag.
+ Entry e1 = readEntry(conn, userDN);
+ String etag1 = e1
+ .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
+ assertNotNull(etag1);
+
+ // Apply a change using the pre and post read controls.
+ List<RawModification> mods = Collections
+ .<RawModification> singletonList(new LDAPModification(
+ ModificationType.REPLACE, RawAttribute.create(DESCRIPTION,
+ "modified value")));
+ List<Control> ctrls = singletonList((Control) new LDAPPostReadRequestControl(
+ true, singleton(ETAG)));
+ ModifyOperation modifyOperation = conn.processModify(userDN, mods, ctrls);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+ // Reread the entry and check that the description has been added and that
+ // the etag has changed.
+ Entry e2 = readEntry(conn, userDN);
+
+ String etag2 = e2
+ .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
+ assertNotNull(etag2);
+ assertFalse(etag1.equals(etag2));
+
+ String description2 = e2.getAttributeValue(descrType,
+ DirectoryStringSyntax.DECODER);
+ assertNotNull(description2);
+ assertEquals(description2, "modified value");
+
+ // Now check that the post-read is the same as the initial etag.
+ LDAPPostReadResponseControl postReadControl = null;
+ for (Control control : modifyOperation.getResponseControls())
+ {
+ if (control instanceof LDAPPostReadResponseControl)
+ {
+ postReadControl = (LDAPPostReadResponseControl) control;
+ break;
+ }
+ }
+ assertNotNull(postReadControl);
+ String etagPostRead = postReadControl.getSearchEntry().getAttributeValue(
+ etagType, DirectoryStringSyntax.DECODER);
+ assertEquals(etagPostRead, etag1);
+ }
+
+
+
private Entry readEntry(InternalClientConnection conn, String userDN)
throws DirectoryException
{
LinkedHashSet<String> attrList = new LinkedHashSet<String>(2);
attrList.add("*");
- attrList.add("etag");
+ attrList.add(ETAG);
InternalSearchOperation searchOperation = conn.processSearch(userDN,
SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0,
false, "(objectClass=*)", attrList);
--
Gitblit v1.10.0