From 616329f4fc7fa4211400dfac82fb7117686c3ae0 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Tue, 13 Aug 2019 16:48:29 +0200
Subject: [PATCH] Added MembersController and tests

---
 .../ia2/gms/controller/GroupsController.java  | 12 ++-
 .../ia2/gms/controller/MembersController.java | 72 ++++++++++++++
 .../gms/controller/PermissionsController.java |  6 +-
 ...dMemberRequest.java => MemberRequest.java} |  2 +-
 .../inaf/ia2/gms/persistence/GroupsDAO.java   | 21 ++++-
 .../ia2/gms/persistence/MembershipsDAO.java   | 17 ++++
 .../ia2/gms/persistence/PermissionsDAO.java   | 17 ++++
 .../inaf/ia2/gms/service/GroupsService.java   | 37 +++++---
 .../ia2/gms/service/GroupsTreeBuilder.java    |  2 +-
 .../gms/controller/GroupsControllerTest.java  |  2 -
 .../gms/controller/MembersControllerTest.java | 94 +++++++++++++++++++
 .../controller/PermissionsControllerTest.java | 26 ++---
 .../controller/WebServiceControllerTest.java  |  2 -
 .../ia2/gms/persistence/GroupsDAOTest.java    | 11 ++-
 .../NestedGroupsIntegrationTest.java          |  7 +-
 15 files changed, 274 insertions(+), 54 deletions(-)
 create mode 100644 gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java
 rename gms/src/main/java/it/inaf/ia2/gms/model/{AddMemberRequest.java => MemberRequest.java} (88%)
 create mode 100644 gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java

diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
index dc12bfb..0c894e2 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
@@ -57,7 +57,7 @@ public class GroupsController {
         GroupEntity parent = groupsService.getGroupById(request.getParentGroupId());
 
         if (permissionsService.getUserPermissionForGroup(parent, session.getUserId()) != Permission.ADMIN) {
-            throw new UnauthorizedException("Missing admin privileges");
+            throw new UnauthorizedException("Missing admin permission");
         }
 
         GroupEntity newGroup = groupsService.addGroup(parent, request.getNewGroupName());
@@ -70,7 +70,13 @@ public class GroupsController {
     @PutMapping(value = "/group/{groupId}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
     public ResponseEntity<PaginatedData<GroupNode>> renameGroup(@PathVariable("groupId") String groupId, @Valid @RequestBody RenameGroupRequest request) {
 
-        GroupEntity renamedGroup = groupsService.renameGroup(groupId, request.getNewGroupName(), session.getUserId());
+        GroupEntity group = groupsService.getGroupById(groupId);
+
+        if (permissionsService.getUserPermissionForGroup(group, session.getUserId()) != Permission.ADMIN) {
+            throw new UnauthorizedException("Missing admin permission");
+        }
+
+        GroupEntity renamedGroup = groupsService.renameGroup(group, request.getNewGroupName());
 
         GroupEntity parent = groupsService.getGroupByPath(renamedGroup.getParentPath());
 
@@ -85,7 +91,7 @@ public class GroupsController {
         GroupEntity group = groupsService.getGroupById(groupId);
 
         if (permissionsService.getUserPermissionForGroup(group, session.getUserId()) != Permission.ADMIN) {
-            throw new UnauthorizedException("Missing admin privileges");
+            throw new UnauthorizedException("Missing admin permission");
         }
 
         GroupEntity parent = groupsService.deleteGroup(group);
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java
new file mode 100644
index 0000000..3aef326
--- /dev/null
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java
@@ -0,0 +1,72 @@
+package it.inaf.ia2.gms.controller;
+
+import it.inaf.ia2.gms.authn.SessionData;
+import it.inaf.ia2.gms.exception.UnauthorizedException;
+import it.inaf.ia2.gms.model.MemberRequest;
+import it.inaf.ia2.gms.model.PaginatedData;
+import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.model.RapUser;
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.service.GroupsService;
+import it.inaf.ia2.gms.service.MembersService;
+import it.inaf.ia2.gms.service.PermissionsService;
+import java.util.List;
+import javax.validation.Valid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class MembersController {
+
+    @Autowired
+    private SessionData session;
+
+    @Autowired
+    private GroupsService groupsService;
+
+    @Autowired
+    private PermissionsService permissionsService;
+
+    @Autowired
+    private MembersService membersService;
+
+    @PostMapping(value = "/member", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public ResponseEntity<PaginatedData<RapUser>> addMember(@Valid @RequestBody MemberRequest request) {
+
+        GroupEntity group = groupsService.getGroupById(request.getGroupId());
+        verifyCurrentUserCanManageMembers(group);
+
+        membersService.addMember(request.getGroupId(), request.getUserId());
+
+        return new ResponseEntity<>(getMembersPanel(request), HttpStatus.CREATED);
+    }
+
+    @DeleteMapping(value = "/member", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public ResponseEntity<PaginatedData<RapUser>> removeMember(@Valid MemberRequest request) {
+
+        GroupEntity group = groupsService.getGroupById(request.getGroupId());
+        verifyCurrentUserCanManageMembers(group);
+
+        membersService.removeMember(group.getId(), request.getUserId());
+
+        return ResponseEntity.ok(getMembersPanel(request));
+    }
+
+    private void verifyCurrentUserCanManageMembers(GroupEntity group) {
+        Permission currentNodePermission = permissionsService.getUserPermissionForGroup(group, session.getUserId());
+        if (currentNodePermission != Permission.ADMIN && currentNodePermission != Permission.MANAGE_MEMBERS) {
+            throw new UnauthorizedException("Missing admin or manage members permissions");
+        }
+    }
+
+    private PaginatedData<RapUser> getMembersPanel(MemberRequest request) {
+        List<RapUser> members = membersService.getMembers(request.getGroupId());
+        return new PaginatedData<>(members, request.getPaginatorPage(), request.getPaginatorPageSize());
+    }
+}
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
index fbf9879..53582bb 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
@@ -36,7 +36,7 @@ public class PermissionsController {
     public ResponseEntity<PaginatedData<UserPermission>> addPermission(@Valid @RequestBody PermissionRequest request) {
 
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
-        verifyAdminSession(group);
+        verifyCurrentUserCanManagePermissions(group);
 
         permissionsService.addPermission(group, request.getUserId(), request.getPermission());
 
@@ -47,14 +47,14 @@ public class PermissionsController {
     public ResponseEntity<PaginatedData<UserPermission>> deletePermission(@Valid PermissionRequest request) {
 
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
-        verifyAdminSession(group);
+        verifyCurrentUserCanManagePermissions(group);
 
         permissionsService.deletePermission(group, request.getUserId(), request.getPermission());
 
         return ResponseEntity.ok(getPermissionsPanel(group, request));
     }
 
-    private void verifyAdminSession(GroupEntity group) {
+    private void verifyCurrentUserCanManagePermissions(GroupEntity group) {
         Permission currentNodePermissions = permissionsService.getUserPermissionForGroup(group, session.getUserId());
         if (currentNodePermissions != Permission.ADMIN) {
             throw new UnauthorizedException("Only admin users can handle permissions");
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/AddMemberRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/MemberRequest.java
similarity index 88%
rename from gms/src/main/java/it/inaf/ia2/gms/model/AddMemberRequest.java
rename to gms/src/main/java/it/inaf/ia2/gms/model/MemberRequest.java
index a22dc85..20d4873 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/AddMemberRequest.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/MemberRequest.java
@@ -2,7 +2,7 @@ package it.inaf.ia2.gms.model;
 
 import javax.validation.constraints.NotEmpty;
 
-public class AddMemberRequest extends PaginatedModelRequest {
+public class MemberRequest extends PaginatedModelRequest {
 
     @NotEmpty
     private String groupId;
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java
index 80d0c87..3469b41 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/GroupsDAO.java
@@ -124,9 +124,12 @@ public class GroupsDAO {
         });
     }
 
-    public List<GroupEntity> listSubGroups(String path) {
+    /**
+     * Returns the direct children (one level).
+     */
+    public List<GroupEntity> getDirectSubGroups(String path) {
 
-        String sql = "SELECT id, name, path from gms_group WHERE path ~ ? ORDER BY name";
+        String sql = "SELECT id, name, path FROM gms_group WHERE path ~ ? ORDER BY name";
 
         return jdbcTemplate.query(conn -> {
             PreparedStatement ps = conn.prepareStatement(sql);
@@ -145,6 +148,20 @@ public class GroupsDAO {
         return path;
     }
 
+    public List<GroupEntity> getAllChildren(String path) {
+
+        String sql = "SELECT id, name, path FROM gms_group WHERE path <@ ? AND path <> ? ORDER BY nlevel(path) DESC";
+
+        return jdbcTemplate.query(conn -> {
+            PreparedStatement ps = conn.prepareStatement(sql);
+            ps.setObject(1, path, Types.OTHER);
+            ps.setObject(2, path, Types.OTHER);
+            return ps;
+        }, resultSet -> {
+            return getGroupsFromResultSet(resultSet);
+        });
+    }
+
     public List<GroupEntity> findGroupsByNames(List<String> names) {
 
         String sql = "SELECT id, name, path from gms_group WHERE name IN ("
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java
index a18832c..550b462 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java
@@ -4,6 +4,7 @@ import it.inaf.ia2.gms.persistence.model.MembershipEntity;
 import java.sql.PreparedStatement;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 import javax.sql.DataSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -76,4 +77,20 @@ public class MembershipsDAO {
             return ps;
         });
     }
+
+    public void deleteAllGroupsMembership(List<String> groupIds) {
+
+        String sql = "DELETE FROM gms_membership WHERE group_id IN ("
+                + String.join(",", groupIds.stream().map(g -> "?").collect(Collectors.toList()))
+                + ")";
+
+        jdbcTemplate.update(conn -> {
+            PreparedStatement ps = conn.prepareStatement(sql);
+            int i = 0;
+            for (String groupId : groupIds) {
+                ps.setString(++i, groupId);
+            }
+            return ps;
+        });
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java
index e442b65..6246031 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java
@@ -7,6 +7,7 @@ import java.sql.Types;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 import javax.sql.DataSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -154,4 +155,20 @@ public class PermissionsDAO {
             return ps;
         });
     }
+
+    public void deleteAllGroupsPermissions(List<String> groupIds) {
+
+        String sql = "DELETE FROM gms_permission WHERE group_id IN ("
+                + String.join(",", groupIds.stream().map(g -> "?").collect(Collectors.toList()))
+                + ")";
+
+        jdbcTemplate.update(conn -> {
+            PreparedStatement ps = conn.prepareStatement(sql);
+            int i = 0;
+            for (String groupId : groupIds) {
+                ps.setString(++i, groupId);
+            }
+            return ps;
+        });
+    }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
index 1960fd2..609a787 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
@@ -5,12 +5,14 @@ import it.inaf.ia2.gms.exception.UnauthorizedException;
 import it.inaf.ia2.gms.model.GroupBreadcrumb;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.persistence.GroupsDAO;
+import it.inaf.ia2.gms.persistence.MembershipsDAO;
+import it.inaf.ia2.gms.persistence.PermissionsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 @Service
 public class GroupsService {
@@ -18,13 +20,15 @@ public class GroupsService {
     public static final String ROOT = "ROOT";
 
     private final GroupsDAO groupsDAO;
-    private final PermissionsService permissionsService;
+    private final PermissionsDAO permissionsDAO;
+    private final MembershipsDAO membershipsDAO;
 
     @Autowired
     public GroupsService(GroupsDAO groupsDAO,
-            PermissionsService permissionsService) {
+            PermissionsDAO permissionsDAO, MembershipsDAO membershipsDAO) {
         this.groupsDAO = groupsDAO;
-        this.permissionsService = permissionsService;
+        this.permissionsDAO = permissionsDAO;
+        this.membershipsDAO = membershipsDAO;
         createRootIfNecessary();
     }
 
@@ -40,7 +44,7 @@ public class GroupsService {
 
     public GroupEntity addGroup(GroupEntity parent, String groupName) {
 
-        if (groupsDAO.listSubGroups(parent.getPath()).stream()
+        if (groupsDAO.getDirectSubGroups(parent.getPath()).stream()
                 .anyMatch(g -> g.getName().equals(groupName))) {
             throw new BadRequestException("There is already a group named " + groupName);
         }
@@ -63,15 +67,9 @@ public class GroupsService {
         return group;
     }
 
-    public GroupEntity renameGroup(String groupId, String newGroupName, String userId) {
+    public GroupEntity renameGroup(GroupEntity group, String newGroupName) {
 
-        GroupEntity group = getGroupById(groupId);
-
-        if (permissionsService.getUserPermissionForGroup(group, userId) != Permission.ADMIN) {
-            throw new UnauthorizedException("Missing admin privileges");
-        }
-
-        if (groupsDAO.listSubGroups(group.getPath()).stream()
+        if (groupsDAO.getDirectSubGroups(group.getPath()).stream()
                 .anyMatch(g -> g.getName().equals(newGroupName))) {
             throw new BadRequestException("There is already a group named " + newGroupName);
         }
@@ -91,7 +89,18 @@ public class GroupsService {
         GroupEntity parent = groupsDAO.findGroupByPath(parentPath)
                 .orElseThrow(() -> new BadRequestException("No group found at path " + parentPath));
 
-        groupsDAO.deleteGroupById(group.getId());
+        List<GroupEntity> groupsToDelete = groupsDAO.getAllChildren(group.getPath());
+        groupsToDelete.add(group);
+
+        List<String> groupsToDeleteIds = groupsToDelete.stream()
+                .map(g -> g.getId()).collect(Collectors.toList());
+
+        membershipsDAO.deleteAllGroupsMembership(groupsToDeleteIds);
+        permissionsDAO.deleteAllGroupsPermissions(groupsToDeleteIds);
+
+        for (String groupId : groupsToDeleteIds) {
+            groupsDAO.deleteGroupById(groupId);
+        }
 
         return parent;
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsTreeBuilder.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsTreeBuilder.java
index f431bf6..280d5ee 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsTreeBuilder.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsTreeBuilder.java
@@ -34,7 +34,7 @@ public class GroupsTreeBuilder {
                 .orElseThrow(() -> new BadRequestException("Group " + parentGroupId + " not found"));
 
         // All the sub groups of given parent
-        List<GroupEntity> allGroups = groupsDAO.listSubGroups(parent.getPath());
+        List<GroupEntity> allGroups = groupsDAO.getDirectSubGroups(parent.getPath());
 
         // Select only the groups visible to the user
         List<PermissionEntity> permissions = permissionsDAO.findUserPermissions(userId);
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java
index 5ab680e..37e7b92 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/GroupsControllerTest.java
@@ -15,7 +15,6 @@ import org.mockito.Mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import org.mockito.junit.MockitoJUnitRunner;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.web.servlet.MockMvc;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -33,7 +32,6 @@ public class GroupsControllerTest {
     @InjectMocks
     private GroupsController controller;
 
-    @Autowired
     private MockMvc mockMvc;
 
     @Before
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
new file mode 100644
index 0000000..8d1a436
--- /dev/null
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
@@ -0,0 +1,94 @@
+package it.inaf.ia2.gms.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import it.inaf.ia2.gms.authn.SessionData;
+import it.inaf.ia2.gms.model.MemberRequest;
+import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.service.GroupsService;
+import it.inaf.ia2.gms.service.MembersService;
+import it.inaf.ia2.gms.service.PermissionsService;
+import static org.hamcrest.CoreMatchers.is;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static org.mockito.ArgumentMatchers.eq;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MembersControllerTest {
+
+    @Mock
+    private SessionData session;
+
+    @Mock
+    private GroupsService groupsService;
+
+    @Mock
+    private PermissionsService permissionsService;
+
+    @Mock
+    private MembersService membersService;
+
+    @InjectMocks
+    private MembersController controller;
+
+    private MockMvc mockMvc;
+
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    @Before
+    public void init() {
+        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+
+        when(session.getUserId()).thenReturn("admin_id");
+
+        GroupEntity group = new GroupEntity();
+        group.setId("group_id");
+        group.setName("GroupName");
+        group.setPath("parent_id.group_id");
+
+        when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
+        when(permissionsService.getUserPermissionForGroup(eq(group), eq("admin_id"))).thenReturn(Permission.ADMIN);
+    }
+
+    @Test
+    public void testAddMember() throws Exception {
+
+        MemberRequest request = new MemberRequest();
+        request.setGroupId("group_id");
+        request.setUserId("user_id");
+        request.setPaginatorPage(1);
+        request.setPaginatorPageSize(10);
+
+        mockMvc.perform(post("/member")
+                .content(mapper.writeValueAsString(request))
+                .contentType(MediaType.APPLICATION_JSON_UTF8))
+                .andExpect(status().isCreated())
+                .andExpect(jsonPath("$.currentPage", is(1)));
+
+        verify(membersService, times(1)).addMember(eq("group_id"), eq("user_id"));
+    }
+
+    @Test
+    public void testRemoveMember() throws Exception {
+
+        mockMvc.perform(delete("/member?groupId=group_id&userId=user_id&paginatorPage=1&paginatorPageSize=10"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.currentPage", is(1)));
+
+        verify(membersService, times(1)).removeMember(eq("group_id"), eq("user_id"));
+    }
+}
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
index f36cb3a..7aa612e 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
@@ -18,7 +18,6 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import org.mockito.junit.MockitoJUnitRunner;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
@@ -42,31 +41,32 @@ public class PermissionsControllerTest {
     @InjectMocks
     private PermissionsController controller;
 
-    @Autowired
     private MockMvc mockMvc;
 
     private final ObjectMapper mapper = new ObjectMapper();
 
+    private GroupEntity group;
+
     @Before
     public void init() {
         mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
-    }
-
-    @Test
-    public void testAddPermission() throws Exception {
 
         when(session.getUserId()).thenReturn("admin_id");
 
-        GroupEntity group = new GroupEntity();
+        group = new GroupEntity();
         group.setId("group_id");
         group.setName("GroupName");
         group.setPath("parent_id.group_id");
 
         when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
         when(permissionsService.getUserPermissionForGroup(eq(group), eq("admin_id"))).thenReturn(Permission.ADMIN);
+    }
+
+    @Test
+    public void testAddPermission() throws Exception {
 
         PermissionRequest request = new PermissionRequest();
-        request.setGroupId(group.getId());
+        request.setGroupId("group_id");
         request.setUserId("user_id");
         request.setPermission(Permission.ADMIN);
         request.setPaginatorPage(1);
@@ -84,16 +84,6 @@ public class PermissionsControllerTest {
     @Test
     public void testDeletePermission() throws Exception {
 
-        when(session.getUserId()).thenReturn("admin_id");
-
-        GroupEntity group = new GroupEntity();
-        group.setId("group_id");
-        group.setName("GroupName");
-        group.setPath("parent_id.group_id");
-
-        when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
-        when(permissionsService.getUserPermissionForGroup(eq(group), eq("admin_id"))).thenReturn(Permission.ADMIN);
-
         mockMvc.perform(delete("/permission?groupId=group_id&userId=user_id&permission=ADMIN&paginatorPage=1&paginatorPageSize=10"))
                 .andExpect(status().isOk())
                 .andExpect(jsonPath("$.currentPage", is(1)));
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java
index 7ccbc78..ee1d3f1 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import org.mockito.junit.MockitoJUnitRunner;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -49,7 +48,6 @@ public class WebServiceControllerTest {
     @InjectMocks
     private WebServiceController controller;
 
-    @Autowired
     private MockMvc mockMvc;
 
     private final ObjectMapper mapper = new ObjectMapper();
diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsDAOTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsDAOTest.java
index ae10ed1..ff5d365 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsDAOTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/GroupsDAOTest.java
@@ -79,15 +79,20 @@ public class GroupsDAOTest {
         assertFalse(group.isPresent());
 
         // Sub list
-        List<GroupEntity> groups = dao.listSubGroups("");
+        List<GroupEntity> groups = dao.getDirectSubGroups(root.getPath());
         assertEquals(2, groups.size());
         assertEquals("LBT", groups.get(0).getName());
         assertEquals("TNG", groups.get(1).getName());
 
-        groups = dao.listSubGroups(lbt.getId());
+        groups = dao.getDirectSubGroups(lbt.getId());
         assertEquals(1, groups.size());
         assertEquals("INAF", groups.get(0).getName());
 
+        // All children
+        groups = dao.getAllChildren(root.getPath());
+        assertEquals(3, groups.size());
+        assertEquals("INAF", groups.get(0).getName()); // order by path DESC
+
         // Group by parent and name
         Optional<GroupEntity> optGroup = dao.findGroupByParentAndName(root.getPath(), lbt.getName());
         assertTrue(optGroup.isPresent());
@@ -123,7 +128,7 @@ public class GroupsDAOTest {
 
         // Delete
         dao.deleteGroupById(lbtInaf.getId());
-        groups = dao.listSubGroups(lbt.getId());
+        groups = dao.getDirectSubGroups(lbt.getId());
         assertTrue(groups.isEmpty());
     }
 
diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
index 0a90226..88f1808 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
@@ -7,9 +7,7 @@ import it.inaf.ia2.gms.model.PaginatedModelRequest;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.persistence.model.PermissionEntity;
-import it.inaf.ia2.gms.rap.RapClient;
 import it.inaf.ia2.gms.service.GroupsTreeBuilder;
-import it.inaf.ia2.gms.service.PermissionsService;
 import java.util.List;
 import javax.sql.DataSource;
 import static org.junit.Assert.assertEquals;
@@ -17,7 +15,6 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import static org.mockito.Mockito.mock;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringRunner;
@@ -34,8 +31,8 @@ public class NestedGroupsIntegrationTest {
 
         GroupsDAO groupsDAO = new GroupsDAO(dataSource);
         PermissionsDAO permissionsDAO = new PermissionsDAO(dataSource);
-        PermissionsService permissionsService = new PermissionsService(permissionsDAO, mock(RapClient.class));
-        GroupsService groupsService = new GroupsService(groupsDAO, permissionsService);
+        MembershipsDAO membershipsDAO = new MembershipsDAO(dataSource);
+        GroupsService groupsService = new GroupsService(groupsDAO, permissionsDAO, membershipsDAO);
         GroupsTreeBuilder groupsTreeBuilder = new GroupsTreeBuilder(groupsDAO, permissionsDAO);
 
         String userId = "USER_ID";
-- 
GitLab