/* * 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.common.project; import java.util.Optional; import org.junit.Rule; import org.junit.jupiter.api.Test; import org.mockito.Answers; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.alm.setting.ProjectAlmSettingDto; import org.sonar.db.component.BranchDto; import org.sonar.db.project.CreationMethod; import org.sonar.db.project.ProjectDto; import org.sonar.server.common.almsettings.DevOpsProjectCreator; import org.sonar.server.common.almsettings.DevOpsProjectCreatorFactory; import org.sonar.server.common.almsettings.DevOpsProjectDescriptor; import org.sonar.server.common.component.ComponentUpdater; import org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver; import org.sonar.server.component.ComponentCreationData; import org.sonar.server.tester.UserSessionRule; import static org.assertj.core.api.Assertions.assertThat; 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.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; import static org.sonar.db.project.CreationMethod.ALM_IMPORT_API; import static org.sonar.db.project.CreationMethod.ALM_IMPORT_MONOREPO_API; class ImportProjectServiceTest { private static final String API_URL = "https://api.com"; private static final String PROJECT_UUID = "project-uuid"; private static final String DOP_REPOSITORY_ID = "repository-id"; private static final String DOP_PROJECT_ID = "project-id"; private static final String PROJECT_KEY = "project-key"; private static final String PROJECT_NAME = "project-name"; private static final String MAIN_BRANCH_UUID = "main-branch-uuid"; private static final String MAIN_BRANCH_KEY = "main-branch-key"; private static final String ALM_SETTING_ID = "alm-setting-id"; @Rule public UserSessionRule userSession = UserSessionRule.standalone(); private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory = mock(); private final DbClient dbClient = mock(Answers.RETURNS_DEEP_STUBS); private final NewCodeDefinitionResolver newCodeDefinitionResolver = mock(); private final ComponentUpdater componentUpdater = mock(); private final ImportProjectService importProjectService = new ImportProjectService(dbClient, devOpsProjectCreatorFactory, userSession, componentUpdater, newCodeDefinitionResolver);; @Test void createdImportedProject_whenAlmSettingDoesntExist_throws() { userSession.logIn().addPermission(PROVISION_PROJECTS); DbSession dbSession = mockDbSession(); when(dbClient.almSettingDao().selectByUuid(dbSession, ALM_SETTING_ID)).thenReturn(Optional.empty()); ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, DOP_REPOSITORY_ID, DOP_PROJECT_ID, null, null, true); assertThatThrownBy(() -> importProjectService.importProject(request)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("ALM setting not found"); } @Test void createImportedProject_whenAlmIsNotSupported_throws() { userSession.logIn().addPermission(PROVISION_PROJECTS); DbSession dbSession = mockDbSession(); AlmSettingDto almSetting = mockAlmSetting(dbSession); when(devOpsProjectCreatorFactory.getDevOpsProjectCreator(eq(almSetting), any())) .thenReturn(Optional.empty()); ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, DOP_REPOSITORY_ID, DOP_PROJECT_ID, null, null, true); assertThatThrownBy(() -> importProjectService.importProject(request)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Platform GITHUB not supported"); } @Test void createImportedProject_whenAlmIsSupportedAndNoNewCodeDefinitionDefined_shouldCreateProject() { userSession.logIn().addPermission(PROVISION_PROJECTS); DbSession dbSession = mockDbSession(); AlmSettingDto almSetting = mockAlmSetting(dbSession); DevOpsProjectCreator devOpsProjectCreator = mockDevOpsProjectCreator(almSetting); ComponentCreationData componentCreationData = mockProjectCreation(devOpsProjectCreator, ALM_IMPORT_MONOREPO_API, true, dbSession); ProjectDto projectDto = mockProjectDto(componentCreationData); when(componentCreationData.mainBranchDto()).thenReturn(mock(BranchDto.class)); ProjectAlmSettingDto projectAlmSettingDto = mockProjectAlmSetting(dbSession, projectDto); ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, DOP_REPOSITORY_ID, DOP_PROJECT_ID, null, null, true); ImportedProject importedProject = importProjectService.importProject(request); assertThat(importedProject.projectDto()).isEqualTo(projectDto); assertThat(importedProject.projectAlmSettingDto()).isEqualTo(projectAlmSettingDto); verify(componentUpdater).commitAndIndex(dbSession, componentCreationData); } @Test void createImportedProject_whenAlmIsSupportedAndNewCodeDefinitionDefined_shouldCreateProjectAndNewCodeDefinition() { userSession.logIn().addPermission(PROVISION_PROJECTS); DbSession dbSession = mockDbSession(); AlmSettingDto almSetting = mockAlmSetting(dbSession); DevOpsProjectCreator devOpsProjectCreator = mockDevOpsProjectCreator(almSetting); ComponentCreationData componentCreationData = mockProjectCreation(devOpsProjectCreator, ALM_IMPORT_API, false, dbSession); ProjectDto projectDto = mockProjectDto(componentCreationData); mockBranchDto(componentCreationData); ProjectAlmSettingDto projectAlmSettingDto = mockProjectAlmSetting(dbSession, projectDto); ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, DOP_REPOSITORY_ID, DOP_PROJECT_ID, "NUMBER_OF_DAYS", "10", false); ImportedProject importedProject = importProjectService.importProject(request); assertThat(importedProject.projectDto()).isEqualTo(projectDto); assertThat(importedProject.projectAlmSettingDto()).isEqualTo(projectAlmSettingDto); verify(newCodeDefinitionResolver).createNewCodeDefinition( dbSession, PROJECT_UUID, MAIN_BRANCH_UUID, MAIN_BRANCH_KEY, "NUMBER_OF_DAYS", "10"); verify(componentUpdater).commitAndIndex(dbSession, componentCreationData); } private DbSession mockDbSession() { DbSession dbSession = mock(DbSession.class); when(dbClient.openSession(false)).thenReturn(dbSession); return dbSession; } private AlmSettingDto mockAlmSetting(DbSession dbSession) { AlmSettingDto almSetting = mock(AlmSettingDto.class); when(almSetting.getAlm()).thenReturn(ALM.GITHUB); when(almSetting.getUrl()).thenReturn(API_URL); when(dbClient.almSettingDao().selectByUuid(dbSession, ALM_SETTING_ID)).thenReturn(Optional.of(almSetting)); return almSetting; } private DevOpsProjectCreator mockDevOpsProjectCreator(AlmSettingDto almSetting) { DevOpsProjectCreator devOpsProjectCreator = mock(DevOpsProjectCreator.class); DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, API_URL, DOP_REPOSITORY_ID, DOP_PROJECT_ID); when(devOpsProjectCreatorFactory.getDevOpsProjectCreator(almSetting, projectDescriptor)) .thenReturn(Optional.of(devOpsProjectCreator)); return devOpsProjectCreator; } private static ComponentCreationData mockProjectCreation(DevOpsProjectCreator devOpsProjectCreator, CreationMethod creationMethod, boolean monorepo, DbSession dbSession) { ComponentCreationData componentCreationData = mock(ComponentCreationData.class); when(devOpsProjectCreator.createProjectAndBindToDevOpsPlatform(dbSession, creationMethod, monorepo, PROJECT_KEY, PROJECT_NAME)) .thenReturn(componentCreationData); return componentCreationData; } private static ProjectDto mockProjectDto(ComponentCreationData componentCreationData) { ProjectDto projectDto = mock(ProjectDto.class); lenient().when(projectDto.getUuid()).thenReturn(PROJECT_UUID); when(componentCreationData.projectDto()).thenReturn(projectDto); return projectDto; } private static void mockBranchDto(ComponentCreationData componentCreationData) { BranchDto mainBrainDto = mock(BranchDto.class); when(mainBrainDto.getUuid()).thenReturn(MAIN_BRANCH_UUID); when(mainBrainDto.getKey()).thenReturn(MAIN_BRANCH_KEY); when(componentCreationData.mainBranchDto()).thenReturn(mainBrainDto); } private ProjectAlmSettingDto mockProjectAlmSetting(DbSession dbSession, ProjectDto projectDto) { ProjectAlmSettingDto projectAlmSetting = mock(ProjectAlmSettingDto.class); when(dbClient.projectAlmSettingDao().selectByProject(dbSession, projectDto)) .thenReturn(Optional.of(projectAlmSetting)); return projectAlmSetting; } }