import java.util.Set; | import java.util.Set; | ||||
import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.apache.ibatis.session.ResultHandler; | |||||
import org.sonar.db.Dao; | import org.sonar.db.Dao; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.RowNotFoundException; | import org.sonar.db.RowNotFoundException; | ||||
import org.sonar.db.WildcardPosition; | |||||
import org.sonar.db.component.ComponentDto; | |||||
import static com.google.common.collect.FluentIterable.from; | import static com.google.common.collect.FluentIterable.from; | ||||
import static org.sonar.db.DaoDatabaseUtils.buildLikeValue; | |||||
import static org.sonar.db.DatabaseUtils.executeLargeInputs; | import static org.sonar.db.DatabaseUtils.executeLargeInputs; | ||||
public class IssueDao implements Dao { | public class IssueDao implements Dao { | ||||
return mapper(session).selectComponentUuidsOfOpenIssuesForProjectUuid(projectUuid); | return mapper(session).selectComponentUuidsOfOpenIssuesForProjectUuid(projectUuid); | ||||
} | } | ||||
public void scrollNonClosedByComponentUuid(DbSession dbSession, String componentUuid, ResultHandler<IssueDto> handler) { | |||||
mapper(dbSession).selectNonClosedByComponentUuid(componentUuid, handler); | |||||
} | |||||
public void scrollNonClosedByModuleOrProject(DbSession dbSession, ComponentDto module, ResultHandler<IssueDto> handler) { | |||||
String likeModuleUuidPath = buildLikeValue(module.moduleUuidPath(), WildcardPosition.AFTER); | |||||
mapper(dbSession).scrollNonClosedByModuleOrProject(module.projectUuid(), likeModuleUuidPath, handler); | |||||
} | |||||
public void insert(DbSession session, IssueDto dto) { | public void insert(DbSession session, IssueDto dto) { | ||||
mapper(session).insert(dto); | mapper(session).insert(dto); | ||||
} | } |
IssueDto selectByKey(String key); | IssueDto selectByKey(String key); | ||||
void selectNonClosedByComponentUuid(@Param("componentUuid") String componentUuid, ResultHandler<IssueDto> resultHandler); | |||||
Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(String projectUuid); | Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(String projectUuid); | ||||
List<IssueDto> selectByKeys(List<String> keys); | List<IssueDto> selectByKeys(List<String> keys); | ||||
int update(IssueDto issue); | int update(IssueDto issue); | ||||
int updateIfBeforeSelectedDate(IssueDto issue); | int updateIfBeforeSelectedDate(IssueDto issue); | ||||
void selectNonClosedByComponentUuid(@Param("componentUuid") String componentUuid, ResultHandler<IssueDto> handler); | |||||
void scrollNonClosedByModuleOrProject( | |||||
@Param("projectUuid") String projectUuid, | |||||
@Param("likeModuleUuidPath") String likeModuleUuidPath, | |||||
ResultHandler<IssueDto> handler); | |||||
} | } |
inner join projects p on p.uuid=i.component_uuid | inner join projects p on p.uuid=i.component_uuid | ||||
inner join projects root on root.uuid=i.project_uuid | inner join projects root on root.uuid=i.project_uuid | ||||
where | where | ||||
i.component_uuid=#{componentUuid,jdbcType=VARCHAR} and | |||||
i.component_uuid = #{componentUuid,jdbcType=VARCHAR} and | |||||
i.status <> 'CLOSED' | i.status <> 'CLOSED' | ||||
</select> | </select> | ||||
#{key,jdbcType=VARCHAR} | #{key,jdbcType=VARCHAR} | ||||
</foreach> | </foreach> | ||||
</select> | </select> | ||||
<select id="scrollNonClosedByModuleOrProject" parameterType="map" resultType="Issue" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY"> | |||||
select | |||||
<include refid="issueColumns"/> | |||||
from issues i | |||||
inner join rules r on r.id = i.rule_id | |||||
inner join projects p on p.uuid = i.component_uuid | |||||
inner join projects root on root.uuid = i.project_uuid | |||||
where | |||||
i.project_uuid = #{projectUuid, jdbcType=VARCHAR} and | |||||
p.module_uuid_path like #{likeModuleUuidPath, jdbcType=VARCHAR} escape '/' and | |||||
i.status <> 'CLOSED' | |||||
</select> | |||||
</mapper> | </mapper> | ||||
*/ | */ | ||||
package org.sonar.db.issue; | package org.sonar.db.issue; | ||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.List; | import java.util.List; | ||||
import org.apache.ibatis.session.ResultContext; | |||||
import org.apache.ibatis.session.ResultHandler; | |||||
import org.junit.Rule; | import org.junit.Rule; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.junit.rules.ExpectedException; | import org.junit.rules.ExpectedException; | ||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.component.ComponentTesting; | import org.sonar.db.component.ComponentTesting; | ||||
import org.sonar.db.organization.OrganizationDto; | import org.sonar.db.organization.OrganizationDto; | ||||
import org.sonar.db.rule.RuleDefinitionDto; | |||||
import org.sonar.db.rule.RuleDto; | import org.sonar.db.rule.RuleDto; | ||||
import org.sonar.db.rule.RuleTesting; | import org.sonar.db.rule.RuleTesting; | ||||
import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||||
public class IssueDaoTest { | public class IssueDaoTest { | ||||
private static final String ISSUE_KEY2 = "I2"; | private static final String ISSUE_KEY2 = "I2"; | ||||
@Rule | @Rule | ||||
public ExpectedException thrown = ExpectedException.none(); | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
@Rule | @Rule | ||||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||||
public DbTester db = DbTester.create(System2.INSTANCE); | |||||
private IssueDao underTest = dbTester.getDbClient().issueDao(); | |||||
private IssueDao underTest = db.getDbClient().issueDao(); | |||||
@Test | @Test | ||||
public void selectByKeyOrFail() { | public void selectByKeyOrFail() { | ||||
prepareTables(); | prepareTables(); | ||||
IssueDto issue = underTest.selectOrFailByKey(dbTester.getSession(), ISSUE_KEY1); | |||||
IssueDto issue = underTest.selectOrFailByKey(db.getSession(), ISSUE_KEY1); | |||||
assertThat(issue.getKee()).isEqualTo(ISSUE_KEY1); | assertThat(issue.getKee()).isEqualTo(ISSUE_KEY1); | ||||
assertThat(issue.getId()).isGreaterThan(0L); | assertThat(issue.getId()).isGreaterThan(0L); | ||||
assertThat(issue.getComponentUuid()).isEqualTo(FILE_UUID); | assertThat(issue.getComponentUuid()).isEqualTo(FILE_UUID); | ||||
@Test | @Test | ||||
public void selectByKeyOrFail_fails_if_key_not_found() { | public void selectByKeyOrFail_fails_if_key_not_found() { | ||||
thrown.expect(RowNotFoundException.class); | |||||
thrown.expectMessage("Issue with key 'DOES_NOT_EXIST' does not exist"); | |||||
expectedException.expect(RowNotFoundException.class); | |||||
expectedException.expectMessage("Issue with key 'DOES_NOT_EXIST' does not exist"); | |||||
prepareTables(); | prepareTables(); | ||||
underTest.selectOrFailByKey(dbTester.getSession(), "DOES_NOT_EXIST"); | |||||
underTest.selectOrFailByKey(db.getSession(), "DOES_NOT_EXIST"); | |||||
} | } | ||||
@Test | @Test | ||||
// contains I1 and I2 | // contains I1 and I2 | ||||
prepareTables(); | prepareTables(); | ||||
List<IssueDto> issues = underTest.selectByKeys(dbTester.getSession(), asList("I1", "I2", "I3")); | |||||
List<IssueDto> issues = underTest.selectByKeys(db.getSession(), asList("I1", "I2", "I3")); | |||||
// results are not ordered, so do not use "containsExactly" | // results are not ordered, so do not use "containsExactly" | ||||
assertThat(issues).extracting("key").containsOnly("I1", "I2"); | assertThat(issues).extracting("key").containsOnly("I1", "I2"); | ||||
} | } | ||||
// contains I1 and I2 | // contains I1 and I2 | ||||
prepareTables(); | prepareTables(); | ||||
Iterable<IssueDto> issues = underTest.selectByOrderedKeys(dbTester.getSession(), asList("I1", "I2", "I3")); | |||||
Iterable<IssueDto> issues = underTest.selectByOrderedKeys(db.getSession(), asList("I1", "I2", "I3")); | |||||
assertThat(issues).extracting("key").containsExactly("I1", "I2"); | assertThat(issues).extracting("key").containsExactly("I1", "I2"); | ||||
issues = underTest.selectByOrderedKeys(dbTester.getSession(), asList("I2", "I3", "I1")); | |||||
issues = underTest.selectByOrderedKeys(db.getSession(), asList("I2", "I3", "I1")); | |||||
assertThat(issues).extracting("key").containsExactly("I2", "I1"); | assertThat(issues).extracting("key").containsExactly("I2", "I1"); | ||||
} | } | ||||
@Test | |||||
public void scrollNonClosedByComponentUuid() { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||||
IssueDto openIssue1OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null)); | |||||
IssueDto openIssue2OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null)); | |||||
IssueDto closedIssueOnFile = db.issues().insert(rule, project, file, i -> i.setStatus("CLOSED").setResolution("FIXED")); | |||||
IssueDto openIssueOnProject = db.issues().insert(rule, project, project, i -> i.setStatus("OPEN").setResolution(null)); | |||||
Accumulator accumulator = new Accumulator(); | |||||
underTest.scrollNonClosedByComponentUuid(db.getSession(), file.uuid(), accumulator); | |||||
accumulator.assertThatContainsOnly(openIssue1OnFile, openIssue2OnFile); | |||||
accumulator.clear(); | |||||
underTest.scrollNonClosedByComponentUuid(db.getSession(), project.uuid(), accumulator); | |||||
accumulator.assertThatContainsOnly(openIssueOnProject); | |||||
accumulator.clear(); | |||||
underTest.scrollNonClosedByComponentUuid(db.getSession(), "does_not_exist", accumulator); | |||||
assertThat(accumulator.list).isEmpty(); | |||||
} | |||||
@Test | |||||
public void scrollNonClosedByModuleOrProject() { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto anotherProject = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module)); | |||||
IssueDto openIssue1OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null)); | |||||
IssueDto openIssue2OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null)); | |||||
IssueDto closedIssueOnFile = db.issues().insert(rule, project, file, i -> i.setStatus("CLOSED").setResolution("FIXED")); | |||||
IssueDto openIssueOnModule = db.issues().insert(rule, project, module, i -> i.setStatus("OPEN").setResolution(null)); | |||||
IssueDto openIssueOnProject = db.issues().insert(rule, project, project, i -> i.setStatus("OPEN").setResolution(null)); | |||||
IssueDto openIssueOnAnotherProject = db.issues().insert(rule, anotherProject, anotherProject, i -> i.setStatus("OPEN").setResolution(null)); | |||||
Accumulator accumulator = new Accumulator(); | |||||
underTest.scrollNonClosedByModuleOrProject(db.getSession(), project, accumulator); | |||||
accumulator.assertThatContainsOnly(openIssue1OnFile, openIssue2OnFile, openIssueOnModule, openIssueOnProject); | |||||
accumulator.clear(); | |||||
underTest.scrollNonClosedByModuleOrProject(db.getSession(), module, accumulator); | |||||
accumulator.assertThatContainsOnly(openIssue1OnFile, openIssue2OnFile, openIssueOnModule); | |||||
accumulator.clear(); | |||||
ComponentDto notPersisted = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()); | |||||
underTest.scrollNonClosedByModuleOrProject(db.getSession(), notPersisted, accumulator); | |||||
assertThat(accumulator.list).isEmpty(); | |||||
} | |||||
private static IssueDto newIssueDto(String key) { | private static IssueDto newIssueDto(String key) { | ||||
IssueDto dto = new IssueDto(); | IssueDto dto = new IssueDto(); | ||||
dto.setComponent(new ComponentDto().setKey("struts:Action").setId(123L).setUuid("component-uuid")); | dto.setComponent(new ComponentDto().setKey("struts:Action").setId(123L).setUuid("component-uuid")); | ||||
} | } | ||||
private void prepareTables() { | private void prepareTables() { | ||||
dbTester.rules().insertRule(RULE); | |||||
OrganizationDto organizationDto = dbTester.organizations().insert(); | |||||
ComponentDto projectDto = dbTester.components().insertPrivateProject(organizationDto, (t) -> t.setUuid(PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
dbTester.components().insertComponent(ComponentTesting.newFileDto(projectDto).setUuid(FILE_UUID).setKey(FILE_KEY)); | |||||
underTest.insert(dbTester.getSession(), newIssueDto(ISSUE_KEY1) | |||||
db.rules().insertRule(RULE); | |||||
OrganizationDto organizationDto = db.organizations().insert(); | |||||
ComponentDto projectDto = db.components().insertPrivateProject(organizationDto, (t) -> t.setUuid(PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
db.components().insertComponent(newFileDto(projectDto).setUuid(FILE_UUID).setKey(FILE_KEY)); | |||||
underTest.insert(db.getSession(), newIssueDto(ISSUE_KEY1) | |||||
.setMessage("the message") | .setMessage("the message") | ||||
.setRuleId(RULE.getId()) | .setRuleId(RULE.getId()) | ||||
.setComponentUuid(FILE_UUID) | .setComponentUuid(FILE_UUID) | ||||
.setProjectUuid(PROJECT_UUID)); | .setProjectUuid(PROJECT_UUID)); | ||||
underTest.insert(dbTester.getSession(), newIssueDto(ISSUE_KEY2) | |||||
underTest.insert(db.getSession(), newIssueDto(ISSUE_KEY2) | |||||
.setRuleId(RULE.getId()) | .setRuleId(RULE.getId()) | ||||
.setComponentUuid(FILE_UUID) | .setComponentUuid(FILE_UUID) | ||||
.setProjectUuid(PROJECT_UUID)); | .setProjectUuid(PROJECT_UUID)); | ||||
dbTester.getSession().commit(); | |||||
db.getSession().commit(); | |||||
} | |||||
private static class Accumulator implements ResultHandler<IssueDto> { | |||||
private final List<IssueDto> list = new ArrayList<>(); | |||||
private void clear() { | |||||
list.clear(); | |||||
} | |||||
@Override | |||||
public void handleResult(ResultContext<? extends IssueDto> resultContext) { | |||||
list.add(resultContext.getResultObject()); | |||||
} | |||||
private void assertThatContainsOnly(IssueDto... issues) { | |||||
assertThat(list) | |||||
.extracting(IssueDto::getKey) | |||||
.containsExactlyInAnyOrder(Arrays.stream(issues).map(IssueDto::getKey).toArray(String[]::new)); | |||||
} | |||||
} | } | ||||
} | } |
*/ | */ | ||||
package org.sonar.server.batch; | package org.sonar.server.batch; | ||||
import com.google.common.base.Splitter; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.apache.ibatis.session.ResultHandler; | |||||
import org.sonar.api.resources.Scopes; | import org.sonar.api.resources.Scopes; | ||||
import org.sonar.api.rules.RuleType; | |||||
import org.sonar.api.server.ws.Request; | import org.sonar.api.server.ws.Request; | ||||
import org.sonar.api.server.ws.Response; | import org.sonar.api.server.ws.Response; | ||||
import org.sonar.api.server.ws.WebService; | import org.sonar.api.server.ws.WebService; | ||||
import org.sonar.db.DbClient; | import org.sonar.db.DbClient; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.issue.IssueDto; | |||||
import org.sonar.scanner.protocol.input.ScannerInput; | import org.sonar.scanner.protocol.input.ScannerInput; | ||||
import org.sonar.server.component.ComponentFinder; | import org.sonar.server.component.ComponentFinder; | ||||
import org.sonar.server.issue.index.IssueDoc; | |||||
import org.sonar.server.issue.index.IssueIndex; | |||||
import org.sonar.server.user.UserSession; | import org.sonar.server.user.UserSession; | ||||
import org.sonarqube.ws.MediaTypes; | import org.sonarqube.ws.MediaTypes; | ||||
import static com.google.common.collect.Maps.newHashMap; | import static com.google.common.collect.Maps.newHashMap; | ||||
import static java.lang.String.format; | |||||
import static org.sonar.api.web.UserRole.USER; | import static org.sonar.api.web.UserRole.USER; | ||||
import static org.sonar.core.util.Protobuf.setNullable; | import static org.sonar.core.util.Protobuf.setNullable; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | ||||
public class IssuesAction implements BatchWsAction { | public class IssuesAction implements BatchWsAction { | ||||
private static final String PARAM_KEY = "key"; | private static final String PARAM_KEY = "key"; | ||||
private static final Splitter MODULE_PATH_SPLITTER = Splitter.on('.').trimResults().omitEmptyStrings(); | |||||
private final DbClient dbClient; | private final DbClient dbClient; | ||||
private final IssueIndex issueIndex; | |||||
private final UserSession userSession; | private final UserSession userSession; | ||||
private final ComponentFinder componentFinder; | private final ComponentFinder componentFinder; | ||||
public IssuesAction(DbClient dbClient, IssueIndex issueIndex, UserSession userSession, ComponentFinder componentFinder) { | |||||
public IssuesAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) { | |||||
this.dbClient = dbClient; | this.dbClient = dbClient; | ||||
this.issueIndex = issueIndex; | |||||
this.userSession = userSession; | this.userSession = userSession; | ||||
this.componentFinder = componentFinder; | this.componentFinder = componentFinder; | ||||
} | } | ||||
@Override | @Override | ||||
public void handle(Request request, Response response) throws Exception { | public void handle(Request request, Response response) throws Exception { | ||||
response.stream().setMediaType(MediaTypes.PROTOBUF); | |||||
try (DbSession session = dbClient.openSession(false)) { | |||||
try (DbSession dbSession = dbClient.openSession(false)) { | |||||
String componentKey = request.mandatoryParam(PARAM_KEY); | String componentKey = request.mandatoryParam(PARAM_KEY); | ||||
ComponentDto component = componentFinder.getByKey(session, componentKey); | |||||
ComponentDto component = componentFinder.getByKey(dbSession, componentKey); | |||||
userSession.checkComponentPermission(USER, component); | userSession.checkComponentPermission(USER, component); | ||||
Map<String, String> keysByUUid = keysByUUid(session, component); | |||||
Map<String, String> keysByUUid = keysByUUid(dbSession, component); | |||||
ScannerInput.ServerIssue.Builder responseBuilder = ScannerInput.ServerIssue.newBuilder(); | |||||
response.stream().setMediaType(MediaTypes.PROTOBUF); | |||||
OutputStream output = response.stream().output(); | |||||
ScannerInput.ServerIssue.Builder issueBuilder = ScannerInput.ServerIssue.newBuilder(); | |||||
for (Iterator<IssueDoc> issueDocIterator = issueIndex.selectIssuesForBatch(component); issueDocIterator.hasNext();) { | |||||
handleIssue(issueDocIterator.next(), issueBuilder, keysByUUid, response.stream().output()); | |||||
ResultHandler<IssueDto> handler = resultContext -> { | |||||
IssueDto issue = resultContext.getResultObject(); | |||||
handleIssue(issue, responseBuilder, keysByUUid, output); | |||||
}; | |||||
switch (component.scope()) { | |||||
case Scopes.PROJECT: | |||||
dbClient.issueDao().scrollNonClosedByModuleOrProject(dbSession, component, handler); | |||||
break; | |||||
case Scopes.FILE: | |||||
dbClient.issueDao().scrollNonClosedByComponentUuid(dbSession, component.uuid(), handler); | |||||
break; | |||||
default: | |||||
// only projects, modules and files are supported. Other types of components are not allowed. | |||||
throw new IllegalStateException(format("Component of scope '%s' is not allowed", component.scope())); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
private static void handleIssue(IssueDoc issue, ScannerInput.ServerIssue.Builder issueBuilder, Map<String, String> keysByUUid, OutputStream out) { | |||||
issueBuilder.setKey(issue.key()); | |||||
issueBuilder.setModuleKey(keysByUUid.get(issue.moduleUuid())); | |||||
setNullable(issue.filePath(), issueBuilder::setPath); | |||||
issueBuilder.setRuleRepository(issue.ruleKey().repository()); | |||||
issueBuilder.setRuleKey(issue.ruleKey().rule()); | |||||
setNullable(issue.checksum(), issueBuilder::setChecksum); | |||||
setNullable(issue.assignee(), issueBuilder::setAssigneeLogin); | |||||
setNullable(issue.line(), issueBuilder::setLine); | |||||
setNullable(issue.message(), issueBuilder::setMsg); | |||||
issueBuilder.setSeverity(org.sonar.scanner.protocol.Constants.Severity.valueOf(issue.severity())); | |||||
private static void handleIssue(IssueDto issue, ScannerInput.ServerIssue.Builder issueBuilder, | |||||
Map<String, String> keysByUUid, OutputStream out) { | |||||
issueBuilder.setKey(issue.getKey()); | |||||
String moduleUuid = extractModuleUuid(issue); | |||||
issueBuilder.setModuleKey(keysByUUid.get(moduleUuid)); | |||||
setNullable(issue.getFilePath(), issueBuilder::setPath); | |||||
issueBuilder.setRuleRepository(issue.getRuleRepo()); | |||||
issueBuilder.setRuleKey(issue.getRule()); | |||||
setNullable(issue.getChecksum(), issueBuilder::setChecksum); | |||||
setNullable(issue.getAssignee(), issueBuilder::setAssigneeLogin); | |||||
setNullable(issue.getLine(), issueBuilder::setLine); | |||||
setNullable(issue.getMessage(), issueBuilder::setMsg); | |||||
issueBuilder.setSeverity(org.sonar.scanner.protocol.Constants.Severity.valueOf(issue.getSeverity())); | |||||
issueBuilder.setManualSeverity(issue.isManualSeverity()); | issueBuilder.setManualSeverity(issue.isManualSeverity()); | ||||
issueBuilder.setStatus(issue.status()); | |||||
setNullable(issue.resolution(), issueBuilder::setResolution); | |||||
issueBuilder.setType(issue.type().name()); | |||||
issueBuilder.setCreationDate(issue.creationDate().getTime()); | |||||
issueBuilder.setStatus(issue.getStatus()); | |||||
setNullable(issue.getResolution(), issueBuilder::setResolution); | |||||
issueBuilder.setType(RuleType.valueOf(issue.getType()).name()); | |||||
issueBuilder.setCreationDate(issue.getIssueCreationTime()); | |||||
try { | try { | ||||
issueBuilder.build().writeDelimitedTo(out); | issueBuilder.build().writeDelimitedTo(out); | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
issueBuilder.clear(); | issueBuilder.clear(); | ||||
} | } | ||||
private static String extractModuleUuid(IssueDto issue) { | |||||
List<String> split = MODULE_PATH_SPLITTER.splitToList(issue.getModuleUuidPath()); | |||||
return split.get(split.size()-1); | |||||
} | |||||
private Map<String, String> keysByUUid(DbSession session, ComponentDto component) { | private Map<String, String> keysByUUid(DbSession session, ComponentDto component) { | ||||
Map<String, String> keysByUUid = newHashMap(); | Map<String, String> keysByUUid = newHashMap(); | ||||
if (Scopes.PROJECT.equals(component.scope())) { | if (Scopes.PROJECT.equals(component.scope())) { |
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Objects; | import java.util.Objects; | ||||
import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
import org.elasticsearch.action.search.SearchRequestBuilder; | import org.elasticsearch.action.search.SearchRequestBuilder; | ||||
import org.elasticsearch.action.search.SearchResponse; | import org.elasticsearch.action.search.SearchResponse; | ||||
import org.elasticsearch.action.search.SearchType; | |||||
import org.elasticsearch.common.unit.TimeValue; | |||||
import org.elasticsearch.index.query.BoolQueryBuilder; | import org.elasticsearch.index.query.BoolQueryBuilder; | ||||
import org.elasticsearch.index.query.QueryBuilder; | import org.elasticsearch.index.query.QueryBuilder; | ||||
import org.elasticsearch.index.query.QueryBuilders; | import org.elasticsearch.index.query.QueryBuilders; | ||||
import org.elasticsearch.search.aggregations.metrics.min.Min; | import org.elasticsearch.search.aggregations.metrics.min.Min; | ||||
import org.elasticsearch.search.aggregations.metrics.sum.SumBuilder; | import org.elasticsearch.search.aggregations.metrics.sum.SumBuilder; | ||||
import org.joda.time.Duration; | import org.joda.time.Duration; | ||||
import org.sonar.api.issue.Issue; | |||||
import org.sonar.api.resources.Scopes; | |||||
import org.sonar.api.utils.DateUtils; | import org.sonar.api.utils.DateUtils; | ||||
import org.sonar.api.utils.System2; | import org.sonar.api.utils.System2; | ||||
import org.sonar.core.util.stream.MoreCollectors; | import org.sonar.core.util.stream.MoreCollectors; | ||||
import org.sonar.db.component.ComponentDto; | |||||
import org.sonar.db.organization.OrganizationDto; | import org.sonar.db.organization.OrganizationDto; | ||||
import org.sonar.server.es.EsClient; | import org.sonar.server.es.EsClient; | ||||
import org.sonar.server.es.EsUtils; | import org.sonar.server.es.EsUtils; | ||||
} | } | ||||
return boolQuery; | return boolQuery; | ||||
} | } | ||||
/** | |||||
* Return non closed issues for a given project, module, or file. Other kind of components are not allowed. | |||||
* Only fields needed for the batch are returned. | |||||
*/ | |||||
public Iterator<IssueDoc> selectIssuesForBatch(ComponentDto component) { | |||||
BoolQueryBuilder filter = boolQuery() | |||||
.must(createAuthorizationFilter(true)) | |||||
.mustNot(termsQuery(IssueIndexDefinition.FIELD_ISSUE_STATUS, Issue.STATUS_CLOSED)); | |||||
switch (component.scope()) { | |||||
case Scopes.PROJECT: | |||||
filter.must(termsQuery(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, component.uuid())); | |||||
break; | |||||
case Scopes.FILE: | |||||
filter.must(termsQuery(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, component.uuid())); | |||||
break; | |||||
default: | |||||
throw new IllegalStateException(format("Component of scope '%s' is not allowed", component.scope())); | |||||
} | |||||
SearchRequestBuilder requestBuilder = client | |||||
.prepareSearch(INDEX_TYPE_ISSUE) | |||||
.setSearchType(SearchType.SCAN) | |||||
.setScroll(TimeValue.timeValueMinutes(EsUtils.SCROLL_TIME_IN_MINUTES)) | |||||
.setSize(10_000) | |||||
.setFetchSource( | |||||
new String[] {IssueIndexDefinition.FIELD_ISSUE_KEY, IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, | |||||
IssueIndexDefinition.FIELD_ISSUE_FILE_PATH, IssueIndexDefinition.FIELD_ISSUE_SEVERITY, IssueIndexDefinition.FIELD_ISSUE_MANUAL_SEVERITY, | |||||
IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, IssueIndexDefinition.FIELD_ISSUE_STATUS, IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE, | |||||
IssueIndexDefinition.FIELD_ISSUE_LINE, IssueIndexDefinition.FIELD_ISSUE_MESSAGE, IssueIndexDefinition.FIELD_ISSUE_CHECKSUM, | |||||
IssueIndexDefinition.FIELD_ISSUE_TYPE, IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT}, | |||||
null) | |||||
.setQuery(boolQuery().must(matchAllQuery()).filter(filter)); | |||||
SearchResponse response = requestBuilder.get(); | |||||
return EsUtils.scroll(client, response.getScrollId(), IssueDoc::new); | |||||
} | |||||
} | } |
*/ | */ | ||||
package org.sonar.server.batch; | package org.sonar.server.batch; | ||||
import com.google.common.base.Throwables; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.junit.Rule; | import org.junit.Rule; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.junit.rules.ExpectedException; | import org.junit.rules.ExpectedException; | ||||
import org.sonar.api.config.internal.MapSettings; | |||||
import org.sonar.api.rule.RuleKey; | |||||
import org.sonar.api.utils.System2; | import org.sonar.api.utils.System2; | ||||
import org.sonar.api.web.UserRole; | import org.sonar.api.web.UserRole; | ||||
import org.sonar.core.util.CloseableIterator; | |||||
import org.sonar.core.util.Protobuf; | |||||
import org.sonar.db.DbTester; | import org.sonar.db.DbTester; | ||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.organization.OrganizationDto; | |||||
import org.sonar.db.issue.IssueDto; | |||||
import org.sonar.db.rule.RuleDefinitionDto; | import org.sonar.db.rule.RuleDefinitionDto; | ||||
import org.sonar.scanner.protocol.Constants.Severity; | import org.sonar.scanner.protocol.Constants.Severity; | ||||
import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue; | import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue; | ||||
import org.sonar.server.component.TestComponentFinder; | import org.sonar.server.component.TestComponentFinder; | ||||
import org.sonar.server.es.EsTester; | |||||
import org.sonar.server.exceptions.ForbiddenException; | import org.sonar.server.exceptions.ForbiddenException; | ||||
import org.sonar.server.issue.index.IssueIndex; | |||||
import org.sonar.server.issue.index.IssueIndexDefinition; | |||||
import org.sonar.server.issue.index.IssueIndexer; | |||||
import org.sonar.server.issue.index.IssueIteratorFactory; | |||||
import org.sonar.server.permission.index.AuthorizationTypeSupport; | |||||
import org.sonar.server.permission.index.PermissionIndexerTester; | |||||
import org.sonar.server.exceptions.NotFoundException; | |||||
import org.sonar.server.tester.UserSessionRule; | import org.sonar.server.tester.UserSessionRule; | ||||
import org.sonar.server.ws.TestResponse; | import org.sonar.server.ws.TestResponse; | ||||
import org.sonar.server.ws.WsActionTester; | import org.sonar.server.ws.WsActionTester; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.assertj.core.api.Assertions.tuple; | |||||
import static org.sonar.api.rules.RuleType.BUG; | import static org.sonar.api.rules.RuleType.BUG; | ||||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||||
import static org.sonar.db.component.ComponentTesting.newFileDto; | import static org.sonar.db.component.ComponentTesting.newFileDto; | ||||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | import static org.sonar.db.component.ComponentTesting.newModuleDto; | ||||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||||
import static org.sonar.db.rule.RuleTesting.newRule; | |||||
public class IssuesActionTest { | public class IssuesActionTest { | ||||
private static final String PROJECT_KEY = "struts"; | |||||
private static final String PROJECT_UUID = "ABCD"; | |||||
private static final String MODULE_KEY = "struts-core"; | |||||
private static final String MODULE_UUID = "BCDE"; | |||||
private final static String FILE_KEY = "Action.java"; | |||||
private static final String FILE_UUID = "CDEF"; | |||||
private System2 system2 = System2.INSTANCE; | private System2 system2 = System2.INSTANCE; | ||||
@Rule | @Rule | ||||
public ExpectedException thrown = ExpectedException.none(); | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
@Rule | @Rule | ||||
public DbTester db = DbTester.create(system2); | public DbTester db = DbTester.create(system2); | ||||
@Rule | @Rule | ||||
public EsTester es = new EsTester(new IssueIndexDefinition(new MapSettings().asConfig())); | |||||
@Rule | |||||
public UserSessionRule userSessionRule = UserSessionRule.standalone(); | public UserSessionRule userSessionRule = UserSessionRule.standalone(); | ||||
private static RuleDefinitionDto RULE_DEFINITION = newRule(RuleKey.of("squid", "AvoidCycle")); | |||||
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), new IssueIteratorFactory(db.getDbClient())); | |||||
private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, issueIndexer); | |||||
private WsActionTester tester = new WsActionTester(new IssuesAction(db.getDbClient(), | |||||
new IssueIndex(es.client(), system2, userSessionRule, new AuthorizationTypeSupport(userSessionRule)), | |||||
userSessionRule, TestComponentFinder.from(db))); | |||||
private WsActionTester tester = new WsActionTester(new IssuesAction(db.getDbClient(), userSessionRule, TestComponentFinder.from(db))); | |||||
@Test | @Test | ||||
public void return_minimal_fields() throws Exception { | |||||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(MODULE_UUID, project).setKey(MODULE_KEY)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null, FILE_UUID).setKey(FILE_KEY).setPath(null)); | |||||
db.rules().insert(RULE_DEFINITION); | |||||
db.issues().insert(RULE_DEFINITION, project, file, issue -> issue | |||||
.setKee("EFGH") | |||||
.setSeverity("BLOCKER") | |||||
.setStatus("RESOLVED") | |||||
.setType(BUG) | |||||
.setResolution(null) | |||||
.setManualSeverity(false) | |||||
.setMessage(null) | |||||
.setLine(null) | |||||
.setChecksum(null) | |||||
.setAssignee(null)); | |||||
indexIssues(project); | |||||
addBrowsePermissionOnComponent(project); | |||||
ServerIssue serverIssue = call(PROJECT_KEY); | |||||
assertThat(serverIssue.getKey()).isEqualTo("EFGH"); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(MODULE_KEY); | |||||
public void test_nullable_fields() throws Exception { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null).setPath(null)); | |||||
IssueDto issue = db.issues().insert(rule, project, file, i -> | |||||
i.setSeverity("BLOCKER") | |||||
// non-null fields | |||||
.setStatus("OPEN") | |||||
.setType(BUG) | |||||
.setManualSeverity(true) | |||||
// all the nullable fields | |||||
.setResolution(null) | |||||
.setMessage(null) | |||||
.setLine(null) | |||||
.setChecksum(null) | |||||
.setAssignee(null)); | |||||
addPermissionTo(project); | |||||
ServerIssue serverIssue = call(project.key()); | |||||
assertThat(serverIssue.getKey()).isEqualTo(issue.getKey()); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(module.getKey()); | |||||
assertThat(serverIssue.getRuleRepository()).isEqualTo(rule.getRepositoryKey()); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo(rule.getRuleKey()); | |||||
assertThat(serverIssue.getStatus()).isEqualTo("OPEN"); | |||||
assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | |||||
assertThat(serverIssue.getType()).isEqualTo(BUG.name()); | |||||
assertThat(serverIssue.getManualSeverity()).isTrue(); | |||||
assertThat(serverIssue.hasPath()).isFalse(); | assertThat(serverIssue.hasPath()).isFalse(); | ||||
assertThat(serverIssue.getRuleRepository()).isEqualTo("squid"); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo("AvoidCycle"); | |||||
assertThat(serverIssue.hasLine()).isFalse(); | assertThat(serverIssue.hasLine()).isFalse(); | ||||
assertThat(serverIssue.hasMsg()).isFalse(); | assertThat(serverIssue.hasMsg()).isFalse(); | ||||
assertThat(serverIssue.hasResolution()).isFalse(); | assertThat(serverIssue.hasResolution()).isFalse(); | ||||
assertThat(serverIssue.getStatus()).isEqualTo("RESOLVED"); | |||||
assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | |||||
assertThat(serverIssue.getType()).isEqualTo(BUG.name()); | |||||
assertThat(serverIssue.getManualSeverity()).isFalse(); | |||||
assertThat(serverIssue.hasChecksum()).isFalse(); | assertThat(serverIssue.hasChecksum()).isFalse(); | ||||
assertThat(serverIssue.hasAssigneeLogin()).isFalse(); | assertThat(serverIssue.hasAssigneeLogin()).isFalse(); | ||||
} | } | ||||
@Test | @Test | ||||
public void issues_from_project() throws Exception { | |||||
OrganizationDto organizationDto = db.organizations().insert(); | |||||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto(organizationDto, PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(MODULE_UUID, project).setKey(MODULE_KEY)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null, FILE_UUID).setKey(FILE_KEY).setPath("src/org/struts/Action.java")); | |||||
db.rules().insert(RULE_DEFINITION); | |||||
db.issues().insert(RULE_DEFINITION, project, file, issue -> issue | |||||
.setKee("EFGH") | |||||
.setSeverity("BLOCKER") | |||||
.setStatus("RESOLVED") | |||||
.setResolution("FALSE-POSITIVE") | |||||
.setManualSeverity(false) | |||||
.setMessage("Do not use this method") | |||||
.setLine(200) | |||||
.setChecksum("123456") | |||||
.setAssignee("john")); | |||||
indexIssues(project); | |||||
addBrowsePermissionOnComponent(project); | |||||
ServerIssue serverIssue = call(PROJECT_KEY); | |||||
assertThat(serverIssue.getKey()).isEqualTo("EFGH"); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(MODULE_KEY); | |||||
assertThat(serverIssue.getPath()).isEqualTo("src/org/struts/Action.java"); | |||||
assertThat(serverIssue.getRuleRepository()).isEqualTo("squid"); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo("AvoidCycle"); | |||||
assertThat(serverIssue.getLine()).isEqualTo(200); | |||||
assertThat(serverIssue.getMsg()).isEqualTo("Do not use this method"); | |||||
assertThat(serverIssue.getResolution()).isEqualTo("FALSE-POSITIVE"); | |||||
assertThat(serverIssue.getStatus()).isEqualTo("RESOLVED"); | |||||
public void test_fields_with_non_null_values() throws Exception { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null)); | |||||
IssueDto issue = db.issues().insert(rule, project, file, i -> | |||||
i.setSeverity("BLOCKER") | |||||
.setStatus("OPEN") | |||||
.setType(BUG) | |||||
.setManualSeverity(true) | |||||
.setResolution("FIXED") | |||||
.setMessage("the message") | |||||
.setLine(10) | |||||
.setChecksum("ABC") | |||||
.setAssignee("foo")); | |||||
addPermissionTo(project); | |||||
ServerIssue serverIssue = call(project.key()); | |||||
assertThat(serverIssue.getKey()).isEqualTo(issue.getKey()); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(module.getKey()); | |||||
assertThat(serverIssue.getRuleRepository()).isEqualTo(rule.getRepositoryKey()); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo(rule.getRuleKey()); | |||||
assertThat(serverIssue.getStatus()).isEqualTo("OPEN"); | |||||
assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | ||||
assertThat(serverIssue.getManualSeverity()).isFalse(); | |||||
assertThat(serverIssue.getChecksum()).isEqualTo("123456"); | |||||
assertThat(serverIssue.getAssigneeLogin()).isEqualTo("john"); | |||||
assertThat(serverIssue.getType()).isEqualTo(BUG.name()); | |||||
assertThat(serverIssue.getManualSeverity()).isTrue(); | |||||
assertThat(serverIssue.getPath()).isEqualTo(file.path()); | |||||
assertThat(serverIssue.getLine()).isEqualTo(issue.getLine()); | |||||
assertThat(serverIssue.getMsg()).isEqualTo(issue.getMessage()); | |||||
assertThat(serverIssue.getResolution()).isEqualTo(issue.getResolution()); | |||||
assertThat(serverIssue.getChecksum()).isEqualTo(issue.getChecksum()); | |||||
assertThat(serverIssue.getAssigneeLogin()).isEqualTo(issue.getAssignee()); | |||||
} | } | ||||
@Test | @Test | ||||
public void issues_from_module() throws Exception { | |||||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(MODULE_UUID, project).setKey(MODULE_KEY)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null, FILE_UUID).setKey(FILE_KEY).setPath("src/org/struts/Action.java")); | |||||
db.rules().insert(RULE_DEFINITION); | |||||
db.issues().insert(RULE_DEFINITION, project, file, issue -> issue | |||||
.setKee("EFGH") | |||||
.setSeverity("BLOCKER") | |||||
.setStatus("RESOLVED") | |||||
.setResolution("FALSE-POSITIVE") | |||||
.setManualSeverity(false) | |||||
.setMessage("Do not use this method") | |||||
.setLine(200) | |||||
.setChecksum("123456") | |||||
.setAssignee("john")); | |||||
indexIssues(project); | |||||
addBrowsePermissionOnComponent(project); | |||||
ServerIssue serverIssue = call(PROJECT_KEY); | |||||
assertThat(serverIssue.getKey()).isEqualTo("EFGH"); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(MODULE_KEY); | |||||
assertThat(serverIssue.getPath()).isEqualTo("src/org/struts/Action.java"); | |||||
assertThat(serverIssue.getRuleRepository()).isEqualTo("squid"); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo("AvoidCycle"); | |||||
assertThat(serverIssue.getLine()).isEqualTo(200); | |||||
assertThat(serverIssue.getMsg()).isEqualTo("Do not use this method"); | |||||
assertThat(serverIssue.getResolution()).isEqualTo("FALSE-POSITIVE"); | |||||
assertThat(serverIssue.getStatus()).isEqualTo("RESOLVED"); | |||||
assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | |||||
assertThat(serverIssue.getManualSeverity()).isFalse(); | |||||
assertThat(serverIssue.getChecksum()).isEqualTo("123456"); | |||||
assertThat(serverIssue.getAssigneeLogin()).isEqualTo("john"); | |||||
public void return_issues_of_project() { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null)); | |||||
IssueDto issueOnFile = db.issues().insert(rule, project, file, i -> i.setKee("ON_FILE")); | |||||
IssueDto issueOnModule = db.issues().insert(rule, project, module, i -> i.setKee("ON_MODULE")); | |||||
IssueDto issueOnProject = db.issues().insert(rule, project, project, i -> i.setKee("ON_PROJECT")); | |||||
addPermissionTo(project); | |||||
try (CloseableIterator<ServerIssue> result = callStream(project.key())) { | |||||
assertThat(result) | |||||
.extracting(ServerIssue::getKey, ServerIssue::getModuleKey) | |||||
.containsExactlyInAnyOrder( | |||||
tuple(issueOnFile.getKey(), module.key()), | |||||
tuple(issueOnModule.getKey(), module.key()), | |||||
tuple(issueOnProject.getKey(), project.key())); | |||||
} | |||||
} | } | ||||
@Test | @Test | ||||
public void issues_from_file() throws Exception { | |||||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(MODULE_UUID, project).setKey(MODULE_KEY)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null, FILE_UUID).setKey(FILE_KEY).setPath("src/org/struts/Action.java")); | |||||
db.rules().insert(RULE_DEFINITION); | |||||
db.issues().insert(RULE_DEFINITION, project, file, issue -> issue | |||||
.setKee("EFGH") | |||||
.setSeverity("BLOCKER") | |||||
.setStatus("RESOLVED") | |||||
.setResolution("FALSE-POSITIVE") | |||||
.setManualSeverity(false) | |||||
.setMessage("Do not use this method") | |||||
.setLine(200) | |||||
.setChecksum("123456") | |||||
.setAssignee("john")); | |||||
indexIssues(project); | |||||
addBrowsePermissionOnComponent(project); | |||||
ServerIssue serverIssue = call(FILE_KEY); | |||||
assertThat(serverIssue.getKey()).isEqualTo("EFGH"); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(MODULE_KEY); | |||||
assertThat(serverIssue.getPath()).isEqualTo("src/org/struts/Action.java"); | |||||
assertThat(serverIssue.getRuleRepository()).isEqualTo("squid"); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo("AvoidCycle"); | |||||
assertThat(serverIssue.getLine()).isEqualTo(200); | |||||
assertThat(serverIssue.getMsg()).isEqualTo("Do not use this method"); | |||||
assertThat(serverIssue.getResolution()).isEqualTo("FALSE-POSITIVE"); | |||||
assertThat(serverIssue.getStatus()).isEqualTo("RESOLVED"); | |||||
assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | |||||
assertThat(serverIssue.getManualSeverity()).isFalse(); | |||||
assertThat(serverIssue.getChecksum()).isEqualTo("123456"); | |||||
assertThat(serverIssue.getAssigneeLogin()).isEqualTo("john"); | |||||
public void return_issues_of_module() { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null)); | |||||
IssueDto issueOnFile = db.issues().insert(rule, project, file, i -> i.setKee("ON_FILE")); | |||||
IssueDto issueOnModule = db.issues().insert(rule, project, module, i -> i.setKee("ON_MODULE")); | |||||
IssueDto issueOnProject = db.issues().insert(rule, project, project, i -> i.setKee("ON_PROJECT")); | |||||
addPermissionTo(project); | |||||
try (CloseableIterator<ServerIssue> result = callStream(module.key())) { | |||||
assertThat(result) | |||||
.extracting(ServerIssue::getKey, ServerIssue::getModuleKey) | |||||
.containsExactlyInAnyOrder( | |||||
tuple(issueOnFile.getKey(), module.key()), | |||||
tuple(issueOnModule.getKey(), module.key())); | |||||
} | |||||
} | } | ||||
@Test | @Test | ||||
public void issues_attached_on_module() throws Exception { | |||||
OrganizationDto organizationDto = db.organizations().insert(); | |||||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto(organizationDto, PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(MODULE_UUID, project).setKey(MODULE_KEY)); | |||||
db.rules().insert(RULE_DEFINITION); | |||||
db.issues().insert(RULE_DEFINITION, project, module, issue -> issue | |||||
.setKee("EFGH") | |||||
.setSeverity("BLOCKER") | |||||
.setStatus("RESOLVED") | |||||
.setResolution("FALSE-POSITIVE") | |||||
.setManualSeverity(false) | |||||
.setMessage("Do not use this method") | |||||
.setLine(200) | |||||
.setChecksum("123456") | |||||
.setAssignee("john")); | |||||
indexIssues(project); | |||||
addBrowsePermissionOnComponent(project); | |||||
ServerIssue serverIssue = call(MODULE_KEY); | |||||
assertThat(serverIssue.getKey()).isEqualTo("EFGH"); | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(MODULE_KEY); | |||||
assertThat(serverIssue.hasPath()).isFalse(); | |||||
assertThat(serverIssue.getRuleRepository()).isEqualTo("squid"); | |||||
assertThat(serverIssue.getRuleKey()).isEqualTo("AvoidCycle"); | |||||
assertThat(serverIssue.getLine()).isEqualTo(200); | |||||
assertThat(serverIssue.getMsg()).isEqualTo("Do not use this method"); | |||||
assertThat(serverIssue.getResolution()).isEqualTo("FALSE-POSITIVE"); | |||||
assertThat(serverIssue.getStatus()).isEqualTo("RESOLVED"); | |||||
assertThat(serverIssue.getSeverity()).isEqualTo(Severity.BLOCKER); | |||||
assertThat(serverIssue.getManualSeverity()).isFalse(); | |||||
assertThat(serverIssue.getChecksum()).isEqualTo("123456"); | |||||
assertThat(serverIssue.getAssigneeLogin()).isEqualTo("john"); | |||||
public void return_issues_of_file() { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null)); | |||||
IssueDto issueOnFile = db.issues().insert(rule, project, file); | |||||
IssueDto issueOnModule = db.issues().insert(rule, project, module); | |||||
IssueDto issueOnProject = db.issues().insert(rule, project, project); | |||||
addPermissionTo(project); | |||||
try (CloseableIterator<ServerIssue> result = callStream(file.key())) { | |||||
assertThat(result) | |||||
.extracting(ServerIssue::getKey, ServerIssue::getModuleKey) | |||||
.containsExactlyInAnyOrder( | |||||
tuple(issueOnFile.getKey(), module.key())); | |||||
} | |||||
} | } | ||||
@Test | @Test | ||||
public void project_issues_attached_file_on_removed_module() throws Exception { | |||||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setKey(PROJECT_KEY)); | |||||
// File and module are removed | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(MODULE_UUID, project).setKey(MODULE_KEY).setEnabled(false)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null, FILE_UUID).setKey(FILE_KEY).setPath("src/org/struts/Action.java").setEnabled(false)); | |||||
db.rules().insert(RULE_DEFINITION); | |||||
db.issues().insert(RULE_DEFINITION, project, file, issue -> issue | |||||
.setKee("EFGH") | |||||
.setSeverity("BLOCKER") | |||||
.setStatus("RESOLVED") | |||||
.setResolution("FALSE-POSITIVE") | |||||
.setManualSeverity(false) | |||||
.setMessage("Do not use this method") | |||||
.setLine(200) | |||||
.setChecksum("123456") | |||||
.setAssignee("john")); | |||||
indexIssues(project); | |||||
addBrowsePermissionOnComponent(project); | |||||
ServerIssue serverIssue = call(PROJECT_KEY); | |||||
assertThat(serverIssue.getKey()).isEqualTo("EFGH"); | |||||
// Module key of removed file should be returned | |||||
assertThat(serverIssue.getModuleKey()).isEqualTo(MODULE_KEY); | |||||
public void fail_if_requested_component_is_a_directory() throws IOException { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto directory = db.components().insertComponent(newDirectory(project, "src/main/java")); | |||||
addPermissionTo(project); | |||||
expectedException.expect(IllegalStateException.class); | |||||
expectedException.expectMessage("Component of scope 'DIR' is not allowed"); | |||||
call(directory.key()); | |||||
} | } | ||||
@Test | @Test | ||||
public void fail_without_browse_permission_on_file() throws Exception { | |||||
public void issues_on_disabled_modules_are_returned() { | |||||
RuleDefinitionDto rule = db.rules().insert(); | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project).setEnabled(false)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(module, null).setEnabled(false)); | |||||
IssueDto issue = db.issues().insert(rule, project, file); | |||||
addPermissionTo(project); | |||||
try (CloseableIterator<ServerIssue> result = callStream(project.key())) { | |||||
// Module key of removed file should be returned | |||||
assertThat(result) | |||||
.extracting(ServerIssue::getKey, ServerIssue::getModuleKey) | |||||
.containsExactly(tuple(issue.getKey(), module.key())); | |||||
} | |||||
} | |||||
@Test | |||||
public void fail_if_user_does_not_have_permission_on_project() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | ComponentDto project = db.components().insertPrivateProject(); | ||||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | ComponentDto file = db.components().insertComponent(newFileDto(project)); | ||||
thrown.expect(ForbiddenException.class); | |||||
expectedException.expect(ForbiddenException.class); | |||||
tester.newRequest().setParam("key", file.key()).execute(); | tester.newRequest().setParam("key", file.key()).execute(); | ||||
} | } | ||||
private void indexIssues(ComponentDto project) { | |||||
issueIndexer.indexOnStartup(null); | |||||
authorizationIndexerTester.allowOnlyAnyone(project); | |||||
@Test | |||||
public void fail_if_component_does_not_exist() { | |||||
expectedException.expect(NotFoundException.class); | |||||
expectedException.expectMessage("Component key 'does_not_exist' not found"); | |||||
tester.newRequest().setParam("key", "does_not_exist").execute(); | |||||
} | } | ||||
private void addBrowsePermissionOnComponent(ComponentDto project) { | |||||
private void addPermissionTo(ComponentDto project) { | |||||
userSessionRule.addProjectPermission(UserRole.USER, project); | userSessionRule.addProjectPermission(UserRole.USER, project); | ||||
} | } | ||||
private ServerIssue call(String componentKey) { | |||||
try { | |||||
TestResponse response = tester.newRequest().setParam("key", componentKey).execute(); | |||||
return ServerIssue.parseDelimitedFrom(response.getInputStream()); | |||||
} catch (IOException e) { | |||||
throw Throwables.propagate(e); | |||||
} | |||||
private ServerIssue call(String componentKey) throws IOException { | |||||
TestResponse response = tester.newRequest().setParam("key", componentKey).execute(); | |||||
return ServerIssue.parseDelimitedFrom(response.getInputStream()); | |||||
} | |||||
private CloseableIterator<ServerIssue> callStream(String componentKey) { | |||||
TestResponse response = tester.newRequest().setParam("key", componentKey).execute(); | |||||
return Protobuf.readStream(response.getInputStream(), ServerIssue.parser()); | |||||
} | } | ||||
} | } |
package org.sonar.server.issue.index; | package org.sonar.server.issue.index; | ||||
import com.google.common.collect.Iterators; | import com.google.common.collect.Iterators; | ||||
import com.google.common.collect.Lists; | |||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.junit.rules.ExpectedException; | import org.junit.rules.ExpectedException; | ||||
import org.sonar.api.config.internal.MapSettings; | import org.sonar.api.config.internal.MapSettings; | ||||
import org.sonar.api.issue.Issue; | import org.sonar.api.issue.Issue; | ||||
import org.sonar.api.resources.Scopes; | |||||
import org.sonar.api.rule.RuleKey; | import org.sonar.api.rule.RuleKey; | ||||
import org.sonar.api.rule.Severity; | import org.sonar.api.rule.Severity; | ||||
import org.sonar.api.utils.Duration; | import org.sonar.api.utils.Duration; | ||||
import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.assertj.core.api.Assertions.entry; | import static org.assertj.core.api.Assertions.entry; | ||||
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; | |||||
import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||
import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||
import static org.sonar.api.rules.RuleType.BUG; | |||||
import static org.sonar.api.utils.DateUtils.parseDate; | import static org.sonar.api.utils.DateUtils.parseDate; | ||||
import static org.sonar.api.utils.DateUtils.parseDateTime; | import static org.sonar.api.utils.DateUtils.parseDateTime; | ||||
import static org.sonar.db.component.ComponentTesting.newFileDto; | import static org.sonar.db.component.ComponentTesting.newFileDto; | ||||
assertThat( | assertThat( | ||||
underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(file.uuid())).build(), new SearchOptions()) | underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(file.uuid())).build(), new SearchOptions()) | ||||
.getDocs()) | .getDocs()) | ||||
.isEmpty(); | |||||
.isEmpty(); | |||||
assertThat( | assertThat( | ||||
underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(module.uuid())).build(), new SearchOptions()) | underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(module.uuid())).build(), new SearchOptions()) | ||||
.getDocs()) | .getDocs()) | ||||
.hasSize(1); | |||||
.hasSize(1); | |||||
assertThat( | assertThat( | ||||
underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(subModule.uuid())).build(), new SearchOptions()) | underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(subModule.uuid())).build(), new SearchOptions()) | ||||
.getDocs()) | .getDocs()) | ||||
.hasSize(2); | |||||
.hasSize(2); | |||||
assertThat( | assertThat( | ||||
underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(project.uuid())).build(), new SearchOptions()) | underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList(project.uuid())).build(), new SearchOptions()) | ||||
.getDocs()) | .getDocs()) | ||||
.isEmpty(); | |||||
.isEmpty(); | |||||
assertThat( | assertThat( | ||||
underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList("unknown")).build(), new SearchOptions()).getDocs()) | underTest.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).moduleUuids(newArrayList("unknown")).build(), new SearchOptions()).getDocs()) | ||||
.isEmpty(); | |||||
.isEmpty(); | |||||
} | } | ||||
@Test | @Test | ||||
assertThat( | assertThat( | ||||
underTest.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE, Issue.RESOLUTION_FIXED)).build(), new SearchOptions()) | underTest.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE, Issue.RESOLUTION_FIXED)).build(), new SearchOptions()) | ||||
.getDocs()) | .getDocs()) | ||||
.hasSize(2); | |||||
.hasSize(2); | |||||
assertThat(underTest.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE)).build(), new SearchOptions()).getDocs()).hasSize(1); | assertThat(underTest.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE)).build(), new SearchOptions()).getDocs()).hasSize(1); | ||||
assertThat(underTest.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_REMOVED)).build(), new SearchOptions()).getDocs()).isEmpty(); | assertThat(underTest.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_REMOVED)).build(), new SearchOptions()).getDocs()).isEmpty(); | ||||
} | } | ||||
SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | ||||
Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | ||||
.createdAfter(parseDateTime("2014-09-01T00:00:00+0100")) | |||||
.createdBefore(parseDateTime("2014-09-21T00:00:00+0100")).build(), | |||||
.createdAfter(parseDateTime("2014-09-01T00:00:00+0100")) | |||||
.createdBefore(parseDateTime("2014-09-21T00:00:00+0100")).build(), | |||||
SearchOptions).getFacets().get("createdAt"); | SearchOptions).getFacets().get("createdAt"); | ||||
assertThat(createdAt).containsOnly( | assertThat(createdAt).containsOnly( | ||||
entry("2014-08-25T01:00:00+0000", 0L), | entry("2014-08-25T01:00:00+0000", 0L), | ||||
SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | ||||
Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | ||||
.createdAfter(parseDateTime("2014-09-01T00:00:00+0100")) | |||||
.createdBefore(parseDateTime("2015-01-19T00:00:00+0100")).build(), | |||||
.createdAfter(parseDateTime("2014-09-01T00:00:00+0100")) | |||||
.createdBefore(parseDateTime("2015-01-19T00:00:00+0100")).build(), | |||||
SearchOptions).getFacets().get("createdAt"); | SearchOptions).getFacets().get("createdAt"); | ||||
assertThat(createdAt).containsOnly( | assertThat(createdAt).containsOnly( | ||||
entry("2014-08-01T01:00:00+0000", 0L), | entry("2014-08-01T01:00:00+0000", 0L), | ||||
SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | ||||
Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | ||||
.createdAfter(parseDateTime("2011-01-01T00:00:00+0100")) | |||||
.createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(), | |||||
.createdAfter(parseDateTime("2011-01-01T00:00:00+0100")) | |||||
.createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(), | |||||
SearchOptions).getFacets().get("createdAt"); | SearchOptions).getFacets().get("createdAt"); | ||||
assertThat(createdAt).containsOnly( | assertThat(createdAt).containsOnly( | ||||
entry("2010-01-01T01:00:00+0000", 0L), | entry("2010-01-01T01:00:00+0000", 0L), | ||||
SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | ||||
Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | ||||
.createdAfter(parseDateTime("2014-09-01T00:00:00-0100")) | |||||
.createdBefore(parseDateTime("2014-09-02T00:00:00-0100")).build(), | |||||
.createdAfter(parseDateTime("2014-09-01T00:00:00-0100")) | |||||
.createdBefore(parseDateTime("2014-09-02T00:00:00-0100")).build(), | |||||
SearchOptions).getFacets().get("createdAt"); | SearchOptions).getFacets().get("createdAt"); | ||||
assertThat(createdAt).containsOnly( | assertThat(createdAt).containsOnly( | ||||
entry("2014-09-01T01:00:00+0000", 2L)); | entry("2014-09-01T01:00:00+0000", 2L)); | ||||
SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | SearchOptions SearchOptions = fixtureForCreatedAtFacet(); | ||||
Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | Map<String, Long> createdAt = underTest.search(IssueQuery.builder() | ||||
.createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(), | |||||
.createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(), | |||||
SearchOptions).getFacets().get("createdAt"); | SearchOptions).getFacets().get("createdAt"); | ||||
assertThat(createdAt).containsOnly( | assertThat(createdAt).containsOnly( | ||||
entry("2011-01-01T01:00:00+0000", 1L), | entry("2011-01-01T01:00:00+0000", 1L), | ||||
String key = "ISSUE" + i; | String key = "ISSUE" + i; | ||||
issues.add(newDoc(key, file)); | issues.add(newDoc(key, file)); | ||||
} | } | ||||
indexIssues(issues.toArray(new IssueDoc[] {})); | |||||
indexIssues(issues.toArray(new IssueDoc[]{})); | |||||
IssueQuery.Builder query = IssueQuery.builder(); | IssueQuery.Builder query = IssueQuery.builder(); | ||||
SearchResult<IssueDoc> result = underTest.search(query.build(), new SearchOptions().setLimit(Integer.MAX_VALUE)); | SearchResult<IssueDoc> result = underTest.search(query.build(), new SearchOptions().setLimit(Integer.MAX_VALUE)); | ||||
assertThat(underTest.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(1); | assertThat(underTest.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(1); | ||||
} | } | ||||
@Test | |||||
public void search_issues_for_batch_return_needed_fields() { | |||||
ComponentDto project = newPrivateProjectDto(newOrganizationDto(), "PROJECT"); | |||||
ComponentDto file = newFileDto(project, null).setPath("src/File.xoo"); | |||||
IssueDoc issue = newDoc("ISSUE", file) | |||||
.setRuleKey("squid:S001") | |||||
.setChecksum("12345") | |||||
.setAssignee("john") | |||||
.setLine(11) | |||||
.setMessage("the message") | |||||
.setSeverity(Severity.BLOCKER) | |||||
.setManualSeverity(true) | |||||
.setStatus(Issue.STATUS_RESOLVED) | |||||
.setResolution(Issue.RESOLUTION_FIXED) | |||||
.setType(BUG) | |||||
.setFuncCreationDate(new Date()); | |||||
indexIssues(issue); | |||||
List<IssueDoc> issues = Lists.newArrayList(underTest.selectIssuesForBatch(file)); | |||||
assertThat(issues).hasSize(1); | |||||
IssueDoc result = issues.get(0); | |||||
assertThat(result.key()).isEqualTo("ISSUE"); | |||||
assertThat(result.moduleUuid()).isEqualTo("PROJECT"); | |||||
assertThat(result.filePath()).isEqualTo("src/File.xoo"); | |||||
assertThat(result.ruleKey()).isEqualTo(RuleKey.of("squid", "S001")); | |||||
assertThat(result.checksum()).isEqualTo("12345"); | |||||
assertThat(result.assignee()).isEqualTo("john"); | |||||
assertThat(result.line()).isEqualTo(11); | |||||
assertThat(result.message()).isEqualTo("the message"); | |||||
assertThat(result.severity()).isEqualTo(Severity.BLOCKER); | |||||
assertThat(result.isManualSeverity()).isTrue(); | |||||
assertThat(result.status()).isEqualTo(Issue.STATUS_RESOLVED); | |||||
assertThat(result.resolution()).isEqualTo(Issue.RESOLUTION_FIXED); | |||||
assertThat(result.type()).isEqualTo(BUG); | |||||
assertThat(result.creationDate()).isNotNull(); | |||||
} | |||||
@Test | |||||
public void search_issues_for_batch() { | |||||
ComponentDto project = ComponentTesting.newPrivateProjectDto(newOrganizationDto()); | |||||
ComponentDto module = ComponentTesting.newModuleDto(project); | |||||
ComponentDto subModule = ComponentTesting.newModuleDto(module); | |||||
ComponentDto file = newFileDto(subModule, null); | |||||
indexIssues( | |||||
newDoc("ISSUE3", module), | |||||
newDoc("ISSUE5", subModule), | |||||
newDoc("ISSUE2", file), | |||||
// Close Issue, should never be returned | |||||
newDoc("CLOSE_ISSUE", file).setStatus(Issue.STATUS_CLOSED).setResolution(Issue.RESOLUTION_FIXED)); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(project))).hasSize(3); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(module))).hasSize(3); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(subModule))).hasSize(2); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(file))).hasSize(1); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(ComponentTesting.newPrivateProjectDto(newOrganizationDto())))).isEmpty(); | |||||
} | |||||
@Test | |||||
public void fail_to_search_issues_for_batch_on_not_allowed_scope() { | |||||
try { | |||||
underTest.selectIssuesForBatch(new ComponentDto().setScope(Scopes.DIRECTORY)); | |||||
failBecauseExceptionWasNotThrown(IllegalStateException.class); | |||||
} catch (IllegalStateException e) { | |||||
assertThat(e).hasMessage("Component of scope 'DIR' is not allowed"); | |||||
} | |||||
} | |||||
@Test | |||||
public void search_issues_for_batch_return_only_authorized_issues() { | |||||
OrganizationDto org = newOrganizationDto(); | |||||
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(org); | |||||
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(org); | |||||
ComponentDto file1 = newFileDto(project1, null); | |||||
ComponentDto file2 = newFileDto(project2, null); | |||||
GroupDto allowedGroup = newGroupDto(); | |||||
GroupDto otherGroup = newGroupDto(); | |||||
// project1 can be seen by allowedGroup | |||||
indexIssue(newDoc("ISSUE1", file1)); | |||||
authorizationIndexerTester.allowOnlyGroup(project1, allowedGroup); | |||||
// project3 can be seen by nobody | |||||
indexIssue(newDoc("ISSUE3", file2)); | |||||
userSessionRule.logIn().setGroups(allowedGroup); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(project1))).hasSize(1); | |||||
userSessionRule.logIn().setGroups(otherGroup); | |||||
assertThat(Lists.newArrayList(underTest.selectIssuesForBatch(project2))).isEmpty(); | |||||
} | |||||
@Test | @Test | ||||
public void list_tags() { | public void list_tags() { | ||||
RuleDefinitionDto r1 = dbTester.rules().insert(); | RuleDefinitionDto r1 = dbTester.rules().insert(); |