diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClient.java b/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClient.java index cc20a0139cf..4e9db964914 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClient.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClient.java @@ -41,7 +41,11 @@ public class ManagedClient extends ManagedTestResource { configBuilder = update.update(configBuilder); } - admin().update(configBuilder.build()); + ClientRepresentation updated = configBuilder.build(); + admin().update(updated); + + ClientRepresentation original = cleanup().getOriginalRepresentation(); + updated.getAttributes().keySet().stream().filter(k -> !original.getAttributes().containsKey(k)).forEach(k -> original.getAttributes().put(k, "")); } public ManagedClientCleanup cleanup() { diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClientCleanup.java b/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClientCleanup.java index 47f75d9c939..ac871ee2456 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClientCleanup.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/realm/ManagedClientCleanup.java @@ -22,6 +22,11 @@ public class ManagedClientCleanup { } } + ClientRepresentation getOriginalRepresentation() { + ResetClient clientCleanup = (ResetClient) cleanupTasks.stream().filter(c -> c instanceof ResetClient).findFirst().orElse(null); + return clientCleanup != null ? clientCleanup.rep() : null; + } + void runCleanupTasks(ClientResource client) { cleanupTasks.forEach(t -> t.cleanup(client)); cleanupTasks.clear(); diff --git a/test-framework/examples/tests/src/test/java/org/keycloak/test/examples/ClientRollbackTest.java b/test-framework/examples/tests/src/test/java/org/keycloak/test/examples/ClientRollbackTest.java new file mode 100644 index 00000000000..47e1f576f62 --- /dev/null +++ b/test-framework/examples/tests/src/test/java/org/keycloak/test/examples/ClientRollbackTest.java @@ -0,0 +1,45 @@ +package org.keycloak.test.examples; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.testframework.annotations.InjectClient; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.realm.ClientConfig; +import org.keycloak.testframework.realm.ClientConfigBuilder; +import org.keycloak.testframework.realm.ManagedClient; + +@KeycloakIntegrationTest +@TestMethodOrder(MethodOrderer.MethodName.class) +public class ClientRollbackTest { + + @InjectClient(config = ClientWithSingleAttribute.class) + ManagedClient client; + + @Test + public void testAddAttributeWithRollback() { + client.updateWithCleanup(u -> u.attribute("one", "two").attribute("two", "two")); + + ClientRepresentation rep = client.admin().toRepresentation(); + Assertions.assertEquals("two", rep.getAttributes().get("one")); + Assertions.assertTrue(rep.getAttributes().containsKey("two")); + } + + @Test + public void testAttributeNotSet() { + ClientRepresentation rep = client.admin().toRepresentation(); + Assertions.assertEquals("one", rep.getAttributes().get("one")); + Assertions.assertFalse(rep.getAttributes().containsKey("two")); + } + + public static class ClientWithSingleAttribute implements ClientConfig { + + @Override + public ClientConfigBuilder configure(ClientConfigBuilder client) { + return client.attribute("one", "one"); + } + + } +}