123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- /*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.almsettings.ws;
-
- import java.util.List;
- import java.util.Map;
- import java.util.Optional;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.mockito.Answers;
- import org.mockito.InjectMocks;
- import org.mockito.Mock;
- import org.mockito.junit.MockitoJUnitRunner;
- import org.sonar.alm.client.github.GithubGlobalSettingsValidator;
- import org.sonar.alm.client.github.GithubPermissionConverter;
- import org.sonar.auth.github.AppInstallationToken;
- import org.sonar.auth.github.GitHubSettings;
- import org.sonar.auth.github.client.GithubApplicationClient;
- import org.sonar.auth.github.security.AccessToken;
- import org.sonar.auth.github.security.UserAccessToken;
- import org.sonar.db.DbClient;
- import org.sonar.db.DbSession;
- import org.sonar.db.alm.pat.AlmPatDto;
- import org.sonar.db.alm.setting.ALM;
- import org.sonar.db.alm.setting.AlmSettingDto;
- import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
- import org.sonar.server.exceptions.BadConfigurationException;
- import org.sonar.server.management.ManagedProjectService;
- import org.sonar.server.permission.PermissionService;
- import org.sonar.server.permission.PermissionUpdater;
- import org.sonar.server.permission.UserPermissionChange;
- import org.sonar.server.project.ProjectDefaultVisibility;
- import org.sonar.server.project.ws.ProjectCreator;
- import org.sonar.server.user.UserSession;
-
- import static java.lang.String.format;
- import static org.assertj.core.api.Assertions.assertThat;
- import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
- import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
- import static org.assertj.core.api.Assertions.assertThatThrownBy;
- import static org.mockito.ArgumentMatchers.any;
- import static org.mockito.ArgumentMatchers.eq;
- import static org.mockito.Mockito.mock;
- import static org.mockito.Mockito.when;
- import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_PROJECT_IDENTIFIER;
- import static org.sonar.core.ce.CeTaskCharacteristics.DEVOPS_PLATFORM_URL;
-
- @RunWith(MockitoJUnitRunner.class)
- public class GithubProjectCreatorFactoryTest {
- private static final String PROJECT_NAME = "projectName";
- private static final String ORGANIZATION_NAME = "orgname";
- private static final String GITHUB_REPO_FULL_NAME = ORGANIZATION_NAME + "/" + PROJECT_NAME;
- private static final String GITHUB_API_URL = "https://api.toto.com";
-
- private static final DevOpsProjectDescriptor GITHUB_PROJECT_DESCRIPTOR = new DevOpsProjectDescriptor(ALM.GITHUB, GITHUB_API_URL, GITHUB_REPO_FULL_NAME);
- private static final Map<String, String> VALID_GITHUB_PROJECT_COORDINATES = Map.of(
- DEVOPS_PLATFORM_URL, GITHUB_PROJECT_DESCRIPTOR.url(),
- DEVOPS_PLATFORM_PROJECT_IDENTIFIER, GITHUB_PROJECT_DESCRIPTOR.projectIdentifier());
- private static final long APP_INSTALLATION_ID = 534534534543L;
- private static final String USER_ACCESS_TOKEN = "userPat";
-
- @Mock
- private DbSession dbSession;
- @Mock
- private GithubGlobalSettingsValidator githubGlobalSettingsValidator;
- @Mock
- private GithubApplicationClient githubApplicationClient;
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private DbClient dbClient;
- @Mock
- private UserSession userSession;
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private ProjectDefaultVisibility projectDefaultVisibility;
- @Mock
- private ProjectKeyGenerator projectKeyGenerator;
- @Mock
- private GitHubSettings gitHubSettings;
- @Mock
- private GithubPermissionConverter githubPermissionConverter;
- @Mock
- private AppInstallationToken appInstallationToken;
- @Mock
- private AppInstallationToken authAppInstallationToken;
- @Mock
- private PermissionService permissionService;
- @Mock
- private PermissionUpdater<UserPermissionChange> permissionUpdater;
- @Mock
- private ManagedProjectService managedProjectService;
- @Mock
- private ProjectCreator projectCreator;
-
- @InjectMocks
- private GithubProjectCreatorFactory githubProjectCreatorFactory;
-
- @Test
- public void getDevOpsProjectCreator_whenNoCharacteristics_shouldReturnEmpty() {
- Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, Map.of());
-
- assertThat(devOpsProjectCreator).isEmpty();
- }
-
- @Test
- public void getDevOpsProjectCreator_whenValidCharacteristicsButNoAlmSettingDao_shouldReturnEmpty() {
- Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES);
- assertThat(devOpsProjectCreator).isEmpty();
- }
-
- @Test
- public void getDevOpsProjectCreator_whenValidCharacteristicsButInvalidAlmSettingDto_shouldThrow() {
- AlmSettingDto almSettingDto = mockAlmSettingDto(true);
- IllegalArgumentException error = new IllegalArgumentException("error happened");
- when(githubGlobalSettingsValidator.validate(almSettingDto)).thenThrow(error);
-
- assertThatIllegalArgumentException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
- .isSameAs(error);
- }
-
- @Test
- public void getDevOpsProjectCreator_whenAppHasNoAccessToRepo_shouldReturnEmpty() {
- mockAlmSettingDto(true);
- when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.empty());
-
- Optional<DevOpsProjectCreator> devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES);
- assertThat(devOpsProjectCreator).isEmpty();
- }
-
- @Test
- public void getDevOpsProjectCreator_whenNotPossibleToGenerateToken_shouldThrow() {
- AlmSettingDto almSettingDto = mockAlmSettingDto(true);
- when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID));
- when(githubGlobalSettingsValidator.validate(almSettingDto)).thenReturn(mock());
- when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.empty());
-
- assertThatIllegalStateException().isThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES))
- .withMessage("Error while generating token for GitHub Api Url null (installation id: 534534534543)");
- }
-
- @Test
- public void getDevOpsProjectCreator_whenOneValidAlmSetting_shouldInstantiateDevOpsProjectCreator() {
- AlmSettingDto almSettingDto = mockAlmSettingDto(true);
- mockSuccessfulGithubInteraction();
-
- DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
-
- GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(almSettingDto, false, appInstallationToken);
- assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
- }
-
- @Test
- public void getDevOpsProjectCreator_whenOneValidAlmSettingAndPublicByDefaultAndAutoProvisioningEnabled_shouldInstantiateDevOpsProjectCreatorAndDefineAnAuthAppToken() {
- AlmSettingDto almSettingDto = mockAlmSettingDto(true);
- mockSuccessfulGithubInteraction();
-
- when(projectDefaultVisibility.get(any()).isPrivate()).thenReturn(true);
- mockValidGitHubSettings();
-
- long authAppInstallationId = 32;
- when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(authAppInstallationId));
- when(githubApplicationClient.createAppInstallationToken(any(), eq(authAppInstallationId))).thenReturn(Optional.of(authAppInstallationToken));
-
- DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
-
- GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(almSettingDto, true, appInstallationToken);
- assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
- }
-
- @Test
- public void getDevOpsProjectCreator_whenOneMatchingAndOneNotMatchingAlmSetting_shouldInstantiateDevOpsProjectCreator() {
- AlmSettingDto matchingAlmSettingDto = mockAlmSettingDto(true);
- AlmSettingDto notMatchingAlmSettingDto = mockAlmSettingDto(false);
- when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(notMatchingAlmSettingDto, matchingAlmSettingDto));
-
- mockSuccessfulGithubInteraction();
-
- DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(dbSession, VALID_GITHUB_PROJECT_COORDINATES).orElseThrow();
-
- GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(matchingAlmSettingDto, false, appInstallationToken);
- assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
- }
-
- @Test
- public void getDevOpsProjectCreatorFromImport_shouldInstantiateDevOpsProjectCreator() {
- AlmSettingDto mockAlmSettingDto = mockAlmSettingDto(true);
- mockAlmPatDto(mockAlmSettingDto);
-
- mockSuccessfulGithubInteraction();
-
- DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(mockAlmSettingDto, GITHUB_PROJECT_DESCRIPTOR).orElseThrow();
-
- GithubProjectCreator expectedGithubProjectCreator = getExpectedGithubProjectCreator(mockAlmSettingDto, false, new UserAccessToken(USER_ACCESS_TOKEN));
- assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator);
- }
-
- @Test
- public void getDevOpsProjectCreatorFromImport_whenGitHubConfigDoesNotAllowAccessToRepo_shouldThrow() {
- AlmSettingDto mockAlmSettingDto = mockAlmSettingDto(false);
- mockAlmPatDto(mockAlmSettingDto);
-
- mockValidGitHubSettings();
-
- when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.empty());
-
- assertThatThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(mockAlmSettingDto, GITHUB_PROJECT_DESCRIPTOR))
- .isInstanceOf(BadConfigurationException.class)
- .hasMessage(format("GitHub auto-provisioning is activated. However the repo %s is not in the scope of the authentication application. "
- + "The permissions can't be checked, and the project can not be created.",
- GITHUB_REPO_FULL_NAME));
- }
-
- private void mockValidGitHubSettings() {
- when(gitHubSettings.appId()).thenReturn("4324");
- when(gitHubSettings.privateKey()).thenReturn("privateKey");
- when(gitHubSettings.apiURL()).thenReturn(GITHUB_API_URL);
- when(gitHubSettings.isProvisioningEnabled()).thenReturn(true);
- }
-
- private void mockSuccessfulGithubInteraction() {
- when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID));
- when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.of(appInstallationToken));
- }
-
- private GithubProjectCreator getExpectedGithubProjectCreator(AlmSettingDto almSettingDto, boolean isInstanceManaged, AccessToken accessToken) {
- DevOpsProjectDescriptor devOpsProjectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, almSettingDto.getUrl(), GITHUB_REPO_FULL_NAME);
- AppInstallationToken authAppInstallToken = isInstanceManaged ? authAppInstallationToken : null;
- GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor, almSettingDto, userSession, accessToken,
- authAppInstallToken);
- return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, permissionUpdater, permissionService,
- managedProjectService, projectCreator, githubProjectCreationParameters, gitHubSettings);
- }
-
- private AlmSettingDto mockAlmSettingDto(boolean repoAccess) {
- AlmSettingDto almSettingDto = mock();
- when(almSettingDto.getUrl()).thenReturn(repoAccess ? GITHUB_PROJECT_DESCRIPTOR.url() : "anotherUrl");
- when(almSettingDto.getAlm()).thenReturn(ALM.GITHUB);
-
- when(dbClient.almSettingDao().selectByAlm(dbSession, ALM.GITHUB)).thenReturn(List.of(almSettingDto));
- return almSettingDto;
- }
-
- private void mockAlmPatDto(AlmSettingDto almSettingDto) {
- when(userSession.getUuid()).thenReturn("userUuid");
- when(dbClient.almPatDao().selectByUserAndAlmSetting(any(), eq("userUuid"), eq(almSettingDto)))
- .thenReturn(Optional.of(new AlmPatDto().setPersonalAccessToken(USER_ACCESS_TOKEN)));
- }
-
- }
|