[#1023] Delete every objectClass value a modification asks for (#1024)
| | |
| | | return true; |
| | | } |
| | | |
| | | boolean allSuccessful = true; |
| | | // The objectClass attribute is present as soon as the entry has an object class: a value of |
| | | // the modification which the entry does not have is a missing value, not an absent attribute. |
| | | boolean attributeTypePresent = !objectClasses.isEmpty(); |
| | | |
| | | MatchingRule rule = attrType.getEqualityMatchingRule(); |
| | | for (ByteString v : attribute) |
| | | { |
| | | String ocName = toLowerName(rule, v); |
| | | |
| | | boolean matchFound = false; |
| | | for (ObjectClass oc : objectClasses.keySet()) |
| | | { |
| | | if (oc.hasNameOrOID(ocName)) |
| | | { |
| | | objectClasses.remove(oc); |
| | | return true; |
| | | matchFound = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | allSuccessful = false; |
| | | missingValues.add(v); |
| | | if (!matchFound) |
| | | { |
| | | missingValues.add(v); |
| | | } |
| | | } |
| | | |
| | | return allSuccessful; |
| | | return attributeTypePresent; |
| | | } |
| | | |
| | | private boolean removeNonObjectClassAttribute(Attribute attribute, Collection<? super ByteString> missingValues) |
| | |
| | | |
| | | |
| | | /** |
| | | * Adds the entry the object class deletes below work on: two auxiliary classes which the entry |
| | | * can lose without breaking the schema. |
| | | */ |
| | | private void addUserWithTwoAuxiliaryObjectClasses(String baseDN) throws Exception |
| | | { |
| | | TestCaseUtils.addEntry( |
| | | "dn: uid=test.user," + baseDN, |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "objectClass: uidObject", |
| | | "objectClass: userSecurityInformation", |
| | | "uid: test.user", |
| | | "givenName: Test", |
| | | "sn: User", |
| | | "cn: Test User"); |
| | | } |
| | | |
| | | private void assertObjectClassesAre(String baseDN, String... objectClasses) throws Exception |
| | | { |
| | | Entry e = DirectoryServer.getEntry(DN.valueOf("uid=test.user," + baseDN)); |
| | | assertThat(e.getObjectClasses().values()).containsOnly(objectClasses); |
| | | } |
| | | |
| | | /** |
| | | * A delete of several object class values must remove every one of them, not just the first |
| | | * (see issue #1023). |
| | | */ |
| | | @Test(dataProvider = "baseDNs") |
| | | public void testSuccessRemoveSeveralObjectClassValues(String baseDN) throws Exception |
| | | { |
| | | addUserWithTwoAuxiliaryObjectClasses(baseDN); |
| | | |
| | | RawModification mod = |
| | | newRawModification(DELETE, "objectClass", "uidObject", "userSecurityInformation"); |
| | | ModifyOperation modifyOperation = processModify("uid=test.user," + baseDN, mod); |
| | | assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); |
| | | retrieveSuccessfulOperationElements(modifyOperation); |
| | | |
| | | assertObjectClassesAre(baseDN, "top", "person", "organizationalPerson", "inetOrgPerson"); |
| | | } |
| | | |
| | | /** |
| | | * A delete of several object class values one of which the entry does not have must name that |
| | | * value: the objectClass attribute itself is there, so this is a missing value and not an |
| | | * absent attribute. |
| | | */ |
| | | @Test(dataProvider = "baseDNs") |
| | | public void testFailRemoveSeveralObjectClassValuesOneOfWhichIsMissing(String baseDN) |
| | | throws Exception |
| | | { |
| | | addUserWithTwoAuxiliaryObjectClasses(baseDN); |
| | | |
| | | RawModification mod = newRawModification(DELETE, "objectClass", "uidObject", "domain"); |
| | | ModifyOperation modifyOperation = processModify("uid=test.user," + baseDN, mod); |
| | | assertEquals(modifyOperation.getResultCode(), ResultCode.NO_SUCH_ATTRIBUTE); |
| | | assertThat(modifyOperation.getErrorMessage().toString()).contains("domain"); |
| | | retrieveFailedOperationElements(modifyOperation); |
| | | |
| | | assertObjectClassesAre(baseDN, "top", "person", "organizationalPerson", "inetOrgPerson", |
| | | "uidObject", "userSecurityInformation"); |
| | | } |
| | | |
| | | /** |
| | | * The permissive modify control drops the object class value which the entry does not have, and |
| | | * the values it does have are all removed. |
| | | */ |
| | | @Test(dataProvider = "baseDNs") |
| | | public void testSuccessPermissiveModifyControlRemoveSeveralObjectClassValuesOneMissing( |
| | | String baseDN) throws Exception |
| | | { |
| | | addUserWithTwoAuxiliaryObjectClasses(baseDN); |
| | | |
| | | ModifyRequest modifyRequest = Requests.newModifyRequest("uid=test.user," + baseDN) |
| | | .addModification(DELETE, "objectClass", "uidObject", "domain", "userSecurityInformation") |
| | | .addControl(newControl(OID_PERMISSIVE_MODIFY_CONTROL)); |
| | | ModifyOperation modifyOperation = getRootConnection().processModify(modifyRequest); |
| | | assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); |
| | | retrieveSuccessfulOperationElements(modifyOperation); |
| | | |
| | | assertObjectClassesAre(baseDN, "top", "person", "organizationalPerson", "inetOrgPerson"); |
| | | } |
| | | |
| | | /** |
| | | * Tests the ability to perform a modification that adds an auxiliary |
| | | * objectclass. |
| | | * |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | |
| | | import java.util.HashSet; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | |
| | | TestCaseUtils.startServer(); |
| | | } |
| | | |
| | | /** Returns an entry to delete object class values from. */ |
| | | private Entry newTestUserEntry() throws Exception |
| | | { |
| | | return TestCaseUtils.makeEntry( |
| | | "dn: cn=Test User,ou=People,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "cn: Test User", |
| | | "sn: User"); |
| | | } |
| | | |
| | | /** |
| | | * A delete of several object class values must remove every one of them, the way a delete of |
| | | * several values of any other attribute does. |
| | | */ |
| | | @Test |
| | | public void testRemoveSeveralObjectClassValues() throws Exception |
| | | { |
| | | Entry e = newTestUserEntry(); |
| | | |
| | | List<ByteString> missingValues = new LinkedList<>(); |
| | | assertTrue(e.removeAttribute( |
| | | Attributes.create("objectClass", "organizationalPerson", "inetOrgPerson"), missingValues)); |
| | | |
| | | assertThat(missingValues).isEmpty(); |
| | | assertThat(e.getObjectClasses().values()).containsOnly("top", "person"); |
| | | } |
| | | |
| | | /** |
| | | * A delete of an object class value which the entry does not have must be reported as a missing |
| | | * value, whatever the other values of the same modification are. |
| | | */ |
| | | @Test |
| | | public void testRemoveObjectClassValuesOneOfWhichIsMissing() throws Exception |
| | | { |
| | | Entry e = newTestUserEntry(); |
| | | |
| | | List<ByteString> missingValues = new LinkedList<>(); |
| | | assertTrue(e.removeAttribute( |
| | | Attributes.create("objectClass", "inetOrgPerson", "domain"), missingValues)); |
| | | |
| | | assertThat(missingValues).containsOnly(ByteString.valueOfUtf8("domain")); |
| | | assertThat(e.getObjectClasses().values()).containsOnly("top", "person", "organizationalPerson"); |
| | | } |
| | | |
| | | /** The same, with the missing value first: the walk must not stop at it. */ |
| | | @Test |
| | | public void testRemoveObjectClassValuesTheFirstOfWhichIsMissing() throws Exception |
| | | { |
| | | Entry e = newTestUserEntry(); |
| | | |
| | | List<ByteString> missingValues = new LinkedList<>(); |
| | | assertTrue(e.removeAttribute( |
| | | Attributes.create("objectClass", "domain", "inetOrgPerson"), missingValues)); |
| | | |
| | | assertThat(missingValues).containsOnly(ByteString.valueOfUtf8("domain")); |
| | | assertThat(e.getObjectClasses().values()).containsOnly("top", "person", "organizationalPerson"); |
| | | } |
| | | |
| | | /** |
| | | * Test the {@link Entry#parseAttribute(String)} method. |
| | | */ |