[KEYCLOAK-13572] Doesn't observe After events due to assume check

This commit is contained in:
Martin Bartos 2020-03-27 10:04:23 +01:00 committed by Marek Posolda
parent 66c7ec6b08
commit 7ebdca48d3
7 changed files with 78 additions and 17 deletions

View file

@ -18,7 +18,26 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Repeatable(DisableFeatures.class) @Repeatable(DisableFeatures.class)
@Inherited @Inherited
public @interface DisableFeature { public @interface DisableFeature {
/**
* Feature, which should be disabled.
*/
Profile.Feature value(); Profile.Feature value();
/**
* The feature will be disabled without restarting of a server.
*/
boolean skipRestart() default false; boolean skipRestart() default false;
/**
* The feature will be disabled only if the `product` profile is activated
*/
boolean onlyForProduct() default false; boolean onlyForProduct() default false;
/**
* Feature disable should be the last action in @Before context.
* If the test halted, the feature is returned to the previous state.
* If it's false, feature will be disabled before @Before method.
*/
boolean executeAsLast() default true;
} }

View file

@ -18,7 +18,26 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Repeatable(EnableFeatures.class) @Repeatable(EnableFeatures.class)
@Inherited @Inherited
public @interface EnableFeature { public @interface EnableFeature {
/**
* Feature, which should be enabled.
*/
Profile.Feature value(); Profile.Feature value();
/**
* The feature will be enabled without restarting of a server.
*/
boolean skipRestart() default false; boolean skipRestart() default false;
/**
* The feature will be enabled only if the `product` profile is activated
*/
boolean onlyForProduct() default false; boolean onlyForProduct() default false;
/**
* Feature enable should be the last action in @Before context.
* If the test halted, the feature is returned to the previous state.
* If it's false, feature will be enabled before @Before method.
*/
boolean executeAsLast() default true;
} }

View file

@ -144,14 +144,14 @@ public class KeycloakContainerFeaturesController {
private void checkAnnotatedElementForFeatureAnnotations(AnnotatedElement annotatedElement, State state) throws Exception { private void checkAnnotatedElementForFeatureAnnotations(AnnotatedElement annotatedElement, State state) throws Exception {
List<UpdateFeature> updateFeatureList = new ArrayList<>(0); List<UpdateFeature> updateFeatureList = new ArrayList<>(0);
if (annotatedElement.isAnnotationPresent(EnableFeatures.class) || annotatedElement.isAnnotationPresent(EnableFeature.class)) { if (isEnableFeature(annotatedElement)) {
updateFeatureList.addAll(Arrays.stream(annotatedElement.getAnnotationsByType(EnableFeature.class)) updateFeatureList.addAll(Arrays.stream(annotatedElement.getAnnotationsByType(EnableFeature.class))
.map(annotation -> new UpdateFeature(annotation.value(), annotation.skipRestart(), .map(annotation -> new UpdateFeature(annotation.value(), annotation.skipRestart(),
state == State.BEFORE ? FeatureAction.ENABLE : FeatureAction.DISABLE, annotation.onlyForProduct())) state == State.BEFORE ? FeatureAction.ENABLE : FeatureAction.DISABLE, annotation.onlyForProduct()))
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
if (annotatedElement.isAnnotationPresent(DisableFeatures.class) || annotatedElement.isAnnotationPresent(DisableFeature.class)) { if (isDisableFeature(annotatedElement)) {
updateFeatureList.addAll(Arrays.stream(annotatedElement.getAnnotationsByType(DisableFeature.class)) updateFeatureList.addAll(Arrays.stream(annotatedElement.getAnnotationsByType(DisableFeature.class))
.map(annotation -> new UpdateFeature(annotation.value(), annotation.skipRestart(), .map(annotation -> new UpdateFeature(annotation.value(), annotation.skipRestart(),
state == State.BEFORE ? FeatureAction.DISABLE : FeatureAction.ENABLE, annotation.onlyForProduct())) state == State.BEFORE ? FeatureAction.DISABLE : FeatureAction.ENABLE, annotation.onlyForProduct()))
@ -163,12 +163,44 @@ public class KeycloakContainerFeaturesController {
} }
} }
private boolean isEnableFeature(AnnotatedElement annotatedElement) {
return (annotatedElement.isAnnotationPresent(EnableFeatures.class) || annotatedElement.isAnnotationPresent(EnableFeature.class));
}
private boolean isDisableFeature(AnnotatedElement annotatedElement) {
return (annotatedElement.isAnnotationPresent(DisableFeatures.class) || annotatedElement.isAnnotationPresent(DisableFeature.class));
}
private boolean shouldExecuteAsLast(AnnotatedElement annotatedElement) {
if (isEnableFeature(annotatedElement)) {
return Arrays.stream(annotatedElement.getAnnotationsByType(EnableFeature.class))
.anyMatch(EnableFeature::executeAsLast);
}
if (isDisableFeature(annotatedElement)) {
return Arrays.stream(annotatedElement.getAnnotationsByType(DisableFeature.class))
.anyMatch(DisableFeature::executeAsLast);
}
return false;
}
public void handleEnableFeaturesAnnotationBeforeClass(@Observes(precedence = 1) BeforeClass event) throws Exception { public void handleEnableFeaturesAnnotationBeforeClass(@Observes(precedence = 1) BeforeClass event) throws Exception {
checkAnnotatedElementForFeatureAnnotations(event.getTestClass().getJavaClass(), State.BEFORE); checkAnnotatedElementForFeatureAnnotations(event.getTestClass().getJavaClass(), State.BEFORE);
} }
public void handleEnableFeaturesAnnotationBeforeTest(@Observes(precedence = 1) Before event) throws Exception { public void handleEnableFeaturesAnnotationBeforeTest(@Observes(precedence = 1) Before event) throws Exception {
checkAnnotatedElementForFeatureAnnotations(event.getTestMethod(), State.BEFORE); if (!shouldExecuteAsLast(event.getTestMethod())) {
checkAnnotatedElementForFeatureAnnotations(event.getTestMethod(), State.BEFORE);
}
}
// KEYCLOAK-13572 Precedence is too low in order to ensure the feature change will be executed as last.
// If some fail occurs in @Before method, the feature doesn't change its state.
public void handleChangeStateFeaturePriorityBeforeTest(@Observes(precedence = -100) Before event) throws Exception {
if (shouldExecuteAsLast(event.getTestMethod())) {
checkAnnotatedElementForFeatureAnnotations(event.getTestMethod(), State.BEFORE);
}
} }
public void handleEnableFeaturesAnnotationAfterTest(@Observes(precedence = 2) After event) throws Exception { public void handleEnableFeaturesAnnotationAfterTest(@Observes(precedence = 2) After event) throws Exception {

View file

@ -131,7 +131,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
} }
@Test @Test
@EnableFeature(value = Profile.Feature.UPLOAD_SCRIPTS) // This requires also SCRIPTS feature, therefore we need to restart container @EnableFeature(value = Profile.Feature.UPLOAD_SCRIPTS, skipRestart = true) // This requires also SCRIPTS feature, therefore we need to restart container
public void testTokenScriptMapping() { public void testTokenScriptMapping() {
{ {
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app"); ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");

View file

@ -18,7 +18,6 @@ package org.keycloak.testsuite.script;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.keycloak.common.Profile.Feature.SCRIPTS; import static org.keycloak.common.Profile.Feature.SCRIPTS;
import static org.keycloak.common.Profile.Feature.UPLOAD_SCRIPTS;
import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT; import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
import java.io.IOException; import java.io.IOException;
@ -35,7 +34,6 @@ import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
@ -51,7 +49,6 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.provider.ScriptProviderDescriptor; import org.keycloak.representations.provider.ScriptProviderDescriptor;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.arquillian.annotation.DisableFeature; import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature; import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.forms.AbstractFlowTest; import org.keycloak.testsuite.forms.AbstractFlowTest;
@ -66,7 +63,7 @@ import org.keycloak.util.JsonSerialization;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
@EnableFeature(SCRIPTS) @EnableFeature(value = SCRIPTS, skipRestart = true)
public class DeployedScriptAuthenticatorTest extends AbstractFlowTest { public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
public static final String EXECUTION_ID = "scriptAuth"; public static final String EXECUTION_ID = "scriptAuth";
@ -210,7 +207,7 @@ public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
} }
@Test @Test
@DisableFeature(SCRIPTS) @DisableFeature(value = SCRIPTS, executeAsLast = false, skipRestart = true)
public void testScriptAuthenticatorNotAvailable() { public void testScriptAuthenticatorNotAvailable() {
assertFalse(testRealm().flows().getAuthenticatorProviders().stream().anyMatch( assertFalse(testRealm().flows().getAuthenticatorProviders().stream().anyMatch(
provider -> ScriptBasedAuthenticatorFactory.PROVIDER_ID.equals(provider.get("id")))); provider -> ScriptBasedAuthenticatorFactory.PROVIDER_ID.equals(provider.get("id"))));

View file

@ -102,7 +102,7 @@ public class DeployedScriptMapperTest extends AbstractTestRealmKeycloakTest {
} }
@Test @Test
@EnableFeature(SCRIPTS) @EnableFeature(value = SCRIPTS, skipRestart = true, executeAsLast = false)
public void testTokenScriptMapping() { public void testTokenScriptMapping() {
{ {
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app"); ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");

View file

@ -16,8 +16,6 @@
*/ */
package org.keycloak.testsuite.script; package org.keycloak.testsuite.script;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.keycloak.common.Profile.Feature.SCRIPTS; import static org.keycloak.common.Profile.Feature.SCRIPTS;
import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId; import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
@ -38,16 +36,12 @@ import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.mappers.ScriptBasedOIDCProtocolMapper;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.provider.ScriptProviderDescriptor; import org.keycloak.representations.provider.ScriptProviderDescriptor;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature; import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.util.ContainerAssume; import org.keycloak.testsuite.util.ContainerAssume;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
/** /**
@ -94,7 +88,7 @@ public class UndeployedScriptMapperNotAvailableTest extends AbstractTestRealmKey
} }
@Test @Test
@EnableFeature(SCRIPTS) @EnableFeature(value = SCRIPTS, skipRestart = true, executeAsLast = false)
public void testMapperNotRecognizedWhenDisabled() throws Exception { public void testMapperNotRecognizedWhenDisabled() throws Exception {
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app"); ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");