You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CreateActionIT.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 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.project.ws;
  21. import com.google.common.base.Strings;
  22. import java.util.Optional;
  23. import javax.annotation.Nullable;
  24. import org.junit.Before;
  25. import org.junit.Rule;
  26. import org.junit.Test;
  27. import org.sonar.api.server.ws.WebService;
  28. import org.sonar.api.utils.System2;
  29. import org.sonar.core.platform.EditionProvider;
  30. import org.sonar.core.platform.PlatformEditionProvider;
  31. import org.sonar.core.util.SequenceUuidFactory;
  32. import org.sonar.db.DbSession;
  33. import org.sonar.db.DbTester;
  34. import org.sonar.db.component.BranchDto;
  35. import org.sonar.db.component.ComponentDto;
  36. import org.sonar.db.newcodeperiod.NewCodePeriodDto;
  37. import org.sonar.db.project.CreationMethod;
  38. import org.sonar.db.project.ProjectDto;
  39. import org.sonar.db.user.UserDto;
  40. import org.sonar.server.common.component.ComponentUpdater;
  41. import org.sonar.server.es.Indexers;
  42. import org.sonar.server.es.TestIndexers;
  43. import org.sonar.server.exceptions.BadRequestException;
  44. import org.sonar.server.exceptions.ForbiddenException;
  45. import org.sonar.server.favorite.FavoriteUpdater;
  46. import org.sonar.server.l18n.I18nRule;
  47. import org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver;
  48. import org.sonar.server.permission.PermissionService;
  49. import org.sonar.server.common.permission.PermissionTemplateService;
  50. import org.sonar.server.common.permission.PermissionUpdater;
  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.project.ws.CreateAction.Builder;
  55. import org.sonar.server.project.ws.CreateAction.CreateRequest;
  56. import org.sonar.server.tester.UserSessionRule;
  57. import org.sonar.server.ws.TestRequest;
  58. import org.sonar.server.ws.WsActionTester;
  59. import org.sonarqube.ws.Projects.CreateWsResponse;
  60. import org.sonarqube.ws.Projects.CreateWsResponse.Project;
  61. import static java.util.Optional.ofNullable;
  62. import static java.util.stream.IntStream.rangeClosed;
  63. import static org.assertj.core.api.Assertions.assertThat;
  64. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  65. import static org.mockito.ArgumentMatchers.any;
  66. import static org.mockito.Mockito.mock;
  67. import static org.mockito.Mockito.when;
  68. import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
  69. import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
  70. import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
  71. import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
  72. import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
  73. import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
  74. import static org.sonar.server.project.Visibility.PRIVATE;
  75. import static org.sonar.test.JsonAssert.assertJson;
  76. import static org.sonarqube.ws.client.WsRequest.Method.POST;
  77. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_MAIN_BRANCH;
  78. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
  79. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE;
  80. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE;
  81. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
  82. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
  83. public class CreateActionIT {
  84. private static final String DEFAULT_PROJECT_KEY = "project-key";
  85. private static final String DEFAULT_PROJECT_NAME = "project-name";
  86. private static final String MAIN_BRANCH = "main-branch";
  87. private final System2 system2 = System2.INSTANCE;
  88. @Rule
  89. public final DbTester db = DbTester.create(system2);
  90. @Rule
  91. public final UserSessionRule userSession = UserSessionRule.standalone();
  92. @Rule
  93. public final I18nRule i18n = new I18nRule().put("qualifier.TRK", "Project");
  94. private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class);
  95. private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class);
  96. private final TestIndexers projectIndexers = new TestIndexers();
  97. private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
  98. private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
  99. private final NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider);
  100. private final WsActionTester ws = new WsActionTester(
  101. new CreateAction(
  102. db.getDbClient(), userSession,
  103. new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()),
  104. projectIndexers, new SequenceUuidFactory(), defaultBranchNameResolver, mock(PermissionUpdater.class), mock(PermissionService.class)),
  105. projectDefaultVisibility, defaultBranchNameResolver, newCodeDefinitionResolver));
  106. @Before
  107. public void before() {
  108. when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PUBLIC);
  109. when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn(DEFAULT_MAIN_BRANCH_NAME);
  110. }
  111. @Test
  112. public void create_project() {
  113. userSession.addPermission(PROVISION_PROJECTS);
  114. CreateWsResponse response = call(CreateRequest.builder()
  115. .setProjectKey(DEFAULT_PROJECT_KEY)
  116. .setName(DEFAULT_PROJECT_NAME)
  117. .setMainBranchKey(MAIN_BRANCH)
  118. .build());
  119. assertThat(response.getProject())
  120. .extracting(Project::getKey, Project::getName, Project::getQualifier, Project::getVisibility)
  121. .containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "public");
  122. ProjectDto projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).orElseThrow();
  123. assertThat(projectDto)
  124. .extracting(ProjectDto::getKey, ProjectDto::getName, ProjectDto::getQualifier, ProjectDto::isPrivate, ProjectDto::getCreationMethod)
  125. .containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", false, CreationMethod.LOCAL_API);
  126. ComponentDto component = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).orElseThrow();
  127. BranchDto branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), component.branchUuid()).orElseThrow();
  128. assertThat(branch)
  129. .extracting(BranchDto::getKey)
  130. .isEqualTo(MAIN_BRANCH);
  131. projectIndexers.hasBeenCalledForEntity(branch.getProjectUuid(), Indexers.EntityEvent.CREATION);
  132. }
  133. @Test
  134. public void apply_project_visibility_public() {
  135. userSession.addPermission(PROVISION_PROJECTS);
  136. CreateWsResponse result = ws.newRequest()
  137. .setParam("project", DEFAULT_PROJECT_KEY)
  138. .setParam("name", DEFAULT_PROJECT_NAME)
  139. .setParam("visibility", "public")
  140. .executeProtobuf(CreateWsResponse.class);
  141. assertThat(result.getProject().getVisibility()).isEqualTo("public");
  142. }
  143. @Test
  144. public void createProject_whenCalIsFromGui_setCreationMethodEqualsUi() {
  145. userSession.logIn().addPermission(PROVISION_PROJECTS).flagSessionAsGui();
  146. ws.newRequest()
  147. .setParam("project", DEFAULT_PROJECT_KEY)
  148. .setParam("name", DEFAULT_PROJECT_NAME)
  149. .setParam("visibility", "public")
  150. .executeProtobuf(CreateWsResponse.class);
  151. ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  152. assertThat(project.getCreationMethod()).isEqualTo(CreationMethod.LOCAL_BROWSER);
  153. }
  154. @Test
  155. public void apply_project_visibility_private() {
  156. userSession.addPermission(PROVISION_PROJECTS);
  157. CreateWsResponse result = ws.newRequest()
  158. .setParam("project", DEFAULT_PROJECT_KEY)
  159. .setParam("name", DEFAULT_PROJECT_NAME)
  160. .setParam("visibility", PRIVATE.getLabel())
  161. .executeProtobuf(CreateWsResponse.class);
  162. assertThat(result.getProject().getVisibility()).isEqualTo("private");
  163. }
  164. @Test
  165. public void apply_default_project_visibility_public() {
  166. when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PUBLIC);
  167. userSession.addPermission(PROVISION_PROJECTS);
  168. CreateWsResponse result = ws.newRequest()
  169. .setParam("project", DEFAULT_PROJECT_KEY)
  170. .setParam("name", DEFAULT_PROJECT_NAME)
  171. .executeProtobuf(CreateWsResponse.class);
  172. assertThat(result.getProject().getVisibility()).isEqualTo("public");
  173. }
  174. @Test
  175. public void apply_default_project_visibility_private() {
  176. when(projectDefaultVisibility.get(any())).thenReturn(PRIVATE);
  177. userSession.addPermission(PROVISION_PROJECTS);
  178. CreateWsResponse result = ws.newRequest()
  179. .setParam("project", DEFAULT_PROJECT_KEY)
  180. .setParam("name", DEFAULT_PROJECT_NAME)
  181. .executeProtobuf(CreateWsResponse.class);
  182. assertThat(result.getProject().getVisibility()).isEqualTo("private");
  183. }
  184. @Test
  185. public void abbreviate_project_name_if_very_long() {
  186. userSession.addPermission(PROVISION_PROJECTS);
  187. String longName = Strings.repeat("a", 1_000);
  188. ws.newRequest()
  189. .setParam("project", DEFAULT_PROJECT_KEY)
  190. .setParam("name", longName)
  191. .executeProtobuf(CreateWsResponse.class);
  192. assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get().name())
  193. .isEqualTo(Strings.repeat("a", 497) + "...");
  194. }
  195. @Test
  196. public void add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template() {
  197. UserDto user = db.users().insertUser();
  198. when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ProjectDto.class))).thenReturn(true);
  199. userSession.logIn(user).addPermission(PROVISION_PROJECTS);
  200. ws.newRequest()
  201. .setParam("project", DEFAULT_PROJECT_KEY)
  202. .setParam("name", DEFAULT_PROJECT_NAME)
  203. .executeProtobuf(CreateWsResponse.class);
  204. ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  205. assertThat(db.favorites().hasFavorite(project, user.getUuid())).isTrue();
  206. }
  207. @Test
  208. public void do_not_add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template_and_already_100_favorites() {
  209. UserDto user = db.users().insertUser();
  210. when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ProjectDto.class))).thenReturn(true);
  211. rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getLogin()));
  212. userSession.logIn(user).addPermission(PROVISION_PROJECTS);
  213. ws.newRequest()
  214. .setParam("project", DEFAULT_PROJECT_KEY)
  215. .setParam("name", DEFAULT_PROJECT_NAME)
  216. .executeProtobuf(CreateWsResponse.class);
  217. ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  218. assertThat(db.favorites().hasNoFavorite(project)).isTrue();
  219. }
  220. @Test
  221. public void fail_when_project_already_exists() {
  222. db.components().insertPublicProject(project -> project.setKey(DEFAULT_PROJECT_KEY)).getMainBranchComponent();
  223. userSession.addPermission(PROVISION_PROJECTS);
  224. CreateRequest request = CreateRequest.builder()
  225. .setProjectKey(DEFAULT_PROJECT_KEY)
  226. .setName(DEFAULT_PROJECT_NAME)
  227. .build();
  228. assertThatThrownBy(() -> call(request))
  229. .isInstanceOf(BadRequestException.class);
  230. }
  231. @Test
  232. public void fail_when_invalid_project_key() {
  233. userSession.addPermission(PROVISION_PROJECTS);
  234. CreateRequest request = CreateRequest.builder()
  235. .setProjectKey("project%Key")
  236. .setName(DEFAULT_PROJECT_NAME)
  237. .build();
  238. assertThatThrownBy(() -> call(request))
  239. .isInstanceOf(BadRequestException.class)
  240. .hasMessage("Malformed key for Project: 'project%Key'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least " +
  241. "one non-digit.");
  242. }
  243. @Test
  244. public void fail_when_missing_project_parameter() {
  245. userSession.addPermission(PROVISION_PROJECTS);
  246. assertThatThrownBy(() -> call(null, DEFAULT_PROJECT_NAME, null, null, null))
  247. .isInstanceOf(IllegalArgumentException.class)
  248. .hasMessage("The 'project' parameter is missing");
  249. }
  250. @Test
  251. public void fail_when_missing_name_parameter() {
  252. userSession.addPermission(PROVISION_PROJECTS);
  253. assertThatThrownBy(() -> call(DEFAULT_PROJECT_KEY, null, null, null, null))
  254. .isInstanceOf(IllegalArgumentException.class)
  255. .hasMessage("The 'name' parameter is missing");
  256. }
  257. @Test
  258. public void fail_when_missing_create_project_permission() {
  259. CreateRequest request = CreateRequest.builder().setProjectKey(DEFAULT_PROJECT_KEY).setName(DEFAULT_PROJECT_NAME)
  260. .build();
  261. assertThatThrownBy(() -> call(request))
  262. .isInstanceOf(ForbiddenException.class);
  263. }
  264. @Test
  265. public void test_example() {
  266. userSession.addPermission(PROVISION_PROJECTS);
  267. String result = ws.newRequest()
  268. .setParam("project", DEFAULT_PROJECT_KEY)
  269. .setParam("name", DEFAULT_PROJECT_NAME)
  270. .execute().getInput();
  271. assertJson(result).isSimilarTo(getClass().getResource("create-example.json"));
  272. }
  273. @Test
  274. public void definition() {
  275. WebService.Action definition = ws.getDef();
  276. assertThat(definition.key()).isEqualTo("create");
  277. assertThat(definition.since()).isEqualTo("4.0");
  278. assertThat(definition.isInternal()).isFalse();
  279. assertThat(definition.responseExampleAsString()).isNotEmpty();
  280. assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder(
  281. PARAM_VISIBILITY,
  282. PARAM_NAME,
  283. PARAM_PROJECT,
  284. PARAM_MAIN_BRANCH,
  285. PARAM_NEW_CODE_DEFINITION_TYPE,
  286. PARAM_NEW_CODE_DEFINITION_VALUE);
  287. WebService.Param visibilityParam = definition.param(PARAM_VISIBILITY);
  288. assertThat(visibilityParam.description()).isNotEmpty();
  289. assertThat(visibilityParam.isInternal()).isFalse();
  290. assertThat(visibilityParam.isRequired()).isFalse();
  291. assertThat(visibilityParam.since()).isEqualTo("6.4");
  292. assertThat(visibilityParam.possibleValues()).containsExactlyInAnyOrder("private", "public");
  293. WebService.Param project = definition.param(PARAM_PROJECT);
  294. assertThat(project.isRequired()).isTrue();
  295. assertThat(project.maximumLength()).isEqualTo(400);
  296. WebService.Param name = definition.param(PARAM_NAME);
  297. assertThat(name.isRequired()).isTrue();
  298. assertThat(name.description()).isEqualTo("Name of the project. If name is longer than 500, it is abbreviated.");
  299. WebService.Param ncdType = definition.param(PARAM_NEW_CODE_DEFINITION_TYPE);
  300. assertThat(ncdType.isRequired()).isFalse();
  301. assertThat(ncdType.description()).isEqualTo(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION);
  302. WebService.Param ncdValue = definition.param(PARAM_NEW_CODE_DEFINITION_VALUE);
  303. assertThat(ncdValue.isRequired()).isFalse();
  304. assertThat(ncdValue.description()).isEqualTo(NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION);
  305. }
  306. @Test
  307. public void fail_when_set_null_project_name_on_create_request_builder() {
  308. Builder builder = CreateRequest.builder()
  309. .setProjectKey(DEFAULT_PROJECT_KEY);
  310. assertThatThrownBy(() -> builder.setName(null))
  311. .isInstanceOf(NullPointerException.class);
  312. }
  313. @Test
  314. public void fail_when_set_null_project_key_on_create_request_builder() {
  315. Builder builder = CreateRequest.builder()
  316. .setName(DEFAULT_PROJECT_NAME);
  317. assertThatThrownBy(() -> builder.setProjectKey(null))
  318. .isInstanceOf(NullPointerException.class);
  319. }
  320. @Test
  321. public void fail_when_project_key_not_set_on_create_request_builder() {
  322. CreateRequest.builder()
  323. .setName(DEFAULT_PROJECT_NAME);
  324. Builder builder = CreateRequest.builder()
  325. .setName(DEFAULT_PROJECT_NAME);
  326. assertThatThrownBy(builder::build)
  327. .isInstanceOf(NullPointerException.class);
  328. }
  329. @Test
  330. public void fail_when_project_name_not_set_on_create_request_builder() {
  331. Builder builder = CreateRequest.builder()
  332. .setProjectKey(DEFAULT_PROJECT_KEY);
  333. assertThatThrownBy(builder::build)
  334. .isInstanceOf(NullPointerException.class);
  335. }
  336. @Test
  337. public void set_default_branch_name_for_reference_branch_NCD_when_no_main_branch_provided() {
  338. userSession.addPermission(PROVISION_PROJECTS);
  339. String otherBranchName = "otherBranchName";
  340. when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn(otherBranchName);
  341. call(CreateRequest.builder()
  342. .setProjectKey(DEFAULT_PROJECT_KEY)
  343. .setName(DEFAULT_PROJECT_NAME)
  344. .setNewCodeDefinitionType(REFERENCE_BRANCH.name())
  345. .build());
  346. ProjectDto projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  347. assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.getUuid()))
  348. .isPresent()
  349. .get()
  350. .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
  351. .containsExactly(REFERENCE_BRANCH, otherBranchName);
  352. }
  353. @Test
  354. public void set_main_branch_name_for_reference_branch_NCD() {
  355. userSession.addPermission(PROVISION_PROJECTS);
  356. call(CreateRequest.builder()
  357. .setProjectKey(DEFAULT_PROJECT_KEY)
  358. .setName(DEFAULT_PROJECT_NAME)
  359. .setMainBranchKey(MAIN_BRANCH)
  360. .setNewCodeDefinitionType(REFERENCE_BRANCH.name())
  361. .build());
  362. ProjectDto projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  363. assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.getUuid()))
  364. .isPresent()
  365. .get()
  366. .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
  367. .containsExactly(REFERENCE_BRANCH, MAIN_BRANCH);
  368. }
  369. @Test
  370. public void set_new_code_definition_on_project_creation() {
  371. userSession.addPermission(PROVISION_PROJECTS);
  372. call(CreateRequest.builder()
  373. .setProjectKey(DEFAULT_PROJECT_KEY)
  374. .setName(DEFAULT_PROJECT_NAME)
  375. .setMainBranchKey(MAIN_BRANCH)
  376. .setNewCodeDefinitionType(NUMBER_OF_DAYS.name())
  377. .setNewCodeDefinitionValue("30")
  378. .build());
  379. ProjectDto projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  380. assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.getUuid()))
  381. .isPresent()
  382. .get()
  383. .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
  384. .containsExactly(NUMBER_OF_DAYS, "30");
  385. }
  386. @Test
  387. public void set_new_code_definition_branch_for_community_edition() {
  388. when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
  389. userSession.addPermission(PROVISION_PROJECTS);
  390. call(CreateRequest.builder()
  391. .setProjectKey(DEFAULT_PROJECT_KEY)
  392. .setName(DEFAULT_PROJECT_NAME)
  393. .setMainBranchKey(MAIN_BRANCH)
  394. .setNewCodeDefinitionType(NUMBER_OF_DAYS.name())
  395. .setNewCodeDefinitionValue("30")
  396. .build());
  397. ProjectDto projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  398. ComponentDto component = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  399. assertThat(db.getDbClient().newCodePeriodDao().selectByBranch(db.getSession(), projectDto.getUuid(), component.uuid()))
  400. .isPresent()
  401. .get()
  402. .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
  403. .containsExactly(NUMBER_OF_DAYS, "30", component.uuid());
  404. }
  405. @Test
  406. public void throw_IAE_if_setting_is_not_cayc_compliant() {
  407. userSession.addPermission(PROVISION_PROJECTS);
  408. CreateRequest request = CreateRequest.builder()
  409. .setProjectKey(DEFAULT_PROJECT_KEY)
  410. .setName(DEFAULT_PROJECT_NAME)
  411. .setMainBranchKey(MAIN_BRANCH)
  412. .setNewCodeDefinitionType(NUMBER_OF_DAYS.name())
  413. .setNewCodeDefinitionValue("99")
  414. .build();
  415. assertThatThrownBy(() -> call(request))
  416. .isInstanceOf(IllegalArgumentException.class)
  417. .hasMessageContaining("Failed to set the New Code Definition. The given value is not compatible with the Clean as You Code methodology. "
  418. + "Please refer to the documentation for compliant options.");
  419. assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY))
  420. .isEmpty();
  421. }
  422. @Test
  423. public void throw_IAE_if_setting_is_new_code_definition_value_provided_without_type() {
  424. userSession.addPermission(PROVISION_PROJECTS);
  425. CreateRequest request = CreateRequest.builder()
  426. .setProjectKey(DEFAULT_PROJECT_KEY)
  427. .setName(DEFAULT_PROJECT_NAME)
  428. .setMainBranchKey(MAIN_BRANCH)
  429. .setNewCodeDefinitionValue("99")
  430. .build();
  431. assertThatThrownBy(() -> call(request))
  432. .isInstanceOf(IllegalArgumentException.class)
  433. .hasMessageContaining("New code definition type is required when new code definition value is provided");
  434. assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY))
  435. .isEmpty();
  436. assertThat(db.getDbClient().newCodePeriodDao().selectAll(db.getSession())).isEmpty();
  437. }
  438. @Test
  439. public void set_new_code_definition_for_project_for_developer_edition() {
  440. when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
  441. userSession.addPermission(PROVISION_PROJECTS);
  442. call(CreateRequest.builder()
  443. .setProjectKey(DEFAULT_PROJECT_KEY)
  444. .setName(DEFAULT_PROJECT_NAME)
  445. .setMainBranchKey(MAIN_BRANCH)
  446. .setNewCodeDefinitionType(NUMBER_OF_DAYS.name())
  447. .setNewCodeDefinitionValue("30")
  448. .build());
  449. ProjectDto projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  450. assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.getUuid()))
  451. .isPresent()
  452. .get()
  453. .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
  454. .containsExactly(NUMBER_OF_DAYS, "30", null);
  455. }
  456. @Test
  457. public void do_not_create_project_when_ncdType_invalid() {
  458. when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
  459. userSession.addPermission(PROVISION_PROJECTS);
  460. CreateRequest request = CreateRequest.builder()
  461. .setProjectKey(DEFAULT_PROJECT_KEY)
  462. .setName(DEFAULT_PROJECT_NAME)
  463. .setMainBranchKey(MAIN_BRANCH)
  464. .setNewCodeDefinitionType("InvalidType")
  465. .build();
  466. assertThatThrownBy(() -> call(request))
  467. .isInstanceOf(IllegalArgumentException.class);
  468. assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY))
  469. .isEmpty();
  470. }
  471. @Test
  472. public void do_not_set_new_code_definition_when_ncdType_not_provided() {
  473. when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
  474. userSession.addPermission(PROVISION_PROJECTS);
  475. call(CreateRequest.builder()
  476. .setProjectKey(DEFAULT_PROJECT_KEY)
  477. .setName(DEFAULT_PROJECT_NAME)
  478. .setMainBranchKey(MAIN_BRANCH)
  479. .build());
  480. ComponentDto component = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
  481. assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), component.uuid()))
  482. .isEmpty();
  483. }
  484. private CreateWsResponse call(CreateRequest request) {
  485. return call(request.getProjectKey(), request.getName(), request.getMainBranchKey(), request.getNewCodeDefinitionType(), request.getNewCodeDefinitionValue());
  486. }
  487. private CreateWsResponse call(@Nullable String projectKey, @Nullable String projectName, @Nullable String mainBranch,
  488. @Nullable String newCodeDefinitionType, @Nullable String newCodeDefinitionValue) {
  489. TestRequest httpRequest = ws.newRequest()
  490. .setMethod(POST.name());
  491. ofNullable(projectKey).ifPresent(key -> httpRequest.setParam("project", key));
  492. ofNullable(projectName).ifPresent(name -> httpRequest.setParam("name", name));
  493. ofNullable(mainBranch).ifPresent(name -> httpRequest.setParam("mainBranch", mainBranch));
  494. ofNullable(newCodeDefinitionType).ifPresent(type -> httpRequest.setParam(PARAM_NEW_CODE_DEFINITION_TYPE, type));
  495. ofNullable(newCodeDefinitionValue).ifPresent(value -> httpRequest.setParam(PARAM_NEW_CODE_DEFINITION_VALUE, value));
  496. return httpRequest.executeProtobuf(CreateWsResponse.class);
  497. }
  498. }