/*
|
* The contents of this file are subject to the terms of the Common Development and
|
* Distribution License (the License). You may not use this file except in compliance with the
|
* License.
|
*
|
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
|
* specific language governing permission and limitations under the License.
|
*
|
* When distributing Covered Software, include this CDDL Header Notice in each file and include
|
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
|
* Header, with the fields enclosed by brackets [] replaced by your own identifying
|
* information: "Portions Copyright [year] [name of copyright owner]".
|
*
|
* Copyright 2025 3A Systems, LLC.
|
*/
|
package org.openidentityplatform.opendj;
|
|
|
import com.forgerock.opendj.ldap.extensions.EndTransactionExtendedRequest;
|
import com.forgerock.opendj.ldap.extensions.EndTransactionExtendedResult;
|
import com.forgerock.opendj.ldap.extensions.StartTransactionExtendedRequest;
|
import org.forgerock.opendj.ldap.*;
|
import org.forgerock.opendj.ldap.controls.TransactionSpecificationRequestControl;
|
import org.forgerock.opendj.ldap.requests.*;
|
import com.forgerock.opendj.ldap.extensions.StartTransactionExtendedResult;
|
import org.forgerock.opendj.ldap.responses.Result;
|
import org.opends.server.DirectoryServerTestCase;
|
import org.opends.server.TestCaseUtils;
|
import org.testng.Assert;
|
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.Test;
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.forgerock.opendj.ldap.requests.Requests.newAddRequest;
|
import static org.testng.Assert.assertThrows;
|
|
@Test(sequential = true)
|
public class Rfc5808TestCase extends DirectoryServerTestCase {
|
Connection connection;
|
|
@BeforeClass
|
public void startServer() throws Exception {
|
TestCaseUtils.startServer();
|
TestCaseUtils.initializeTestBackend(true);
|
|
final LDAPConnectionFactory factory =new LDAPConnectionFactory("localhost", TestCaseUtils.getServerLdapPort());
|
connection = factory.getConnection();
|
connection.bind("cn=Directory Manager", "password".toCharArray());
|
assertThat(connection.isValid()).isTrue();
|
}
|
|
@Test
|
public void test() throws LdapException {
|
//unknown transaction in TransactionSpecificationRequestControl
|
assertThrows(CancelledResultException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
AddRequest add=Requests
|
.newAddRequest("ou=People,o=test")
|
.addAttribute("objectClass", "top", "organizationalUnit")
|
.addAttribute("ou", "People")
|
.addControl(new TransactionSpecificationRequestControl("bad"))
|
;
|
Result result = connection.add(add);
|
}
|
});
|
|
//unknown transaction in EndTransactionExtendedRequest
|
assertThrows(CancelledResultException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID("unknown").setCommit(true));
|
}
|
});
|
assertThrows(CancelledResultException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID("unknown"));
|
}
|
});
|
|
//commit
|
StartTransactionExtendedResult resStart=connection.extendedRequest(new StartTransactionExtendedRequest());
|
assertThat(resStart.isSuccess()).isTrue();
|
assertThat(resStart.getOID()).isEqualTo("1.3.6.1.1.21.1");
|
String transactionID=resStart.getTransactionID();
|
assertThat(transactionID).isNotEmpty();
|
|
AddRequest add=Requests
|
.newAddRequest("ou=People,o=test")
|
.addAttribute("objectClass", "top", "organizationalUnit")
|
.addAttribute("ou", "People")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
Result result = connection.add(add);
|
assertThat(result.isSuccess()).isTrue();
|
|
add= Requests.newAddRequest("sn=bjensen,ou=People,o=test")
|
.addAttribute("objectClass","top","person")
|
.addAttribute("cn","bjensen")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.add(add);
|
assertThat(result.isSuccess()).isTrue();
|
|
ModifyDNRequest mdn=Requests.newModifyDNRequest("sn=bjensen,ou=People,o=test","sn=bjensen2")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.modifyDN(mdn);
|
assertThat(result.isSuccess()).isTrue();
|
|
ModifyRequest edit= Requests.newModifyRequest("sn=bjensen2,ou=People,o=test")
|
.addModification(ModificationType.REPLACE,"cn","bjensen2")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.modify(edit);
|
assertThat(result.isSuccess()).isTrue();
|
|
DeleteRequest delete=Requests.newDeleteRequest("sn=bjensen2,ou=People,o=test")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.delete(delete);
|
assertThat(result.isSuccess()).isTrue();
|
|
assertThrows(EntryNotFoundException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
connection.searchSingleEntry("o=test",SearchScope.SINGLE_LEVEL,"(ou=People)");
|
}
|
});
|
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID(transactionID));
|
assertThat(resEnd.isSuccess()).isTrue();
|
assertThat(resEnd.getOID()).isEqualTo("1.3.6.1.1.21.3");
|
|
//check commit successfully
|
assertThat(connection.searchSingleEntry("o=test",SearchScope.SINGLE_LEVEL,"(ou=People)")).isNotNull();
|
|
//check transaction finished
|
String finalTransactionID = transactionID;
|
assertThrows(CancelledResultException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID(finalTransactionID).setCommit(true));
|
}
|
});
|
|
//rollback by EndTransactionExtendedRequest
|
resStart=connection.extendedRequest(new StartTransactionExtendedRequest());
|
assertThat(resStart.isSuccess()).isTrue();
|
assertThat(resStart.getOID()).isEqualTo("1.3.6.1.1.21.1");
|
transactionID=resStart.getTransactionID();
|
assertThat(transactionID).isNotEmpty();
|
|
add=Requests
|
.newAddRequest("ou=People2,o=test")
|
.addAttribute("objectClass", "top", "organizationalUnit")
|
.addAttribute("ou", "People2")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.add(add);
|
assertThat(result.isSuccess()).isTrue();
|
|
resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID(transactionID).setCommit(false));
|
assertThat(resEnd.isSuccess()).isTrue();
|
assertThat(resEnd.getOID()).isEqualTo("1.3.6.1.1.21.3");
|
|
//check transaction finished
|
String finalTransactionID1 = transactionID;
|
assertThrows(CancelledResultException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID(finalTransactionID1).setCommit(false));
|
}
|
});
|
|
//check rollback successfully
|
assertThrows(EntryNotFoundException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
connection.searchSingleEntry("o=test",SearchScope.SINGLE_LEVEL,"(ou=People2)");
|
}
|
});
|
|
//rollback by error
|
resStart=connection.extendedRequest(new StartTransactionExtendedRequest());
|
assertThat(resStart.isSuccess()).isTrue();
|
assertThat(resStart.getOID()).isEqualTo("1.3.6.1.1.21.1");
|
transactionID=resStart.getTransactionID();
|
assertThat(transactionID).isNotEmpty();
|
|
add= Requests.newAddRequest("sn=bjensen0,ou=People,o=test")
|
.addAttribute("objectClass","top","person")
|
.addAttribute("cn","bjensen0")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.add(add);
|
assertThat(result.isSuccess()).isTrue();
|
|
add= Requests.newAddRequest("sn=bjensen,ou=People,o=test")
|
.addAttribute("objectClass","top","person")
|
.addAttribute("cn","bjensen")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.add(add);
|
assertThat(result.isSuccess()).isTrue();
|
|
mdn=Requests.newModifyDNRequest("sn=bjensen,ou=People,o=test","sn=bjensen2")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.modifyDN(mdn);
|
assertThat(result.isSuccess()).isTrue();
|
|
edit= Requests.newModifyRequest("sn=bjensen2,ou=People,o=test")
|
.addModification(ModificationType.REPLACE,"cn","bjensen2")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.modify(edit);
|
assertThat(result.isSuccess()).isTrue();
|
|
delete=Requests.newDeleteRequest("sn=bjensen2,ou=People,o=test")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.delete(delete);
|
assertThat(result.isSuccess()).isTrue();
|
|
delete=Requests.newDeleteRequest("sn=bjensen3,ou=People,o=test")
|
.addControl(new TransactionSpecificationRequestControl(transactionID))
|
;
|
result = connection.delete(delete);
|
assertThat(result.isSuccess()).isTrue();
|
|
String finalTransactionID3 = transactionID;
|
assertThrows(EntryNotFoundException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID(finalTransactionID3).setCommit(true));
|
}
|
});
|
|
//check transaction finished
|
String finalTransactionID2 = transactionID;
|
assertThrows(CancelledResultException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
EndTransactionExtendedResult resEnd=connection.extendedRequest(new EndTransactionExtendedRequest().setTransactionID(finalTransactionID2).setCommit(false));
|
}
|
});
|
|
//check rollback successfully
|
assertThrows(EntryNotFoundException.class, new Assert.ThrowingRunnable() {
|
@Override
|
public void run() throws Throwable {
|
connection.searchSingleEntry("ou=People,o=test",SearchScope.SINGLE_LEVEL,"(cn=bjensen0)");
|
}
|
});
|
|
}
|
}
|