diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml index a0ca45d4fb..d851c9b522 100755 --- a/model/jpa/pom.xml +++ b/model/jpa/pom.xml @@ -29,6 +29,18 @@ Keycloak Model JPA + + org.h2.Driver + keycloak + sa + + jdbc:h2:mem:test;MVCC=TRUE;DB_CLOSE_DELAY=-1 + com.h2database + h2 + ${h2.version} + file:${project.build.directory}/dependency/log4j.properties + + org.bouncycastle @@ -60,10 +72,6 @@ - - com.h2database - h2 - jakarta.persistence jakarta.persistence-api @@ -92,6 +100,50 @@ junit test + + org.hamcrest + hamcrest-all + test + + + log4j + log4j + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + + + org.keycloak + keycloak-saml-core + + + ${jdbc.mvn.groupId} + ${jdbc.mvn.artifactId} + ${jdbc.mvn.version} + test + + + + + maven-surefire-plugin + + + ${keycloak.connectionsJpa.driver} + ${keycloak.connectionsJpa.database} + ${keycloak.connectionsJpa.user} + ${keycloak.connectionsJpa.password} + ${keycloak.connectionsJpa.url} + file:${project.build.directory}/test-classes/log4j.properties + + + + + diff --git a/model/jpa/src/test/java/org/keycloak/events/jpa/JpaAdminEventQueryTest.java b/model/jpa/src/test/java/org/keycloak/events/jpa/JpaAdminEventQueryTest.java new file mode 100644 index 0000000000..4f06ff2ea4 --- /dev/null +++ b/model/jpa/src/test/java/org/keycloak/events/jpa/JpaAdminEventQueryTest.java @@ -0,0 +1,155 @@ +/* + * 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.events.jpa; + +import org.keycloak.Config.Scope; +import org.keycloak.common.ClientConnection; +import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory; +import org.keycloak.connections.jpa.JpaConnectionSpi; +import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory; +import org.keycloak.connections.jpa.updater.JpaUpdaterSpi; +import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProviderFactory; +import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi; +import org.keycloak.connections.jpa.updater.liquibase.lock.LiquibaseDBLockProviderFactory; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventStoreProvider; +import org.keycloak.events.EventStoreProviderFactory; +import org.keycloak.events.EventStoreSpi; +import org.keycloak.events.EventType; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RealmSpi; +import org.keycloak.models.dblock.DBLockSpi; +import org.keycloak.models.jpa.JpaRealmProviderFactory; +import org.keycloak.provider.Provider; +import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.ProviderManager; +import org.keycloak.provider.Spi; +import org.keycloak.services.DefaultKeycloakSession; +import org.keycloak.services.DefaultKeycloakSessionFactory; +import com.google.common.collect.ImmutableSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * + * @author hmlnarik + */ +public class JpaAdminEventQueryTest { + + private static final Set> ALLOWED_SPIS = ImmutableSet.>builder() + .add(DBLockSpi.class) + .add(EventStoreSpi.class) + .add(JpaConnectionSpi.class) + .add(JpaUpdaterSpi.class) + .add(LiquibaseConnectionSpi.class) + .add(RealmSpi.class) + .build(); + + private static final Set> ALLOWED_FACTORIES = ImmutableSet.>builder() + .add(DefaultJpaConnectionProviderFactory.class) + .add(EventStoreProviderFactory.class) + .add(JpaUpdaterProviderFactory.class) + .add(JpaRealmProviderFactory.class) + .add(LiquibaseConnectionProviderFactory.class) + .add(LiquibaseDBLockProviderFactory.class) + .build(); + + private static final DefaultKeycloakSessionFactory factory = new DefaultKeycloakSessionFactory() { + @Override + protected boolean isEnabled(ProviderFactory factory, Scope scope) { + return super.isEnabled(factory, scope) && ALLOWED_FACTORIES.stream().filter(c -> c.isAssignableFrom(factory.getClass())).findAny().isPresent(); + } + + @Override + protected Map, Map> loadFactories(ProviderManager pm) { + spis.removeIf(s -> ! ALLOWED_SPIS.contains(s.getClass())); + return super.loadFactories(pm); + } + }; + static { factory.init(); } + + private final KeycloakSession session = new DefaultKeycloakSession(factory); + private final EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); + + @Before + public void startTransaction() { + session.getTransactionManager().begin(); + } + + @After + public void stopTransaction() { + session.getTransactionManager().rollback(); + } + + @Test + public void testClear() { + eventStore.clear(); + } + + @Test + public void testQuery() { + RealmModel realm = session.realms().createRealm("realm"); + ClientConnection cc = new DummyClientConnection(); + eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u1").getEvent()); + eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u2").getEvent()); + eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u3").getEvent()); + eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u4").getEvent()); + + assertThat(eventStore.createQuery() + .firstResult(2) + .getResultStream() + .collect(Collectors.counting()), + is(2L) + ); + } + + private static class DummyClientConnection implements ClientConnection { + + @Override + public String getRemoteAddr() { + return "remoteAddr"; + } + + @Override + public String getRemoteHost() { + return "remoteHost"; + } + + @Override + public int getRemotePort() { + return -1; + } + + @Override + public String getLocalAddr() { + return "localAddr"; + } + + @Override + public int getLocalPort() { + return -2; + } + } + +} diff --git a/model/jpa/src/test/resources/log4j.properties b/model/jpa/src/test/resources/log4j.properties new file mode 100644 index 0000000000..2d89ff6a06 --- /dev/null +++ b/model/jpa/src/test/resources/log4j.properties @@ -0,0 +1,42 @@ +# +# Copyright 2016 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. +# + +log4j.rootLogger=info, keycloak + +log4j.appender.keycloak=org.apache.log4j.ConsoleAppender +log4j.appender.keycloak.layout=org.apache.log4j.EnhancedPatternLayout +keycloak.testsuite.logging.pattern=%d{HH:mm:ss,SSS} %-5p [%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=${keycloak.logging.level:debug} + +keycloak.testsuite.logging.level=debug +log4j.logger.org.keycloak.testsuite=${keycloak.testsuite.logging.level} + +# Enable to view loaded SPI and Providers +log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug +log4j.logger.org.keycloak.provider.ProviderManager=debug +# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug + +# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level" +keycloak.liquibase.logging.level=info +log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase.logging.level} +log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug + +# Enable to log short stack traces for log entries enabled with StackUtil.getShortStackTrace() calls +# log4j.logger.org.keycloak.STACK_TRACE=trace