keycloak-aplcache

KEYCLOAK 2538 - UI group pagination - TU + some code improvement

9/12/2017 10:09:08 AM

Details

diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index 54166f5..5994089 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -111,6 +111,11 @@
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/model/jpa/src/test/java/org/keycloak/models/jpa/JpaRealmProviderTest.java b/model/jpa/src/test/java/org/keycloak/models/jpa/JpaRealmProviderTest.java
new file mode 100644
index 0000000..fc8ffa4
--- /dev/null
+++ b/model/jpa/src/test/java/org/keycloak/models/jpa/JpaRealmProviderTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+package org.keycloak.models.jpa;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.jpa.entities.GroupEntity;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+import java.util.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+
+/**
+ * @author <a href="mailto:levente.nagy@itesoft.com">NAGY Léventé</a>
+ * @version $Revision: 1 $
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class JpaRealmProviderTest {
+
+    private JpaRealmProvider subject;
+
+    private RealmModel realmModelMock;
+    private RealmProvider realmProviderMock;
+    private KeycloakSession sessionMock;
+    private EntityManager entityManagerMock;
+
+    @Before
+    public void setup() {
+        realmModelMock = mock(RealmModel.class);
+        realmProviderMock = mock(RealmProvider.class);
+        sessionMock = mock(KeycloakSession.class);
+        entityManagerMock = mock(EntityManager.class);
+
+        subject = new JpaRealmProvider(sessionMock, entityManagerMock);
+
+        // Common behaviours
+        when(realmProviderMock.getGroupById(anyString(), any(RealmModel.class))).thenAnswer((Answer<GroupModel>) invocationOnMock -> {
+            GroupEntity entity = new GroupEntity();
+            entity.setId((String) invocationOnMock.getArguments()[0]);
+            entity.setName((String) invocationOnMock.getArguments()[0]);
+            return new GroupAdapter(realmModelMock, entityManagerMock, entity);
+        });
+    }
+
+    @Test
+    public void testGetGroupsCountAllGroups() {
+        // Given
+        Long result = 10L;
+        String idRealm = "idGroup";
+        TypedQuery<Long> query = mock(TypedQuery.class);
+
+        // When
+        when(entityManagerMock.createNamedQuery("getGroupCount", Long.class)).thenReturn(query);
+        when(realmModelMock.getId()).thenReturn(idRealm);
+        when(query.setParameter("realm", idRealm)).thenReturn(query);
+        when(query.getSingleResult()).thenReturn(result);
+
+        // Then
+        Long countResult = subject.getGroupsCount(realmModelMock, false);
+
+        assertEquals(result, countResult);
+    }
+
+    @Test
+    public void testGetGroupsCountOnlyTopLevelGroups() {
+        // Given
+        Long result = 10L;
+        String idRealm = "idGroup";
+        TypedQuery<Long> query = mock(TypedQuery.class);
+
+        // When
+        when(entityManagerMock.createNamedQuery("getTopLevelGroupCount", Long.class)).thenReturn(query);
+        when(realmModelMock.getId()).thenReturn(idRealm);
+        when(query.setParameter("realm", idRealm)).thenReturn(query);
+        when(query.getSingleResult()).thenReturn(result);
+
+        // Then
+        Long countResult = subject.getGroupsCount(realmModelMock, true);
+
+        assertEquals(result, countResult);
+    }
+
+    @Test
+    public void testSearchForGroupByNameWithAllParams() {
+        // Given
+        List<String> result = Arrays.asList("idGroup1", "idGroup2", "idGroup3");
+        String idRealm = "idGroup";
+        TypedQuery<String> query = mock(TypedQuery.class);
+        String search = "findMe";
+        Integer first = 0;
+        Integer max = 10;
+
+        // When
+        when(entityManagerMock.createNamedQuery("getGroupIdsByNameContaining", String.class)).thenReturn(query);
+        when(realmModelMock.getId()).thenReturn(idRealm);
+        when(query.setParameter("realm", idRealm)).thenReturn(query);
+        when(query.setParameter("search", search)).thenReturn(query);
+        when(query.setFirstResult(first)).thenReturn(query);
+        when(query.setMaxResults(max)).thenReturn(query);
+        when(query.getResultList()).thenReturn(result);
+        when(sessionMock.realms()).thenReturn(realmProviderMock);
+
+        // Then
+        List<GroupModel> searchResult = subject.searchForGroupByName(realmModelMock, search, first, max);
+
+        assertEquals(result.size(), searchResult.size());
+    }
+
+    @Test
+    public void testSearchForGroupByNameWithNullQueryResult() {
+        // Given
+        String idRealm = "idGroup";
+        TypedQuery<String> query = mock(TypedQuery.class);
+        String search = "findMe";
+
+        // When
+        when(entityManagerMock.createNamedQuery("getGroupIdsByNameContaining", String.class)).thenReturn(query);
+        when(realmModelMock.getId()).thenReturn(idRealm);
+        when(query.setParameter("realm", idRealm)).thenReturn(query);
+        when(query.setParameter("search", search)).thenReturn(query);
+        when(query.getResultList()).thenReturn(null);
+        when(sessionMock.realms()).thenReturn(realmProviderMock);
+
+        // Then
+        List<GroupModel> searchResult = subject.searchForGroupByName(realmModelMock, search, null, null);
+
+        assertEquals(Collections.EMPTY_LIST, searchResult);
+    }
+
+    @Test
+    public void testSearchForGroupByNameWithNonTopLevelGroupInQueryResult() {
+        // Given
+        List<String> result = Arrays.asList("idGroup1", "idGroup2", "idGroup3", "idGroup4");
+        String idRealm = "idGroup";
+        TypedQuery<String> query = mock(TypedQuery.class);
+        String search = "findMe";
+        Integer first = 0;
+        Integer max = 10;
+
+        // When
+        when(entityManagerMock.createNamedQuery("getGroupIdsByNameContaining", String.class)).thenReturn(query);
+        when(realmModelMock.getId()).thenReturn(idRealm);
+        when(query.setParameter("realm", idRealm)).thenReturn(query);
+        when(query.setParameter("search", search)).thenReturn(query);
+        when(query.setFirstResult(first)).thenReturn(query);
+        when(query.setMaxResults(max)).thenReturn(query);
+        when(query.getResultList()).thenReturn(result);
+        when(sessionMock.realms()).thenReturn(realmProviderMock);
+        when(realmProviderMock.getGroupById(anyString(), any(RealmModel.class))).thenAnswer((Answer<GroupModel>) invocationOnMock -> {
+            GroupEntity entity = new GroupEntity();
+            entity.setId((String) invocationOnMock.getArguments()[0]);
+            entity.setName((String) invocationOnMock.getArguments()[0]);
+            if(Arrays.asList("idGroup2", "idGroup4").contains(invocationOnMock.getArguments()[0])) {
+                entity.setParent(new GroupEntity());
+                entity.getParent().setId("idGroup5");
+                entity.getParent().setName("idGroup5");
+            }
+            return new GroupAdapter(realmModelMock, entityManagerMock, entity);
+        });
+
+        // Then
+        List<GroupModel> searchResult = subject.searchForGroupByName(realmModelMock, search, first, max);
+
+        assertEquals(3,searchResult.size());
+    }
+
+    @Test
+    public void testGetGroupsCountByNameContaining() {
+        // Given
+        List<String> result = Arrays.asList("idGroup1", "idGroup2", "idGroup3", "idGroup4");
+        String idRealm = "idGroup";
+        TypedQuery<String> query = mock(TypedQuery.class);
+        String search = "findMe";
+
+        // When
+        when(entityManagerMock.createNamedQuery("getGroupIdsByNameContaining", String.class)).thenReturn(query);
+        when(realmModelMock.getId()).thenReturn(idRealm);
+        when(query.setParameter("realm", idRealm)).thenReturn(query);
+        when(query.setParameter("search", search)).thenReturn(query);
+        when(query.getResultList()).thenReturn(result);
+        when(sessionMock.realms()).thenReturn(realmProviderMock);
+
+        // Then
+        Long countResult = subject.getGroupsCountByNameContaining(realmModelMock, search);
+
+        verify(query, never()).setFirstResult(anyInt());
+        verify(query, never()).setFirstResult(anyInt());
+        assertEquals(result.size(), countResult.intValue());
+    }
+}

pom.xml 7(+7 -0)

diff --git a/pom.xml b/pom.xml
index 8b216dc..e437123 100755
--- a/pom.xml
+++ b/pom.xml
@@ -108,6 +108,7 @@
         <hamcrest.version>1.3</hamcrest.version>
         <jmeter.version>2.10</jmeter.version>
         <junit.version>4.12</junit.version>
+        <mockito.version>1.9.5</mockito.version>
         <picketlink.version>2.7.0.Final</picketlink.version>
         <selenium.version>2.35.0</selenium.version>
         <xml-apis.version>1.4.01</xml-apis.version>
@@ -368,6 +369,12 @@
                 <scope>test</scope>
             </dependency>
             <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-all</artifactId>
+                <scope>test</scope>
+                <version>${mockito.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>org.hamcrest</groupId>
                 <artifactId>hamcrest-all</artifactId>
                 <version>${hamcrest.version}</version>
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index d11c272..225117d 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -76,12 +76,7 @@ public class ModelToRepresentation {
             } else {
                 ClientModel client = (ClientModel)role.getContainer();
                 String clientId = client.getClientId();
-                List<String> currentClientRoles = clientRoleNames.get(clientId);
-                if (currentClientRoles == null) {
-                    currentClientRoles = new ArrayList<>();
-                    clientRoleNames.put(clientId, currentClientRoles);
-                }
-
+                List<String> currentClientRoles = clientRoleNames.computeIfAbsent(clientId, k -> new ArrayList<>());
                 currentClientRoles.add(role.getName());
             }
         }
@@ -153,9 +148,7 @@ public class ModelToRepresentation {
 
         List<String> reqActions = new ArrayList<String>();
         Set<String> requiredActions = user.getRequiredActions();
-        for (String ra : requiredActions){
-            reqActions.add(ra);
-        }
+        reqActions.addAll(requiredActions);
 
         rep.setRequiredActions(reqActions);
 
@@ -609,11 +602,7 @@ public class ModelToRepresentation {
         Map<String, List<String>> grantedProtocolMappers = new HashMap<String, List<String>>();
         for (ProtocolMapperModel protocolMapper : model.getGrantedProtocolMappers()) {
             String protocol = protocolMapper.getProtocol();
-            List<String> currentProtocolMappers = grantedProtocolMappers.get(protocol);
-            if (currentProtocolMappers == null) {
-                currentProtocolMappers = new LinkedList<String>();
-                grantedProtocolMappers.put(protocol, currentProtocolMappers);
-            }
+            List<String> currentProtocolMappers = grantedProtocolMappers.computeIfAbsent(protocol, k -> new LinkedList<String>());
             currentProtocolMappers.add(protocolMapper.getName());
         }
 
@@ -626,11 +615,7 @@ public class ModelToRepresentation {
                 ClientModel client2 = (ClientModel) role.getContainer();
 
                 String clientId2 = client2.getClientId();
-                List<String> currentClientRoles = grantedClientRoles.get(clientId2);
-                if (currentClientRoles == null) {
-                    currentClientRoles = new LinkedList<String>();
-                    grantedClientRoles.put(clientId2, currentClientRoles);
-                }
+                List<String> currentClientRoles = grantedClientRoles.computeIfAbsent(clientId2, k -> new LinkedList<String>());
                 currentClientRoles.add(role.getName());
             }
         }

services/pom.xml 5(+5 -0)

diff --git a/services/pom.xml b/services/pom.xml
index 733b812..cbbf3da 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -180,6 +180,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
index ef70455..958b995 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
@@ -126,7 +126,6 @@ public class GroupsResource {
         try {
             response.put("count", results);
         } catch (JSONException e) {
-            e.printStackTrace();
             return ErrorResponse.error("Cannot create response object", Response.Status.INTERNAL_SERVER_ERROR);
         }
         return Response.ok(response.toString(), MediaType.APPLICATION_JSON).build();
diff --git a/services/src/test/java/org/keycloak/services/resources/admin/GroupsResourceTest.java b/services/src/test/java/org/keycloak/services/resources/admin/GroupsResourceTest.java
new file mode 100644
index 0000000..9783bbb
--- /dev/null
+++ b/services/src/test/java/org/keycloak/services/resources/admin/GroupsResourceTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+package org.keycloak.services.resources.admin;
+
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
+import org.keycloak.services.resources.admin.permissions.GroupPermissionEvaluator;
+import twitter4j.JSONException;
+import twitter4j.JSONObject;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author <a href="mailto:levente.nagy@itesoft.com">NAGY Léventé</a>
+ * @version $Revision: 1 $
+ */
+public class GroupsResourceTest {
+
+    private GroupsResource subject;
+
+    private RealmModel realmMock;
+    private KeycloakSession sessionMock;
+    private AdminPermissionEvaluator authMock;
+    private AdminEventBuilder adminEventBuilderMock;
+
+    @Before
+    public void setup() {
+        realmMock = mock(RealmModel.class);
+        sessionMock = mock(KeycloakSession.class);
+        authMock = mock(AdminPermissionEvaluator.class);
+        when(authMock.groups()).thenReturn(mock(GroupPermissionEvaluator.class));
+
+        adminEventBuilderMock = mock(AdminEventBuilder.class);
+        when(adminEventBuilderMock.resource(ResourceType.GROUP)).thenReturn(adminEventBuilderMock);
+
+        subject= new GroupsResource(realmMock, sessionMock, authMock, adminEventBuilderMock);
+    }
+
+    @Test
+    public void testGetGroupWithAllParams() {
+        // Given
+        String search = "hello";
+        Integer first = 0;
+        Integer max = 20;
+        String groupId = "groupId";
+        String groupName = "groupName";
+        GroupModel groupMock = mock(GroupModel.class);
+        List<GroupModel> groupsList = Collections.singletonList(groupMock);
+
+        // When
+        when(realmMock.searchForGroupByName(search, first, max)).thenReturn(groupsList);
+        when(groupMock.getSubGroups()).thenReturn(Collections.EMPTY_SET);
+        when(groupMock.getId()).thenReturn(groupId);
+        when(groupMock.getName()).thenReturn(groupName);
+        when(groupMock.getParent()).thenReturn(null);
+
+        //Then
+        List<GroupRepresentation> result = subject.getGroups(search, first,max);
+
+        Assert.assertEquals(groupsList.size(), result.size());
+        Assert.assertEquals(groupId, result.get(0).getId());
+        Assert.assertEquals(groupName, result.get(0).getName());
+        Assert.assertTrue(result.get(0).getSubGroups().isEmpty());
+    }
+
+    @Test
+    public void testGetGroupWithoutSearch() {
+        // Given
+        Integer first = 0;
+        Integer max = 20;
+        String groupId = "groupId";
+        String groupName = "groupName";
+        GroupModel groupMock = mock(GroupModel.class);
+        List<GroupModel> groupsList = Collections.singletonList(groupMock);
+
+        // When
+        when(realmMock.getTopLevelGroups(first, max)).thenReturn(groupsList);
+        when(groupMock.getSubGroups()).thenReturn(Collections.EMPTY_SET);
+        when(groupMock.getId()).thenReturn(groupId);
+        when(groupMock.getName()).thenReturn(groupName);
+        when(groupMock.getParent()).thenReturn(null);
+
+        //Then
+        List<GroupRepresentation> result = subject.getGroups(null, first,max);
+
+        Assert.assertEquals(groupsList.size(), result.size());
+        Assert.assertEquals(groupId, result.get(0).getId());
+        Assert.assertEquals(groupName, result.get(0).getName());
+        Assert.assertTrue(result.get(0).getSubGroups().isEmpty());
+    }
+
+    @Test
+    public void testGetGroupWithoutSearchAndPagination() {
+        // Given
+        String groupId = "groupId";
+        String groupName = "groupName";
+        GroupModel groupMock = mock(GroupModel.class);
+        List<GroupModel> groupsList = Collections.singletonList(groupMock);
+
+        // When
+        when(realmMock.getTopLevelGroups()).thenReturn(groupsList);
+        when(groupMock.getSubGroups()).thenReturn(Collections.EMPTY_SET);
+        when(groupMock.getId()).thenReturn(groupId);
+        when(groupMock.getName()).thenReturn(groupName);
+        when(groupMock.getParent()).thenReturn(null);
+
+        //Then
+        List<GroupRepresentation> result = subject.getGroups(null, null, null);
+
+        Assert.assertEquals(groupsList.size(), result.size());
+        Assert.assertEquals(groupId, result.get(0).getId());
+        Assert.assertEquals(groupName, result.get(0).getName());
+        Assert.assertTrue(result.get(0).getSubGroups().isEmpty());
+    }
+
+    @Test
+    public void testGetGroupCountWithSearchAndTopLevelFlagTrue() {
+        // Given
+        String search = "search";
+        Long countResult = 5L;
+        JSONObject response = new JSONObject();
+        try {
+            response.put("count", countResult);
+        } catch (JSONException e) {
+            fail(e.getMessage());
+        }
+
+        // When
+        when(realmMock.getGroupsCountByNameContaining(search)).thenReturn(countResult);
+
+        //Then
+        Response restResponse = subject.getGroupCount(search, "true");
+
+        assertEquals(response.toString(), restResponse.getEntity());
+        assertEquals(MediaType.APPLICATION_JSON, restResponse.getMediaType().toString());
+    }
+
+    @Test
+    public void testGetGroupCountWithoutSearchAndTopLevelFlagTrue() {
+        // Given
+        Long countResult = 5L;
+        JSONObject response = new JSONObject();
+        try {
+            response.put("count", countResult);
+        } catch (JSONException e) {
+            fail(e.getMessage());
+        }
+
+        // When
+        when(realmMock.getGroupsCount(true)).thenReturn(countResult);
+
+        //Then
+        Response restResponse = subject.getGroupCount(null, "true");
+
+        assertEquals(response.toString(), restResponse.getEntity());
+        assertEquals(MediaType.APPLICATION_JSON, restResponse.getMediaType().toString());
+    }
+
+    @Test
+    public void testGetGroupCountWithoutSearchAndTopLevelFlagFalse() {
+        // Given
+        Long countResult = 5L;
+        JSONObject response = new JSONObject();
+        try {
+            response.put("count", countResult);
+        } catch (JSONException e) {
+            fail(e.getMessage());
+        }
+
+        // When
+        when(realmMock.getGroupsCount(false)).thenReturn(countResult);
+
+        //Then
+        Response restResponse = subject.getGroupCount(null, "false");
+
+        assertEquals(response.toString(), restResponse.getEntity());
+        assertEquals(MediaType.APPLICATION_JSON, restResponse.getMediaType().toString());
+    }
+
+    @Test
+    public void testGetGroupCountWithoutSearchAndTopLevelFlagNull() {
+        // Given
+        Long countResult = 5L;
+        JSONObject response = new JSONObject();
+        try {
+            response.put("count", countResult);
+        } catch (JSONException e) {
+            fail(e.getMessage());
+        }
+
+        // When
+        when(realmMock.getGroupsCount(false)).thenReturn(countResult);
+
+        //Then
+        Response restResponse = subject.getGroupCount(null, null);
+
+        assertEquals(response.toString(), restResponse.getEntity());
+        assertEquals(MediaType.APPLICATION_JSON, restResponse.getMediaType().toString());
+    }
+}