]> source.dussan.org Git - sonarqube.git/blob
9092fbac4c84e0a1f1a9dec13d2db15cee5e3b6e
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2020 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.issue.ws;
21
22 import java.time.Clock;
23 import java.util.Arrays;
24 import java.util.Date;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.ExpectedException;
28 import org.sonar.api.resources.Languages;
29 import org.sonar.api.resources.Qualifiers;
30 import org.sonar.api.rule.RuleKey;
31 import org.sonar.api.utils.Durations;
32 import org.sonar.api.utils.System2;
33 import org.sonar.db.DbClient;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.issue.IssueDto;
37 import org.sonar.db.organization.OrganizationDto;
38 import org.sonar.db.rule.RuleDefinitionDto;
39 import org.sonar.server.es.EsTester;
40 import org.sonar.server.issue.AvatarResolverImpl;
41 import org.sonar.server.issue.IssueFieldsSetter;
42 import org.sonar.server.issue.TextRangeResponseFormatter;
43 import org.sonar.server.issue.TransitionService;
44 import org.sonar.server.issue.index.IssueIndex;
45 import org.sonar.server.issue.index.IssueIndexer;
46 import org.sonar.server.issue.index.IssueIteratorFactory;
47 import org.sonar.server.issue.index.IssueQueryFactory;
48 import org.sonar.server.issue.workflow.FunctionExecutor;
49 import org.sonar.server.issue.workflow.IssueWorkflow;
50 import org.sonar.server.permission.index.PermissionIndexerTester;
51 import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
52 import org.sonar.server.tester.UserSessionRule;
53 import org.sonar.server.view.index.ViewIndexer;
54 import org.sonar.server.ws.WsActionTester;
55 import org.sonarqube.ws.Issues;
56 import org.sonarqube.ws.Issues.Component;
57 import org.sonarqube.ws.Issues.Issue;
58 import org.sonarqube.ws.Issues.SearchWsResponse;
59
60 import static org.assertj.core.api.Assertions.assertThat;
61 import static org.assertj.core.api.Assertions.tuple;
62 import static org.sonar.api.resources.Qualifiers.APP;
63 import static org.sonar.api.utils.DateUtils.addDays;
64 import static org.sonar.api.utils.DateUtils.parseDateTime;
65 import static org.sonar.api.web.UserRole.USER;
66 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
67 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
68 import static org.sonar.db.component.BranchType.BRANCH;
69 import static org.sonar.db.component.BranchType.PULL_REQUEST;
70 import static org.sonar.db.component.ComponentTesting.newDirectory;
71 import static org.sonar.db.component.ComponentTesting.newFileDto;
72 import static org.sonar.db.component.ComponentTesting.newModuleDto;
73 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
74 import static org.sonar.db.component.ComponentTesting.newSubView;
75 import static org.sonar.db.component.ComponentTesting.newView;
76 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
77 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
78 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUIDS;
79 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES;
80 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILE_UUIDS;
81 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS;
82 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
83 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS;
84 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST;
85 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
86
87 public class SearchActionComponentsTest {
88
89   @Rule
90   public ExpectedException expectedException = ExpectedException.none();
91   @Rule
92   public UserSessionRule userSession = UserSessionRule.standalone();
93   @Rule
94   public DbTester db = DbTester.create();
95   @Rule
96   public EsTester es = EsTester.create();
97
98   private DbClient dbClient = db.getDbClient();
99   private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
100   private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), null);
101   private ViewIndexer viewIndexer = new ViewIndexer(dbClient, es.client());
102   private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
103   private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
104   private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
105   private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
106   private Languages languages = new Languages();
107   private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
108   private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
109   private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
110
111   private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
112     System2.INSTANCE, dbClient));
113
114   @Test
115   public void search_all_issues_when_no_parameter() {
116     RuleDefinitionDto rule = db.rules().insertIssueRule();
117     ComponentDto project = db.components().insertPublicProject();
118     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
119     IssueDto issue = db.issues().insertIssue(rule, project, projectFile);
120     allowAnyoneOnProjects(project);
121     indexIssues();
122
123     SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
124
125     assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey)
126       .containsExactlyInAnyOrder(issue.getKey());
127   }
128
129   @Test
130   public void issues_on_different_projects() {
131     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
132     OrganizationDto organization1 = db.organizations().insert();
133     ComponentDto project = db.components().insertPublicProject(organization1);
134     ComponentDto file = db.components().insertComponent(newFileDto(project));
135     IssueDto issue1 = db.issues().insertIssue(rule, project, file);
136     OrganizationDto organization2 = db.organizations().insert();
137     ComponentDto project2 = db.components().insertPublicProject(organization2);
138     ComponentDto file2 = db.components().insertComponent(newFileDto(project2));
139     IssueDto issue2 = db.issues().insertIssue(rule, project2, file2);
140     allowAnyoneOnProjects(project, project2);
141     indexIssues();
142
143     SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class);
144
145     assertThat(response.getIssuesList())
146       .extracting(Issue::getKey, Issue::getComponent, Issue::getProject)
147       .containsExactlyInAnyOrder(
148         tuple(issue1.getKey(), file.getKey(), project.getKey()),
149         tuple(issue2.getKey(), file2.getKey(), project2.getKey()));
150     assertThat(response.getComponentsList())
151       .extracting(Component::getKey, Component::getEnabled)
152       .containsExactlyInAnyOrder(tuple(project.getKey(), true), tuple(file.getKey(), true), tuple(project2.getKey(), true), tuple(file2.getKey(), true));
153   }
154
155   @Test
156   public void search_by_module() {
157     ComponentDto project = db.components().insertPublicProject();
158     ComponentDto module1 = db.components().insertComponent(newModuleDto(project));
159     ComponentDto file1 = db.components().insertComponent(newFileDto(module1));
160     ComponentDto module2 = db.components().insertComponent(newModuleDto(project));
161     ComponentDto file2 = db.components().insertComponent(newFileDto(module2));
162     RuleDefinitionDto rule = db.rules().insertIssueRule();
163     IssueDto issue1 = db.issues().insertIssue(rule, project, file1);
164     IssueDto issue2 = db.issues().insertIssue(rule, project, file2);
165     allowAnyoneOnProjects(project);
166     indexIssues();
167
168     assertThat(ws.newRequest()
169       .setParam(PARAM_COMPONENT_KEYS, module1.getKey())
170       .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
171       .containsExactlyInAnyOrder(issue1.getKey());
172
173     assertThat(ws.newRequest()
174       .setParam(PARAM_MODULE_UUIDS, module1.uuid())
175       .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
176       .containsExactlyInAnyOrder(issue1.getKey());
177   }
178
179   @Test
180   public void do_not_return_module_key_on_single_module_projects() {
181     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
182     ComponentDto module = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
183     ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setDbKey("FK1"));
184     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
185     db.issues().insertIssue(rule, project, file, i -> i.setKee("ISSUE_IN_MODULE"));
186     db.issues().insertIssue(rule, project, project, i -> i.setKee("ISSUE_IN_ROOT_MODULE"));
187     allowAnyoneOnProjects(project);
188     indexIssues();
189
190     SearchWsResponse searchResponse = ws.newRequest().executeProtobuf(SearchWsResponse.class);
191     assertThat(searchResponse.getIssuesCount()).isEqualTo(2);
192
193     for (Issue issue : searchResponse.getIssuesList()) {
194       assertThat(issue.getProject()).isEqualTo("PK1");
195       if (issue.getKey().equals("ISSUE_IN_MODULE")) {
196         assertThat(issue.getSubProject()).isEqualTo("MK1");
197       } else if (issue.getKey().equals("ISSUE_IN_ROOT_MODULE")) {
198         assertThat(issue.hasSubProject()).isFalse();
199       }
200     }
201   }
202
203   @Test
204   public void search_since_leak_period_on_project() {
205     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
206     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
207     db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
208     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
209     IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
210       .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
211       .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
212     IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
213       .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
214       .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
215     allowAnyoneOnProjects(project);
216     indexIssues();
217
218     ws.newRequest()
219       .setParam(PARAM_COMPONENT_UUIDS, project.uuid())
220       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
221       .execute()
222       .assertJson(this.getClass(), "search_since_leak_period.json");
223   }
224
225   @Test
226   public void search_since_leak_period_on_file_in_module_project() {
227     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
228     ComponentDto module = db.components().insertComponent(newModuleDto(project));
229     ComponentDto file = db.components().insertComponent(newFileDto(module, null, "F1").setDbKey("FK1"));
230     db.components().insertSnapshot(project, a -> a.setPeriodDate(parseDateTime("2015-09-03T00:00:00+0100").getTime()));
231     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
232     IssueDto issueAfterLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_01)
233       .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
234       .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
235     IssueDto issueBeforeLeak = db.issues().insertIssue(rule, project, file, i -> i.setKee(UUID_EXAMPLE_02)
236       .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
237       .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100")));
238     allowAnyoneOnProjects(project);
239     indexIssues();
240
241     ws.newRequest()
242       .setParam(PARAM_COMPONENT_UUIDS, project.uuid())
243       .setParam(PARAM_FILE_UUIDS, file.uuid())
244       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
245       .execute()
246       .assertJson(this.getClass(), "search_since_leak_period.json");
247   }
248
249   @Test
250   public void search_by_file_uuid() {
251     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
252     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
253     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
254     IssueDto issue = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
255     allowAnyoneOnProjects(project);
256     indexIssues();
257
258     ws.newRequest()
259       .setParam(PARAM_FILE_UUIDS, file.uuid())
260       .execute()
261       .assertJson(this.getClass(), "search_by_file_uuid.json");
262
263     ws.newRequest()
264       .setParam(PARAM_FILE_UUIDS, "unknown")
265       .execute()
266       .assertJson(this.getClass(), "no_issue.json");
267
268     ws.newRequest()
269       .setParam(PARAM_COMPONENT_UUIDS, file.uuid())
270       .execute()
271       .assertJson(this.getClass(), "search_by_file_uuid.json");
272
273     ws.newRequest()
274       .setParam(PARAM_COMPONENT_UUIDS, "unknown")
275       .execute()
276       .assertJson(this.getClass(), "no_issue.json");
277   }
278
279   @Test
280   public void search_by_file_key() {
281     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
282     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
283     ComponentDto unitTest = db.components().insertComponent(newFileDto(project, null, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setDbKey("FK2"));
284     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
285     IssueDto issueOnFile = db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
286     IssueDto issueOnTest = db.issues().insertIssue(rule, project, unitTest, i -> i.setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"));
287     allowAnyoneOnProjects(project);
288     indexIssues();
289
290     ws.newRequest()
291       .setParam(PARAM_COMPONENT_KEYS, file.getKey())
292       .execute()
293       .assertJson(this.getClass(), "search_by_file_key.json");
294
295     ws.newRequest()
296       .setParam(PARAM_COMPONENT_KEYS, unitTest.getKey())
297       .execute()
298       .assertJson(this.getClass(), "search_by_test_key.json");
299   }
300
301   @Test
302   public void search_by_directory_path() {
303     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
304     ComponentDto directory = db.components().insertComponent(newDirectory(project, "D1", "src/main/java/dir"));
305     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1").setPath(directory.path() + "/MyComponent.java"));
306     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
307     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
308     allowAnyoneOnProjects(project);
309     indexIssues();
310
311     ws.newRequest()
312       .setParam(PARAM_COMPONENT_KEYS, directory.getKey())
313       .execute()
314       .assertJson(this.getClass(), "search_by_file_uuid.json");
315
316     ws.newRequest()
317       .setParam(PARAM_DIRECTORIES, "unknown")
318       .execute()
319       .assertJson(this.getClass(), "no_issue.json");
320
321     ws.newRequest()
322       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
323       .execute()
324       .assertJson(this.getClass(), "search_by_file_uuid.json");
325
326     ws.newRequest()
327       .setParam(PARAM_DIRECTORIES, "src/main/java")
328       .execute()
329       .assertJson(this.getClass(), "no_issue.json");
330   }
331
332   @Test
333   public void search_by_directory_path_in_different_modules() {
334     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
335     ComponentDto module1 = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
336     ComponentDto module2 = db.components().insertComponent(newModuleDto("M2", project).setDbKey("MK2"));
337     ComponentDto directory1 = db.components().insertComponent(newDirectory(module1, "D1", "src/main/java/dir"));
338     ComponentDto directory2 = db.components().insertComponent(newDirectory(module2, "D2", "src/main/java/dir"));
339     ComponentDto file1 = db.components().insertComponent(newFileDto(module1, directory1, "F1").setDbKey("FK1").setPath(directory1.path() + "/MyComponent.java"));
340     db.components().insertComponent(newFileDto(module2, directory2, "F2").setDbKey("FK2").setPath(directory2.path() + "/MyComponent.java"));
341     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
342     db.issues().insertIssue(rule, project, file1, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
343     allowAnyoneOnProjects(project);
344     indexIssues();
345
346     ws.newRequest()
347       .setParam(PARAM_COMPONENT_KEYS, directory1.getKey())
348       .execute()
349       .assertJson(this.getClass(), "search_by_directory_uuid.json");
350
351     ws.newRequest()
352       .setParam(PARAM_COMPONENT_KEYS, directory2.getKey())
353       .execute()
354       .assertJson(this.getClass(), "no_issue.json");
355
356     ws.newRequest()
357       .setParam(PARAM_MODULE_UUIDS, module1.uuid())
358       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
359       .execute()
360       .assertJson(this.getClass(), "search_by_directory_uuid.json");
361
362     ws.newRequest()
363       .setParam(PARAM_MODULE_UUIDS, module2.uuid())
364       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
365       .execute()
366       .assertJson(this.getClass(), "no_issue.json");
367
368     ws.newRequest()
369       .setParam(PARAM_DIRECTORIES, "src/main/java/dir")
370       .execute()
371       .assertJson(this.getClass(), "search_by_directory_uuid.json");
372
373     ws.newRequest()
374       .setParam(PARAM_DIRECTORIES, "src/main/java")
375       .execute()
376       .assertJson(this.getClass(), "no_issue.json");
377   }
378
379   @Test
380   public void search_by_view_uuid() {
381     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
382     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
383     ComponentDto view = db.components().insertComponent(newView(db.getDefaultOrganization(), "V1").setDbKey("MyView"));
384     db.components().insertComponent(newProjectCopy(project, view));
385     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
386     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
387     allowAnyoneOnProjects(project, view);
388     indexIssuesAndViews();
389
390     ws.newRequest()
391       .setParam(PARAM_COMPONENT_KEYS, view.getKey())
392       .execute()
393       .assertJson(this.getClass(), "search_by_view_uuid.json");
394   }
395
396   @Test
397   public void search_by_sub_view_uuid() {
398     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
399     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
400     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
401     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
402     ComponentDto view = db.components().insertComponent(newView(db.getDefaultOrganization(), "V1").setDbKey("MyView"));
403     ComponentDto subView = db.components().insertComponent(newSubView(view, "SV1", "MySubView"));
404     db.components().insertComponent(newProjectCopy(project, subView));
405     allowAnyoneOnProjects(project, view, subView);
406     indexIssuesAndViews();
407
408     ws.newRequest()
409       .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
410       .execute()
411       .assertJson(this.getClass(), "search_by_view_uuid.json");
412   }
413
414   @Test
415   public void search_by_sub_view_uuid_return_only_authorized_view() {
416     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
417     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
418     RuleDefinitionDto rule = db.rules().insertIssueRule(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
419     db.issues().insertIssue(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
420     ComponentDto view = db.components().insertComponent(newView(db.getDefaultOrganization(), "V1").setDbKey("MyView"));
421     ComponentDto subView = db.components().insertComponent(newSubView(view, "SV1", "MySubView"));
422     db.components().insertComponent(newProjectCopy(project, subView));
423     // User has no permission on the view, no issue will be returned
424     allowAnyoneOnProjects(project);
425     indexIssuesAndViews();
426
427     ws.newRequest()
428       .setParam(PARAM_COMPONENT_KEYS, subView.getKey())
429       .execute()
430       .assertJson(this.getClass(), "no_issue.json");
431   }
432
433   @Test
434   public void search_by_application_key() {
435     ComponentDto application = db.components().insertPrivateApplication(db.getDefaultOrganization());
436     ComponentDto project1 = db.components().insertPrivateProject();
437     ComponentDto project2 = db.components().insertPrivateProject();
438     db.components().insertComponents(newProjectCopy(project1, application));
439     db.components().insertComponents(newProjectCopy(project2, application));
440     RuleDefinitionDto rule = db.rules().insertIssueRule();
441     IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
442     IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
443     allowAnyoneOnProjects(project1, project2, application);
444     userSession.addProjectPermission(USER, application);
445     indexIssuesAndViews();
446
447     SearchWsResponse result = ws.newRequest()
448       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
449       .executeProtobuf(SearchWsResponse.class);
450
451     assertThat(result.getIssuesList()).extracting(Issue::getKey)
452       .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
453   }
454
455   @Test
456   public void search_by_application_key_and_branch() {
457     ComponentDto application = db.components().insertPrivateProject(c -> c.setQualifier(APP).setDbKey("app"));
458     ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
459     ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
460     ComponentDto project1 = db.components().insertPrivateProject(p -> p.setDbKey("prj1"));
461     ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
462     ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
463     ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
464     ComponentDto project2 = db.components().insertPrivateProject(p -> p.setDbKey("prj2"));
465     db.components().insertComponents(newProjectCopy(project1Branch1, applicationBranch1));
466     db.components().insertComponents(newProjectCopy(project2, applicationBranch1));
467     db.components().insertComponents(newProjectCopy(project1Branch2, applicationBranch2));
468
469     RuleDefinitionDto issueRule = db.rules().insertIssueRule();
470     RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule();
471     IssueDto issueOnProject1 = db.issues().insertIssue(issueRule, project1, project1);
472     IssueDto issueOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, project1Branch1);
473     db.issues().insertHotspot(hotspotRule, project1Branch1, project1Branch1);
474     IssueDto issueOnFileOnProject1Branch1 = db.issues().insertIssue(issueRule, project1Branch1, fileOnProject1Branch1);
475     IssueDto issueOnProject1Branch2 = db.issues().insertIssue(issueRule, project1Branch2, project1Branch2);
476     IssueDto issueOnProject2 = db.issues().insertIssue(issueRule, project2, project2);
477     db.issues().insertHotspot(hotspotRule, project2, project2);
478     allowAnyoneOnProjects(project1, project2, application);
479     userSession.addProjectPermission(USER, application);
480     indexIssuesAndViews();
481
482     // All issues on applicationBranch1
483     assertThat(ws.newRequest()
484       .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
485       .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
486       .executeProtobuf(SearchWsResponse.class).getIssuesList())
487       .extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
488       .containsExactlyInAnyOrder(
489         tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
490         tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
491         tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
492
493     // Issues on project1Branch1
494     assertThat(ws.newRequest()
495       .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
496       .setParam(PARAM_PROJECTS, project1.getKey())
497       .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
498       .executeProtobuf(SearchWsResponse.class).getIssuesList())
499       .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
500       .containsExactlyInAnyOrder(
501         tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
502         tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
503   }
504
505   @Test
506   public void ignore_application_without_browse_permission() {
507     ComponentDto project = db.components().insertPublicProject();
508     ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
509     db.components().insertComponents(newProjectCopy("PC1", project, application));
510     RuleDefinitionDto rule = db.rules().insertIssueRule();
511     db.issues().insertIssue(rule, project, project);
512     allowAnyoneOnProjects(project);
513     indexIssuesAndViews();
514
515     SearchWsResponse result = ws.newRequest()
516       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
517       .executeProtobuf(SearchWsResponse.class);
518
519     assertThat(result.getIssuesList()).isEmpty();
520   }
521
522   @Test
523   public void search_application_without_projects() {
524     ComponentDto project = db.components().insertPublicProject();
525     ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
526     RuleDefinitionDto rule = db.rules().insertIssueRule();
527     db.issues().insertIssue(rule, project, project);
528     allowAnyoneOnProjects(project, application);
529     indexIssuesAndViews();
530
531     SearchWsResponse result = ws.newRequest()
532       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
533       .executeProtobuf(SearchWsResponse.class);
534
535     assertThat(result.getIssuesList()).isEmpty();
536   }
537
538   @Test
539   public void search_by_application_and_by_leak() {
540     Date now = new Date();
541     RuleDefinitionDto rule = db.rules().insertIssueRule();
542     ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
543     // Project 1
544     ComponentDto project1 = db.components().insertPublicProject();
545     db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
546     db.components().insertComponents(newProjectCopy("PC1", project1, application));
547     IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
548     IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
549     // Project 2
550     ComponentDto project2 = db.components().insertPublicProject();
551     db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
552     db.components().insertComponents(newProjectCopy("PC2", project2, application));
553     IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
554     IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
555     // Permissions and index
556     allowAnyoneOnProjects(project1, project2, application);
557     indexIssuesAndViews();
558
559     SearchWsResponse result = ws.newRequest()
560       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
561       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
562       .executeProtobuf(SearchWsResponse.class);
563
564     assertThat(result.getIssuesList()).extracting(Issue::getKey)
565       .containsExactlyInAnyOrder(project1Issue1.getKey(), project2Issue1.getKey())
566       .doesNotContain(project1Issue2.getKey(), project2Issue2.getKey());
567   }
568
569   @Test
570   public void search_by_application_and_project() {
571     ComponentDto project1 = db.components().insertPublicProject();
572     ComponentDto project2 = db.components().insertPublicProject();
573     ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
574     db.components().insertComponents(newProjectCopy("PC1", project1, application));
575     db.components().insertComponents(newProjectCopy("PC2", project2, application));
576     RuleDefinitionDto rule = db.rules().insertIssueRule();
577     IssueDto issue1 = db.issues().insertIssue(rule, project1, project1);
578     IssueDto issue2 = db.issues().insertIssue(rule, project2, project2);
579     allowAnyoneOnProjects(project1, project2, application);
580     indexIssuesAndViews();
581
582     SearchWsResponse result = ws.newRequest()
583       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
584       .setParam(PARAM_PROJECT_KEYS, project1.getDbKey())
585       .executeProtobuf(SearchWsResponse.class);
586
587     assertThat(result.getIssuesList()).extracting(Issue::getKey)
588       .containsExactlyInAnyOrder(issue1.getKey())
589       .doesNotContain(issue2.getKey());
590   }
591
592   @Test
593   public void search_by_application_and_project_and_leak() {
594     Date now = new Date();
595     RuleDefinitionDto rule = db.rules().insertIssueRule();
596     ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
597     // Project 1
598     ComponentDto project1 = db.components().insertPublicProject();
599     db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
600     db.components().insertComponents(newProjectCopy("PC1", project1, application));
601     IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
602     IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
603     // Project 2
604     ComponentDto project2 = db.components().insertPublicProject();
605     db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
606     db.components().insertComponents(newProjectCopy("PC2", project2, application));
607     IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
608     IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
609     // Permissions and index
610     allowAnyoneOnProjects(project1, project2, application);
611     indexIssuesAndViews();
612
613     SearchWsResponse result = ws.newRequest()
614       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
615       .setParam(PARAM_PROJECT_KEYS, project1.getDbKey())
616       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
617       .executeProtobuf(SearchWsResponse.class);
618
619     assertThat(result.getIssuesList()).extracting(Issue::getKey)
620       .containsExactlyInAnyOrder(project1Issue1.getKey())
621       .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
622   }
623
624   @Test
625   public void search_by_application_and_by_leak_when_one_project_has_no_leak() {
626     Date now = new Date();
627     RuleDefinitionDto rule = db.rules().insertIssueRule();
628     ComponentDto application = db.components().insertPublicApplication(db.getDefaultOrganization());
629     // Project 1
630     ComponentDto project1 = db.components().insertPublicProject();
631     db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
632     db.components().insertComponents(newProjectCopy("PC1", project1, application));
633     IssueDto project1Issue1 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10)));
634     IssueDto project1Issue2 = db.issues().insertIssue(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20)));
635     // Project 2, without leak => no issue form it should be returned
636     ComponentDto project2 = db.components().insertPublicProject();
637     db.components().insertSnapshot(project2, s -> s.setPeriodDate(null));
638     db.components().insertComponents(newProjectCopy("PC2", project2, application));
639     IssueDto project2Issue1 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15)));
640     IssueDto project2Issue2 = db.issues().insertIssue(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30)));
641     // Permissions and index
642     allowAnyoneOnProjects(project1, project2, application);
643     indexIssuesAndViews();
644
645     SearchWsResponse result = ws.newRequest()
646       .setParam(PARAM_COMPONENT_KEYS, application.getDbKey())
647       .setParam(PARAM_SINCE_LEAK_PERIOD, "true")
648       .executeProtobuf(SearchWsResponse.class);
649
650     assertThat(result.getIssuesList()).extracting(Issue::getKey)
651       .containsExactlyInAnyOrder(project1Issue1.getKey())
652       .doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
653   }
654
655   @Test
656   public void search_by_branch() {
657     RuleDefinitionDto rule = db.rules().insertIssueRule();
658     ComponentDto project = db.components().insertPublicProject();
659     ComponentDto file = db.components().insertComponent(newFileDto(project));
660     IssueDto issue = db.issues().insertIssue(rule, project, file);
661
662     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
663     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
664     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
665     allowAnyoneOnProjects(project);
666     indexIssuesAndViews();
667
668     // On component key + branch
669     assertThat(ws.newRequest()
670       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
671       .setParam(PARAM_BRANCH, branch.getBranch())
672       .executeProtobuf(SearchWsResponse.class).getIssuesList())
673       .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
674       .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
675
676     // On project key + branch
677     assertThat(ws.newRequest()
678       .setParam(PARAM_PROJECT_KEYS, project.getKey())
679       .setParam(PARAM_BRANCH, branch.getBranch())
680       .executeProtobuf(SearchWsResponse.class).getIssuesList())
681       .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
682       .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
683
684     // On file key + branch
685     assertThat(ws.newRequest()
686       .setParam(PARAM_COMPONENT_KEYS, branchFile.getKey())
687       .setParam(PARAM_BRANCH, branch.getBranch())
688       .executeProtobuf(SearchWsResponse.class).getIssuesList())
689       .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
690       .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
691   }
692
693   @Test
694   public void return_branch_in_component_list() {
695     RuleDefinitionDto rule = db.rules().insertIssueRule();
696     ComponentDto project = db.components().insertPrivateProject();
697     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
698     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
699     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
700     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
701     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
702     allowAnyoneOnProjects(project);
703     indexIssuesAndViews();
704
705     SearchWsResponse result = ws.newRequest()
706       .setParam(PARAM_COMPONENT_KEYS, branch.getKey())
707       .setParam(PARAM_BRANCH, branch.getBranch())
708       .executeProtobuf(SearchWsResponse.class);
709
710     assertThat(result.getComponentsList())
711       .extracting(Issues.Component::getKey, Issues.Component::getBranch)
712       .containsExactlyInAnyOrder(
713         tuple(branchFile.getKey(), branchFile.getBranch()),
714         tuple(branch.getKey(), branch.getBranch()));
715   }
716
717   @Test
718   public void search_by_pull_request() {
719     RuleDefinitionDto rule = db.rules().insertIssueRule();
720     ComponentDto project = db.components().insertPrivateProject();
721     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
722     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
723     ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST));
724     ComponentDto pullRequestFile = db.components().insertComponent(newFileDto(pullRequest));
725     IssueDto pullRequestIssue = db.issues().insertIssue(rule, pullRequest, pullRequestFile);
726     allowAnyoneOnProjects(project);
727     indexIssuesAndViews();
728
729     SearchWsResponse result = ws.newRequest()
730       .setParam(PARAM_COMPONENT_KEYS, pullRequest.getKey())
731       .setParam(PARAM_PULL_REQUEST, pullRequest.getPullRequest())
732       .executeProtobuf(SearchWsResponse.class);
733
734     assertThat(result.getIssuesList())
735       .extracting(Issue::getKey, Issue::getComponent, Issue::getPullRequest)
736       .containsExactlyInAnyOrder(tuple(pullRequestIssue.getKey(), pullRequestFile.getKey(), pullRequestFile.getPullRequest()));
737     assertThat(result.getComponentsList())
738       .extracting(Issues.Component::getKey, Issues.Component::getPullRequest)
739       .containsExactlyInAnyOrder(
740         tuple(pullRequestFile.getKey(), pullRequestFile.getPullRequest()),
741         tuple(pullRequest.getKey(), pullRequest.getPullRequest()));
742   }
743
744   @Test
745   public void search_using_main_branch_name() {
746     RuleDefinitionDto rule = db.rules().insertIssueRule();
747     ComponentDto project = db.components().insertPublicProject();
748     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
749     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
750     allowAnyoneOnProjects(project);
751     indexIssuesAndViews();
752
753     SearchWsResponse result = ws.newRequest()
754       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
755       .setParam(PARAM_BRANCH, "master")
756       .executeProtobuf(SearchWsResponse.class);
757
758     assertThat(result.getIssuesList())
759       .extracting(Issue::getKey, Issue::getComponent, Issue::hasBranch)
760       .containsExactlyInAnyOrder(tuple(projectIssue.getKey(), projectFile.getKey(), false));
761     assertThat(result.getComponentsList())
762       .extracting(Issues.Component::getKey, Issues.Component::hasBranch)
763       .containsExactlyInAnyOrder(
764         tuple(projectFile.getKey(), false),
765         tuple(project.getKey(), false));
766   }
767
768   @Test
769   public void does_not_return_branch_issues_on_not_contextualized_search() {
770     RuleDefinitionDto rule = db.rules().insertIssueRule();
771     ComponentDto project = db.components().insertPrivateProject();
772     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
773     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
774     ComponentDto branch = db.components().insertProjectBranch(project);
775     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
776     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
777     allowAnyoneOnProjects(project);
778     indexIssuesAndViews();
779
780     SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class);
781
782     assertThat(result.getIssuesList()).extracting(Issue::getKey)
783       .containsExactlyInAnyOrder(projectIssue.getKey())
784       .doesNotContain(branchIssue.getKey());
785   }
786
787   @Test
788   public void does_not_return_branch_issues_when_using_db_key() {
789     RuleDefinitionDto rule = db.rules().insertIssueRule();
790     ComponentDto project = db.components().insertPrivateProject();
791     ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
792     IssueDto projectIssue = db.issues().insertIssue(rule, project, projectFile);
793     ComponentDto branch = db.components().insertProjectBranch(project);
794     ComponentDto branchFile = db.components().insertComponent(newFileDto(branch));
795     IssueDto branchIssue = db.issues().insertIssue(rule, branch, branchFile);
796     allowAnyoneOnProjects(project);
797     indexIssues();
798
799     SearchWsResponse result = ws.newRequest()
800       .setParam(PARAM_COMPONENT_KEYS, branch.getDbKey())
801       .executeProtobuf(SearchWsResponse.class);
802
803     assertThat(result.getIssuesList()).isEmpty();
804   }
805
806   private void allowAnyoneOnProjects(ComponentDto... projects) {
807     userSession.registerComponents(projects);
808     Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
809   }
810
811   private void indexIssues() {
812     issueIndexer.indexAllIssues();
813   }
814
815   private void indexIssuesAndViews() {
816     indexIssues();
817     viewIndexer.indexOnStartup(null);
818   }
819 }