]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4463 Added service facade to manage permission template CRUD operations
authorJean-Baptiste Vilain <jean-baptiste.vilain@sonarsource.com>
Fri, 5 Jul 2013 08:39:04 +0000 (10:39 +0200)
committerJean-Baptiste Vilain <jean-baptiste.vilain@sonarsource.com>
Fri, 5 Jul 2013 08:39:21 +0000 (10:39 +0200)
sonar-core/src/main/java/org/sonar/core/user/PermissionDao.java
sonar-server/src/main/java/org/sonar/server/exceptions/ServerErrorException.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplate.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateUpdaterTest.java [new file with mode: 0644]

index 8e9bbf5d2ded2cef16a587c65f2aa246a87916ed..ed8967b29593186d533db65c74050d542423eaa2 100644 (file)
@@ -25,6 +25,7 @@ import org.sonar.api.ServerExtension;
 import org.sonar.api.task.TaskExtension;
 import org.sonar.core.persistence.MyBatis;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import java.util.Date;
 import java.util.List;
@@ -37,6 +38,7 @@ public class PermissionDao implements TaskExtension, ServerExtension {
     this.myBatis = myBatis;
   }
 
+  @CheckForNull
   public PermissionTemplateDto selectTemplateByName(String templateName) {
     SqlSession session = myBatis.openSession();
     try {
@@ -47,6 +49,7 @@ public class PermissionDao implements TaskExtension, ServerExtension {
     }
   }
 
+  @CheckForNull
   public PermissionTemplateDto selectPermissionTemplate(String templateName) {
     PermissionTemplateDto permissionTemplate = null;
     SqlSession session = myBatis.openSession();
diff --git a/sonar-server/src/main/java/org/sonar/server/exceptions/ServerErrorException.java b/sonar-server/src/main/java/org/sonar/server/exceptions/ServerErrorException.java
new file mode 100644 (file)
index 0000000..c5110bf
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.exceptions;
+
+public class ServerErrorException extends HttpException {
+
+  private static final int SERVER_ERROR = 500;
+
+  public ServerErrorException(String message) {
+    super(SERVER_ERROR, message);
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java b/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java
new file mode 100644 (file)
index 0000000..e996b13
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.user.*;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ServerErrorException;
+
+import javax.annotation.CheckForNull;
+import java.util.List;
+
+/**
+ * Used by ruby code <pre>Internal.permission_templates</pre>
+ */
+public class InternalPermissionTemplateService implements ServerComponent {
+
+  private static final Logger LOG = LoggerFactory.getLogger(InternalPermissionTemplateService.class);
+
+  private final PermissionDao permissionDao;
+  private final UserDao userDao;
+
+  public InternalPermissionTemplateService(PermissionDao permissionDao, UserDao userDao) {
+    this.permissionDao = permissionDao;
+    this.userDao = userDao;
+  }
+
+  public PermissionTemplate createPermissionTemplate(String name, String description) {
+    PermissionTemplateUpdater.checkUserCredentials();
+    PermissionTemplateDto permissionTemplateDto = permissionDao.createPermissionTemplate(name, description);
+    checkThatTemplateNameIsUnique(name);
+    if(permissionTemplateDto == null) {
+      String errorMsg = "Template creation failed";
+      LOG.error(errorMsg);
+      throw new ServerErrorException(errorMsg);
+    }
+    return PermissionTemplate.create(permissionTemplateDto);
+  }
+
+  @CheckForNull
+  public PermissionTemplate selectPermissionTemplate(String templateName) {
+    PermissionTemplateUpdater.checkUserCredentials();
+    PermissionTemplateDto permissionTemplateDto = permissionDao.selectPermissionTemplate(templateName);
+    return PermissionTemplate.create(permissionTemplateDto);
+  }
+
+  public void deletePermissionTemplate(String templateName) {
+    PermissionTemplateUpdater.checkUserCredentials();
+    PermissionTemplateDto permissionTemplateDto = permissionDao.selectTemplateByName(templateName);
+    if(permissionTemplateDto == null) {
+      String errorMsg = "Unknown template:" + templateName;
+      LOG.error(errorMsg);
+      throw new BadRequestException(errorMsg);
+    } else {
+      permissionDao.deletePermissionTemplate(permissionTemplateDto.getId());
+    }
+  }
+
+  public void addUserPermission(String templateName, String permission, final String userLogin) {
+    PermissionTemplateUpdater updater = new PermissionTemplateUpdater(templateName, permission, userLogin, permissionDao, userDao) {
+      @Override
+      protected void doExecute(Long templateId, String permission) {
+        Long userId = getUserId();
+        permissionDao.addUserPermission(templateId, userId, permission);
+      }
+    };
+    updater.executeUpdate();
+  }
+
+  public void removeUserPermission(String templateName, String permission, String userLogin) {
+    PermissionTemplateUpdater updater = new PermissionTemplateUpdater(templateName, permission, userLogin, permissionDao, userDao) {
+      @Override
+      protected void doExecute(Long templateId, String permission) {
+        Long userId = getUserId();
+        permissionDao.removeUserPermission(templateId, userId, permission);
+      }
+    };
+    updater.executeUpdate();
+  }
+
+  public void addGroupPermission(String templateName, String permission, String groupName) {
+    PermissionTemplateUpdater updater = new PermissionTemplateUpdater(templateName, permission, groupName, permissionDao, userDao) {
+      @Override
+      protected void doExecute(Long templateId, String permission) {
+        Long groupId = getGroupId();
+        permissionDao.addGroupPermission(templateId, groupId, permission);
+      }
+    };
+    updater.executeUpdate();
+  }
+
+  public void removeGroupPermission(String templateName, String permission, String groupName) {
+    PermissionTemplateUpdater updater = new PermissionTemplateUpdater(templateName, permission, groupName, permissionDao, userDao) {
+      @Override
+      protected void doExecute(Long templateId, String permission) {
+        Long groupId = getGroupId();
+        permissionDao.removeGroupPermission(templateId, groupId, permission);
+      }
+    };
+    updater.executeUpdate();
+  }
+
+  private void checkThatTemplateNameIsUnique(String name) {
+    List<PermissionTemplateDto> existingTemplates = permissionDao.selectAllPermissionTemplates();
+    for (PermissionTemplateDto existingTemplate : existingTemplates) {
+      if(existingTemplate.getName().equals(name)) {
+        String errorMsg = "A template with that name already exists";
+        LOG.error(errorMsg);
+        throw new BadRequestException(errorMsg);
+      }
+    }
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplate.java b/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplate.java
new file mode 100644 (file)
index 0000000..97054b9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+import org.sonar.core.user.PermissionTemplateDto;
+import org.sonar.core.user.PermissionTemplateGroupDto;
+import org.sonar.core.user.PermissionTemplateUserDto;
+
+import java.util.List;
+
+public class PermissionTemplate {
+
+  private final Long id;
+  private final String name;
+  private final String description;
+  private Multimap<String, String> usersByPermission;
+  private Multimap<String, String> groupsByPermission;
+
+  private PermissionTemplate(Long id, String name, String description) {
+    this.id = id;
+    this.name = name;
+    this.description = description;
+    usersByPermission = HashMultimap.create();
+    groupsByPermission = HashMultimap.create();
+  }
+
+  public static PermissionTemplate create(PermissionTemplateDto permissionTemplateDto) {
+    PermissionTemplate permissionTemplate =
+      new PermissionTemplate(permissionTemplateDto.getId(), permissionTemplateDto.getName(), permissionTemplateDto.getDescription());
+    if(permissionTemplateDto.getUsersPermissions() != null) {
+      for (PermissionTemplateUserDto userPermission : permissionTemplateDto.getUsersPermissions()) {
+        permissionTemplate.registerUserPermission(userPermission.getPermission(), userPermission.getUserName());
+      }
+    }
+    if(permissionTemplateDto.getGroupsPermissions() != null) {
+      for (PermissionTemplateGroupDto groupPermission : permissionTemplateDto.getGroupsPermissions()) {
+        permissionTemplate.registerGroupPermission(groupPermission.getPermission(), groupPermission.getGroupName());
+      }
+    }
+    return permissionTemplate;
+  }
+
+  public Long getId() {
+    return id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public List<String> getUsersForPermission(String permission) {
+    return ImmutableList.copyOf(usersByPermission.get(permission));
+  }
+
+  public List<String> getGroupsForPermission(String permission) {
+    return ImmutableList.copyOf(groupsByPermission.get(permission));
+  }
+
+  private void registerUserPermission(String permission, String userName) {
+    usersByPermission.put(permission, userName);
+  }
+
+  private void registerGroupPermission(String permission, String groupName) {
+    groupsByPermission.put(permission, groupName);
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java b/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java
new file mode 100644 (file)
index 0000000..24ac25b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import org.sonar.core.user.*;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.user.UserSession;
+
+abstract class PermissionTemplateUpdater {
+
+  private final String templateName;
+  private final String permission;
+  private final String updatedReference;
+  private final PermissionDao permissionDao;
+  private final UserDao userDao;
+
+  PermissionTemplateUpdater(String templateName, String permission, String updatedReference, PermissionDao permissionDao, UserDao userDao) {
+    this.templateName = templateName;
+    this.permission = permission;
+    this.updatedReference = updatedReference;
+    this.permissionDao = permissionDao;
+    this.userDao = userDao;
+  }
+
+  void executeUpdate() {
+    checkUserCredentials();
+    Long templateId = getTemplateId(templateName);
+    validatePermission(permission);
+    doExecute(templateId, permission);
+  }
+
+  abstract void doExecute(Long templateId, String permission);
+
+  Long getUserId() {
+    UserDto userDto = userDao.selectActiveUserByLogin(updatedReference);
+    if(userDto == null) {
+      throw new BadRequestException("Unknown user: " + updatedReference);
+    }
+    return userDto.getId();
+  }
+
+  Long getGroupId() {
+    GroupDto groupDto = userDao.selectGroupByName(updatedReference);
+    if(groupDto == null) {
+      throw new BadRequestException("Unknown group: " + updatedReference);
+    }
+    return groupDto.getId();
+  }
+
+  static void checkUserCredentials() {
+    UserSession currentSession = UserSession.get();
+    currentSession.checkLoggedIn();
+    currentSession.checkGlobalPermission(Permission.SYSTEM_ADMIN);
+  }
+
+  private void validatePermission(String permission) {
+    if(!Permission.isValid(permission)) {
+      throw new BadRequestException("Invalid permission: " + permission);
+    }
+  }
+
+  private Long getTemplateId(String name) {
+    PermissionTemplateDto permissionTemplateDto = permissionDao.selectTemplateByName(name);
+    if(permissionTemplateDto == null) {
+      throw new BadRequestException("Unknown template: " + name);
+    }
+    return permissionTemplateDto.getId();
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java b/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java
new file mode 100644 (file)
index 0000000..7abe57e
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import com.google.common.collect.Lists;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.core.user.*;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.user.MockUserSession;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class InternalPermissionTemplateServiceTest {
+
+  private static final String DEFAULT_NAME = "my template";
+  private static final String DEFAULT_DESC = "my description";
+  private static final String DEFAULT_PERMISSION = Permission.DRY_RUN_EXECUTION.key();
+  private static final PermissionTemplateDto DEFAULT_TEMPLATE =
+    new PermissionTemplateDto().setId(1L).setName(DEFAULT_NAME).setDescription(DEFAULT_DESC);
+
+  private PermissionDao permissionDao;
+  private UserDao userDao;
+  private InternalPermissionTemplateService permissionTemplateService;
+
+  @Rule
+  public ExpectedException expected = ExpectedException.none();
+
+  @Before
+  public void setUp() {
+    MockUserSession.set().setLogin("admin").setPermissions(Permission.SYSTEM_ADMIN);
+    permissionDao = mock(PermissionDao.class);
+    userDao = mock(UserDao.class);
+    permissionTemplateService = new InternalPermissionTemplateService(permissionDao, userDao);
+  }
+
+  @Test
+  public void should_create_permission_template() throws Exception {
+    when(permissionDao.createPermissionTemplate(DEFAULT_NAME, DEFAULT_DESC)).thenReturn(DEFAULT_TEMPLATE);
+
+    PermissionTemplate permissionTemplate = permissionTemplateService.createPermissionTemplate(DEFAULT_NAME, DEFAULT_DESC);
+
+    assertThat(permissionTemplate.getId()).isEqualTo(1L);
+    assertThat(permissionTemplate.getName()).isEqualTo(DEFAULT_NAME);
+    assertThat(permissionTemplate.getDescription()).isEqualTo(DEFAULT_DESC);
+  }
+
+  @Test
+  public void should_enforce_unique_template_name() throws Exception {
+    expected.expect(BadRequestException.class);
+    expected.expectMessage("A template with that name already exists");
+
+    when(permissionDao.selectAllPermissionTemplates()).thenReturn(Lists.newArrayList(DEFAULT_TEMPLATE));
+
+    permissionTemplateService.createPermissionTemplate(DEFAULT_NAME, DEFAULT_DESC);
+  }
+
+  @Test
+  public void should_delete_permission_template() throws Exception {
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+
+    permissionTemplateService.deletePermissionTemplate(DEFAULT_NAME);
+
+    verify(permissionDao, times(1)).deletePermissionTemplate(1L);
+  }
+
+  @Test
+  public void should_validate_template_name_on_deletion() throws Exception {
+    expected.expect(BadRequestException.class);
+    expected.expectMessage("Unknown template:");
+
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(null);
+
+    permissionTemplateService.deletePermissionTemplate(DEFAULT_NAME);
+  }
+
+  @Test
+  public void should_retrieve_permission_template() throws Exception {
+
+    List<PermissionTemplateUserDto> usersPermissions = Lists.newArrayList(
+      buildUserPermission("user_scan", Permission.SCAN_EXECUTION.key()),
+      buildUserPermission("user_dry_run", Permission.DRY_RUN_EXECUTION.key()),
+      buildUserPermission("user_scan_and_dry_run", Permission.SCAN_EXECUTION.key()),
+      buildUserPermission("user_scan_and_dry_run", Permission.DRY_RUN_EXECUTION.key())
+    );
+
+    List<PermissionTemplateGroupDto> groupsPermissions = Lists.newArrayList(
+      buildGroupPermission("admin_group", Permission.SYSTEM_ADMIN.key()),
+      buildGroupPermission("scan_group", Permission.SCAN_EXECUTION.key()),
+      buildGroupPermission(null, Permission.DRY_RUN_EXECUTION.key())
+    );
+
+    PermissionTemplateDto permissionTemplateDto = new PermissionTemplateDto()
+      .setId(1L)
+      .setName("my template")
+      .setDescription("my description")
+      .setUsersPermissions(usersPermissions)
+      .setGroupsByPermission(groupsPermissions);
+
+    when(permissionDao.selectPermissionTemplate("my template")).thenReturn(permissionTemplateDto);
+
+    PermissionTemplate permissionTemplate = permissionTemplateService.selectPermissionTemplate("my template");
+
+    assertThat(permissionTemplate.getUsersForPermission(Permission.DASHBOARD_SHARING.key())).isEmpty();
+    assertThat(permissionTemplate.getUsersForPermission(Permission.SCAN_EXECUTION.key())).containsOnly("user_scan", "user_scan_and_dry_run");
+    assertThat(permissionTemplate.getUsersForPermission(Permission.DRY_RUN_EXECUTION.key())).containsOnly("user_dry_run", "user_scan_and_dry_run");
+    assertThat(permissionTemplate.getGroupsForPermission(Permission.DASHBOARD_SHARING.key())).isEmpty();
+    assertThat(permissionTemplate.getGroupsForPermission(Permission.SCAN_EXECUTION.key())).containsOnly("scan_group");
+    assertThat(permissionTemplate.getGroupsForPermission(Permission.SYSTEM_ADMIN.key())).containsOnly("admin_group");
+  }
+
+  @Test
+  public void should_add_user_permission() throws Exception {
+    UserDto userDto = new UserDto().setId(1L).setLogin("user").setName("user");
+    when(userDao.selectActiveUserByLogin("user")).thenReturn(userDto);
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+
+    permissionTemplateService.addUserPermission(DEFAULT_NAME, DEFAULT_PERMISSION, "user");
+
+    verify(permissionDao, times(1)).addUserPermission(1L, 1L, DEFAULT_PERMISSION);
+  }
+
+  @Test
+  public void should_validate_provided_user_login() throws Exception {
+    expected.expect(BadRequestException.class);
+    expected.expectMessage("Unknown user:");
+
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+    when(userDao.selectActiveUserByLogin("unknown")).thenReturn(null);
+
+    permissionTemplateService.addUserPermission(DEFAULT_NAME, DEFAULT_PERMISSION, "unknown");
+  }
+
+  @Test
+  public void should_remove_user_permission() throws Exception {
+    UserDto userDto = new UserDto().setId(1L).setLogin("user").setName("user");
+    when(userDao.selectActiveUserByLogin("user")).thenReturn(userDto);
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+
+    permissionTemplateService.removeUserPermission(DEFAULT_NAME, DEFAULT_PERMISSION, "user");
+
+    verify(permissionDao, times(1)).removeUserPermission(1L, 1L, DEFAULT_PERMISSION);
+  }
+
+  @Test
+  public void should_add_group_permission() throws Exception {
+    GroupDto groupDto = new GroupDto().setId(1L).setName("group");
+    when(userDao.selectGroupByName("group")).thenReturn(groupDto);
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+
+    permissionTemplateService.addGroupPermission(DEFAULT_NAME, DEFAULT_PERMISSION, "group");
+
+    verify(permissionDao, times(1)).addGroupPermission(1L, 1L, DEFAULT_PERMISSION);
+  }
+
+  @Test
+  public void should_validate_provided_group_name() throws Exception {
+    expected.expect(BadRequestException.class);
+    expected.expectMessage("Unknown group:");
+
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+    when(userDao.selectGroupByName("unknown")).thenReturn(null);
+
+    permissionTemplateService.addGroupPermission(DEFAULT_NAME, DEFAULT_PERMISSION, "unknown");
+  }
+
+  @Test
+  public void should_remove_group_permission() throws Exception {
+    GroupDto groupDto = new GroupDto().setId(1L).setName("group");
+    when(userDao.selectGroupByName("group")).thenReturn(groupDto);
+    when(permissionDao.selectTemplateByName(DEFAULT_NAME)).thenReturn(DEFAULT_TEMPLATE);
+
+    permissionTemplateService.removeGroupPermission(DEFAULT_NAME, DEFAULT_PERMISSION, "group");
+
+    verify(permissionDao, times(1)).removeGroupPermission(1L, 1L, DEFAULT_PERMISSION);
+  }
+
+  private PermissionTemplateUserDto buildUserPermission(String userName, String permission) {
+    return new PermissionTemplateUserDto().setUserName(userName).setPermission(permission);
+  }
+
+  private PermissionTemplateGroupDto buildGroupPermission(String groupName, String permission) {
+    return new PermissionTemplateGroupDto().setGroupName(groupName).setPermission(permission);
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateTest.java b/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateTest.java
new file mode 100644 (file)
index 0000000..3b23c4b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+import org.sonar.core.user.PermissionTemplateDto;
+import org.sonar.core.user.PermissionTemplateGroupDto;
+import org.sonar.core.user.PermissionTemplateUserDto;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class PermissionTemplateTest {
+
+  @Test
+  public void should_populate_template_with_permissions() throws Exception {
+
+    PermissionTemplateDto permissionTemplateDto = new PermissionTemplateDto()
+      .setId(1L)
+      .setName("name")
+      .setDescription("description")
+      .setUsersPermissions(Lists.newArrayList(
+        new PermissionTemplateUserDto().setId(1L).setUserName("user1").setPermission("permission1"),
+        new PermissionTemplateUserDto().setId(2L).setUserName("user1").setPermission("permission2"),
+        new PermissionTemplateUserDto().setId(3L).setUserName("user2").setPermission("permission1")
+      ))
+      .setGroupsByPermission(Lists.newArrayList(
+        new PermissionTemplateGroupDto().setId(1L).setGroupName("group1").setPermission("permission3"),
+        new PermissionTemplateGroupDto().setId(2L).setGroupName("group2").setPermission("permission3")
+      ));
+
+    PermissionTemplate permissionTemplate = PermissionTemplate.create(permissionTemplateDto);
+
+    assertThat(permissionTemplate.getId()).isEqualTo(1L);
+    assertThat(permissionTemplate.getName()).isEqualTo("name");
+    assertThat(permissionTemplate.getDescription()).isEqualTo("description");
+    assertThat(permissionTemplate.getUsersForPermission("unmatchedPermission")).isEmpty();
+    assertThat(permissionTemplate.getUsersForPermission("permission1")).containsOnly("user1", "user2");
+    assertThat(permissionTemplate.getUsersForPermission("permission2")).containsOnly("user1");
+    assertThat(permissionTemplate.getGroupsForPermission("permission3")).containsOnly("group1", "group2");
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateUpdaterTest.java b/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateUpdaterTest.java
new file mode 100644 (file)
index 0000000..9af7eeb
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.core.user.*;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.user.MockUserSession;
+
+import static org.mockito.Mockito.*;
+
+public class PermissionTemplateUpdaterTest {
+
+  private static final UserDto DEFAULT_USER = new UserDto().setId(1L).setLogin("user").setName("user");
+  private static final GroupDto DEFAULT_GROUP = new GroupDto().setId(1L).setName("group");
+
+  private UserDao userDao;
+
+  @Rule
+  public ExpectedException expected = ExpectedException.none();
+
+  @Before
+  public void setUpCommonMocks() {
+    MockUserSession.set().setLogin("admin").setPermissions(Permission.SYSTEM_ADMIN);
+    userDao = mock(UserDao.class);
+    stub(userDao.selectActiveUserByLogin("user")).toReturn(DEFAULT_USER);
+    stub(userDao.selectGroupByName("group")).toReturn(DEFAULT_GROUP);
+  }
+
+  @Test
+  public void should_execute_on_valid_parameters() throws Exception {
+
+    final PermissionDao permissionDao = mock(PermissionDao.class);
+    when(permissionDao.selectTemplateByName("my template")).thenReturn(new PermissionTemplateDto().setId(1L));
+
+    PermissionTemplateUpdater updater =
+      new PermissionTemplateUpdater("my template", Permission.SCAN_EXECUTION.key(), "user", permissionDao, userDao) {
+      @Override
+      void doExecute(Long templateId, String permission) {
+        permissionDao.addUserPermission(1L, 1L, Permission.SCAN_EXECUTION.key());
+      }
+    };
+    updater.executeUpdate();
+
+    verify(permissionDao, times(1)).addUserPermission(1L, 1L, Permission.SCAN_EXECUTION.key());
+  }
+
+  @Test
+  public void should_validate_template_reference() throws Exception {
+    expected.expect(BadRequestException.class);
+    expected.expectMessage("Unknown template:");
+
+    final PermissionDao permissionDao = mock(PermissionDao.class);
+    when(permissionDao.selectTemplateByName("my template")).thenReturn(null);
+
+    PermissionTemplateUpdater updater =
+      new PermissionTemplateUpdater("my template", Permission.SCAN_EXECUTION.key(), "user", permissionDao, userDao) {
+        @Override
+        void doExecute(Long templateId, String permission) {
+        }
+      };
+    updater.executeUpdate();
+  }
+
+  @Test
+  public void should_validate_permission_reference() throws Exception {
+    expected.expect(BadRequestException.class);
+    expected.expectMessage("Invalid permission:");
+
+    final PermissionDao permissionDao = mock(PermissionDao.class);
+    when(permissionDao.selectTemplateByName("my template")).thenReturn(new PermissionTemplateDto().setId(1L));
+
+    PermissionTemplateUpdater updater =
+      new PermissionTemplateUpdater("my template", "invalid", "user", permissionDao, userDao) {
+        @Override
+        void doExecute(Long templateId, String permission) {
+        }
+      };
+    updater.executeUpdate();
+  }
+
+  @Test
+  public void should_check_that_user_is_logged_in() throws Exception {
+    expected.expect(UnauthorizedException.class);
+    expected.expectMessage("Authentication is required");
+
+    MockUserSession.set();
+
+    PermissionTemplateUpdater updater = new PermissionTemplateUpdater(null, null, null, null, null) {
+        @Override
+        void doExecute(Long templateId, String permission) {
+        }
+      };
+    updater.executeUpdate();
+  }
+
+  @Test
+  public void should_check_that_user_is_a_system_admin() throws Exception {
+    expected.expect(ForbiddenException.class);
+    expected.expectMessage("Insufficient privileges");
+
+    MockUserSession.set().setLogin("user").setPermissions(Permission.SCAN_EXECUTION);
+
+    PermissionTemplateUpdater updater = new PermissionTemplateUpdater(null, null, null, null, null) {
+      @Override
+      void doExecute(Long templateId, String permission) {
+      }
+    };
+    updater.executeUpdate();
+  }
+}