3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.permission.ws.template;
22 import java.util.Collections;
23 import java.util.List;
24 import org.apache.commons.lang.StringUtils;
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.sonar.api.resources.Qualifiers;
28 import org.sonar.api.server.ws.WebService.Param;
29 import org.sonar.api.web.UserRole;
30 import org.sonar.db.component.ComponentDto;
31 import org.sonar.db.component.ComponentTesting;
32 import org.sonar.db.organization.OrganizationDto;
33 import org.sonar.db.permission.PermissionQuery;
34 import org.sonar.db.permission.template.PermissionTemplateDto;
35 import org.sonar.db.user.GroupDto;
36 import org.sonar.db.user.UserDto;
37 import org.sonar.server.es.ProjectIndexers;
38 import org.sonar.server.es.TestProjectIndexers;
39 import org.sonar.server.exceptions.BadRequestException;
40 import org.sonar.server.exceptions.NotFoundException;
41 import org.sonar.server.l18n.I18nRule;
42 import org.sonar.server.permission.PermissionTemplateService;
43 import org.sonar.server.permission.ws.BasePermissionWsTest;
45 import static org.assertj.core.api.Assertions.assertThat;
46 import static org.sonar.api.utils.DateUtils.parseDate;
47 import static org.sonar.db.component.ComponentTesting.newApplication;
48 import static org.sonar.db.component.ComponentTesting.newView;
49 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
50 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION;
51 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
52 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
53 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
54 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
55 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
56 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
57 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
59 public class BulkApplyTemplateActionTest extends BasePermissionWsTest<BulkApplyTemplateAction> {
62 public DefaultTemplatesResolverRule defaultTemplatesResolver = DefaultTemplatesResolverRule.withoutGovernance();
64 private UserDto user1;
65 private UserDto user2;
66 private GroupDto group1;
67 private GroupDto group2;
68 private OrganizationDto organization;
69 private PermissionTemplateDto template1;
70 private PermissionTemplateDto template2;
71 private ProjectIndexers projectIndexers = new TestProjectIndexers();
74 protected BulkApplyTemplateAction buildWsAction() {
75 PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
76 projectIndexers, userSession, defaultTemplatesResolver);
77 return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
82 organization = db.organizations().insert();
84 user1 = db.users().insertUser();
85 user2 = db.users().insertUser();
86 group1 = db.users().insertGroup(organization);
87 group2 = db.users().insertGroup(organization);
89 db.organizations().addMember(organization, user1);
90 db.organizations().addMember(organization, user2);
92 // template 1 for org 1
93 template1 = db.permissionTemplates().insertTemplate(organization);
94 addUserToTemplate(user1, template1, UserRole.CODEVIEWER);
95 addUserToTemplate(user2, template1, UserRole.ISSUE_ADMIN);
96 addGroupToTemplate(group1, template1, UserRole.ADMIN);
97 addGroupToTemplate(group2, template1, UserRole.USER);
99 template2 = db.permissionTemplates().insertTemplate(organization);
100 addUserToTemplate(user1, template2, UserRole.USER);
101 addUserToTemplate(user2, template2, UserRole.USER);
102 addGroupToTemplate(group1, template2, UserRole.USER);
103 addGroupToTemplate(group2, template2, UserRole.USER);
107 public void bulk_apply_template_by_template_uuid() {
108 // this project should not be applied the template
109 OrganizationDto otherOrganization = db.organizations().insert();
110 db.components().insertPrivateProject(otherOrganization);
112 ComponentDto privateProject = db.components().insertPrivateProject(organization);
113 ComponentDto publicProject = db.components().insertPublicProject(organization);
114 loginAsAdmin(organization);
117 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
120 assertTemplate1AppliedToPrivateProject(privateProject);
121 assertTemplate1AppliedToPublicProject(publicProject);
125 public void request_throws_NotFoundException_if_template_with_specified_name_does_not_exist_in_specified_organization() {
126 OrganizationDto otherOrganization = db.organizations().insert();
127 loginAsAdmin(otherOrganization);
129 expectedException.expect(NotFoundException.class);
130 expectedException.expectMessage("Permission template with name '" + template1.getName()
131 + "' is not found (case insensitive) in organization with key '" + otherOrganization.getKey() + "'");
134 .setParam(PARAM_ORGANIZATION, otherOrganization.getKey())
135 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
140 public void request_throws_IAE_if_more_than_1000_projects() {
141 expectedException.expect(IllegalArgumentException.class);
142 expectedException.expectMessage("'projects' can contains only 1000 values, got 1001");
145 .setParam(PARAM_ORGANIZATION, organization.getKey())
146 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
147 .setParam(PARAM_PROJECTS, StringUtils.join(Collections.nCopies(1_001, "foo"), ","))
152 public void bulk_apply_template_by_template_name() {
153 ComponentDto privateProject = db.components().insertPrivateProject(organization);
154 ComponentDto publicProject = db.components().insertPublicProject(organization);
155 loginAsAdmin(organization);
158 .setParam(PARAM_ORGANIZATION, organization.getKey())
159 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
162 assertTemplate1AppliedToPrivateProject(privateProject);
163 assertTemplate1AppliedToPublicProject(publicProject);
167 public void apply_template_by_qualifiers() {
168 ComponentDto publicProject = db.components().insertPublicProject(organization);
169 ComponentDto privateProject = db.components().insertPrivateProject(organization);
170 ComponentDto view = db.components().insertComponent(newView(organization));
171 ComponentDto application = db.components().insertComponent(newApplication(organization));
172 loginAsAdmin(organization);
175 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
176 .setParam(PARAM_QUALIFIERS, String.join(",", Qualifiers.PROJECT, Qualifiers.APP))
179 assertTemplate1AppliedToPrivateProject(privateProject);
180 assertTemplate1AppliedToPublicProject(publicProject);
181 assertTemplate1AppliedToPublicProject(application);
182 assertNoPermissionOnProject(view);
186 public void apply_template_by_query_on_name_and_key_public_project() {
187 ComponentDto publicProjectFoundByKey = ComponentTesting.newPublicProjectDto(organization).setDbKey("sonar");
188 db.components().insertProjectAndSnapshot(publicProjectFoundByKey);
189 ComponentDto publicProjectFoundByName = ComponentTesting.newPublicProjectDto(organization).setName("name-sonar-name");
190 db.components().insertProjectAndSnapshot(publicProjectFoundByName);
191 ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
192 db.components().insertProjectAndSnapshot(projectUntouched);
193 loginAsAdmin(organization);
196 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
197 .setParam(Param.TEXT_QUERY, "SONAR")
200 assertTemplate1AppliedToPublicProject(publicProjectFoundByKey);
201 assertTemplate1AppliedToPublicProject(publicProjectFoundByName);
202 assertNoPermissionOnProject(projectUntouched);
206 public void apply_template_by_query_on_name_and_key() {
207 // partial match on key
208 ComponentDto privateProjectFoundByKey = ComponentTesting.newPrivateProjectDto(organization).setDbKey("sonarqube");
209 db.components().insertProjectAndSnapshot(privateProjectFoundByKey);
210 ComponentDto privateProjectFoundByName = ComponentTesting.newPrivateProjectDto(organization).setName("name-sonar-name");
211 db.components().insertProjectAndSnapshot(privateProjectFoundByName);
212 ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
213 db.components().insertProjectAndSnapshot(projectUntouched);
214 loginAsAdmin(organization);
217 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
218 .setParam(Param.TEXT_QUERY, "SONAR")
221 assertTemplate1AppliedToPrivateProject(privateProjectFoundByKey);
222 assertTemplate1AppliedToPrivateProject(privateProjectFoundByName);
223 assertNoPermissionOnProject(projectUntouched);
227 public void apply_template_by_project_keys() {
228 ComponentDto project1 = db.components().insertPrivateProject(organization);
229 ComponentDto project2 = db.components().insertPrivateProject(organization);
230 ComponentDto untouchedProject = db.components().insertPrivateProject(organization);
231 loginAsAdmin(organization);
234 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
235 .setParam(PARAM_PROJECTS, String.join(",", project1.getKey(), project2.getKey()))
238 assertTemplate1AppliedToPrivateProject(project1);
239 assertTemplate1AppliedToPrivateProject(project2);
240 assertNoPermissionOnProject(untouchedProject);
244 public void apply_template_by_provisioned_only() {
245 ComponentDto provisionedProject1 = db.components().insertPrivateProject(organization);
246 ComponentDto provisionedProject2 = db.components().insertPrivateProject(organization);
247 ComponentDto analyzedProject = db.components().insertPrivateProject(organization);
248 db.components().insertSnapshot(newAnalysis(analyzedProject));
249 loginAsAdmin(organization);
252 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
253 .setParam(PARAM_ON_PROVISIONED_ONLY, "true")
256 assertTemplate1AppliedToPrivateProject(provisionedProject1);
257 assertTemplate1AppliedToPrivateProject(provisionedProject2);
258 assertNoPermissionOnProject(analyzedProject);
262 public void apply_template_by_analyzed_before() {
263 ComponentDto oldProject1 = db.components().insertPrivateProject(organization);
264 ComponentDto oldProject2 = db.components().insertPrivateProject(organization);
265 ComponentDto recentProject = db.components().insertPrivateProject(organization);
266 db.components().insertSnapshot(oldProject1, a -> a.setCreatedAt(parseDate("2015-02-03").getTime()));
267 db.components().insertSnapshot(oldProject2, a -> a.setCreatedAt(parseDate("2016-12-11").getTime()));
268 db.components().insertSnapshot(recentProject, a -> a.setCreatedAt(System.currentTimeMillis()));
269 loginAsAdmin(organization);
272 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
273 .setParam(PARAM_ANALYZED_BEFORE, "2017-09-07")
276 assertTemplate1AppliedToPrivateProject(oldProject1);
277 assertTemplate1AppliedToPrivateProject(oldProject2);
278 assertNoPermissionOnProject(recentProject);
282 public void apply_template_by_visibility() {
283 ComponentDto privateProject1 = db.components().insertPrivateProject(organization);
284 ComponentDto privateProject2 = db.components().insertPrivateProject(organization);
285 ComponentDto publicProject = db.components().insertPublicProject(organization);
286 loginAsAdmin(organization);
289 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
290 .setParam(PARAM_VISIBILITY, "private")
293 assertTemplate1AppliedToPrivateProject(privateProject1);
294 assertTemplate1AppliedToPrivateProject(privateProject2);
295 assertNoPermissionOnProject(publicProject);
299 public void fail_if_no_template_parameter() {
300 loginAsAdmin(db.getDefaultOrganization());
302 expectedException.expect(BadRequestException.class);
303 expectedException.expectMessage("Template name or template id must be provided, not both.");
305 newRequest().execute();
309 public void fail_if_template_name_is_incorrect() {
310 loginAsAdmin(db.getDefaultOrganization());
312 expectedException.expect(NotFoundException.class);
313 expectedException.expectMessage("Permission template with id 'unknown-template-uuid' is not found");
315 newRequest().setParam(PARAM_TEMPLATE_ID, "unknown-template-uuid").execute();
318 private void assertTemplate1AppliedToPublicProject(ComponentDto project) {
319 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
320 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
321 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
322 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
323 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
326 private void assertTemplate1AppliedToPrivateProject(ComponentDto project) {
327 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
328 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).containsExactly(group2.getName());
329 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
330 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getId());
331 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
334 private void assertNoPermissionOnProject(ComponentDto project) {
335 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).isEmpty();
336 assertThat(selectProjectPermissionGroups(project, UserRole.CODEVIEWER)).isEmpty();
337 assertThat(selectProjectPermissionGroups(project, UserRole.ISSUE_ADMIN)).isEmpty();
338 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
339 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
340 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
341 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).isEmpty();
342 assertThat(selectProjectPermissionUsers(project, UserRole.USER)).isEmpty();
345 private void addUserToTemplate(UserDto user, PermissionTemplateDto permissionTemplate, String permission) {
346 db.getDbClient().permissionTemplateDao().insertUserPermission(db.getSession(), permissionTemplate.getId(), user.getId(), permission);
350 private void addGroupToTemplate(GroupDto group, PermissionTemplateDto permissionTemplate, String permission) {
351 db.getDbClient().permissionTemplateDao().insertGroupPermission(db.getSession(), permissionTemplate.getId(), group.getId(), permission);
355 private List<String> selectProjectPermissionGroups(ComponentDto project, String permission) {
356 PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
357 return db.getDbClient().groupPermissionDao().selectGroupNamesByQuery(db.getSession(), query);
360 private List<Integer> selectProjectPermissionUsers(ComponentDto project, String permission) {
361 PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
362 return db.getDbClient().userPermissionDao().selectUserIdsByQuery(db.getSession(), query);