diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c61509fd2..0176a11cf0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,6 +82,45 @@ jobs: path: reports-unit-tests.zip if-no-files-found: ignore + model-tests: + name: Model Tests + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Cache Maven packages + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: cache-1-${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: cache-1-${{ runner.os }}-m2 + - name: Cleanup org.keycloak artifacts + run: rm -rf ~/.m2/repository/org/keycloak >/dev/null || true + - name: Download built keycloak + id: download-keycloak + uses: actions/download-artifact@v2 + with: + path: ~/.m2/repository/org/keycloak/ + name: keycloak-artifacts.zip + - name: Run model tests + run: | + if ! testsuite/model/test-all-profiles.sh; then + find . -path '*/target/surefire-reports*/*.xml' | zip -q reports-model-tests.zip -@ + exit 1 + fi + + - name: Model test reports + uses: actions/upload-artifact@v2 + if: failure() + with: + name: reports-model-tests + retention-days: 14 + path: reports-model-tests.zip + if-no-files-found: ignore + test: name: Base testsuite needs: build diff --git a/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java b/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java index e6ff2c1f8d..1af7bc85be 100755 --- a/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java +++ b/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java @@ -171,8 +171,11 @@ public class UserStorageSyncManager { return; } - UserStorageProviderClusterEvent event = UserStorageProviderClusterEvent.createEvent(removed, realm.getId(), provider); - session.getProvider(ClusterProvider.class).notify(USER_STORAGE_TASK_KEY, event, false, ClusterProvider.DCNotify.ALL_DCS); + final ClusterProvider cp = session.getProvider(ClusterProvider.class); + if (cp != null) { + UserStorageProviderClusterEvent event = UserStorageProviderClusterEvent.createEvent(removed, realm.getId(), provider); + cp.notify(USER_STORAGE_TASK_KEY, event, false, ClusterProvider.DCNotify.ALL_DCS); + } } diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/BackwardsCompatibilityUserStorage.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/BackwardsCompatibilityUserStorage.java index 9f919228f0..5c9ab87b59 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/BackwardsCompatibilityUserStorage.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/BackwardsCompatibilityUserStorage.java @@ -74,12 +74,15 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us this.users = users; } + private static String translateUserName(String userName) { + return userName == null ? null : userName.toLowerCase(); + } @Override public UserModel getUserById(String id, RealmModel realm) { StorageId storageId = new StorageId(id); final String username = storageId.getExternalId(); - if (!users.containsKey(username)) return null; + if (!users.containsKey(translateUserName(username))) return null; return createUser(realm, username); } @@ -152,7 +155,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us assertNotNull(newPassword.getValue()); assertNotNull(newPassword.getSalt()); - users.get(user.getUsername()).hashedPassword = newPassword; + users.get(translateUserName(user.getUsername())).hashedPassword = newPassword; UserCache userCache = session.userCache(); if (userCache != null) { @@ -179,7 +182,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us newOTP.setAlgorithm(otpPolicy.getAlgorithm()); newOTP.setPeriod(otpPolicy.getPeriod()); - users.get(user.getUsername()).otp = newOTP; + users.get(translateUserName(user.getUsername())).otp = newOTP; return true; } else { @@ -208,7 +211,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us } private MyUser getMyUser(UserModel user) { - return users.get(user.getUsername()); + return users.get(translateUserName(user.getUsername())); } @Override @@ -240,7 +243,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us @Override public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) { - MyUser myUser = users.get(user.getUsername()); + MyUser myUser = users.get(translateUserName(user.getUsername())); if (myUser == null) return false; if (input.getType().equals(UserCredentialModel.PASSWORD)) { @@ -289,7 +292,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us @Override public UserModel getUserByUsername(String username, RealmModel realm) { - if (!users.containsKey(username)) return null; + if (!users.containsKey(translateUserName(username))) return null; return createUser(realm, username); } @@ -301,13 +304,13 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us @Override public UserModel addUser(RealmModel realm, String username) { - users.put(username, new MyUser(username)); + users.put(translateUserName(username), new MyUser(username)); return createUser(realm, username); } @Override public boolean removeUser(RealmModel realm, UserModel user) { - return users.remove(user.getUsername()) != null; + return users.remove(translateUserName(user.getUsername())) != null; } diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/UserMapStorage.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/UserMapStorage.java index bb5bdb85d5..9a40a1854b 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/UserMapStorage.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/UserMapStorage.java @@ -94,7 +94,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, public UserModel getUserById(String id, RealmModel realm) { StorageId storageId = new StorageId(id); final String username = storageId.getExternalId(); - if (!userPasswords.containsKey(username)) { + if (!userPasswords.containsKey(translateUserName(username))) { return null; } @@ -159,7 +159,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, return false; } if (input.getType().equals(PasswordCredentialModel.TYPE)) { - userPasswords.put(user.getUsername(), input.getChallengeResponse()); + userPasswords.put(translateUserName(user.getUsername()), input.getChallengeResponse()); return true; } else { @@ -189,7 +189,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, return false; } if (input.getType().equals(PasswordCredentialModel.TYPE)) { - String pw = userPasswords.get(user.getUsername()); + String pw = userPasswords.get(translateUserName(user.getUsername())); // Using "getValue" on purpose here, to test that backwards compatibility works as expected return pw != null && pw.equals(((UserCredentialModel) input).getValue()); @@ -200,7 +200,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, @Override public UserModel getUserByUsername(String username, RealmModel realm) { - if (!userPasswords.containsKey(username)) { + if (!userPasswords.containsKey(translateUserName(username))) { return null; } @@ -218,7 +218,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, throw new ReadOnlyException("Federated storage is not writable"); } - userPasswords.put(username, ""); + userPasswords.put(translateUserName(username), ""); return createUser(realm, username); } @@ -226,21 +226,21 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, public boolean removeUser(RealmModel realm, UserModel user) { if (editMode == UserStorageProvider.EditMode.READ_ONLY || editMode == UserStorageProvider.EditMode.UNSYNCED) { log.warnf("User '%s' can't be deleted in LDAP as editMode is '%s'. Deleting user just from Keycloak DB, but he will be re-imported from LDAP again once searched in Keycloak", user.getUsername(), editMode.toString()); - userPasswords.remove(user.getUsername()); + userPasswords.remove(translateUserName(user.getUsername())); return true; } - return userPasswords.remove(user.getUsername()) != null; + return userPasswords.remove(translateUserName(user.getUsername())) != null; } public boolean removeUserByName(String userName) { if (editMode == UserStorageProvider.EditMode.READ_ONLY || editMode == UserStorageProvider.EditMode.UNSYNCED) { log.warnf("User '%s' can't be deleted in LDAP as editMode is '%s'. Deleting user just from Keycloak DB, but he will be re-imported from LDAP again once searched in Keycloak", userName, editMode.toString()); - userPasswords.remove(userName); + userPasswords.remove(translateUserName(userName)); return true; } - return userPasswords.remove(userName) != null; + return userPasswords.remove(translateUserName(userName)) != null; } public boolean isImportEnabled() { @@ -307,17 +307,19 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, @Override public Stream searchForUserStream(String search, RealmModel realm) { + String tSearch = translateUserName(search); return userPasswords.keySet().stream() .sorted() - .filter(userName -> userName.contains(search)) + .filter(userName -> translateUserName(userName).contains(tSearch)) .map(userName -> createUser(realm, userName)); } @Override public Stream searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) { + String tSearch = translateUserName(search); Stream userStream = userPasswords.keySet().stream() .sorted() - .filter(userName -> userName.contains(search)); + .filter(userName -> translateUserName(userName).contains(search)); if (firstResult > 0) userStream = userStream.skip(firstResult); if (maxResults >= 0) @@ -421,11 +423,15 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider, @Override public UserModel validate(RealmModel realm, UserModel local) { - final boolean userExists = userPasswords.containsKey(local.getUsername()); + final boolean userExists = userPasswords.containsKey(translateUserName(local.getUsername())); if (! userExists) { userGroups.remove(getUserIdInMap(realm, local.getUsername())); } return userExists ? local : null; } + private static String translateUserName(String userName) { + return userName == null ? null : userName.toLowerCase(); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java index e431fd3986..2be06693cb 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java @@ -266,6 +266,10 @@ public class LDAPRule extends ExternalResource { return ldapTestConfiguration.getSleepTime(); } + public LDAPEmbeddedServer getLdapEmbeddedServer() { + return ldapEmbeddedServer; + } + /** Allows to run particular LDAP test just under specific conditions (eg. some test running just on Active Directory) **/ public interface LDAPAssume { diff --git a/testsuite/model/pom.xml b/testsuite/model/pom.xml index d403365417..e62096be1c 100644 --- a/testsuite/model/pom.xml +++ b/testsuite/model/pom.xml @@ -61,6 +61,11 @@ org.keycloak keycloak-server-spi + + org.keycloak.testsuite + integration-arquillian-tests-base + ${project.version} + ${jdbc.mvn.groupId} ${jdbc.mvn.artifactId} @@ -127,14 +132,28 @@ jpa-federation+infinispan - Infinispan,JpaFederation,BackwardsCompatibilityUserStorage + Infinispan,JpaFederation,TestsuiteUserMapStorage jpa-federation - JpaFederation,BackwardsCompatibilityUserStorage + JpaFederation,TestsuiteUserMapStorage + + + + + jpa-federation+ldap + + JpaFederation,LdapUserStorage + + + + + jpa-federation+ldap+infinispan + + JpaFederation,LdapUserStorage,Infinispan diff --git a/testsuite/model/src/test/java/org/keycloak/model/KeycloakModelParameters.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelParameters.java similarity index 68% rename from testsuite/model/src/test/java/org/keycloak/model/KeycloakModelParameters.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelParameters.java index cd6af346f2..2d90095074 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/KeycloakModelParameters.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelParameters.java @@ -14,11 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model; +package org.keycloak.testsuite.model; import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.Spi; import java.util.Set; +import java.util.stream.Stream; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; /** * @@ -42,4 +45,23 @@ public class KeycloakModelParameters { return allowedFactories.stream().anyMatch((c) -> c.isAssignableFrom(factory.getClass())); } + /** + * Returns stream of parameters of the given type, or an empty stream if no parameters of the given type are supplied + * by this clazz. + * @param + * @param clazz + * @return + */ + public Stream getParameters(Class clazz) { + return Stream.empty(); + } + + public Statement classRule(Statement base, Description description) { + return base; + } + + public Statement instanceRule(Statement base, Description description) { + return base; + } + } diff --git a/testsuite/model/src/test/java/org/keycloak/model/KeycloakModelTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java similarity index 74% rename from testsuite/model/src/test/java/org/keycloak/model/KeycloakModelTest.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java index 2f4533c942..df155e71f2 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/KeycloakModelTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java @@ -14,14 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model; +package org.keycloak.testsuite.model; import org.keycloak.Config.Scope; import org.keycloak.authorization.AuthorizationSpi; import org.keycloak.authorization.DefaultAuthorizationProviderFactory; import org.keycloak.authorization.store.StoreFactorySpi; import org.keycloak.cluster.ClusterSpi; -import org.keycloak.component.ComponentModel; import org.keycloak.events.EventStoreSpi; import org.keycloak.executors.DefaultExecutorsProviderFactory; import org.keycloak.executors.ExecutorsSpi; @@ -30,7 +29,6 @@ import org.keycloak.models.ClientSpi; import org.keycloak.models.GroupSpi; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.models.RealmModel; import org.keycloak.models.RealmSpi; import org.keycloak.models.RoleSpi; import org.keycloak.models.UserSpi; @@ -41,28 +39,29 @@ import org.keycloak.provider.ProviderManager; import org.keycloak.provider.Spi; import org.keycloak.services.DefaultKeycloakSession; import org.keycloak.services.DefaultKeycloakSessionFactory; -import org.keycloak.storage.UserStorageProvider; -import org.keycloak.storage.UserStorageProviderModel; import com.google.common.collect.ImmutableSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import org.hamcrest.Matchers; import org.jboss.logging.Logger; import org.junit.After; import org.junit.Assume; +import org.junit.AssumptionViolatedException; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertThat; /** * Base of testcases that operate on session level. The tests derived from this class @@ -87,13 +86,56 @@ public abstract class KeycloakModelTest { @Override public Statement apply(Statement base, Description description) { Class testClass = description.getTestClass(); + Stream st = Stream.empty(); while (testClass != Object.class) { - for (RequireProvider ann : testClass.getAnnotationsByType(RequireProvider.class)) { - Assume.assumeThat("Provider must exist: " + ann.value(), FACTORY.getProviderFactory(ann.value()), Matchers.notNullValue()); - } + st = Stream.concat(Stream.of(testClass.getAnnotationsByType(RequireProvider.class)), st); testClass = testClass.getSuperclass(); } - return base; + List> notFound = st.map(RequireProvider::value) + .filter(pClass -> FACTORY.getProviderFactory(pClass) == null) + .collect(Collectors.toList()); + Assume.assumeThat("Some required providers not found", notFound, Matchers.empty()); + + Statement res = base; + for (KeycloakModelParameters kmp : KeycloakModelTest.MODEL_PARAMETERS) { + res = kmp.classRule(res, description); + } + return res; + } + }; + + @Rule + public final TestRule guaranteeRequiredFactoryOnMethod = new TestRule() { + @Override + public Statement apply(Statement base, Description description) { + Stream st = Optional.ofNullable(description.getAnnotation(RequireProviders.class)) + .map(RequireProviders::value) + .map(Stream::of) + .orElseGet(Stream::empty); + + RequireProvider rp = description.getAnnotation(RequireProvider.class); + if (rp != null) { + st = Stream.concat(st, Stream.of(rp)); + } + + for (Iterator> iterator = st.map(RequireProvider::value).iterator(); iterator.hasNext();) { + Class providerClass = iterator.next(); + + if (FACTORY.getProviderFactory(providerClass) == null) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + throw new AssumptionViolatedException("Provider must exist: " + providerClass); + } + }; + } + } + + Statement res = base; + for (KeycloakModelParameters kmp : KeycloakModelTest.MODEL_PARAMETERS) { + res = kmp.instanceRule(res, description); + } + return res; } }; @@ -124,7 +166,7 @@ public abstract class KeycloakModelTest { Stream.of(basicParameters), Stream.of(System.getProperty("keycloak.model.parameters", "").split("\\s*,\\s*")) .filter(s -> s != null && ! s.trim().isEmpty()) - .map(cn -> { try { return Class.forName(cn.indexOf('.') >= 0 ? cn : ("org.keycloak.model.parameters." + cn)); } catch (Exception e) { LOG.error("Cannot find " + cn); return null; }}) + .map(cn -> { try { return Class.forName(cn.indexOf('.') >= 0 ? cn : ("org.keycloak.testsuite.model.parameters." + cn)); } catch (Exception e) { LOG.error("Cannot find " + cn); return null; }}) .filter(Objects::nonNull) .map(c -> { try { return c.newInstance(); } catch (Exception e) { LOG.error("Cannot instantiate " + c); return null; }} ) .filter(KeycloakModelParameters.class::isInstance) @@ -176,21 +218,12 @@ public abstract class KeycloakModelTest { KeycloakModelUtils.runJobInTransaction(FACTORY, this::cleanEnvironment); } - protected String registerUserFederationIfAvailable(RealmModel realm) { - final List userFedProviders = FACTORY.getProviderFactories(UserStorageProvider.class); + protected Stream getParameters(Class clazz) { + return MODEL_PARAMETERS.stream().flatMap(mp -> mp.getParameters(clazz)).filter(Objects::nonNull); + } - if (! userFedProviders.isEmpty() && realm != null) { - assertThat("Cannot handle more than 1 user federation provider", userFedProviders, hasSize(1)); - UserStorageProviderModel federatedStorage = new UserStorageProviderModel(); - federatedStorage.setName(userFedProviders.get(0).getId()); - federatedStorage.setProviderId(userFedProviders.get(0).getId()); - federatedStorage.setProviderType(UserStorageProvider.class.getName()); - federatedStorage.setParentId(realm.getId()); - ComponentModel res = realm.addComponentModel(federatedStorage); - log.infof("Added %s user federation provider: %s", federatedStorage.getName(), res.getId()); - return res.getId(); - } - return null; + protected void withEach(Class parameterClazz, Consumer what) { + getParameters(parameterClazz).forEach(what); } protected void inRolledBackTransaction(T parameter, BiConsumer what) { diff --git a/testsuite/model/src/test/java/org/keycloak/model/RequireProvider.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/RequireProvider.java similarity index 93% rename from testsuite/model/src/test/java/org/keycloak/model/RequireProvider.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/RequireProvider.java index bb7a70a51c..d0975b3d38 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/RequireProvider.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/RequireProvider.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model; +package org.keycloak.testsuite.model; import org.keycloak.provider.Provider; import java.lang.annotation.ElementType; @@ -30,7 +30,7 @@ import java.lang.annotation.Target; * @author hmlnarik */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target({ElementType.TYPE, ElementType.METHOD}) @Repeatable(RequireProviders.class) public @interface RequireProvider { Class value() default Provider.class; diff --git a/testsuite/model/src/test/java/org/keycloak/model/RequireProviders.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/RequireProviders.java similarity index 91% rename from testsuite/model/src/test/java/org/keycloak/model/RequireProviders.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/RequireProviders.java index 0786125567..335c0f6027 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/RequireProviders.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/RequireProviders.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model; +package org.keycloak.testsuite.model; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -26,7 +26,7 @@ import java.lang.annotation.Target; * @author hmlnarik */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target({ElementType.TYPE, ElementType.METHOD}) public @interface RequireProviders { RequireProvider[] value(); } diff --git a/testsuite/model/src/test/java/org/keycloak/model/UserModelTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/UserModelTest.java similarity index 74% rename from testsuite/model/src/test/java/org/keycloak/model/UserModelTest.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/UserModelTest.java index 1210d6c3b1..695483c8a4 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/UserModelTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/UserModelTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model; +package org.keycloak.testsuite.model; import org.keycloak.component.ComponentModel; import org.keycloak.models.GroupModel; @@ -26,7 +26,6 @@ import org.keycloak.models.UserProvider; import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProviderFactory; import org.keycloak.storage.UserStorageProviderModel; -import org.keycloak.storage.user.UserLookupProvider; import org.keycloak.storage.user.UserRegistrationProvider; import java.util.ArrayList; import java.util.HashSet; @@ -55,6 +54,9 @@ import static org.junit.Assume.assumeThat; public class UserModelTest extends KeycloakModelTest { protected static final int NUM_GROUPS = 100; + private static final int FIRST_DELETED_USER_INDEX = 10; + private static final int LAST_DELETED_USER_INDEX = 90; + private static final int DELETED_USER_COUNT = LAST_DELETED_USER_INDEX - FIRST_DELETED_USER_INDEX; private String realmId; private final List groupIds = new ArrayList<>(NUM_GROUPS); @@ -65,8 +67,6 @@ public class UserModelTest extends KeycloakModelTest { RealmModel realm = s.realms().createRealm("realm"); this.realmId = realm.getId(); - this.userFederationId = registerUserFederationIfAvailable(realm); - IntStream.range(0, NUM_GROUPS).forEach(i -> { groupIds.add(s.groups().createGroup(realm, "group-" + i).getId()); }); @@ -150,12 +150,42 @@ public class UserModelTest extends KeycloakModelTest { } @Test - public void testAddDirtyRemoveFederationUsersInTheSameGroupConcurrent() { - assumeThat("Test for federated providers only", userFederationId, Matchers.notNullValue()); + @RequireProvider(UserStorageProvider.class) + public void testAddDirtyRemoveFederationUser() { + registerUserFederationWithRealm(); + inComittedTransaction(1, (session, i) -> { + final RealmModel realm = session.realms().getRealm(realmId); + final UserModel user = session.users().addUser(realm, "user-A"); + }); + + // Remove user _from the federation_, simulates eg. user being removed from LDAP without Keycloak knowing + inComittedTransaction(1, (session, i) -> { + final RealmModel realm = session.realms().getRealm(realmId); + final UserStorageProvider instance = getUserFederationInstance(session, realm); + log.debugf("Removing selected users from backend"); + final UserModel user = session.users().getUserByUsername("user-A", realm); + ((UserRegistrationProvider) instance).removeUser(realm, user); + }); + + inComittedTransaction(1, (session, i) -> { + final RealmModel realm = session.realms().getRealm(realmId); + if (session.userCache() != null) { + session.userCache().clear(); + } + final UserModel user = session.users().getUserByUsername("user-A", realm); + assertThat("User should not be found in the main store", user, Matchers.nullValue()); + }); + } + + @Test + @RequireProvider(UserStorageProvider.class) + public void testAddDirtyRemoveFederationUsersInTheSameGroupConcurrent() { final ConcurrentSkipListSet userIds = new ConcurrentSkipListSet<>(); String groupId = groupIds.get(0); + registerUserFederationWithRealm(); + // Create users and let them join first group IntStream.range(0, 100).parallel().forEach(index -> inComittedTransaction(index, (session, i) -> { final RealmModel realm = session.realms().getRealm(realmId); @@ -167,25 +197,11 @@ public class UserModelTest extends KeycloakModelTest { // Remove users _from the federation_, simulates eg. user being removed from LDAP without Keycloak knowing inComittedTransaction(1, (session, i) -> { final RealmModel realm = session.realms().getRealm(realmId); - UserStorageProvider instance = (UserStorageProvider)session.getAttribute(userFederationId); - - if (instance == null) { - ComponentModel model = realm.getComponent(userFederationId); - UserStorageProviderModel storageModel = new UserStorageProviderModel(model); - UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId()); - instance = factory.create(session, model); - if (instance == null) { - throw new RuntimeException("UserStorageProvideFactory (of type " + factory.getClass().getName() + ") produced a null instance"); - } - session.enlistForClose(instance); - session.setAttribute(userFederationId, instance); - } - - final UserStorageProvider lambdaInstance = instance; + UserStorageProvider instance = getUserFederationInstance(session, realm); log.debugf("Removing selected users from backend"); IntStream.range(FIRST_DELETED_USER_INDEX, LAST_DELETED_USER_INDEX).forEach(j -> { - final UserModel user = ((UserLookupProvider) lambdaInstance).getUserByUsername("user-" + j, realm); - ((UserRegistrationProvider) lambdaInstance).removeUser(realm, user); + final UserModel user = session.users().getUserByUsername("user-" + j, realm); + ((UserRegistrationProvider) instance).removeUser(realm, user); }); }); @@ -229,7 +245,34 @@ public class UserModelTest extends KeycloakModelTest { assertThat(session.users().getGroupMembersStream(realm, group).collect(Collectors.toList()), Matchers.empty()); }); } - private static final int FIRST_DELETED_USER_INDEX = 10; - private static final int LAST_DELETED_USER_INDEX = 90; - private static final int DELETED_USER_COUNT = LAST_DELETED_USER_INDEX - FIRST_DELETED_USER_INDEX; + + private void registerUserFederationWithRealm() { + getParameters(UserStorageProviderModel.class).forEach(fs -> inComittedTransaction(fs, (session, federatedStorage) -> { + assumeThat("Cannot handle more than 1 user federation provider", userFederationId, Matchers.nullValue()); + RealmModel realm = session.realms().getRealm(realmId); + federatedStorage.setParentId(realmId); + federatedStorage.setImportEnabled(true); + ComponentModel res = realm.addComponentModel(federatedStorage); + userFederationId = res.getId(); + log.infof("Added %s user federation provider: %s", federatedStorage.getName(), userFederationId); + })); + } + + private UserStorageProvider getUserFederationInstance(KeycloakSession session, final RealmModel realm) throws RuntimeException { + UserStorageProvider instance = (UserStorageProvider)session.getAttribute(userFederationId); + + if (instance == null) { + ComponentModel model = realm.getComponent(userFederationId); + UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId()); + instance = factory.create(session, model); + if (instance == null) { + throw new RuntimeException("UserStorageProvideFactory (of type " + factory.getClass().getName() + ") produced a null instance"); + } + session.enlistForClose(instance); + session.setAttribute(userFederationId, instance); + } + + return instance; + } + } diff --git a/testsuite/model/src/test/java/org/keycloak/model/events/AdminEventQueryTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/events/AdminEventQueryTest.java similarity index 95% rename from testsuite/model/src/test/java/org/keycloak/model/events/AdminEventQueryTest.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/events/AdminEventQueryTest.java index 98985f4122..3e491e9c5e 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/events/AdminEventQueryTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/events/AdminEventQueryTest.java @@ -14,14 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.events; +package org.keycloak.testsuite.model.events; import org.keycloak.common.ClientConnection; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; -import org.keycloak.model.KeycloakModelTest; -import org.keycloak.model.RequireProvider; +import org.keycloak.testsuite.model.KeycloakModelTest; +import org.keycloak.testsuite.model.RequireProvider; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import java.util.stream.Collectors; diff --git a/testsuite/model/src/test/java/org/keycloak/model/parameters/BackwardsCompatibilityUserStorage.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/BackwardsCompatibilityUserStorage.java similarity index 58% rename from testsuite/model/src/test/java/org/keycloak/model/parameters/BackwardsCompatibilityUserStorage.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/BackwardsCompatibilityUserStorage.java index a644e25f4f..1a66196f0f 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/parameters/BackwardsCompatibilityUserStorage.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/BackwardsCompatibilityUserStorage.java @@ -14,17 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.parameters; +package org.keycloak.testsuite.model.parameters; -import org.keycloak.model.KeycloakModelParameters; +import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.Spi; -import org.keycloak.storage.UserStorageProviderSpi; -import org.keycloak.storage.federated.UserFederatedStorageProviderSpi; -import org.keycloak.storage.jpa.JpaUserFederatedStorageProviderFactory; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.testsuite.federation.BackwardsCompatibilityUserStorageFactory; import com.google.common.collect.ImmutableSet; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; /** * @@ -39,7 +40,22 @@ public class BackwardsCompatibilityUserStorage extends KeycloakModelParameters { .add(BackwardsCompatibilityUserStorageFactory.class) .build(); + private final AtomicInteger counter = new AtomicInteger(); + public BackwardsCompatibilityUserStorage() { super(ALLOWED_SPIS, ALLOWED_FACTORIES); } + + @Override + public Stream getParameters(Class clazz) { + if (UserStorageProviderModel.class.isAssignableFrom(clazz)) { + UserStorageProviderModel federatedStorage = new UserStorageProviderModel(); + federatedStorage.setName(BackwardsCompatibilityUserStorageFactory.PROVIDER_ID + ":" + counter.getAndIncrement()); + federatedStorage.setProviderId(BackwardsCompatibilityUserStorageFactory.PROVIDER_ID); + federatedStorage.setProviderType(UserStorageProvider.class.getName()); + return Stream.of((T) federatedStorage); + } else { + return super.getParameters(clazz); + } + } } diff --git a/testsuite/model/src/test/java/org/keycloak/model/parameters/ConcurrentHashMapStorage.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/ConcurrentHashMapStorage.java similarity index 94% rename from testsuite/model/src/test/java/org/keycloak/model/parameters/ConcurrentHashMapStorage.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/ConcurrentHashMapStorage.java index 537e7a9395..a9ce346325 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/parameters/ConcurrentHashMapStorage.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/ConcurrentHashMapStorage.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.parameters; +package org.keycloak.testsuite.model.parameters; -import org.keycloak.model.KeycloakModelParameters; +import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.models.map.client.MapClientProviderFactory; import org.keycloak.models.map.group.MapGroupProviderFactory; import org.keycloak.models.map.role.MapRoleProviderFactory; diff --git a/testsuite/model/src/test/java/org/keycloak/model/parameters/Infinispan.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java similarity index 95% rename from testsuite/model/src/test/java/org/keycloak/model/parameters/Infinispan.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java index 273320fb71..ecc8117413 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/parameters/Infinispan.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Infinispan.java @@ -14,12 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.parameters; +package org.keycloak.testsuite.model.parameters; import org.keycloak.cluster.infinispan.InfinispanClusterProviderFactory; import org.keycloak.connections.infinispan.InfinispanConnectionProviderFactory; import org.keycloak.connections.infinispan.InfinispanConnectionSpi; -import org.keycloak.model.KeycloakModelParameters; +import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.models.cache.CacheRealmProviderSpi; import org.keycloak.models.cache.CacheUserProviderSpi; import org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderFactory; diff --git a/testsuite/model/src/test/java/org/keycloak/model/parameters/Jpa.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Jpa.java similarity index 96% rename from testsuite/model/src/test/java/org/keycloak/model/parameters/Jpa.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Jpa.java index b0d6c90bcc..c23ae8ebea 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/parameters/Jpa.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Jpa.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.parameters; +package org.keycloak.testsuite.model.parameters; import org.keycloak.authorization.jpa.store.JPAAuthorizationStoreFactory; import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory; @@ -25,7 +25,7 @@ import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionPr import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi; import org.keycloak.connections.jpa.updater.liquibase.lock.LiquibaseDBLockProviderFactory; import org.keycloak.events.jpa.JpaEventStoreProviderFactory; -import org.keycloak.model.KeycloakModelParameters; +import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.models.dblock.DBLockSpi; import org.keycloak.models.jpa.JpaClientProviderFactory; import org.keycloak.models.jpa.JpaGroupProviderFactory; diff --git a/testsuite/model/src/test/java/org/keycloak/model/parameters/JpaFederation.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaFederation.java similarity index 94% rename from testsuite/model/src/test/java/org/keycloak/model/parameters/JpaFederation.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaFederation.java index 8e7a422eaf..ce893fcde6 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/parameters/JpaFederation.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaFederation.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.parameters; +package org.keycloak.testsuite.model.parameters; -import org.keycloak.model.KeycloakModelParameters; +import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.Spi; import org.keycloak.storage.UserStorageProviderSpi; diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/LdapUserStorage.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/LdapUserStorage.java new file mode 100644 index 0000000000..ed2c71991f --- /dev/null +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/LdapUserStorage.java @@ -0,0 +1,101 @@ +/* + * Copyright 2020 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.testsuite.model.parameters; + +import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.testsuite.model.KeycloakModelParameters; +import org.keycloak.models.LDAPConstants; +import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.Spi; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.storage.UserStorageProviderModel; +import org.keycloak.storage.UserStorageProviderSpi; +import org.keycloak.storage.federated.UserFederatedStorageProviderSpi; +import org.keycloak.storage.ldap.LDAPStorageProviderFactory; +import org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory; +import org.keycloak.storage.ldap.mappers.LDAPStorageMapperSpi; +import org.keycloak.testsuite.util.LDAPRule; +import org.keycloak.util.ldap.LDAPEmbeddedServer; +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * + * @author hmlnarik + */ +public class LdapUserStorage extends KeycloakModelParameters { + + static final Set> ALLOWED_SPIS = ImmutableSet.>builder() + .add(UserStorageProviderSpi.class) + .add(UserFederatedStorageProviderSpi.class) + .add(LDAPStorageMapperSpi.class) + + .build(); + + static final Set> ALLOWED_FACTORIES = ImmutableSet.>builder() + .add(LDAPStorageMapperFactory.class) + .add(LDAPStorageProviderFactory.class) + + .build(); + + private final AtomicInteger counter = new AtomicInteger(); + + private final LDAPRule ldapRule = new LDAPRule(); + + public LdapUserStorage() { + super(ALLOWED_SPIS, ALLOWED_FACTORIES); + } + + @Override + public Stream getParameters(Class clazz) { + if (UserStorageProviderModel.class.isAssignableFrom(clazz)) { + MultivaluedHashMap config = new MultivaluedHashMap<>(); + for (java.util.Map.Entry entry : ldapRule.getConfig().entrySet()) { + config.add(entry.getKey(), entry.getValue()); + } + config.putSingle(LDAPConstants.SYNC_REGISTRATIONS, "true"); + config.putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.toString()); + + UserStorageProviderModel federatedStorage = new UserStorageProviderModel(); + federatedStorage.setName(LDAPStorageProviderFactory.PROVIDER_NAME + ":" + counter.getAndIncrement()); + federatedStorage.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME); + federatedStorage.setProviderType(UserStorageProvider.class.getName()); + federatedStorage.setLastSync(0); + federatedStorage.setChangedSyncPeriod(-1); + federatedStorage.setFullSyncPeriod(-1); + federatedStorage.setPriority(0); + federatedStorage.setConfig(config); + return Stream.of((T) federatedStorage); + } else { + return super.getParameters(clazz); + } + } + + static { + System.setProperty(LDAPEmbeddedServer.PROPERTY_ENABLE_SSL, "false"); + } + + @Override + public Statement classRule(Statement base, Description description) { + return ldapRule.apply(base, description); + } + +} diff --git a/testsuite/model/src/test/java/org/keycloak/model/parameters/Map.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Map.java similarity index 94% rename from testsuite/model/src/test/java/org/keycloak/model/parameters/Map.java rename to testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Map.java index 1fe04a8643..9c4707a4ca 100644 --- a/testsuite/model/src/test/java/org/keycloak/model/parameters/Map.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/Map.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.model.parameters; +package org.keycloak.testsuite.model.parameters; -import org.keycloak.model.KeycloakModelParameters; +import org.keycloak.testsuite.model.KeycloakModelParameters; import org.keycloak.models.map.client.MapClientProviderFactory; import org.keycloak.models.map.group.MapGroupProviderFactory; import org.keycloak.models.map.role.MapRoleProviderFactory; diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/TestsuiteUserMapStorage.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/TestsuiteUserMapStorage.java new file mode 100644 index 0000000000..b59b46c4f0 --- /dev/null +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/TestsuiteUserMapStorage.java @@ -0,0 +1,62 @@ +/* + * Copyright 2020 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.testsuite.model.parameters; + +import org.keycloak.testsuite.model.KeycloakModelParameters; +import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.Spi; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.storage.UserStorageProviderModel; +import org.keycloak.testsuite.federation.BackwardsCompatibilityUserStorageFactory; +import org.keycloak.testsuite.federation.UserMapStorageFactory; +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +/** + * + * @author hmlnarik + */ +public class TestsuiteUserMapStorage extends KeycloakModelParameters { + + static final Set> ALLOWED_SPIS = ImmutableSet.>builder() + .build(); + + static final Set> ALLOWED_FACTORIES = ImmutableSet.>builder() + .add(UserMapStorageFactory.class) + .build(); + + private final AtomicInteger counter = new AtomicInteger(); + + public TestsuiteUserMapStorage() { + super(ALLOWED_SPIS, ALLOWED_FACTORIES); + } + + @Override + public Stream getParameters(Class clazz) { + if (UserStorageProviderModel.class.isAssignableFrom(clazz)) { + UserStorageProviderModel federatedStorage = new UserStorageProviderModel(); + federatedStorage.setName(UserMapStorageFactory.PROVIDER_ID + ":" + counter.getAndIncrement()); + federatedStorage.setProviderId(UserMapStorageFactory.PROVIDER_ID); + federatedStorage.setProviderType(UserStorageProvider.class.getName()); + return Stream.of((T) federatedStorage); + } else { + return super.getParameters(clazz); + } + } +} diff --git a/testsuite/model/src/test/resources/kerberos b/testsuite/model/src/test/resources/kerberos new file mode 120000 index 0000000000..f75e12e68e --- /dev/null +++ b/testsuite/model/src/test/resources/kerberos @@ -0,0 +1 @@ +../../../../integration-arquillian/tests/base/src/test/resources/kerberos \ No newline at end of file diff --git a/testsuite/model/src/test/resources/keystore b/testsuite/model/src/test/resources/keystore new file mode 120000 index 0000000000..335be5d124 --- /dev/null +++ b/testsuite/model/src/test/resources/keystore @@ -0,0 +1 @@ +../../../../integration-arquillian/tests/base/src/test/resources/keystore \ No newline at end of file diff --git a/testsuite/model/src/test/resources/ldap b/testsuite/model/src/test/resources/ldap new file mode 120000 index 0000000000..cc9bf1ab49 --- /dev/null +++ b/testsuite/model/src/test/resources/ldap @@ -0,0 +1 @@ +../../../../integration-arquillian/tests/base/src/test/resources/ldap \ No newline at end of file diff --git a/testsuite/model/src/test/resources/log4j.properties b/testsuite/model/src/test/resources/log4j.properties index 1d0c1c002a..9107af6188 100644 --- a/testsuite/model/src/test/resources/log4j.properties +++ b/testsuite/model/src/test/resources/log4j.properties @@ -23,7 +23,12 @@ keycloak.testsuite.logging.pattern=%d{HH:mm:ss,SSS} %-5p %t [%c] %m%n log4j.appender.keycloak.layout.ConversionPattern=${keycloak.testsuite.logging.pattern} # Logging with "info" when running test from IDE, but disabled when running test with "mvn" . Both cases can be overriden by use system property "keycloak.logging.level" (eg. -Dkeycloak.logging.level=debug ) -log4j.logger.org.keycloak.models=debug +log4j.logger.org.keycloak=${keycloak.logging.level:info} + +keycloak.testsuite.logging.level=debug +log4j.logger.org.keycloak.testsuite=${keycloak.testsuite.logging.level} + +# Logging with "info" when running test from IDE, but disabled when running test with "mvn" . Both cases can be overriden by use system property "keycloak.logging.level" (eg. -Dkeycloak.logging.level=debug ) # log4j.logger.org.hibernate=debug # Enable to view loaded SPI and Providers diff --git a/testsuite/model/test-all-profiles.sh b/testsuite/model/test-all-profiles.sh new file mode 100755 index 0000000000..f606a5ecf5 --- /dev/null +++ b/testsuite/model/test-all-profiles.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +cd "$(dirname $0)" + +EXIT_CODE=0 +mvn clean +for I in `perl -ne 'print "$1\n" if (m,([^<]+),)' pom.xml`; do + echo "========" + echo "======== Profile $I" + echo "========" + mvn test "-P$I" "$@" + EXIT_CODE=$[$EXIT_CODE + $?] + mv target/surefire-reports "target/surefire-reports-$I" +done + +exit $EXIT_CODE