]> source.dussan.org Git - sonarqube.git/blob
0afb9ab71c606f93f5112da7613fb06eeb0e3d33
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 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.almsettings.ws;
21
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Optional;
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 import org.mockito.Answers;
28 import org.mockito.InjectMocks;
29 import org.mockito.Mock;
30 import org.mockito.junit.MockitoJUnitRunner;
31 import org.sonar.alm.client.github.AppInstallationToken;
32 import org.sonar.alm.client.github.GithubApplicationClient;
33 import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
34 import org.sonar.alm.client.github.GithubPermissionConverter;
35 import org.sonar.auth.github.GitHubSettings;
36 import org.sonar.db.DbClient;
37 import org.sonar.db.DbSession;
38 import org.sonar.db.alm.setting.ALM;
39 import org.sonar.db.alm.setting.AlmSettingDto;
40 import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
41 import org.sonar.server.component.ComponentUpdater;
42 import org.sonar.server.management.ManagedProjectService;
43 import org.sonar.server.permission.PermissionService;
44 import org.sonar.server.permission.PermissionUpdater;
45 import org.sonar.server.permission.UserPermissionChange;
46 import org.sonar.server.project.ProjectDefaultVisibility;
47 import org.sonar.server.user.UserSession;
48
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
51 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
52 import static org.mockito.ArgumentMatchers.any;
53 import static org.mockito.ArgumentMatchers.eq;
54 import static org.mockito.Mockito.mock;
55 import static org.mockito.Mockito.when;
56 import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
57 import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
58
59 @RunWith(MockitoJUnitRunner.class)
60 public class GithubProjectCreatorFactoryTest {
61   private static final String PROJECT_NAME = "projectName";
62   private static final String ORGANIZATION_NAME = "orgname";
63   private static final String GITHUB_REPO_FULL_NAME = ORGANIZATION_NAME + "/" + PROJECT_NAME;
64   private static final String GITHUB_API_URL = "https://api.toto.com";
65
66   private static final DevOpsProjectDescriptor GITHUB_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, GITHUB_API_URL, GITHUB_REPO_FULL_NAME);
67   private static final Map<String, String> VALID_GITHUB_PROJECT_COORDINATES = Map.of(
68     DEVOPS_PLATFORM_URL, GITHUB_PROJECT_DESCRIPTOR.url(),
69     DEVOPS_PLATFORM_PROJECT_IDENTIFIER, GITHUB_PROJECT_DESCRIPTOR.projectIdentifier());
70   private static final long APP_INSTALLATION_ID = 534534534543L;
71
72   @Mock
73   private DbSession dbSession;
74   @Mock
75   private GithubGlobalSettingsValidator githubGlobalSettingsValidator;
76   @Mock
77   private GithubApplicationClient githubApplicationClient;
78   @Mock
79   private ComponentUpdater componentUpdater;
80   @Mock(answer = Answers.RETURNS_DEEP_STUBS)
81   private DbClient dbClient;
82   @Mock
83   private UserSession userSession;
84   @Mock(answer = Answers.RETURNS_DEEP_STUBS)
85   private ProjectDefaultVisibility projectDefaultVisibility;
86   @Mock
87   private ProjectKeyGenerator projectKeyGenerator;
88   @Mock
89   private GitHubSettings gitHubSettings;
90   @Mock
91   private GithubPermissionConverter githubPermissionConverter;
92   @Mock
93   private AppInstallationToken appInstallationToken;
94   @Mock
95   private AppInstallationToken authAppInstallationToken;
96   @Mock
97   private PermissionService permissionService;
98   @Mock
99   private PermissionUpdater<UserPermissionChange> permissionUpdater;
100   @Mock
101   private ManagedProjectService managedProjectService;
102
103   @InjectMocks
104   private GithubProjectCreatorFactory githubProjectCreatorFactory;
105
106   @Test
107   public void getDevOpsProjectCreator_whenNoCharacteristics_shouldReturnEmpty() {
108     Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, Map.of());
109
110     assertThat(devOpsProjectCreator).isEmpty();
111   }
112
113   @Test
114   public void getDevOpsProjectCreator_whenValidCharacteristicsButNoAlmSettingDao_shouldReturnEmpty() {
115     Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES);
116     assertThat(devOpsProjectCreator).isEmpty();
117   }
118
119   @Test
120   public void getDevOpsProjectCreator_whenValidCharacteristicsButInvalidAlmSettingDto_shouldThrow() {
121     AlmSettingDto almSettingDto = mockAlmSettingDto(true);
122     IllegalArgumentException error = new IllegalArgumentException("error happened");
123     when(githubGlobalSettingsValidator.validate(almSettingDto)).thenThrow(error);
124
125     assertThatIllegalArgumentException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
126       .isSameAs(error);
127   }
128
129   @Test
130   public void getDevOpsProjectCreator_whenAppHasNoAccessToRepo_shouldReturnEmpty() {
131     mockAlmSettingDto(true);
132     when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.empty());
133
134     Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES);
135     assertThat(devOpsProjectCreator).isEmpty();
136   }
137
138   @Test
139   public void getDevOpsProjectCreator_whenNotPossibleToGenerateToken_shouldThrow() {
140     AlmSettingDto almSettingDto = mockAlmSettingDto(true);
141     when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID));
142     when(githubGlobalSettingsValidator.validate(almSettingDto)).thenReturn(mock());
143     when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.empty());
144
145     assertThatIllegalStateException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
146       .withMessage("Error while generating token for GitHub Api Url null (installation id: 534534534543)");
147   }
148
149   @Test
150   public void getDevOpsProjectCreator_whenOneValidAlmSetting_shouldInstantiateDevOpsProjectCreator() {
151     AlmSettingDto almSettingDto = mockAlmSettingDto(true);
152     mockSuccessfulGithubInteraction();
153
154     DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
155
156     GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(almSettingDto, false, false);
157     assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
158   }
159
160   @Test
161   public void getDevOpsProjectCreator_whenOneValidAlmSettingAndPublicByDefaultAndAutoProvisioningEnabled_shouldInstantiateDevOpsProjectCreatorAndDefineAnAuthAppToken() {
162     AlmSettingDto almSettingDto = mockAlmSettingDto(true);
163     mockSuccessfulGithubInteraction();
164
165     when(projectDefaultVisibility.get(any()).isPrivate()).thenReturn(true);
166     when(gitHubSettings.isProvisioningEnabled()).thenReturn(true);
167     when(gitHubSettings.appId()).thenReturn("4324");
168     when(gitHubSettings.privateKey()).thenReturn("privateKey");
169     when(gitHubSettings.apiURL()).thenReturn(GITHUB_API_URL);
170
171     long authAppInstallationId = 32;
172     when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(authAppInstallationId));
173     when(githubApplicationClient.createAppInstallationToken(any(), eq(authAppInstallationId))).thenReturn(Optional.of(authAppInstallationToken));
174
175     DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
176
177     GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(almSettingDto, true, true);
178     assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
179   }
180
181   @Test
182   public void getDevOpsProjectCreator_whenOneMatchingAndOneNotMatchingAlmSetting_shouldInstantiateDevOpsProjectCreator() {
183     AlmSettingDto matchingAlmSettingDto = mockAlmSettingDto(true);
184     AlmSettingDto notMatchingAlmSettingDto = mockAlmSettingDto(false);
185     when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(notMatchingAlmSettingDto, matchingAlmSettingDto));
186
187     mockSuccessfulGithubInteraction();
188
189     DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
190
191     GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(matchingAlmSettingDto, false, false);
192     assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
193   }
194
195   @Test
196   public void getDevOpsProjectCreatorFromImport_shouldInstantiateDevOpsProjectCreator() {
197     AlmSettingDto mockAlmSettingDto = mockAlmSettingDto(true);
198
199     mockSuccessfulGithubInteraction();
200
201     DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, mockAlmSettingDto, appInstallationToken, GITHUB_PROJECT_DESCRIPTOR);
202
203     GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(mockAlmSettingDto, false, false);
204     assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
205   }
206
207   private void mockSuccessfulGithubInteraction() {
208     when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID));
209     when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.of(appInstallationToken));
210   }
211
212   private GithubProjectCreator getExpectedGithubProjectCreator(AlmSettingDto almSettingDto, boolean projectsArePrivateByDefault, boolean isInstanceManaged) {
213     DevOpsProjectDescriptor devOpsProjectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, almSettingDto.getUrl(), GITHUB_REPO_FULL_NAME);
214     AppInstallationToken authAppInstallToken = isInstanceManaged ? authAppInstallationToken : null;
215     GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
216       almSettingDto, projectsArePrivateByDefault, isInstanceManaged, userSession, appInstallationToken, authAppInstallToken);
217     return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, permissionUpdater, permissionService,
218       managedProjectService, githubProjectCreationParameters);
219   }
220
221   private AlmSettingDto mockAlmSettingDto(boolean repoAccess) {
222     AlmSettingDto almSettingDto = mock();
223     when(almSettingDto.getUrl()).thenReturn(repoAccess ? GITHUB_PROJECT_DESCRIPTOR.url() : "anotherUrl");
224
225     when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(almSettingDto));
226     return almSettingDto;
227   }
228
229 }