keycloak-uncached

Changes

testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java 339(+0 -339)

Details

diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index b92f65b..eca236f 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -63,9 +63,9 @@ supported-locales=Supported Locales
 supported-locales.placeholder=Type a locale and enter
 default-locale=Default Locale
 realm-cache-enabled=Realm Cache Enabled
-realm-cache-enabled.tooltip=Enable/disable cache for realm, client and role data.
+realm-cache-enabled.tooltip=Enable/disable cache for realms, clients and roles.
 user-cache-enabled=User Cache Enabled
-user-cache-enabled.tooltip=Enable/disable user and user role mapping cache.
+user-cache-enabled.tooltip=Enable/disable cache for users and user role mappings.
 revoke-refresh-token=Revoke Refresh Token
 revoke-refresh-token.tooltip=If enabled refresh tokens can only be used once. Otherwise refresh tokens are not revoked when used and can be used multiple times.
 sso-session-idle=SSO Session Idle
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
index 431a646..bc75fa9 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
@@ -6,6 +6,7 @@ import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
 import org.keycloak.admin.client.resource.BearerAuthFilter;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.RealmsResource;
+import org.keycloak.admin.client.resource.ServerInfoResource;
 import org.keycloak.admin.client.token.TokenManager;
 
 /**
@@ -51,6 +52,10 @@ public class Keycloak {
         return realms().realm(realmName);
     }
 
+    public ServerInfoResource serverInfo(){
+        return target.proxy(ServerInfoResource.class);
+    }
+
     public TokenManager tokenManager(){
         return tokenManager;
     }
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java
new file mode 100644
index 0000000..6ebd642
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ServerInfoResource.java
@@ -0,0 +1,20 @@
+package org.keycloak.admin.client.resource;
+
+import org.keycloak.representations.info.ServerInfoRepresentation;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+@Path("/admin/serverinfo")
+public interface ServerInfoResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    ServerInfoRepresentation getInfo();
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/OTPPolicy.java b/model/api/src/main/java/org/keycloak/models/OTPPolicy.java
index 1c6665a..157842e 100755
--- a/model/api/src/main/java/org/keycloak/models/OTPPolicy.java
+++ b/model/api/src/main/java/org/keycloak/models/OTPPolicy.java
@@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
 import org.keycloak.models.utils.Base32;
 import org.keycloak.models.utils.HmacOTP;
 
+import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.HashMap;
@@ -13,7 +14,7 @@ import java.util.Map;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class OTPPolicy {
+public class OTPPolicy implements Serializable {
 
     protected static final Logger logger = Logger.getLogger(OTPPolicy.class);
 
diff --git a/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java b/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
index e1c356b..0ecf878 100755
--- a/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
@@ -1,5 +1,6 @@
 package org.keycloak.models;
 
+import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -7,7 +8,7 @@ import java.util.Map;
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
-public class RequiredActionProviderModel {
+public class RequiredActionProviderModel implements Serializable {
 
     private String id;
     private String alias;
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index 20c8725..2f7e61f 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -29,7 +29,7 @@ public class ClientAdapter implements ClientModel {
     private void getDelegateForUpdate() {
         if (updated == null) {
             cacheSession.registerApplicationInvalidation(getId());
-            updated = updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm);
+            updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm);
             if (updated == null) throw new IllegalStateException("Not found in database");
         }
     }
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
index 4b96241..5a76153 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
@@ -1,6 +1,16 @@
 package org.keycloak.models.cache.infinispan;
 
 import org.infinispan.Cache;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
+import org.jboss.logging.Logger;
 import org.keycloak.Config;
 import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
 import org.keycloak.models.KeycloakSession;
@@ -8,6 +18,8 @@ import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.cache.CacheRealmProvider;
 import org.keycloak.models.cache.CacheRealmProviderFactory;
 import org.keycloak.models.cache.RealmCache;
+import org.keycloak.models.cache.entities.CachedRealm;
+import org.keycloak.models.cache.entities.CachedUser;
 
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -17,15 +29,43 @@ import java.util.concurrent.ConcurrentHashMap;
  */
 public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFactory {
 
-    protected final ConcurrentHashMap<String, String> realmLookup = new ConcurrentHashMap<String, String>();
+    private static final Logger log = Logger.getLogger(InfinispanCacheRealmProviderFactory.class);
+
+    protected volatile InfinispanRealmCache realmCache;
+
+    protected final ConcurrentHashMap<String, String> realmLookup = new ConcurrentHashMap<>();
+
+    private boolean isNewInfinispan;
 
     @Override
     public CacheRealmProvider create(KeycloakSession session) {
-        Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
-        RealmCache realmCache = new InfinispanRealmCache(cache, realmLookup);
+        lazyInit(session);
         return new DefaultCacheRealmProvider(realmCache, session);
     }
 
+    private void lazyInit(KeycloakSession session) {
+        if (realmCache == null) {
+            synchronized (this) {
+                if (realmCache == null) {
+                    checkIspnVersion();
+
+                    Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
+                    cache.addListener(new CacheListener());
+                    realmCache = new InfinispanRealmCache(cache, realmLookup);
+                }
+            }
+        }
+    }
+
+    protected void checkIspnVersion() {
+        try {
+            CacheEntryCreatedEvent.class.getMethod("getValue");
+            isNewInfinispan = true;
+        } catch (NoSuchMethodException nsme) {
+            isNewInfinispan = false;
+        }
+    }
+
     @Override
     public void init(Config.Scope config) {
     }
@@ -44,4 +84,71 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa
         return "infinispan";
     }
 
+    @Listener
+    public class CacheListener {
+
+        @CacheEntryCreated
+        public void created(CacheEntryCreatedEvent<String, Object> event) {
+            if (!event.isPre()) {
+                Object object;
+
+                // Try optimized version if available
+                if (isNewInfinispan) {
+                    object = event.getValue();
+                } else {
+                    String id = event.getKey();
+                    object = event.getCache().get(id);
+                }
+
+                if (object != null) {
+                    if (object instanceof CachedRealm) {
+                        CachedRealm realm = (CachedRealm) object;
+                        realmLookup.put(realm.getName(), realm.getId());
+                        log.tracev("Realm added realm={0}", realm.getName());
+                    }
+                }
+            }
+        }
+
+        @CacheEntryRemoved
+        public void removed(CacheEntryRemovedEvent<String, Object> event) {
+            if (event.isPre()) {
+                Object object = event.getValue();
+                if (object != null) {
+                    remove(object);
+                }
+            }
+        }
+
+        @CacheEntryInvalidated
+        public void removed(CacheEntryInvalidatedEvent<String, Object> event) {
+            if (event.isPre()) {
+                Object object = event.getValue();
+                if (object != null) {
+                    remove(object);
+                }
+            }
+        }
+
+        @CacheEntriesEvicted
+        public void userEvicted(CacheEntriesEvictedEvent<String, Object> event) {
+            for (Object object : event.getEntries().values()) {
+                remove(object);
+            }
+        }
+
+        private void remove(Object object) {
+            if (object instanceof CachedRealm) {
+                CachedRealm realm = (CachedRealm) object;
+
+                realmLookup.remove(realm.getName());
+
+                for (String c : realm.getClients().values()) {
+                    realmCache.evictCachedApplicationById(c);
+                }
+
+                log.tracev("Realm removed realm={0}", realm.getName());
+            }
+        }
+    }
 }
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
index 4eb0bdf..ec69912 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
@@ -26,7 +26,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact
 
     private static final Logger log = Logger.getLogger(InfinispanCacheUserProviderFactory.class);
 
-    protected InfinispanUserCache userCache;
+    protected volatile InfinispanUserCache userCache;
 
     protected final RealmLookup usernameLookup = new RealmLookup();
 
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java
index a5239fb..8155801 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java
@@ -38,9 +38,10 @@ public class InfinispanRealmCache implements RealmCache {
 
     @Override
     public void setEnabled(boolean enabled) {
-        clear();
+        if (this.enabled && !enabled) {
+            clear();
+        }
         this.enabled = enabled;
-        clear();
     }
 
     @Override
@@ -66,7 +67,7 @@ public class InfinispanRealmCache implements RealmCache {
     public void addCachedRealm(CachedRealm realm) {
         if (!enabled) return;
         logger.tracev("Adding realm {0}", realm.getId());
-        cache.put(realm.getId(), realm);
+        cache.putForExternalRead(realm.getId(), realm);
         realmLookup.put(realm.getName(), realm.getId());
     }
 
@@ -93,7 +94,7 @@ public class InfinispanRealmCache implements RealmCache {
     public void addCachedClient(CachedClient app) {
         if (!enabled) return;
         logger.tracev("Adding application {0}", app.getId());
-        cache.put(app.getId(), app);
+        cache.putForExternalRead(app.getId(), app);
     }
 
     @Override
@@ -103,6 +104,12 @@ public class InfinispanRealmCache implements RealmCache {
     }
 
     @Override
+    public void evictCachedApplicationById(String id) {
+        logger.tracev("Evicting application {0}", id);
+        cache.evict(id);
+    }
+
+    @Override
     public CachedGroup getGroup(String id) {
         if (!enabled) return null;
         return get(id, CachedGroup.class);
@@ -112,15 +119,13 @@ public class InfinispanRealmCache implements RealmCache {
     public void invalidateGroup(CachedGroup role) {
         logger.tracev("Removing group {0}", role.getId());
         cache.remove(role.getId());
-
     }
 
     @Override
     public void addCachedGroup(CachedGroup role) {
         if (!enabled) return;
         logger.tracev("Adding group {0}", role.getId());
-        cache.put(role.getId(), role);
-
+        cache.putForExternalRead(role.getId(), role);
     }
 
     @Override
@@ -134,7 +139,6 @@ public class InfinispanRealmCache implements RealmCache {
     public void invalidateGroupById(String id) {
         logger.tracev("Removing group {0}", id);
         cache.remove(id);
-
     }
 
     @Override
@@ -143,8 +147,6 @@ public class InfinispanRealmCache implements RealmCache {
         return get(id, CachedRole.class);
     }
 
-
-
     @Override
     public void invalidateRole(CachedRole role) {
         logger.tracev("Removing role {0}", role.getId());
@@ -161,7 +163,7 @@ public class InfinispanRealmCache implements RealmCache {
     public void addCachedRole(CachedRole role) {
         if (!enabled) return;
         logger.tracev("Adding role {0}", role.getId());
-        cache.put(role.getId(), role);
+        cache.putForExternalRead(role.getId(), role);
     }
 
     @Override
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java
index fbb36c5..c5e960c 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java
@@ -35,9 +35,10 @@ public class InfinispanUserCache implements UserCache {
 
     @Override
     public void setEnabled(boolean enabled) {
-        clear();
+        if (this.enabled && !enabled) {
+            clear();
+        }
         this.enabled = enabled;
-        clear();
     }
 
     @Override
@@ -62,7 +63,7 @@ public class InfinispanUserCache implements UserCache {
     @Override
     public void addCachedUser(String realmId, CachedUser user) {
         logger.tracev("Adding user {0}", user.getId());
-        cache.put(user.getId(), user);
+        cache.putForExternalRead(user.getId(), user);
     }
 
     @Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java
index df74b53..007daac 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmCache.java
@@ -26,6 +26,8 @@ public interface RealmCache {
 
     void invalidateApplication(CachedClient app);
 
+    void evictCachedApplicationById(String id);
+
     void addCachedClient(CachedClient app);
 
     void invalidateCachedApplicationById(String id);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
index 660b1c4..672745c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
@@ -31,6 +31,7 @@ import org.keycloak.provider.Spi;
 import org.keycloak.representations.idm.ConfigPropertyRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
+import org.keycloak.representations.info.*;
 import org.keycloak.social.SocialIdentityProvider;
 
 /**
@@ -51,7 +52,7 @@ public class ServerInfoAdminResource {
     @GET
     public ServerInfoRepresentation getInfo() {
         ServerInfoRepresentation info = new ServerInfoRepresentation();
-        info.setSystemInfo(SystemInfoRepresentation.create(session));
+        info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp()));
         info.setMemoryInfo(MemoryInfoRepresentation.create());
 
         setSocialProviders(info);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index dd575b1..31f88bc 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -1,24 +1,26 @@
 package org.keycloak.testsuite.admin;
 
+import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.ProtocolMappersResource;
 import org.keycloak.models.Constants;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
-import org.keycloak.representations.idm.ClientRepresentation;
-import org.keycloak.representations.idm.ProtocolMapperRepresentation;
-import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.representations.idm.*;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
 import javax.ws.rs.NotFoundException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -46,19 +48,21 @@ public class ClientTest extends AbstractClientTest {
         assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID);
     }
 
-    private String createClient() {
+    private ClientRepresentation createClient() {
         ClientRepresentation rep = new ClientRepresentation();
         rep.setClientId("my-app");
         rep.setDescription("my-app description");
         rep.setEnabled(true);
         Response response = realm.clients().create(rep);
         response.close();
-        return ApiUtil.getCreatedId(response);
+        String id = ApiUtil.getCreatedId(response);
+        rep.setId(id);
+        return rep;
     }
 
     @Test
     public void createClientVerify() {
-        String id = createClient();
+        String id = createClient().getId();
 
         assertNotNull(realm.clients().get(id));
         assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app", Constants.ADMIN_CLI_CLIENT_ID);
@@ -66,14 +70,14 @@ public class ClientTest extends AbstractClientTest {
 
     @Test
     public void removeClient() {
-        String id = createClient();
+        String id = createClient().getId();
 
         realm.clients().get(id).remove();
     }
 
     @Test
     public void getClientRepresentation() {
-        String id = createClient();
+        String id = createClient().getId();
 
         ClientRepresentation rep = realm.clients().get(id).toRepresentation();
         assertEquals(id, rep.getId());
@@ -86,8 +90,7 @@ public class ClientTest extends AbstractClientTest {
      */
     @Test
     public void getClientDescription() {
-
-        String id = createClient();
+        String id = createClient().getId();
 
         ClientRepresentation rep = realm.clients().get(id).toRepresentation();
         assertEquals(id, rep.getId());
@@ -145,6 +148,28 @@ public class ClientTest extends AbstractClientTest {
         protocolMappersTest(mappersResource);
     }
 
+    @Test
+    public void updateClient() {
+        ClientRepresentation client = createClient();
+
+        ClientRepresentation newClient = new ClientRepresentation();
+        newClient.setId(client.getId());
+        newClient.setClientId(client.getClientId());
+        newClient.setBaseUrl("http://baseurl");
+
+        realm.clients().get(client.getId()).update(newClient);
+
+        ClientRepresentation storedClient = realm.clients().get(client.getId()).toRepresentation();
+
+        assertClient(client, storedClient);
+
+        newClient.setSecret("new-secret");
+
+        realm.clients().get(client.getId()).update(newClient);
+
+        storedClient = realm.clients().get(client.getId()).toRepresentation();
+        assertClient(client, storedClient);
+    }
 
     public static void protocolMappersTest(ProtocolMappersResource mappersResource) {
         // assert default mappers found
@@ -197,4 +222,62 @@ public class ClientTest extends AbstractClientTest {
         }
     }
 
+    public static void assertClient(ClientRepresentation client, ClientRepresentation storedClient) {
+        if (client.getClientId() != null) Assert.assertEquals(client.getClientId(), storedClient.getClientId());
+        if (client.getName() != null) Assert.assertEquals(client.getName(), storedClient.getName());
+        if (client.isEnabled() != null) Assert.assertEquals(client.isEnabled(), storedClient.isEnabled());
+        if (client.isBearerOnly() != null) Assert.assertEquals(client.isBearerOnly(), storedClient.isBearerOnly());
+        if (client.isPublicClient() != null) Assert.assertEquals(client.isPublicClient(), storedClient.isPublicClient());
+        if (client.isFullScopeAllowed() != null) Assert.assertEquals(client.isFullScopeAllowed(), storedClient.isFullScopeAllowed());
+        if (client.getRootUrl() != null) Assert.assertEquals(client.getRootUrl(), storedClient.getRootUrl());
+        if (client.getAdminUrl() != null) Assert.assertEquals(client.getAdminUrl(), storedClient.getAdminUrl());
+        if (client.getBaseUrl() != null) Assert.assertEquals(client.getBaseUrl(), storedClient.getBaseUrl());
+        if (client.isSurrogateAuthRequired() != null) Assert.assertEquals(client.isSurrogateAuthRequired(), storedClient.isSurrogateAuthRequired());
+        if (client.getClientAuthenticatorType() != null) Assert.assertEquals(client.getClientAuthenticatorType(), storedClient.getClientAuthenticatorType());
+
+        if (client.getNotBefore() != null) {
+            Assert.assertEquals(client.getNotBefore(), storedClient.getNotBefore());
+        }
+        if (client.getDefaultRoles() != null) {
+            Set<String> set = new HashSet<String>();
+            for (String val : client.getDefaultRoles()) {
+                set.add(val);
+            }
+            Set<String> storedSet = new HashSet<String>();
+            for (String val : storedClient.getDefaultRoles()) {
+                storedSet.add(val);
+            }
+
+            Assert.assertEquals(set, storedSet);
+        }
+
+        List<String> redirectUris = client.getRedirectUris();
+        if (redirectUris != null) {
+            Set<String> set = new HashSet<String>();
+            for (String val : client.getRedirectUris()) {
+                set.add(val);
+            }
+            Set<String> storedSet = new HashSet<String>();
+            for (String val : storedClient.getRedirectUris()) {
+                storedSet.add(val);
+            }
+
+            Assert.assertEquals(set, storedSet);
+        }
+
+        List<String> webOrigins = client.getWebOrigins();
+        if (webOrigins != null) {
+            Set<String> set = new HashSet<String>();
+            for (String val : client.getWebOrigins()) {
+                set.add(val);
+            }
+            Set<String> storedSet = new HashSet<String>();
+            for (String val : storedClient.getWebOrigins()) {
+                storedSet.add(val);
+            }
+
+            Assert.assertEquals(set, storedSet);
+        }
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
index 42870a6..604dcff 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
@@ -1,6 +1,7 @@
 package org.keycloak.testsuite.admin;
 
 import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -8,6 +9,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.KeycloakServer;
 import org.keycloak.util.JsonSerialization;
 
 import javax.ws.rs.NotFoundException;
@@ -43,7 +45,7 @@ public class RealmTest extends AbstractClientTest {
     }
 
     @Test
-    public void createRealm() {
+    public void createRealmEmpty() {
         try {
             RealmRepresentation rep = new RealmRepresentation();
             rep.setRealm("new-realm");
@@ -63,6 +65,25 @@ public class RealmTest extends AbstractClientTest {
     }
 
     @Test
+    public void createRealm() {
+        try {
+            RealmRepresentation rep = KeycloakServer.loadJson(getClass().getResourceAsStream("/admin-test/testrealm.json"), RealmRepresentation.class);
+            keycloak.realms().create(rep);
+
+            RealmRepresentation created = keycloak.realms().realm("admin-test-1").toRepresentation();
+            assertRealm(rep, created);
+        } finally {
+            KeycloakSession session = keycloakRule.startSession();
+            RealmManager manager = new RealmManager(session);
+            RealmModel newRealm = manager.getRealmByName("admin-test-1");
+            if (newRealm != null) {
+                manager.removeRealm(newRealm);
+            }
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+    @Test
     public void removeRealm() {
         realm.remove();
 
@@ -194,4 +215,64 @@ public class RealmTest extends AbstractClientTest {
         assertEquals("https://LoadBalancer-9.siroe.com:3443/federation/Consumer/metaAlias/sp", converted.getRedirectUris().get(0));
     }
 
+    public static void assertRealm(RealmRepresentation realm, RealmRepresentation storedRealm) {
+        if (realm.getId() != null) {
+            Assert.assertEquals(realm.getId(), storedRealm.getId());
+        }
+        if (realm.getRealm() != null) {
+            Assert.assertEquals(realm.getRealm(), storedRealm.getRealm());
+        }
+        if (realm.isEnabled() != null) Assert.assertEquals(realm.isEnabled(), storedRealm.isEnabled());
+        if (realm.isBruteForceProtected() != null) Assert.assertEquals(realm.isBruteForceProtected(), storedRealm.isBruteForceProtected());
+        if (realm.getMaxFailureWaitSeconds() != null) Assert.assertEquals(realm.getMaxFailureWaitSeconds(), storedRealm.getMaxFailureWaitSeconds());
+        if (realm.getMinimumQuickLoginWaitSeconds() != null) Assert.assertEquals(realm.getMinimumQuickLoginWaitSeconds(), storedRealm.getMinimumQuickLoginWaitSeconds());
+        if (realm.getWaitIncrementSeconds() != null) Assert.assertEquals(realm.getWaitIncrementSeconds(), storedRealm.getWaitIncrementSeconds());
+        if (realm.getQuickLoginCheckMilliSeconds() != null) Assert.assertEquals(realm.getQuickLoginCheckMilliSeconds(), storedRealm.getQuickLoginCheckMilliSeconds());
+        if (realm.getMaxDeltaTimeSeconds() != null) Assert.assertEquals(realm.getMaxDeltaTimeSeconds(), storedRealm.getMaxDeltaTimeSeconds());
+        if (realm.getFailureFactor() != null) Assert.assertEquals(realm.getFailureFactor(), storedRealm.getFailureFactor());
+        if (realm.isRegistrationAllowed() != null) Assert.assertEquals(realm.isRegistrationAllowed(), storedRealm.isRegistrationAllowed());
+        if (realm.isRegistrationEmailAsUsername() != null) Assert.assertEquals(realm.isRegistrationEmailAsUsername(), storedRealm.isRegistrationEmailAsUsername());
+        if (realm.isRememberMe() != null) Assert.assertEquals(realm.isRememberMe(), storedRealm.isRememberMe());
+        if (realm.isVerifyEmail() != null) Assert.assertEquals(realm.isVerifyEmail(), storedRealm.isVerifyEmail());
+        if (realm.isResetPasswordAllowed() != null) Assert.assertEquals(realm.isResetPasswordAllowed(), storedRealm.isResetPasswordAllowed());
+        if (realm.isEditUsernameAllowed() != null) Assert.assertEquals(realm.isEditUsernameAllowed(), storedRealm.isEditUsernameAllowed());
+        if (realm.getSslRequired() != null) Assert.assertEquals(realm.getSslRequired(), storedRealm.getSslRequired());
+        if (realm.getAccessCodeLifespan() != null) Assert.assertEquals(realm.getAccessCodeLifespan(), storedRealm.getAccessCodeLifespan());
+        if (realm.getAccessCodeLifespanUserAction() != null)
+            Assert.assertEquals(realm.getAccessCodeLifespanUserAction(), storedRealm.getAccessCodeLifespanUserAction());
+        if (realm.getNotBefore() != null) Assert.assertEquals(realm.getNotBefore(), storedRealm.getNotBefore());
+        if (realm.getAccessTokenLifespan() != null) Assert.assertEquals(realm.getAccessTokenLifespan(), storedRealm.getAccessTokenLifespan());
+        if (realm.getAccessTokenLifespanForImplicitFlow() != null) Assert.assertEquals(realm.getAccessTokenLifespanForImplicitFlow(), storedRealm.getAccessTokenLifespanForImplicitFlow());
+        if (realm.getSsoSessionIdleTimeout() != null) Assert.assertEquals(realm.getSsoSessionIdleTimeout(), storedRealm.getSsoSessionIdleTimeout());
+        if (realm.getSsoSessionMaxLifespan() != null) Assert.assertEquals(realm.getSsoSessionMaxLifespan(), storedRealm.getSsoSessionMaxLifespan());
+        if (realm.getRequiredCredentials() != null) {
+            Assert.assertNotNull(storedRealm.getRequiredCredentials());
+            for (String cred : realm.getRequiredCredentials()) {
+                Assert.assertTrue(storedRealm.getRequiredCredentials().contains(cred));
+            }
+        }
+        if (realm.getLoginTheme() != null) Assert.assertEquals(realm.getLoginTheme(), storedRealm.getLoginTheme());
+        if (realm.getAccountTheme() != null) Assert.assertEquals(realm.getAccountTheme(), storedRealm.getAccountTheme());
+        if (realm.getAdminTheme() != null) Assert.assertEquals(realm.getAdminTheme(), storedRealm.getAdminTheme());
+        if (realm.getEmailTheme() != null) Assert.assertEquals(realm.getEmailTheme(), storedRealm.getEmailTheme());
+
+        if (realm.getPasswordPolicy() != null) Assert.assertEquals(realm.getPasswordPolicy(), storedRealm.getPasswordPolicy());
+
+        if (realm.getDefaultRoles() != null) {
+            Assert.assertNotNull(storedRealm.getDefaultRoles());
+            for (String role : realm.getDefaultRoles()) {
+                Assert.assertTrue(storedRealm.getDefaultRoles().contains(role));
+            }
+        }
+
+        if (realm.getSmtpServer() != null) {
+            Assert.assertEquals(realm.getSmtpServer(), storedRealm.getSmtpServer());
+        }
+
+        if (realm.getBrowserSecurityHeaders() != null) {
+            Assert.assertEquals(realm.getBrowserSecurityHeaders(), storedRealm.getBrowserSecurityHeaders());
+        }
+
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ServerInfoTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ServerInfoTest.java
new file mode 100644
index 0000000..6c839c5
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ServerInfoTest.java
@@ -0,0 +1,44 @@
+package org.keycloak.testsuite.admin;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.common.Version;
+import org.keycloak.representations.info.ServerInfoRepresentation;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ServerInfoTest extends AbstractClientTest {
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @WebResource
+    protected WebDriver driver;
+
+    @WebResource
+    protected OAuthClient oauth;
+
+    @Test
+    public void testServerInfo() {
+        ServerInfoRepresentation info = keycloak.serverInfo().getInfo();
+
+        Assert.assertNotNull(info);
+        Assert.assertNotNull(info.getProviders());
+        Assert.assertNotNull(info.getThemes());
+        Assert.assertNotNull(info.getEnums());
+
+        Assert.assertNotNull(info.getMemoryInfo());
+        Assert.assertNotNull(info.getSystemInfo());
+
+        Assert.assertEquals(Version.VERSION, info.getSystemInfo().getVersion());
+        Assert.assertNotNull(info.getSystemInfo().getServerTime());
+        Assert.assertNotNull(info.getSystemInfo().getUptime());
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
index 597e7dd..a9b907c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
@@ -7,10 +7,12 @@ import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.keycloak.models.*;
+import org.keycloak.models.cache.infinispan.ClientAdapter;
 import org.keycloak.models.cache.infinispan.RealmAdapter;
 import org.keycloak.testsuite.rule.KeycloakRule;
 
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -27,10 +29,12 @@ public class CacheTest {
             // load up cache
             KeycloakSession session = kc.startSession();
             RealmModel realm = session.realms().getRealmByName("test");
+            assertTrue(realm instanceof RealmAdapter);
             ClientModel testApp = realm.getClientByClientId("test-app");
+            assertTrue(testApp instanceof ClientAdapter);
             assertNotNull(testApp);
             appId = testApp.getId();
-            Assert.assertTrue(testApp.isEnabled());
+            assertTrue(testApp.isEnabled());
             kc.stopSession(session, true);
         }
         {
@@ -40,16 +44,18 @@ public class CacheTest {
             // KEYCLOAK-1240 - obtain the realm via session.realms().getRealms()
             RealmModel realm = null;
             List<RealmModel> realms = session.realms().getRealms();
+
             for (RealmModel current : realms) {
+                assertTrue(current instanceof RealmAdapter);
                 if ("test".equals(current.getName())) {
                     realm = current;
                     break;
                 }
             }
 
-            Assert.assertTrue(realm instanceof RealmAdapter);
             realm.setAccessCodeLifespanLogin(200);
             ClientModel testApp = realm.getClientByClientId("test-app");
+
             assertNotNull(testApp);
             testApp.setEnabled(false);
             kc.stopSession(session, true);
@@ -62,10 +68,7 @@ public class CacheTest {
             ClientModel testApp = session.realms().getClientById(appId, realm);
             Assert.assertFalse(testApp.isEnabled());
             kc.stopSession(session, true);
-
         }
-
-
     }
 
     @Test
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index 5bccb0e..01f6cd5 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -21,6 +21,9 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterP
 # Enable to view infinispan initialization
 # log4j.logger.org.keycloak.models.sessions.infinispan.initializer=trace
 
+# Enable to view cache activity
+# log4j.logger.org.keycloak.models.cache=trace
+
 # Enable to view database updates
 # log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
 # log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug