]> source.dussan.org Git - sonarqube.git/blob
bf7ffd17cfd64c7e462182de90275eba25c31f39
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.almintegration.ws.azure;
21
22 import java.util.Optional;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.sonar.alm.client.azure.AzureDevOpsHttpClient;
27 import org.sonar.alm.client.azure.GsonAzureProject;
28 import org.sonar.alm.client.azure.GsonAzureRepo;
29 import org.sonar.api.config.internal.Encryption;
30 import org.sonar.api.server.ws.WebService;
31 import org.sonar.api.utils.System2;
32 import org.sonar.core.util.SequenceUuidFactory;
33 import org.sonar.db.DbTester;
34 import org.sonar.db.alm.pat.AlmPatDto;
35 import org.sonar.db.alm.setting.AlmSettingDto;
36 import org.sonar.db.alm.setting.ProjectAlmSettingDto;
37 import org.sonar.db.component.BranchDto;
38 import org.sonar.db.project.ProjectDto;
39 import org.sonar.db.user.UserDto;
40 import org.sonar.server.almintegration.ws.ImportHelper;
41 import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
42 import org.sonar.server.component.ComponentUpdater;
43 import org.sonar.server.es.TestProjectIndexers;
44 import org.sonar.server.exceptions.BadRequestException;
45 import org.sonar.server.exceptions.ForbiddenException;
46 import org.sonar.server.exceptions.NotFoundException;
47 import org.sonar.server.exceptions.UnauthorizedException;
48 import org.sonar.server.favorite.FavoriteUpdater;
49 import org.sonar.server.l18n.I18nRule;
50 import org.sonar.server.permission.PermissionTemplateService;
51 import org.sonar.server.project.DefaultBranchNameResolver;
52 import org.sonar.server.project.ProjectDefaultVisibility;
53 import org.sonar.server.project.Visibility;
54 import org.sonar.server.tester.UserSessionRule;
55 import org.sonar.server.ws.TestRequest;
56 import org.sonar.server.ws.WsActionTester;
57 import org.sonarqube.ws.Projects;
58
59 import static org.assertj.core.api.Assertions.assertThat;
60 import static org.assertj.core.api.Assertions.assertThatThrownBy;
61 import static org.assertj.core.api.Assertions.tuple;
62 import static org.mockito.ArgumentMatchers.any;
63 import static org.mockito.Mockito.mock;
64 import static org.mockito.Mockito.verify;
65 import static org.mockito.Mockito.when;
66 import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto;
67 import static org.sonar.db.component.BranchDto.DEFAULT_PROJECT_MAIN_BRANCH_NAME;
68 import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
69 import static org.sonar.db.permission.GlobalPermission.SCAN;
70
71 public class ImportAzureProjectActionTest {
72
73   private static final String GENERATED_PROJECT_KEY = "TEST_PROJECT_KEY";
74
75   @Rule
76   public UserSessionRule userSession = UserSessionRule.standalone();
77   @Rule
78   public DbTester db = DbTester.create();
79   @Rule
80   public final I18nRule i18n = new I18nRule();
81
82   private final AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class);
83
84   private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class);
85
86   private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
87     mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory(),
88     defaultBranchNameResolver);
89
90   private final Encryption encryption = mock(Encryption.class);
91   private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
92   private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class);
93   private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
94   private final ImportAzureProjectAction importAzureProjectAction = new ImportAzureProjectAction(db.getDbClient(), userSession,
95     azureDevOpsHttpClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator);
96   private final WsActionTester ws = new WsActionTester(importAzureProjectAction);
97
98   @Before
99   public void before() {
100     when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PRIVATE);
101     when(projectKeyGenerator.generateUniqueProjectKey(any(), any())).thenReturn(GENERATED_PROJECT_KEY);
102     when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn(DEFAULT_PROJECT_MAIN_BRANCH_NAME);
103   }
104
105   @Test
106   public void import_project() {
107     UserDto user = db.users().insertUser();
108     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
109     AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting();
110     db.almPats().insert(dto -> {
111       dto.setAlmSettingUuid(almSetting.getUuid());
112       dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption));
113       dto.setUserUuid(user.getUuid());
114     });
115     GsonAzureRepo repo = getGsonAzureRepo();
116     when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
117       "project-name", "repo-name"))
118       .thenReturn(repo);
119
120     Projects.CreateWsResponse response = ws.newRequest()
121       .setParam("almSetting", almSetting.getKey())
122       .setParam("projectName", "project-name")
123       .setParam("repositoryName", "repo-name")
124       .executeProtobuf(Projects.CreateWsResponse.class);
125
126     Projects.CreateWsResponse.Project result = response.getProject();
127     assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY);
128     assertThat(result.getName()).isEqualTo(repo.getName());
129
130     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
131     assertThat(projectDto).isPresent();
132
133     Optional<ProjectAlmSettingDto> projectAlmSettingDto = db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get());
134     assertThat(projectAlmSettingDto.get().getAlmRepo()).isEqualTo("repo-name");
135     assertThat(projectAlmSettingDto.get().getAlmSettingUuid()).isEqualTo(almSetting.getUuid());
136     assertThat(projectAlmSettingDto.get().getAlmSlug()).isEqualTo("project-name");
137
138     Optional<BranchDto> mainBranch = db.getDbClient()
139       .branchDao()
140       .selectByProject(db.getSession(), projectDto.get())
141       .stream()
142       .filter(BranchDto::isMain)
143       .findFirst();
144     assertThat(mainBranch).isPresent();
145     assertThat(mainBranch.get().getKey()).hasToString("repo-default-branch");
146
147     verify(projectKeyGenerator).generateUniqueProjectKey(repo.getProject().getName(), repo.getName());
148   }
149
150   @Test
151   public void import_project_from_empty_repo() {
152     UserDto user = db.users().insertUser();
153     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
154     AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting();
155     db.almPats().insert(dto -> {
156       dto.setAlmSettingUuid(almSetting.getUuid());
157       dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption));
158       dto.setUserUuid(user.getUuid());
159     });
160     GsonAzureRepo repo = getEmptyGsonAzureRepo();
161     when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
162       "project-name", "repo-name"))
163       .thenReturn(repo);
164
165     Projects.CreateWsResponse response = ws.newRequest()
166       .setParam("almSetting", almSetting.getKey())
167       .setParam("projectName", "project-name")
168       .setParam("repositoryName", "repo-name")
169       .executeProtobuf(Projects.CreateWsResponse.class);
170
171     Projects.CreateWsResponse.Project result = response.getProject();
172     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
173     Optional<BranchDto> mainBranch = db.getDbClient()
174       .branchDao()
175       .selectByProject(db.getSession(), projectDto.get())
176       .stream()
177       .filter(BranchDto::isMain)
178       .findFirst();
179
180     assertThat(mainBranch).isPresent();
181     assertThat(mainBranch.get().getKey()).hasToString(DEFAULT_PROJECT_MAIN_BRANCH_NAME);
182   }
183
184   @Test
185   public void fail_when_not_logged_in() {
186     TestRequest request = ws.newRequest()
187       .setParam("almSetting", "azure")
188       .setParam("projectName", "project-name")
189       .setParam("repositoryName", "repo-name");
190
191     assertThatThrownBy(request::execute)
192       .isInstanceOf(UnauthorizedException.class);
193   }
194
195   @Test
196   public void fail_when_missing_project_creator_permission() {
197     UserDto user = db.users().insertUser();
198     userSession.logIn(user).addPermission(SCAN);
199
200     TestRequest request = ws.newRequest()
201       .setParam("almSetting", "azure")
202       .setParam("projectName", "project-name")
203       .setParam("repositoryName", "repo-name");
204
205     assertThatThrownBy(request::execute)
206       .isInstanceOf(ForbiddenException.class)
207       .hasMessage("Insufficient privileges");
208   }
209
210   @Test
211   public void check_pat_is_missing() {
212     UserDto user = db.users().insertUser();
213     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
214     AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting();
215
216     TestRequest request = ws.newRequest()
217       .setParam("almSetting", almSetting.getKey())
218       .setParam("projectName", "project-name")
219       .setParam("repositoryName", "repo-name");
220
221     assertThatThrownBy(request::execute)
222       .isInstanceOf(IllegalArgumentException.class)
223       .hasMessage("personal access token for '" + almSetting.getKey() + "' is missing");
224   }
225
226   @Test
227   public void fail_check_alm_setting_not_found() {
228     UserDto user = db.users().insertUser();
229     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
230     AlmPatDto almPatDto = newAlmPatDto();
231     db.getDbClient().almPatDao().insert(db.getSession(), almPatDto, user.getLogin(), null);
232
233     TestRequest request = ws.newRequest()
234       .setParam("almSetting", "testKey");
235
236     assertThatThrownBy(request::execute)
237       .isInstanceOf(NotFoundException.class)
238       .hasMessage("ALM Setting 'testKey' not found");
239   }
240
241   @Test
242   public void fail_project_already_exists() {
243     UserDto user = db.users().insertUser();
244     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
245     AlmSettingDto almSetting = db.almSettings().insertAzureAlmSetting();
246     db.almPats().insert(dto -> {
247       dto.setAlmSettingUuid(almSetting.getUuid());
248       dto.setPersonalAccessToken(almSetting.getDecryptedPersonalAccessToken(encryption));
249       dto.setUserUuid(user.getUuid());
250     });
251     GsonAzureRepo repo = getGsonAzureRepo();
252     db.components().insertPublicProject(p -> p.setKey(GENERATED_PROJECT_KEY));
253
254     when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
255       "project-name", "repo-name")).thenReturn(repo);
256     TestRequest request = ws.newRequest()
257       .setParam("almSetting", almSetting.getKey())
258       .setParam("projectName", "project-name")
259       .setParam("repositoryName", "repo-name");
260
261     assertThatThrownBy(request::execute)
262       .isInstanceOf(BadRequestException.class)
263       .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", GENERATED_PROJECT_KEY, GENERATED_PROJECT_KEY);
264   }
265
266   @Test
267   public void define() {
268     WebService.Action def = ws.getDef();
269
270     assertThat(def.since()).isEqualTo("8.6");
271     assertThat(def.isPost()).isTrue();
272     assertThat(def.params())
273       .extracting(WebService.Param::key, WebService.Param::isRequired)
274       .containsExactlyInAnyOrder(
275         tuple("almSetting", true),
276         tuple("projectName", true),
277         tuple("repositoryName", true));
278   }
279
280   private GsonAzureRepo getGsonAzureRepo() {
281     return new GsonAzureRepo("repo-id", "repo-name", "repo-url",
282       new GsonAzureProject("project-name", "project-description"),
283       "refs/heads/repo-default-branch");
284   }
285
286   private GsonAzureRepo getEmptyGsonAzureRepo() {
287     return new GsonAzureRepo("repo-id", "repo-name", "repo-url",
288       new GsonAzureProject("project-name", "project-description"), null);
289   }
290
291 }