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.

TreeActionIT.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  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.component.ws;
  21. import com.google.gson.JsonArray;
  22. import com.google.gson.JsonElement;
  23. import com.google.gson.JsonObject;
  24. import com.google.gson.JsonParser;
  25. import java.io.IOException;
  26. import java.util.Date;
  27. import javax.annotation.CheckForNull;
  28. import javax.annotation.Nullable;
  29. import org.apache.commons.io.IOUtils;
  30. import org.junit.Rule;
  31. import org.junit.Test;
  32. import org.sonar.api.resources.ResourceTypeTree;
  33. import org.sonar.api.resources.ResourceTypes;
  34. import org.sonar.api.server.ws.Change;
  35. import org.sonar.api.server.ws.WebService;
  36. import org.sonar.api.server.ws.WebService.Param;
  37. import org.sonar.api.utils.System2;
  38. import org.sonar.api.web.UserRole;
  39. import org.sonar.core.component.DefaultResourceTypes;
  40. import org.sonar.core.i18n.I18n;
  41. import org.sonar.db.DbClient;
  42. import org.sonar.db.DbTester;
  43. import org.sonar.db.component.ComponentDto;
  44. import org.sonar.db.component.ComponentTesting;
  45. import org.sonar.db.component.ProjectData;
  46. import org.sonar.db.component.ResourceTypesRule;
  47. import org.sonar.db.project.ProjectDto;
  48. import org.sonar.server.component.ComponentFinder;
  49. import org.sonar.server.exceptions.ForbiddenException;
  50. import org.sonar.server.exceptions.NotFoundException;
  51. import org.sonar.server.tester.UserSessionRule;
  52. import org.sonar.server.ws.TestRequest;
  53. import org.sonar.server.ws.WsActionTester;
  54. import org.sonar.test.JsonAssert;
  55. import org.sonarqube.ws.Components.Component;
  56. import org.sonarqube.ws.Components.TreeWsResponse;
  57. import static java.lang.String.format;
  58. import static java.nio.charset.StandardCharsets.UTF_8;
  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.Mockito.mock;
  63. import static org.sonar.api.resources.Qualifiers.APP;
  64. import static org.sonar.api.resources.Qualifiers.FILE;
  65. import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
  66. import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
  67. import static org.sonar.db.component.BranchType.PULL_REQUEST;
  68. import static org.sonar.db.component.ComponentTesting.newChildComponent;
  69. import static org.sonar.db.component.ComponentTesting.newDirectory;
  70. import static org.sonar.db.component.ComponentTesting.newDirectoryOnBranch;
  71. import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
  72. import static org.sonar.db.component.ComponentTesting.newProjectBranchCopy;
  73. import static org.sonar.db.component.ComponentTesting.newProjectCopy;
  74. import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
  75. import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT;
  76. import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_PULL_REQUEST;
  77. import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS;
  78. import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_STRATEGY;
  79. public class TreeActionIT {
  80. @Rule
  81. public UserSessionRule userSession = UserSessionRule.standalone();
  82. @Rule
  83. public DbTester db = DbTester.create(System2.INSTANCE);
  84. private final DbClient dbClient = db.getDbClient();
  85. private final ResourceTypes defaultResourceTypes = new ResourceTypes(new ResourceTypeTree[]{DefaultResourceTypes.get()});
  86. private final ResourceTypesRule resourceTypes = new ResourceTypesRule()
  87. .setRootQualifiers(defaultResourceTypes.getRoots())
  88. .setAllQualifiers(defaultResourceTypes.getAll())
  89. .setLeavesQualifiers(FILE, UNIT_TEST_FILE);
  90. private final WsActionTester ws = new WsActionTester(new TreeAction(dbClient, new ComponentFinder(dbClient, resourceTypes), resourceTypes, userSession,
  91. mock(I18n.class)));
  92. @Test
  93. public void verify_definition() {
  94. WebService.Action action = ws.getDef();
  95. assertThat(action.since()).isEqualTo("5.4");
  96. assertThat(action.description()).isNotNull();
  97. assertThat(action.responseExample()).isNotNull();
  98. assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactlyInAnyOrder(
  99. tuple("10.1", "The use of module keys in parameter 'component' is removed"),
  100. tuple("10.1", "The use of 'BRC' as value for parameter 'qualifiers' is removed"),
  101. tuple("7.6", "The use of 'BRC' as value for parameter 'qualifiers' is deprecated"),
  102. tuple("7.6", "The use of module keys in parameter 'component' is deprecated"));
  103. assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("component", "branch", "pullRequest", "qualifiers", "strategy",
  104. "q", "s", "p", "asc", "ps");
  105. Param component = action.param(PARAM_COMPONENT);
  106. assertThat(component.isRequired()).isTrue();
  107. assertThat(component.description()).isNotNull();
  108. assertThat(component.exampleValue()).isNotNull();
  109. Param branch = action.param(PARAM_BRANCH);
  110. assertThat(branch.isInternal()).isFalse();
  111. assertThat(branch.isRequired()).isFalse();
  112. assertThat(branch.since()).isEqualTo("6.6");
  113. }
  114. @Test
  115. public void json_example() throws IOException {
  116. ProjectData project = initJsonExampleComponents();
  117. logInWithBrowsePermission(project);
  118. String response = ws.newRequest()
  119. .setParam(PARAM_COMPONENT, project.projectKey())
  120. .execute()
  121. .getInput();
  122. JsonAssert.assertJson(response)
  123. .withStrictArrayOrder()
  124. .isSimilarTo(getClass().getResource("tree-example.json"));
  125. }
  126. @Test
  127. public void return_children() {
  128. ProjectData projectData = db.components().insertPrivateProject(p->p.setUuid("project-uuid").setBranchUuid("project-uuid"));
  129. ComponentDto projectMainBranch = projectData.getMainBranchComponent();
  130. db.components().insertSnapshot(projectMainBranch);
  131. ComponentDto dir = newDirectory(projectMainBranch, "dir");
  132. db.components().insertComponent(dir);
  133. db.components().insertComponent(newFileDto(projectMainBranch, 1));
  134. for (int i = 2; i <= 9; i++) {
  135. db.components().insertComponent(newFileDto(dir, i));
  136. }
  137. ComponentDto directory = newDirectory(dir, "directory-path-1");
  138. db.components().insertComponent(directory);
  139. db.components().insertComponent(newFileDto(projectMainBranch, directory, 10));
  140. db.commit();
  141. logInWithBrowsePermission(projectData);
  142. TreeWsResponse response = ws.newRequest()
  143. .setParam(PARAM_STRATEGY, "children")
  144. .setParam(PARAM_COMPONENT, dir.getKey())
  145. .setParam(Param.PAGE, "2")
  146. .setParam(Param.PAGE_SIZE, "3")
  147. .setParam(Param.TEXT_QUERY, "file-name")
  148. .setParam(Param.ASCENDING, "false")
  149. .setParam(Param.SORT, "name").executeProtobuf(TreeWsResponse.class);
  150. assertThat(response.getComponentsCount()).isEqualTo(3);
  151. assertThat(response.getPaging().getTotal()).isEqualTo(8);
  152. assertThat(response.getComponentsList()).extracting("key").containsExactly("file-key-6", "file-key-5", "file-key-4");
  153. }
  154. @Test
  155. public void return_descendants() {
  156. ProjectData projectData = db.components()
  157. .insertPrivateProject(p->p.setUuid("project-uuid").setBranchUuid("project-uuid"));
  158. ComponentDto projectMainBranch = projectData.getMainBranchComponent();
  159. db.components().insertSnapshot(projectMainBranch);
  160. ComponentDto module = newDirectory(projectMainBranch, "path");
  161. db.components().insertComponent(module);
  162. db.components().insertComponent(newFileDto(projectMainBranch, 10));
  163. for (int i = 2; i <= 9; i++) {
  164. db.components().insertComponent(newFileDto(module, i));
  165. }
  166. ComponentDto directory = newDirectory(module, "directory-path-1");
  167. db.components().insertComponent(directory);
  168. db.components().insertComponent(newFileDto(module, directory, 1));
  169. db.commit();
  170. logInWithBrowsePermission(projectData);
  171. TreeWsResponse response = ws.newRequest()
  172. .setParam(PARAM_STRATEGY, "all")
  173. .setParam(PARAM_COMPONENT, module.getKey())
  174. .setParam(Param.PAGE, "2")
  175. .setParam(Param.PAGE_SIZE, "3")
  176. .setParam(Param.TEXT_QUERY, "file-name")
  177. .setParam(Param.ASCENDING, "true")
  178. .setParam(Param.SORT, "path").executeProtobuf(TreeWsResponse.class);
  179. assertThat(response.getComponentsCount()).isEqualTo(3);
  180. assertThat(response.getPaging().getTotal()).isEqualTo(9);
  181. assertThat(response.getComponentsList()).extracting("key").containsExactly("file-key-4", "file-key-5", "file-key-6");
  182. }
  183. @Test
  184. public void filter_descendants_by_qualifier() {
  185. ProjectData projectData = db.components()
  186. .insertPrivateProject(p->p.setUuid("project-uuid").setBranchUuid("project-uuid"));
  187. ComponentDto projectMainBranch = projectData.getMainBranchComponent();
  188. db.components().insertSnapshot(projectMainBranch);
  189. db.components().insertComponent(newFileDto(projectMainBranch, 1));
  190. db.components().insertComponent(newFileDto(projectMainBranch, 2));
  191. db.commit();
  192. logInWithBrowsePermission(projectData);
  193. TreeWsResponse response = ws.newRequest()
  194. .setParam(PARAM_STRATEGY, "all")
  195. .setParam(PARAM_QUALIFIERS, FILE)
  196. .setParam(PARAM_COMPONENT, projectMainBranch.getKey()).executeProtobuf(TreeWsResponse.class);
  197. assertThat(response.getComponentsList()).extracting("key").containsExactly("file-key-1", "file-key-2");
  198. }
  199. @Test
  200. public void return_leaves() {
  201. ProjectData projectData = db.components()
  202. .insertPrivateProject(p->p.setUuid("mainBranch-uuid").setBranchUuid("mainBranch-uuid"));
  203. ComponentDto mainBranch = projectData.getMainBranchComponent();
  204. db.components().insertSnapshot(mainBranch);
  205. db.components().insertComponent(newFileDto(mainBranch, 1));
  206. db.components().insertComponent(newFileDto(mainBranch, 2));
  207. ComponentDto directory = newDirectory(mainBranch, "directory-path-1");
  208. db.components().insertComponent(directory);
  209. db.components().insertComponent(newFileDto(mainBranch, directory, 3));
  210. db.commit();
  211. logInWithBrowsePermission(projectData);
  212. TreeWsResponse response = ws.newRequest()
  213. .setParam(PARAM_STRATEGY, "leaves")
  214. .setParam(PARAM_COMPONENT, mainBranch.getKey())
  215. .setParam(PARAM_QUALIFIERS, FILE).executeProtobuf(TreeWsResponse.class);
  216. assertThat(response.getComponentsCount()).isEqualTo(3);
  217. assertThat(response.getPaging().getTotal()).isEqualTo(3);
  218. assertThat(response.getComponentsList()).extracting("key").containsExactly("file-key-1", "file-key-2", "file-key-3");
  219. }
  220. @Test
  221. public void sort_descendants_by_qualifier() {
  222. ProjectData projectData = db.components()
  223. .insertPrivateProject(p->p.setUuid("project-uuid").setBranchUuid("project-uuid").setKey("project-key"));
  224. ComponentDto mainBranch = projectData.getMainBranchComponent();
  225. db.components().insertSnapshot(mainBranch);
  226. db.components().insertComponent(newFileDto(mainBranch, 1));
  227. db.components().insertComponent(newFileDto(mainBranch, 2));
  228. db.components().insertComponent(newDirectory(mainBranch, "path/directory/", "directory-uuid-1"));
  229. db.commit();
  230. logInWithBrowsePermission(projectData);
  231. TreeWsResponse response = ws.newRequest()
  232. .setParam(PARAM_STRATEGY, "all")
  233. .setParam(Param.SORT, "qualifier, name")
  234. .setParam(PARAM_COMPONENT, mainBranch.getKey()).executeProtobuf(TreeWsResponse.class);
  235. assertThat(response.getComponentsList()).extracting("key").containsExactly("project-key:directory-uuid-1", "file-key-1", "file-key-2");
  236. }
  237. @Test
  238. public void project_reference_from_portfolio() {
  239. ComponentDto view = ComponentTesting.newPortfolio("view-uuid");
  240. db.components().insertPortfolioAndSnapshot(view);
  241. ProjectData project = db.components().insertPrivateProject(p->p.setUuid("project-uuid-1").setBranchUuid("project-uuid-1").setName("project-name").setKey("project-key-1"));
  242. db.components().insertSnapshot(project.getMainBranchComponent());
  243. db.components().insertComponent(newProjectCopy("project-uuid-1-copy", project.getMainBranchComponent(), view));
  244. db.components().insertComponent(ComponentTesting.newSubPortfolio(view, "sub-view-uuid", "sub-view-key").setName("sub-view-name"));
  245. db.commit();
  246. userSession.logIn()
  247. .registerPortfolios(view)
  248. .registerProjects(project.getProjectDto());
  249. TreeWsResponse response = ws.newRequest()
  250. .setParam(PARAM_STRATEGY, "children")
  251. .setParam(PARAM_COMPONENT, view.getKey())
  252. .setParam(Param.TEXT_QUERY, "name").executeProtobuf(TreeWsResponse.class);
  253. assertThat(response.getComponentsList()).extracting("key").containsExactly("KEY_view-uuidproject-key-1", "sub-view-key");
  254. assertThat(response.getComponentsList()).extracting("refId").containsExactly("project-uuid-1", "");
  255. assertThat(response.getComponentsList()).extracting("refKey").containsExactly("project-key-1", "");
  256. }
  257. @Test
  258. public void project_branch_reference_from_portfolio() {
  259. ComponentDto view = ComponentTesting.newPortfolio("view-uuid");
  260. db.components().insertPortfolioAndSnapshot(view);
  261. ProjectData projectData = db.components().insertPrivateProject(p->p.setUuid("project-uuid-1").setBranchUuid("project-uuid-1").setName("project-name").setKey("project-key-1"));
  262. ComponentDto mainBranch = projectData.getMainBranchComponent();
  263. db.components().insertSnapshot(mainBranch);
  264. db.components().insertComponent(newProjectBranchCopy("project-uuid-1-copy", mainBranch, view, "branch1"));
  265. db.components().insertComponent(ComponentTesting.newSubPortfolio(view, "sub-view-uuid", "sub-view-key").setName("sub-view-name"));
  266. db.commit();
  267. userSession.logIn()
  268. .registerPortfolios(view)
  269. .registerProjects(projectData.getProjectDto());
  270. TreeWsResponse response = ws.newRequest()
  271. .setParam(PARAM_STRATEGY, "children")
  272. .setParam(PARAM_COMPONENT, view.getKey())
  273. .setParam(Param.TEXT_QUERY, "name").executeProtobuf(TreeWsResponse.class);
  274. assertThat(response.getComponentsList()).extracting("key").containsExactly("KEY_view-uuidproject-key-1", "sub-view-key");
  275. assertThat(response.getComponentsList()).extracting("refId").containsExactly("project-uuid-1", "");
  276. assertThat(response.getComponentsList()).extracting("refKey").containsExactly("project-key-1", "");
  277. }
  278. @Test
  279. public void project_branch_reference_from_application_branch() {
  280. String appBranchName = "app-branch";
  281. String projectBranchName = "project-branch";
  282. ProjectData applicationData = db.components().insertPrivateProject(c -> c.setQualifier(APP).setKey("app-key"));
  283. ProjectDto application = applicationData.getProjectDto();
  284. ComponentDto applicationBranch = db.components().insertProjectBranch(applicationData.getMainBranchComponent(), a -> a.setKey(appBranchName));
  285. ComponentDto project = db.components().insertPrivateProject(p -> p.setKey("project-key")).getMainBranchComponent();
  286. ComponentDto projectBranch = db.components().insertProjectBranch(project, b -> b.setKey(projectBranchName));
  287. ComponentDto techProjectBranch = db.components().insertComponent(newProjectCopy(projectBranch, applicationBranch)
  288. .setKey(applicationBranch.getKey() + project.getKey()));
  289. logInWithBrowsePermission(applicationData);
  290. userSession.addProjectBranchMapping(application.getUuid(), applicationBranch);
  291. TreeWsResponse result = ws.newRequest()
  292. .setParam(MeasuresWsParameters.PARAM_COMPONENT, applicationBranch.getKey())
  293. .setParam(MeasuresWsParameters.PARAM_BRANCH, appBranchName)
  294. .executeProtobuf(TreeWsResponse.class);
  295. assertThat(result.getBaseComponent())
  296. .extracting(Component::getKey, Component::getBranch)
  297. .containsExactlyInAnyOrder(applicationBranch.getKey(), appBranchName);
  298. assertThat(result.getComponentsList())
  299. .extracting(Component::getKey, Component::getBranch, Component::getRefId, Component::getRefKey)
  300. .containsExactlyInAnyOrder(tuple(techProjectBranch.getKey(), projectBranchName, projectBranch.uuid(), project.getKey()));
  301. }
  302. @Test
  303. public void response_is_empty_on_provisioned_projects() {
  304. ProjectData projectData = db.components().insertPrivateProject("project-uuid");
  305. ProjectDto project = projectData.getProjectDto();
  306. logInWithBrowsePermission(projectData);
  307. TreeWsResponse response = ws.newRequest()
  308. .setParam(PARAM_COMPONENT, project.getKey()).executeProtobuf(TreeWsResponse.class);
  309. assertThat(response.getBaseComponent().getKey()).isEqualTo(project.getKey());
  310. assertThat(response.getComponentsList()).isEmpty();
  311. assertThat(response.getPaging().getTotal()).isZero();
  312. assertThat(response.getPaging().getPageSize()).isEqualTo(100);
  313. assertThat(response.getPaging().getPageIndex()).isOne();
  314. }
  315. @Test
  316. public void return_projects_composing_a_view() {
  317. ProjectData projectData = db.components().insertPrivateProject(p -> p.setUuid("project-uuid").setBranchUuid("project-uuid"));
  318. ComponentDto project = projectData.getMainBranchComponent();
  319. db.components().insertSnapshot(project);
  320. ComponentDto view = ComponentTesting.newPortfolio("view-uuid");
  321. db.components().insertPortfolioAndSnapshot(view);
  322. ComponentDto projectCopy = db.components().insertComponent(newProjectCopy("project-copy-uuid", project, view));
  323. userSession.logIn()
  324. .registerProjects(projectData.getProjectDto())
  325. .registerPortfolios(view);
  326. TreeWsResponse response = ws.newRequest()
  327. .setParam(PARAM_COMPONENT, view.getKey())
  328. .executeProtobuf(TreeWsResponse.class);
  329. assertThat(response.getBaseComponent().getKey()).isEqualTo(view.getKey());
  330. assertThat(response.getComponentsCount()).isOne();
  331. assertThat(response.getComponents(0).getKey()).isEqualTo(projectCopy.getKey());
  332. assertThat(response.getComponents(0).getRefKey()).isEqualTo(project.getKey());
  333. }
  334. @Test
  335. public void branch() {
  336. ProjectData project = db.components().insertPrivateProject();
  337. userSession.addProjectPermission(UserRole.USER, project.getProjectDto());
  338. String branchKey = "my_branch";
  339. ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setKey(branchKey));
  340. userSession.addProjectBranchMapping(project.projectUuid(), branch);
  341. ComponentDto directory = db.components().insertComponent(newDirectoryOnBranch(branch, "dir", project.mainBranchUuid()));
  342. ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(directory, project.mainBranchUuid()));
  343. TreeWsResponse response = ws.newRequest()
  344. .setParam(PARAM_COMPONENT, branch.getKey())
  345. .setParam(PARAM_BRANCH, branchKey)
  346. .executeProtobuf(TreeWsResponse.class);
  347. assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
  348. .containsExactlyInAnyOrder(branch.getKey(), branchKey);
  349. assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getBranch)
  350. .containsExactlyInAnyOrder(
  351. tuple(directory.getKey(), branchKey),
  352. tuple(file.getKey(), branchKey));
  353. }
  354. @Test
  355. public void dont_show_branch_if_main_branch() {
  356. ProjectData project = db.components().insertPrivateProject();
  357. ComponentDto file = db.components().insertFile(project.getMainBranchDto());
  358. userSession.addProjectPermission(UserRole.USER, project.getProjectDto())
  359. .addProjectBranchMapping(project.projectUuid(), project.getMainBranchComponent());
  360. TreeWsResponse response = ws.newRequest()
  361. .setParam(PARAM_COMPONENT, file.getKey())
  362. .setParam(PARAM_BRANCH, DEFAULT_MAIN_BRANCH_NAME)
  363. .executeProtobuf(TreeWsResponse.class);
  364. assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
  365. .containsExactlyInAnyOrder(file.getKey(), "");
  366. }
  367. @Test
  368. public void pull_request() {
  369. ProjectData project = db.components().insertPrivateProject();
  370. userSession.addProjectPermission(UserRole.USER, project.getProjectDto());
  371. String pullRequestId = "pr-123";
  372. ComponentDto branch = db.components().insertProjectBranch(project.getMainBranchComponent(), b -> b.setKey(pullRequestId).setBranchType(PULL_REQUEST));
  373. userSession.addProjectBranchMapping(project.projectUuid(), branch);
  374. ComponentDto directory = db.components().insertComponent(newDirectoryOnBranch(branch, "dir", project.mainBranchUuid()));
  375. ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(directory, project.mainBranchUuid()));
  376. TreeWsResponse response = ws.newRequest()
  377. .setParam(PARAM_COMPONENT, directory.getKey())
  378. .setParam(PARAM_PULL_REQUEST, pullRequestId)
  379. .executeProtobuf(TreeWsResponse.class);
  380. assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
  381. .containsExactlyInAnyOrder(directory.getKey(), pullRequestId);
  382. assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getPullRequest)
  383. .containsExactlyInAnyOrder(
  384. tuple(file.getKey(), pullRequestId));
  385. }
  386. @Test
  387. public void fail_when_not_enough_privileges() {
  388. ProjectData project = db.components().insertPrivateProject("project-uuid");
  389. userSession.logIn()
  390. .addProjectPermission(UserRole.CODEVIEWER, project.getProjectDto());
  391. db.commit();
  392. TestRequest request = ws.newRequest()
  393. .setParam(PARAM_COMPONENT, project.projectKey());
  394. assertThatThrownBy(request::execute)
  395. .isInstanceOf(ForbiddenException.class);
  396. }
  397. @Test
  398. public void fail_when_page_size_above_500() {
  399. ComponentDto project = db.components().insertComponent(newPrivateProjectDto("project-uuid"));
  400. db.commit();
  401. TestRequest request = ws.newRequest()
  402. .setParam(PARAM_COMPONENT, project.getKey())
  403. .setParam(Param.PAGE_SIZE, "501");
  404. assertThatThrownBy(request::execute)
  405. .isInstanceOf(IllegalArgumentException.class)
  406. .hasMessage("'ps' value (501) must be less than 500");
  407. }
  408. @Test
  409. public void fail_when_search_query_has_less_than_3_characters() {
  410. ComponentDto project = db.components().insertComponent(newPrivateProjectDto("project-uuid"));
  411. db.commit();
  412. TestRequest request = ws.newRequest()
  413. .setParam(PARAM_COMPONENT, project.getKey())
  414. .setParam(Param.TEXT_QUERY, "fi");
  415. assertThatThrownBy(request::execute)
  416. .isInstanceOf(IllegalArgumentException.class)
  417. .hasMessage("'q' length (2) is shorter than the minimum authorized (3)");
  418. }
  419. @Test
  420. public void fail_when_sort_is_unknown() {
  421. db.components().insertComponent(newPrivateProjectDto("project-uuid"));
  422. db.commit();
  423. TestRequest request = ws.newRequest()
  424. .setParam(PARAM_COMPONENT, "project-key")
  425. .setParam(Param.SORT, "unknown-sort");
  426. assertThatThrownBy(request::execute)
  427. .isInstanceOf(IllegalArgumentException.class);
  428. }
  429. @Test
  430. public void fail_when_strategy_is_unknown() {
  431. db.components().insertComponent(newPrivateProjectDto("project-uuid"));
  432. db.commit();
  433. TestRequest request = ws.newRequest()
  434. .setParam(PARAM_COMPONENT, "project-key")
  435. .setParam(PARAM_STRATEGY, "unknown-strategy");
  436. assertThatThrownBy(request::execute)
  437. .isInstanceOf(IllegalArgumentException.class);
  438. }
  439. @Test
  440. public void fail_when_base_component_not_found() {
  441. TestRequest request = ws.newRequest()
  442. .setParam(PARAM_COMPONENT, "project-key");
  443. assertThatThrownBy(request::execute)
  444. .isInstanceOf(NotFoundException.class);
  445. }
  446. @Test
  447. public void fail_when_base_component_is_removed() {
  448. ProjectData projectData = db.components().insertPrivateProject(p->p.setKey("file-key").setEnabled(false));
  449. db.components().insertSnapshot(projectData.getMainBranchComponent());
  450. logInWithBrowsePermission(projectData);
  451. TestRequest request = ws.newRequest()
  452. .setParam(PARAM_COMPONENT, "file-key");
  453. assertThatThrownBy(request::execute)
  454. .isInstanceOf(NotFoundException.class)
  455. .hasMessage("Component key 'file-key' not found");
  456. }
  457. @Test
  458. public void fail_when_no_base_component_parameter() {
  459. TestRequest request = ws.newRequest();
  460. assertThatThrownBy(request::execute)
  461. .isInstanceOf(IllegalArgumentException.class)
  462. .hasMessage("The 'component' parameter is missing");
  463. }
  464. @Test
  465. public void fail_if_branch_does_not_exist() {
  466. ProjectData project = db.components().insertPrivateProject();
  467. userSession.addProjectPermission(UserRole.USER, project.getProjectDto());
  468. db.components().insertProjectBranch(project.getProjectDto(), b -> b.setKey("my_branch"));
  469. TestRequest request = ws.newRequest()
  470. .setParam(PARAM_COMPONENT, project.projectKey())
  471. .setParam(PARAM_BRANCH, "another_branch");
  472. assertThatThrownBy(request::execute)
  473. .isInstanceOf(NotFoundException.class)
  474. .hasMessage(format("Component '%s' on branch '%s' not found", project.projectKey(), "another_branch"));
  475. }
  476. private static ComponentDto newFileDto(ComponentDto moduleOrProject, @Nullable ComponentDto directory, int i) {
  477. return ComponentTesting.newFileDto(moduleOrProject, directory, "file-uuid-" + i)
  478. .setName("file-name-" + i)
  479. .setKey("file-key-" + i)
  480. .setPath("file-path-" + i);
  481. }
  482. private static ComponentDto newFileDto(ComponentDto moduleOrProject, int i) {
  483. return newFileDto(moduleOrProject, null, i);
  484. }
  485. private ProjectData initJsonExampleComponents() throws IOException {
  486. ProjectData projectData = db.components().insertPrivateProject(c -> c.setUuid("MY_PROJECT_ID")
  487. .setDescription("MY_PROJECT_DESCRIPTION")
  488. .setKey("MY_PROJECT_KEY")
  489. .setName("Project Name")
  490. .setBranchUuid("MY_PROJECT_ID"),
  491. p -> p.setTagsString("abc,def"));
  492. db.components().insertSnapshot(projectData.getMainBranchComponent());
  493. Date now = new Date();
  494. JsonElement jsonTree = JsonParser.parseString(IOUtils.toString(getClass().getResource("tree-example.json"), UTF_8));
  495. JsonArray components = jsonTree.getAsJsonObject().getAsJsonArray("components");
  496. for (int i = 0; i < components.size(); i++) {
  497. JsonElement componentAsJsonElement = components.get(i);
  498. JsonObject componentAsJsonObject = componentAsJsonElement.getAsJsonObject();
  499. String uuid = format("child-component-uuid-%d", i);
  500. db.components().insertComponent(newChildComponent(uuid, projectData.getMainBranchComponent(), projectData.getMainBranchComponent())
  501. .setKey(getJsonField(componentAsJsonObject, "key"))
  502. .setName(getJsonField(componentAsJsonObject, "name"))
  503. .setLanguage(getJsonField(componentAsJsonObject, "language"))
  504. .setPath(getJsonField(componentAsJsonObject, "path"))
  505. .setQualifier(getJsonField(componentAsJsonObject, "qualifier"))
  506. .setDescription(getJsonField(componentAsJsonObject, "description"))
  507. .setEnabled(true)
  508. .setCreatedAt(now));
  509. }
  510. db.commit();
  511. return projectData;
  512. }
  513. @CheckForNull
  514. private static String getJsonField(JsonObject jsonObject, String field) {
  515. JsonElement jsonElement = jsonObject.get(field);
  516. return jsonElement == null ? null : jsonElement.getAsString();
  517. }
  518. private void logInWithBrowsePermission(ProjectData project) {
  519. userSession.logIn().addProjectPermission(UserRole.USER, project.getProjectDto())
  520. .addProjectBranchMapping(project.projectUuid(), project.getMainBranchComponent());
  521. }
  522. @Test
  523. public void doHandle_whenPassingUnsupportedQualifier_ShouldThrowIllegalArgumentException() {
  524. ProjectData project = db.components().insertPrivateProject(p->p.setUuid("project-uuid").setBranchUuid("project-uuid"));
  525. db.components().insertSnapshot(project.getMainBranchComponent());
  526. db.commit();
  527. logInWithBrowsePermission(project);
  528. TestRequest testRequest = ws.newRequest()
  529. .setParam(PARAM_QUALIFIERS, "BRC")
  530. .setParam(PARAM_COMPONENT, project.getProjectDto().getKey());
  531. assertThatThrownBy(testRequest::execute).isInstanceOf(IllegalArgumentException.class)
  532. .hasMessage("Value of parameter 'qualifiers' (BRC) must be one of: [UTS, FIL, DIR, TRK]");
  533. }
  534. }