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.

SearchActionTest.java 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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.projectanalysis.ws;
  21. import com.tngtech.java.junit.dataprovider.DataProvider;
  22. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  23. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  24. import java.util.Date;
  25. import java.util.List;
  26. import java.util.function.Function;
  27. import java.util.stream.IntStream;
  28. import javax.annotation.Nullable;
  29. import org.junit.Rule;
  30. import org.junit.Test;
  31. import org.junit.rules.ExpectedException;
  32. import org.junit.runner.RunWith;
  33. import org.sonar.api.server.ws.WebService;
  34. import org.sonar.api.server.ws.WebService.Param;
  35. import org.sonar.api.utils.log.LogAndArguments;
  36. import org.sonar.api.utils.log.LogTester;
  37. import org.sonar.api.utils.log.LoggerLevel;
  38. import org.sonar.api.web.UserRole;
  39. import org.sonar.core.util.UuidFactoryFast;
  40. import org.sonar.db.DbClient;
  41. import org.sonar.db.DbTester;
  42. import org.sonar.db.component.ComponentDto;
  43. import org.sonar.db.component.ComponentTesting;
  44. import org.sonar.db.component.SnapshotDto;
  45. import org.sonar.db.event.EventComponentChangeDto;
  46. import org.sonar.db.event.EventComponentChangeDto.ChangeCategory;
  47. import org.sonar.db.event.EventDto;
  48. import org.sonar.db.event.EventPurgeData;
  49. import org.sonar.db.organization.OrganizationDto;
  50. import org.sonar.server.component.TestComponentFinder;
  51. import org.sonar.server.exceptions.ForbiddenException;
  52. import org.sonar.server.exceptions.NotFoundException;
  53. import org.sonar.server.tester.UserSessionRule;
  54. import org.sonar.server.ws.TestRequest;
  55. import org.sonar.server.ws.WsActionTester;
  56. import org.sonarqube.ws.Common.Paging;
  57. import org.sonarqube.ws.ProjectAnalyses.Analysis;
  58. import org.sonarqube.ws.ProjectAnalyses.Event;
  59. import org.sonarqube.ws.ProjectAnalyses.Project;
  60. import org.sonarqube.ws.ProjectAnalyses.SearchResponse;
  61. import static java.lang.String.format;
  62. import static java.util.Optional.ofNullable;
  63. import static org.assertj.core.api.Assertions.assertThat;
  64. import static org.assertj.core.api.Assertions.tuple;
  65. import static org.sonar.api.utils.DateUtils.formatDate;
  66. import static org.sonar.api.utils.DateUtils.formatDateTime;
  67. import static org.sonar.api.utils.DateUtils.parseDateTime;
  68. import static org.sonar.db.component.BranchType.PULL_REQUEST;
  69. import static org.sonar.db.component.ComponentTesting.newFileDto;
  70. import static org.sonar.db.component.SnapshotTesting.newAnalysis;
  71. import static org.sonar.db.event.EventComponentChangeDto.ChangeCategory.ADDED;
  72. import static org.sonar.db.event.EventComponentChangeDto.ChangeCategory.FAILED_QUALITY_GATE;
  73. import static org.sonar.db.event.EventComponentChangeDto.ChangeCategory.REMOVED;
  74. import static org.sonar.db.event.EventDto.CATEGORY_ALERT;
  75. import static org.sonar.db.event.EventTesting.newEvent;
  76. import static org.sonar.server.projectanalysis.ws.EventCategory.DEFINITION_CHANGE;
  77. import static org.sonar.server.projectanalysis.ws.EventCategory.OTHER;
  78. import static org.sonar.server.projectanalysis.ws.EventCategory.QUALITY_GATE;
  79. import static org.sonar.server.projectanalysis.ws.EventCategory.VERSION;
  80. import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_BRANCH;
  81. import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_CATEGORY;
  82. import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_FROM;
  83. import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_PROJECT;
  84. import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_PULL_REQUEST;
  85. import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_TO;
  86. import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
  87. import static org.sonar.test.JsonAssert.assertJson;
  88. import static org.sonarqube.ws.client.WsRequest.Method.POST;
  89. @RunWith(DataProviderRunner.class)
  90. public class SearchActionTest {
  91. @Rule
  92. public ExpectedException expectedException = ExpectedException.none();
  93. @Rule
  94. public UserSessionRule userSession = UserSessionRule.standalone();
  95. @Rule
  96. public DbTester db = DbTester.create();
  97. @Rule
  98. public LogTester logTester = new LogTester();
  99. private DbClient dbClient = db.getDbClient();
  100. private WsActionTester ws = new WsActionTester(new SearchAction(dbClient, TestComponentFinder.from(db), userSession));
  101. private UuidFactoryFast uuidFactoryFast = UuidFactoryFast.getInstance();
  102. @DataProvider
  103. public static Object[][] changedBranches() {
  104. return new Object[][] {
  105. { null, "newbranch" },
  106. { "newbranch", "anotherbranch" },
  107. { "newbranch", null },
  108. };
  109. }
  110. @Test
  111. public void json_example() {
  112. OrganizationDto organizationDto = db.organizations().insert();
  113. ComponentDto project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setDbKey(KEY_PROJECT_EXAMPLE_001));
  114. userSession.addProjectPermission(UserRole.USER, project);
  115. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("A1").setCreatedAt(parseDateTime("2016-12-11T17:12:45+0100").getTime()));
  116. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("A2").setCreatedAt(parseDateTime("2016-12-12T17:12:45+0100").getTime()));
  117. SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("P1").setCreatedAt(parseDateTime("2015-11-11T10:00:00+0100").getTime()));
  118. db.events().insertEvent(newEvent(a1).setUuid("E11")
  119. .setName("Quality Gate is Red (was Orange)")
  120. .setCategory(EventCategory.QUALITY_GATE.getLabel())
  121. .setDescription("Coverage is < 80%"));
  122. db.events().insertEvent(newEvent(a1).setUuid("E12")
  123. .setName("6.3").setCategory(VERSION.getLabel()));
  124. db.events().insertEvent(newEvent(a2).setUuid("E21")
  125. .setName("Quality Profile changed to Sonar Way")
  126. .setCategory(EventCategory.QUALITY_PROFILE.getLabel()));
  127. db.events().insertEvent(newEvent(a2).setUuid("E22")
  128. .setName("6.3").setCategory(OTHER.getLabel()));
  129. EventDto eventDto = db.events().insertEvent(newEvent(a3)
  130. .setUuid("E31")
  131. .setName("Quality Gate is Red")
  132. .setData("{stillFailing: true, status: \"ERROR\"}")
  133. .setCategory(CATEGORY_ALERT)
  134. .setDescription(""));
  135. EventComponentChangeDto changeDto1 = generateEventComponentChange(eventDto, FAILED_QUALITY_GATE, "My project", "app1", "master", project.uuid());
  136. EventComponentChangeDto changeDto2 = generateEventComponentChange(eventDto, FAILED_QUALITY_GATE, "Another project", "app2", "master", uuidFactoryFast.create());
  137. insertEventComponentChanges(project, a3, changeDto1, changeDto2);
  138. String result = ws.newRequest()
  139. .setParam(PARAM_PROJECT, KEY_PROJECT_EXAMPLE_001)
  140. .execute().getInput();
  141. assertJson(result).isSimilarTo(getClass().getResource("search-example.json"));
  142. }
  143. @Test
  144. public void return_analyses_ordered_by_analysis_date() {
  145. ComponentDto project = db.components().insertPrivateProject();
  146. userSession.addProjectPermission(UserRole.USER, project);
  147. db.components().insertSnapshot(newAnalysis(project).setUuid("A1").setCreatedAt(1_000_000L));
  148. db.components().insertSnapshot(newAnalysis(project).setUuid("A2").setCreatedAt(2_000_000L));
  149. db.components().insertSnapshot(newAnalysis(project).setUuid("A3").setCreatedAt(3_000_000L));
  150. List<Analysis> result = call(project.getKey()).getAnalysesList();
  151. assertThat(result).hasSize(3);
  152. assertThat(result).extracting(Analysis::getKey, a -> parseDateTime(a.getDate()).getTime()).containsExactly(
  153. tuple("A3", 3_000_000L),
  154. tuple("A2", 2_000_000L),
  155. tuple("A1", 1_000_000L));
  156. }
  157. @Test
  158. public void return_only_processed_analyses() {
  159. ComponentDto project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("P1"));
  160. userSession.addProjectPermission(UserRole.USER, project);
  161. db.components().insertSnapshot(newAnalysis(project).setUuid("A1"));
  162. db.components().insertSnapshot(newAnalysis(project).setUuid("A2").setStatus(SnapshotDto.STATUS_UNPROCESSED));
  163. List<Analysis> result = call("P1").getAnalysesList();
  164. assertThat(result).hasSize(1);
  165. assertThat(result.get(0).getKey()).isEqualTo("A1");
  166. }
  167. @Test
  168. public void return_events() {
  169. OrganizationDto organizationDto = db.organizations().insert();
  170. ComponentDto project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setDbKey("P1"));
  171. userSession.addProjectPermission(UserRole.USER, project);
  172. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("A1"));
  173. SnapshotDto a42 = db.components().insertSnapshot(newAnalysis(ComponentTesting.newPrivateProjectDto(organizationDto)).setUuid("A42"));
  174. EventDto e1 = db.events().insertEvent(newEvent(a1).setUuid("E1").setName("N1").setCategory(EventCategory.QUALITY_GATE.getLabel()).setDescription("D1"));
  175. EventDto e2 = db.events().insertEvent(newEvent(a1).setUuid("E2").setName("N2").setCategory(VERSION.getLabel()).setDescription("D2"));
  176. db.events().insertEvent(newEvent(a42));
  177. List<Analysis> result = call("P1").getAnalysesList();
  178. assertThat(result).hasSize(1);
  179. List<Event> events = result.get(0).getEventsList();
  180. assertThat(events).hasSize(2);
  181. assertThat(events).extracting(Event::getKey, wsToDbCategory(), Event::getName, Event::getDescription).containsOnly(
  182. tuple(e1.getUuid(), e1.getCategory(), e1.getName(), e1.getDescription()),
  183. tuple(e2.getUuid(), e2.getCategory(), e2.getName(), e2.getDescription()));
  184. }
  185. @Test
  186. public void return_analyses_of_application() {
  187. OrganizationDto organization = db.organizations().insert();
  188. ComponentDto application = db.components().insertApplication(organization);
  189. userSession.registerComponents(application);
  190. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  191. SnapshotDto secondAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(2_000_000L));
  192. SnapshotDto thirdAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(3_000_000L));
  193. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  194. assertThat(result)
  195. .hasSize(3)
  196. .extracting(Analysis::getKey).containsExactly(thirdAnalysis.getUuid(), secondAnalysis.getUuid(), firstAnalysis.getUuid());
  197. assertThat(result.get(0).getEventsList()).isEmpty();
  198. assertThat(result.get(1).getEventsList()).isEmpty();
  199. assertThat(result.get(2).getEventsList()).isEmpty();
  200. }
  201. @Test
  202. public void return_definition_change_events_on_application_analyses() {
  203. OrganizationDto organization = db.organizations().insert();
  204. ComponentDto application = db.components().insertApplication(organization);
  205. userSession.registerComponents(application);
  206. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  207. EventDto event = db.events().insertEvent(newEvent(firstAnalysis).setName("").setUuid("E11").setCategory(DEFINITION_CHANGE.getLabel()));
  208. EventComponentChangeDto changeDto1 = generateEventComponentChange(event, ADDED, "My project", "app1", "master", uuidFactoryFast.create());
  209. EventComponentChangeDto changeDto2 = generateEventComponentChange(event, REMOVED, "Another project", "app2", "master", uuidFactoryFast.create());
  210. insertEventComponentChanges(application, firstAnalysis, changeDto1, changeDto2);
  211. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  212. assertThat(result).hasSize(1);
  213. List<Event> events = result.get(0).getEventsList();
  214. assertThat(events)
  215. .extracting(Event::getName, Event::getCategory, Event::getKey)
  216. .containsExactly(tuple("", DEFINITION_CHANGE.name(), "E11"));
  217. assertThat(events.get(0).getDefinitionChange().getProjectsList())
  218. .extracting(Project::getChangeType, Project::getName, Project::getKey, Project::getNewBranch, Project::getOldBranch)
  219. .containsExactly(
  220. tuple("ADDED", "My project", "app1", "", ""),
  221. tuple("REMOVED", "Another project", "app2", "", ""));
  222. }
  223. @Test
  224. @UseDataProvider("changedBranches")
  225. public void application_definition_change_with_branch(@Nullable String oldBranch, @Nullable String newBranch) {
  226. OrganizationDto organization = db.organizations().insert();
  227. ComponentDto application = db.components().insertApplication(organization);
  228. userSession.registerComponents(application);
  229. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  230. EventDto event = db.events().insertEvent(newEvent(firstAnalysis).setName("").setUuid("E11").setCategory(DEFINITION_CHANGE.getLabel()));
  231. EventComponentChangeDto changeDto1 = generateEventComponentChange(event, REMOVED, "My project", "app1", oldBranch, uuidFactoryFast.create());
  232. EventComponentChangeDto changeDto2 = generateEventComponentChange(event, ADDED, "My project", "app1", newBranch, changeDto1.getComponentUuid());
  233. insertEventComponentChanges(application, firstAnalysis, changeDto1, changeDto2);
  234. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  235. assertThat(result).hasSize(1);
  236. List<Event> events = result.get(0).getEventsList();
  237. assertThat(events)
  238. .extracting(Event::getName, Event::getCategory, Event::getKey)
  239. .containsExactly(tuple("", DEFINITION_CHANGE.name(), "E11"));
  240. assertThat(events.get(0).getDefinitionChange().getProjectsList())
  241. .extracting(Project::getChangeType, Project::getKey, Project::getName, Project::getNewBranch, Project::getOldBranch)
  242. .containsExactly(tuple("BRANCH_CHANGED", "app1", "My project", newBranch == null ? "" : newBranch, oldBranch == null ? "" : oldBranch));
  243. }
  244. @Test
  245. public void incorrect_eventcomponentchange_two_identical_changes_added_on_same_project() {
  246. OrganizationDto organization = db.organizations().insert();
  247. ComponentDto application = db.components().insertApplication(organization);
  248. userSession.registerComponents(application);
  249. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  250. EventDto event = db.events().insertEvent(newEvent(firstAnalysis).setName("").setUuid("E11").setCategory(DEFINITION_CHANGE.getLabel()));
  251. EventComponentChangeDto changeDto1 = generateEventComponentChange(event, ADDED, "My project", "app1", "master", uuidFactoryFast.create());
  252. EventComponentChangeDto changeDto2 = generateEventComponentChange(event, ADDED, "My project", "app1", "master", uuidFactoryFast.create());
  253. EventPurgeData eventPurgeData = new EventPurgeData(application.uuid(), firstAnalysis.getUuid());
  254. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto1, eventPurgeData);
  255. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto2, eventPurgeData);
  256. db.getSession().commit();
  257. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  258. assertThat(result).hasSize(1);
  259. List<Event> events = result.get(0).getEventsList();
  260. assertThat(events)
  261. .extracting(Event::getName, Event::getCategory, Event::getKey)
  262. .containsExactly(tuple("", DEFINITION_CHANGE.name(), "E11"));
  263. assertThat(events.get(0).getDefinitionChange().getProjectsList())
  264. .isEmpty();
  265. assertThat(logTester.getLogs(LoggerLevel.ERROR))
  266. .extracting(LogAndArguments::getFormattedMsg)
  267. .containsExactly(
  268. format("Incorrect changes : [uuid=%s change=ADDED, branch=master] and [uuid=%s, change=ADDED, branch=master]", changeDto1.getUuid(), changeDto2.getUuid()));
  269. }
  270. @Test
  271. public void incorrect_eventcomponentchange_incorrect_category() {
  272. OrganizationDto organization = db.organizations().insert();
  273. ComponentDto application = db.components().insertApplication(organization);
  274. userSession.registerComponents(application);
  275. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  276. EventDto event = db.events().insertEvent(newEvent(firstAnalysis).setName("").setUuid("E11").setCategory(DEFINITION_CHANGE.getLabel()));
  277. EventComponentChangeDto changeDto1 = generateEventComponentChange(event, FAILED_QUALITY_GATE, "My project", "app1", "master", uuidFactoryFast.create());
  278. EventPurgeData eventPurgeData = new EventPurgeData(application.uuid(), firstAnalysis.getUuid());
  279. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto1, eventPurgeData);
  280. db.getSession().commit();
  281. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  282. assertThat(result).hasSize(1);
  283. List<Event> events = result.get(0).getEventsList();
  284. assertThat(events)
  285. .extracting(Event::getName, Event::getCategory, Event::getKey)
  286. .containsExactly(tuple("", DEFINITION_CHANGE.name(), "E11"));
  287. assertThat(events.get(0).getDefinitionChange().getProjectsList())
  288. .isEmpty();
  289. assertThat(logTester.getLogs(LoggerLevel.ERROR))
  290. .extracting(LogAndArguments::getFormattedMsg)
  291. .containsExactly("Unknown change FAILED_QUALITY_GATE for eventComponentChange uuid: " + changeDto1.getUuid());
  292. }
  293. @Test
  294. public void incorrect_eventcomponentchange_three_component_changes_on_same_project() {
  295. OrganizationDto organization = db.organizations().insert();
  296. ComponentDto application = db.components().insertApplication(organization);
  297. userSession.registerComponents(application);
  298. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  299. EventDto event = db.events().insertEvent(newEvent(firstAnalysis).setName("").setUuid("E11").setCategory(DEFINITION_CHANGE.getLabel()));
  300. EventComponentChangeDto changeDto1 = generateEventComponentChange(event, ADDED, "My project", "app1", "master", uuidFactoryFast.create());
  301. EventComponentChangeDto changeDto2 = generateEventComponentChange(event, REMOVED, "Another project", "app1", "", uuidFactoryFast.create());
  302. EventComponentChangeDto changeDto3 = generateEventComponentChange(event, REMOVED, "Another project", "app1", "", uuidFactoryFast.create());
  303. EventPurgeData eventPurgeData = new EventPurgeData(application.uuid(), firstAnalysis.getUuid());
  304. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto1, eventPurgeData);
  305. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto2, eventPurgeData);
  306. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto3, eventPurgeData);
  307. db.getSession().commit();
  308. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  309. assertThat(result).hasSize(1);
  310. List<Event> events = result.get(0).getEventsList();
  311. assertThat(events)
  312. .extracting(Event::getName, Event::getCategory, Event::getKey)
  313. .containsExactly(tuple("", DEFINITION_CHANGE.name(), "E11"));
  314. assertThat(events.get(0).getDefinitionChange().getProjectsList())
  315. .isEmpty();
  316. assertThat(logTester.getLogs(LoggerLevel.ERROR))
  317. .extracting(LogAndArguments::getFormattedMsg)
  318. .containsExactly(
  319. format("Too many changes on same project (3) for eventComponentChange uuids : %s,%s,%s", changeDto1.getUuid(), changeDto2.getUuid(), changeDto3.getUuid()));
  320. }
  321. @Test
  322. public void incorrect_quality_gate_information() {
  323. OrganizationDto organization = db.organizations().insert();
  324. ComponentDto application = db.components().insertApplication(organization);
  325. userSession.registerComponents(application);
  326. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(application).setCreatedAt(1_000_000L));
  327. EventDto event = db.events().insertEvent(
  328. newEvent(firstAnalysis)
  329. .setName("")
  330. .setUuid("E11")
  331. .setCategory(CATEGORY_ALERT)
  332. .setData("UNPARSEABLE JSON")); // Error in Data
  333. EventComponentChangeDto changeDto1 = generateEventComponentChange(event, FAILED_QUALITY_GATE, "My project", "app1", "master", uuidFactoryFast.create());
  334. EventPurgeData eventPurgeData = new EventPurgeData(application.uuid(), firstAnalysis.getUuid());
  335. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), changeDto1, eventPurgeData);
  336. db.getSession().commit();
  337. List<Analysis> result = call(application.getDbKey()).getAnalysesList();
  338. assertThat(result).hasSize(1);
  339. List<Event> events = result.get(0).getEventsList();
  340. assertThat(events)
  341. .extracting(Event::getName, Event::getCategory, Event::getKey)
  342. .containsExactly(tuple("", QUALITY_GATE.name(), "E11"));
  343. // Verify that the values are not populated
  344. assertThat(events.get(0).getQualityGate().hasStatus()).isFalse();
  345. assertThat(events.get(0).getQualityGate().hasStillFailing()).isFalse();
  346. assertThat(logTester.getLogs(LoggerLevel.ERROR))
  347. .extracting(LogAndArguments::getFormattedMsg)
  348. .containsExactly("Unable to retrieve data from event uuid=E11");
  349. }
  350. @Test
  351. public void return_analyses_of_portfolio() {
  352. OrganizationDto organization = db.organizations().insert();
  353. ComponentDto view = db.components().insertView(organization);
  354. userSession.registerComponents(view);
  355. SnapshotDto firstAnalysis = db.components().insertSnapshot(newAnalysis(view).setCreatedAt(1_000_000L));
  356. SnapshotDto secondAnalysis = db.components().insertSnapshot(newAnalysis(view).setCreatedAt(2_000_000L));
  357. SnapshotDto thirdAnalysis = db.components().insertSnapshot(newAnalysis(view).setCreatedAt(3_000_000L));
  358. List<Analysis> result = call(view.getDbKey()).getAnalysesList();
  359. assertThat(result)
  360. .hasSize(3)
  361. .extracting(Analysis::getKey).containsExactly(thirdAnalysis.getUuid(), secondAnalysis.getUuid(), firstAnalysis.getUuid());
  362. }
  363. @Test
  364. public void paginate_analyses() {
  365. ComponentDto project = db.components().insertPrivateProject();
  366. userSession.addProjectPermission(UserRole.USER, project);
  367. IntStream.rangeClosed(1, 9).forEach(i -> db.components().insertSnapshot(newAnalysis(project).setCreatedAt(1_000_000L * i).setUuid("A" + i)));
  368. SearchResponse result = call(SearchRequest.builder()
  369. .setProject(project.getDbKey())
  370. .setPage(2)
  371. .setPageSize(3)
  372. .build());
  373. assertThat(result.getAnalysesList()).extracting(Analysis::getKey)
  374. .containsExactly("A6", "A5", "A4");
  375. }
  376. @Test
  377. public void filter_by_category() {
  378. ComponentDto project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("P1"));
  379. userSession.addProjectPermission(UserRole.USER, project);
  380. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("A1"));
  381. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("A2"));
  382. SnapshotDto a42 = db.components().insertSnapshot(newAnalysis(project).setUuid("A42"));
  383. db.events().insertEvent(newEvent(a1).setUuid("E11").setCategory(VERSION.getLabel()));
  384. db.events().insertEvent(newEvent(a1).setUuid("E12").setCategory(QUALITY_GATE.getLabel()));
  385. db.events().insertEvent(newEvent(a2).setUuid("E21").setCategory(QUALITY_GATE.getLabel()));
  386. // Analysis A42 doesn't have a quality gate event
  387. db.events().insertEvent(newEvent(a42).setCategory(OTHER.getLabel()));
  388. List<Analysis> result = call(SearchRequest.builder()
  389. .setProject("P1")
  390. .setCategory(QUALITY_GATE)
  391. .build()).getAnalysesList();
  392. assertThat(result).extracting(Analysis::getKey).containsOnly("A1", "A2");
  393. }
  394. @Test
  395. public void paginate_with_filter_on_category() {
  396. ComponentDto project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("P1"));
  397. userSession.addProjectPermission(UserRole.USER, project);
  398. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("A1").setCreatedAt(1_000_000L));
  399. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("A2").setCreatedAt(2_000_000L));
  400. SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("A3").setCreatedAt(3_000_000L));
  401. SnapshotDto a42 = db.components().insertSnapshot(newAnalysis(project).setUuid("A42"));
  402. db.events().insertEvent(newEvent(a1).setUuid("E11").setCategory(VERSION.getLabel()));
  403. db.events().insertEvent(newEvent(a1).setUuid("E12").setCategory(QUALITY_GATE.getLabel()));
  404. db.events().insertEvent(newEvent(a2).setUuid("E21").setCategory(QUALITY_GATE.getLabel()));
  405. db.events().insertEvent(newEvent(a3).setUuid("E31").setCategory(QUALITY_GATE.getLabel()));
  406. // Analysis A42 doesn't have a quality gate event
  407. db.events().insertEvent(newEvent(a42).setCategory(OTHER.getLabel()));
  408. SearchResponse result = call(SearchRequest.builder()
  409. .setProject("P1")
  410. .setCategory(QUALITY_GATE)
  411. .setPage(2)
  412. .setPageSize(1)
  413. .build());
  414. assertThat(result.getAnalysesList()).extracting(Analysis::getKey).containsOnly("A2");
  415. assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal)
  416. .containsExactly(2, 1, 3);
  417. }
  418. @Test
  419. public void filter_from_date() {
  420. ComponentDto project = db.components().insertPrivateProject();
  421. userSession.addProjectPermission(UserRole.USER, project);
  422. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L));
  423. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L));
  424. SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L));
  425. SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L));
  426. SearchResponse result = call(SearchRequest.builder()
  427. .setProject(project.getDbKey())
  428. .setFrom(formatDateTime(2_000_000_000L))
  429. .build());
  430. assertThat(result.getAnalysesList())
  431. .extracting(Analysis::getKey)
  432. .containsOnly(a2.getUuid(), a3.getUuid(), a4.getUuid())
  433. .doesNotContain(a1.getUuid());
  434. }
  435. @Test
  436. public void filter_to_date() {
  437. ComponentDto project = db.components().insertPrivateProject();
  438. userSession.addProjectPermission(UserRole.USER, project);
  439. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L));
  440. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L));
  441. SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L));
  442. SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L));
  443. SearchResponse result = call(SearchRequest.builder()
  444. .setProject(project.getDbKey())
  445. .setTo(formatDateTime(2_000_000_000L))
  446. .build());
  447. assertThat(result.getAnalysesList())
  448. .extracting(Analysis::getKey)
  449. .containsOnly(a1.getUuid(), a2.getUuid())
  450. .doesNotContain(a3.getUuid(), a4.getUuid());
  451. }
  452. @Test
  453. public void filter_by_dates_using_datetime_format() {
  454. ComponentDto project = db.components().insertPrivateProject();
  455. userSession.addProjectPermission(UserRole.USER, project);
  456. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L));
  457. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L));
  458. SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L));
  459. SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L));
  460. SearchResponse result = call(SearchRequest.builder()
  461. .setProject(project.getDbKey())
  462. .setFrom(formatDateTime(2_000_000_000L))
  463. .setTo(formatDateTime(3_000_000_000L))
  464. .build());
  465. assertThat(result.getAnalysesList())
  466. .extracting(Analysis::getKey)
  467. .containsOnly(a2.getUuid(), a3.getUuid())
  468. .doesNotContain(a1.getUuid(), a4.getUuid());
  469. }
  470. @Test
  471. public void filter_by_dates_using_date_format() {
  472. ComponentDto project = db.components().insertPrivateProject();
  473. userSession.addProjectPermission(UserRole.USER, project);
  474. SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L));
  475. SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L));
  476. SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L));
  477. SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L));
  478. SearchResponse result = call(SearchRequest.builder()
  479. .setProject(project.getDbKey())
  480. .setFrom(formatDate(new Date(2_000_000_000L)))
  481. .setTo(formatDate(new Date(3_000_000_000L)))
  482. .build());
  483. assertThat(result.getAnalysesList())
  484. .extracting(Analysis::getKey)
  485. .containsOnly(a2.getUuid(), a3.getUuid())
  486. .doesNotContain(a1.getUuid(), a4.getUuid());
  487. }
  488. @Test
  489. public void branch() {
  490. ComponentDto project = db.components().insertPrivateProject();
  491. userSession.addProjectPermission(UserRole.USER, project);
  492. ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
  493. SnapshotDto analysis = db.components().insertSnapshot(newAnalysis(branch));
  494. EventDto event = db.events().insertEvent(newEvent(analysis).setCategory(EventCategory.QUALITY_GATE.getLabel()));
  495. List<Analysis> result = call(SearchRequest.builder()
  496. .setProject(project.getKey())
  497. .setBranch("my_branch")
  498. .build())
  499. .getAnalysesList();
  500. assertThat(result).extracting(Analysis::getKey).containsExactlyInAnyOrder(analysis.getUuid());
  501. assertThat(result.get(0).getEventsList()).extracting(Event::getKey).containsExactlyInAnyOrder(event.getUuid());
  502. }
  503. @Test
  504. public void pull_request() {
  505. ComponentDto project = db.components().insertPrivateProject();
  506. userSession.addProjectPermission(UserRole.USER, project);
  507. ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST));
  508. SnapshotDto analysis = db.components().insertSnapshot(newAnalysis(branch));
  509. EventDto event = db.events().insertEvent(newEvent(analysis).setCategory(EventCategory.QUALITY_GATE.getLabel()));
  510. List<Analysis> result = call(SearchRequest.builder()
  511. .setProject(project.getKey())
  512. .setPullRequest("pr-123")
  513. .build())
  514. .getAnalysesList();
  515. assertThat(result).extracting(Analysis::getKey).containsExactlyInAnyOrder(analysis.getUuid());
  516. assertThat(result.get(0).getEventsList()).extracting(Event::getKey).containsExactlyInAnyOrder(event.getUuid());
  517. }
  518. @Test
  519. public void empty_response() {
  520. ComponentDto project = db.components().insertPrivateProject();
  521. userSession.addProjectPermission(UserRole.USER, project);
  522. SearchResponse result = call(project.getDbKey());
  523. assertThat(result.hasPaging()).isTrue();
  524. assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsExactly(1, 100, 0);
  525. assertThat(result.getAnalysesCount()).isEqualTo(0);
  526. }
  527. @Test
  528. public void fail_if_not_enough_permissions() {
  529. userSession.anonymous();
  530. ComponentDto project = db.components().insertPrivateProject();
  531. expectedException.expect(ForbiddenException.class);
  532. call(project.getDbKey());
  533. }
  534. @Test
  535. public void fail_if_project_does_not_exist() {
  536. expectedException.expect(NotFoundException.class);
  537. call("P1");
  538. }
  539. @Test
  540. public void fail_if_not_a_project_portfolio_or_application() {
  541. ComponentDto project = db.components().insertPrivateProject();
  542. ComponentDto file = db.components().insertComponent(newFileDto(project));
  543. db.components().insertSnapshot(newAnalysis(project));
  544. userSession.registerComponents(project, file);
  545. expectedException.expect(IllegalArgumentException.class);
  546. expectedException.expectMessage("A project, portfolio or application is required");
  547. call(file.getDbKey());
  548. }
  549. @Test
  550. public void fail_if_branch_does_not_exist() {
  551. ComponentDto project = db.components().insertPrivateProject();
  552. userSession.addProjectPermission(UserRole.USER, project);
  553. db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
  554. expectedException.expect(NotFoundException.class);
  555. expectedException.expectMessage(format("Component '%s' on branch '%s' not found", project.getKey(), "another_branch"));
  556. call(SearchRequest.builder()
  557. .setProject(project.getKey())
  558. .setBranch("another_branch")
  559. .build());
  560. }
  561. @Test
  562. public void definition() {
  563. WebService.Action definition = ws.getDef();
  564. assertThat(definition.key()).isEqualTo("search");
  565. assertThat(definition.since()).isEqualTo("6.3");
  566. assertThat(definition.responseExampleAsString()).isNotEmpty();
  567. assertThat(definition.param("project").isRequired()).isTrue();
  568. assertThat(definition.param("category")).isNotNull();
  569. assertThat(definition.params()).hasSize(8);
  570. Param from = definition.param("from");
  571. assertThat(from.since()).isEqualTo("6.5");
  572. Param to = definition.param("to");
  573. assertThat(to.since()).isEqualTo("6.5");
  574. Param branch = definition.param("branch");
  575. assertThat(branch.since()).isEqualTo("6.6");
  576. assertThat(branch.isInternal()).isTrue();
  577. assertThat(branch.isRequired()).isFalse();
  578. }
  579. private EventComponentChangeDto generateEventComponentChange(EventDto event, ChangeCategory category, String name, String key, @Nullable String branch,
  580. String componentUuid) {
  581. return new EventComponentChangeDto()
  582. .setCategory(category)
  583. .setUuid(uuidFactoryFast.create())
  584. .setComponentName(name)
  585. .setComponentKey(key)
  586. .setComponentBranchKey(branch)
  587. .setComponentUuid(componentUuid)
  588. .setEventUuid(event.getUuid());
  589. }
  590. private void insertEventComponentChanges(ComponentDto component, SnapshotDto analysis, EventComponentChangeDto... changes) {
  591. EventPurgeData eventPurgeData = new EventPurgeData(component.uuid(), analysis.getUuid());
  592. for (EventComponentChangeDto change : changes) {
  593. db.getDbClient().eventComponentChangeDao().insert(db.getSession(), change, eventPurgeData);
  594. }
  595. db.getSession().commit();
  596. }
  597. private static Function<Event, String> wsToDbCategory() {
  598. return e -> e == null ? null : EventCategory.valueOf(e.getCategory()).getLabel();
  599. }
  600. private SearchResponse call(@Nullable String project) {
  601. SearchRequest.Builder request = SearchRequest.builder();
  602. ofNullable(project).ifPresent(request::setProject);
  603. return call(request.build());
  604. }
  605. private SearchResponse call(SearchRequest wsRequest) {
  606. TestRequest request = ws.newRequest()
  607. .setMethod(POST.name());
  608. ofNullable(wsRequest.getProject()).ifPresent(project -> request.setParam(PARAM_PROJECT, project));
  609. ofNullable(wsRequest.getBranch()).ifPresent(branch1 -> request.setParam(PARAM_BRANCH, branch1));
  610. ofNullable(wsRequest.getPullRequest()).ifPresent(branch -> request.setParam(PARAM_PULL_REQUEST, branch));
  611. ofNullable(wsRequest.getCategory()).ifPresent(category -> request.setParam(PARAM_CATEGORY, category.name()));
  612. ofNullable(wsRequest.getPage()).ifPresent(page -> request.setParam(Param.PAGE, String.valueOf(page)));
  613. ofNullable(wsRequest.getPageSize()).ifPresent(pageSize -> request.setParam(Param.PAGE_SIZE, String.valueOf(pageSize)));
  614. ofNullable(wsRequest.getFrom()).ifPresent(from -> request.setParam(PARAM_FROM, from));
  615. ofNullable(wsRequest.getTo()).ifPresent(to -> request.setParam(PARAM_TO, to));
  616. return request.executeProtobuf(SearchResponse.class);
  617. }
  618. }