package org.sonar.server.computation;
import com.google.common.annotations.VisibleForTesting;
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonReader;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.protocol.GsonHelper;
+import org.sonar.batch.protocol.output.issue.ReportIssue;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
+import org.sonar.batch.protocol.output.resource.ReportComponents;
import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.core.issue.db.IssueStorage;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.db.DbClient;
import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
public class AnalysisReportService implements ServerComponent {
private static final Logger LOG = LoggerFactory.getLogger(AnalysisReportService.class);
+ private static final int MAX_ISSUES_SIZE = 1000;
+ private final ComputeEngineIssueStorageFactory issueStorageFactory;
private final DbClient dbClient;
+ private final Gson gson;
- public AnalysisReportService(DbClient dbClient) {
+ public AnalysisReportService(DbClient dbClient, ComputeEngineIssueStorageFactory issueStorageFactory) {
+ this.issueStorageFactory = issueStorageFactory;
this.dbClient = dbClient;
+ gson = GsonHelper.create();
}
public void digest(DbSession session, ComputeEngineContext context) {
decompress(session, context);
+ loadResources(context);
+ saveIssues(context);
+ }
+
+ @VisibleForTesting
+ void loadResources(ComputeEngineContext context) {
+ File file = new File(context.getReportDirectory(), "components.json");
+
+ try {
+ InputStream resourcesStream = new FileInputStream(file);
+ String json = IOUtils.toString(resourcesStream);
+ ReportComponents reportComponents = ReportComponents.fromJson(json);
+ context.addResources(reportComponents);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to read issues", e);
+ }
}
@VisibleForTesting
context.setReportDirectory(decompressedDirectory);
}
- public void clean(@Nullable File directory) {
+ @VisibleForTesting
+ void saveIssues(ComputeEngineContext context) {
+ IssueStorage issueStorage = issueStorageFactory.newComputeEngineIssueStorage(context.getProject());
+
+ File issuesFile = new File(context.getReportDirectory(), "issues.json");
+ List<DefaultIssue> issues = new ArrayList<>(MAX_ISSUES_SIZE);
+
+ try {
+ InputStream issuesStream = new FileInputStream(issuesFile);
+ JsonReader reader = new JsonReader(new InputStreamReader(issuesStream));
+ reader.beginArray();
+ while (reader.hasNext()) {
+ ReportIssue reportIssue = gson.fromJson(reader, ReportIssue.class);
+ DefaultIssue defaultIssue = toIssue(context, reportIssue);
+ issues.add(defaultIssue);
+ if (shouldPersistIssues(issues, reader)) {
+ issueStorage.save(issues);
+ issues.clear();
+ }
+ }
+
+ reader.endArray();
+ reader.close();
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to read issues", e);
+ }
+ }
+
+ private boolean shouldPersistIssues(List<DefaultIssue> issues, JsonReader reader) throws IOException {
+ return issues.size() == MAX_ISSUES_SIZE || !reader.hasNext();
+ }
+
+ private DefaultIssue toIssue(ComputeEngineContext context, ReportIssue issue) {
+ ReportComponent component = context.getComponentByBatchId(issue.componentBatchId());
+ DefaultIssue defaultIssue = new DefaultIssue();
+ defaultIssue.setKey(issue.key());
+ defaultIssue.setComponentId(Long.valueOf(component.id()));
+ defaultIssue.setRuleKey(RuleKey.of(issue.ruleRepo(), issue.ruleKey()));
+ defaultIssue.setSeverity(issue.severity());
+ defaultIssue.setManualSeverity(issue.isManualSeverity());
+ defaultIssue.setMessage(issue.message());
+ defaultIssue.setLine(issue.line());
+ defaultIssue.setEffortToFix(issue.effortToFix());
+ setDebt(defaultIssue, issue.debt());
+ defaultIssue.setStatus(issue.status());
+ defaultIssue.setResolution(issue.resolution());
+ defaultIssue.setReporter(issue.reporter());
+ defaultIssue.setAssignee(issue.assignee());
+ defaultIssue.setChecksum(issue.checksum());
+ defaultIssue.setAttributes(KeyValueFormat.parse(issue.issueAttributes()));
+ defaultIssue.setAuthorLogin(issue.authorLogin());
+ defaultIssue.setActionPlanKey(issue.actionPlanKey());
+ defaultIssue.setCreationDate(issue.creationDate());
+ defaultIssue.setUpdateDate(issue.updateDate());
+ defaultIssue.setCloseDate(issue.closeDate());
+ defaultIssue.setCurrentChange(FieldDiffs.parse(issue.diffFields()));
+ defaultIssue.setChanged(issue.isChanged());
+ defaultIssue.setNew(issue.isNew());
+ defaultIssue.setSelectedAt(issue.selectedAt());
+ return defaultIssue;
+ }
+
+ private DefaultIssue setDebt(DefaultIssue issue, Long debt) {
+ if (debt != null) {
+ issue.setDebt(Duration.create(debt));
+ }
+
+ return issue;
+ }
+
+ public void deleteDirectory(@Nullable File directory) {
if (directory == null) {
return;
}
package org.sonar.server.computation;
+import com.google.common.annotations.VisibleForTesting;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
+import org.sonar.batch.protocol.output.resource.ReportComponents;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.computation.db.AnalysisReportDto;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
public class ComputeEngineContext {
private final AnalysisReportDto reportDto;
private final ComponentDto project;
private File reportDirectory;
+ private Map<Long, ReportComponent> components = new HashMap<>();
public ComputeEngineContext(AnalysisReportDto reportDto, ComponentDto project) {
this.reportDto = reportDto;
public void setReportDirectory(@Nullable File reportDirectory) {
this.reportDirectory = reportDirectory;
}
+
+ public void addResources(ReportComponents reportComponents) {
+ addResource(reportComponents.root());
+ }
+
+ @CheckForNull
+ public ReportComponent getComponentByBatchId(Long batchId) {
+ return components.get(batchId);
+ }
+
+ @VisibleForTesting
+ Map<Long, ReportComponent> getComponents() {
+ return components;
+ }
+
+ private void addResource(ReportComponent resource) {
+ this.components.put(resource.batchId(), resource);
+ for (ReportComponent childResource : resource.children()) {
+ addResource(childResource);
+ }
+ }
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.issue.db.IssueMapper;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.issue.db.UpdateConflictResolver;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+class ComputeEngineIssueStorage extends IssueStorage {
+
+ private final DbClient dbClient;
+ private final ComponentDto project;
+ private final UpdateConflictResolver conflictResolver = new UpdateConflictResolver();
+
+ public ComputeEngineIssueStorage(MyBatis mybatis, DbClient dbClient, RuleFinder ruleFinder, ComponentDto project) {
+ super(mybatis, ruleFinder);
+ this.dbClient = dbClient;
+ this.project = project;
+ }
+
+ @Override
+ protected void doInsert(DbSession session, long now, DefaultIssue issue) {
+ IssueMapper issueMapper = session.getMapper(IssueMapper.class);
+ long componentId = componentId(session, issue);
+ long projectId = projectId();
+ Rule rule = rule(issue);
+ List<String> allTags = new ArrayList<String>();
+ allTags.addAll(Arrays.asList(rule.getTags()));
+ allTags.addAll(Arrays.asList(rule.getSystemTags()));
+ issue.setTags(allTags);
+ IssueDto dto = IssueDto.toDtoForBatchInsert(issue, componentId, projectId, rule.getId(), now);
+ issueMapper.insert(dto);
+ }
+
+ @Override
+ protected void doUpdate(DbSession session, long now, DefaultIssue issue) {
+ IssueMapper issueMapper = session.getMapper(IssueMapper.class);
+ IssueDto dto = IssueDto.toDtoForUpdate(issue, projectId(), now);
+ if (Issue.STATUS_CLOSED.equals(issue.status()) || issue.selectedAt() == null) {
+ // Issue is closed by scan or changed by end-user
+ issueMapper.update(dto);
+
+ } else {
+ int count = issueMapper.updateIfBeforeSelectedDate(dto);
+ if (count == 0) {
+ // End-user and scan changed the issue at the same time.
+ // See https://jira.codehaus.org/browse/SONAR-4309
+ conflictResolver.resolve(issue, issueMapper);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ long componentId(DbSession session, DefaultIssue issue) {
+ if (issue.componentId() != null) {
+ return issue.componentId();
+ }
+
+ ComponentDto componentDto = dbClient.componentDao().getNullableByKey(session, issue.componentKey());
+ if (componentDto == null) {
+ throw new IllegalStateException("Unknown component: " + issue.componentKey());
+ }
+ return componentDto.getId();
+ }
+
+ @VisibleForTesting
+ long projectId() {
+ return project.getId();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+
+public class ComputeEngineIssueStorageFactory implements ServerComponent {
+ private final MyBatis myBatis;
+ private final DbClient dbClient;
+ private final RuleFinder ruleFinder;
+
+ public ComputeEngineIssueStorageFactory(MyBatis myBatis, DbClient dbClient, RuleFinder ruleFinder) {
+ this.myBatis = myBatis;
+ this.dbClient = dbClient;
+ this.ruleFinder = ruleFinder;
+ }
+
+ public IssueStorage newComputeEngineIssueStorage(ComponentDto project) {
+ return new ComputeEngineIssueStorage(myBatis, dbClient, ruleFinder, project);
+ }
+}
ps.executeUpdate();
connection.commit();
- } catch (SQLException e) {
+ } catch (SQLException | IOException e) {
throw new IllegalStateException(String.format("Failed to insert %s in the database", report), e);
- } catch (IOException e) {
- throw new IllegalStateException(String.format("Failed to read report data of %s", report), e);
} finally {
DatabaseUtils.closeQuietly(ps);
}
@Override
public void execute(DbSession session, ComputeEngineContext context) {
projectCleaner.purge(session, new IdUuidPair(context.getProject().getId(), context.getProject().uuid()));
- // reportService.clean(context.getReportDirectory());
+ // reportService.deleteDirectory(context.getReportDirectory());
}
@Override
pico.addSingleton(ProjectCleaner.class);
pico.addSingleton(ProjectSettingsFactory.class);
pico.addSingleton(IndexPurgeListener.class);
+ pico.addSingleton(ComputeEngineIssueStorageFactory.class);
for (Object components : level4AddedComponents) {
pico.addSingleton(components);
package org.sonar.server.computation;
+import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
+import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.core.issue.db.IssueStorage;
import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
import org.sonar.server.computation.db.AnalysisReportDao;
import org.sonar.server.db.DbClient;
import java.io.File;
+import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
public class AnalysisReportServiceTest {
private AnalysisReportService sut;
+ private IssueStorage issueStorage;
+ private DbClient dbClient;
+
+ @Before
+ public void before() throws Exception {
+ dbClient = mock(DbClient.class);
+ issueStorage = new FakeIssueStorage();
+ ComputeEngineIssueStorageFactory issueStorageFactory = mock(ComputeEngineIssueStorageFactory.class);
+ when(issueStorageFactory.newComputeEngineIssueStorage(any(ComponentDto.class))).thenReturn(issueStorage);
+ sut = new AnalysisReportService(dbClient, issueStorageFactory);
+ }
+
@Test
public void call_dao_to_decompress_report() throws Exception {
- DbClient dbClient = mock(DbClient.class);
AnalysisReportDao dao = mock(AnalysisReportDao.class);
when(dbClient.analysisReportDao()).thenReturn(dao);
- sut = new AnalysisReportService(dbClient);
- ComputeEngineContext context = new ComputeEngineContext(mock(AnalysisReportDto.class), mock(ComponentDto.class));
+ AnalysisReportDto report = AnalysisReportDto.newForTests(123L);
+ ComputeEngineContext context = new ComputeEngineContext(report, mock(ComponentDto.class));
sut.decompress(mock(DbSession.class), context);
- verify(dao).getDecompressedReport(any(DbSession.class), anyLong());
+ verify(dao).getDecompressedReport(any(DbSession.class), eq(123L));
}
@Test
public void clean_null_directory_does_not_throw_any_exception() throws Exception {
- sut = new AnalysisReportService(mock(DbClient.class));
-
- sut.clean(null);
+ sut.deleteDirectory(null);
}
@Test
public void clean_temp_folder() throws Exception {
- sut = new AnalysisReportService(mock(DbClient.class));
- File origin = new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder").getFile());
+ File origin = new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile());
File destination = new File("target/tmp/report-folder-to-delete");
FileUtils.copyDirectory(origin, destination);
assertThat(destination.exists()).isTrue();
- sut.clean(destination);
+ sut.deleteDirectory(destination);
assertThat(destination.exists()).isFalse();
}
+
+ @Test
+ public void load_resources() throws Exception {
+ ComputeEngineContext context = new ComputeEngineContext(mock(AnalysisReportDto.class), mock(ComponentDto.class));
+ context.setReportDirectory(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile()));
+
+ sut.loadResources(context);
+
+ assertThat(context.getComponents()).hasSize(4);
+ }
+
+ @Test
+ public void save_issues() throws Exception {
+ ComputeEngineContext context = new FakeComputeEngineContext();
+ context.setReportDirectory(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile()));
+
+ sut.saveIssues(context);
+
+ assertThat(((FakeIssueStorage) issueStorage).issues).hasSize(6);
+ }
+
+ private static class FakeIssueStorage extends IssueStorage {
+
+ public List<DefaultIssue> issues = null;
+
+ protected FakeIssueStorage() {
+ super(mock(MyBatis.class), mock(RuleFinder.class));
+ }
+
+ @Override
+ public void save(Iterable<DefaultIssue> issues) {
+ this.issues = Lists.newArrayList(issues);
+ }
+
+ @Override
+ protected void doInsert(DbSession batchSession, long now, DefaultIssue issue) {
+
+ }
+
+ @Override
+ protected void doUpdate(DbSession batchSession, long now, DefaultIssue issue) {
+
+ }
+ }
+
+ private static class FakeComputeEngineContext extends ComputeEngineContext {
+
+ public FakeComputeEngineContext() {
+ super(mock(AnalysisReportDto.class), mock(ComponentDto.class));
+ }
+
+ @Override
+ public ReportComponent getComponentByBatchId(Long batchId) {
+ return new ReportComponent()
+ .setBatchId(123)
+ .setId(456);
+ }
+ }
+
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation;
+
+import org.junit.Test;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ComputeEngineIssueStorageFactoryTest {
+
+ ComputeEngineIssueStorageFactory sut;
+
+ @Test
+ public void return_instance_of_compute_engine_issue_storage() throws Exception {
+ sut = new ComputeEngineIssueStorageFactory(mock(MyBatis.class), mock(DbClient.class), mock(RuleFinder.class));
+
+ IssueStorage issueStorage = sut.newComputeEngineIssueStorage(mock(ComponentDto.class));
+
+ assertThat(issueStorage).isInstanceOf(ComputeEngineIssueStorage.class);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.DefaultIssueComment;
+import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.System2;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.issue.db.IssueDao;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ComputeEngineIssueStorageTest extends AbstractDaoTestCase {
+
+ DbClient dbClient;
+ DbSession dbSession;
+ Map<Long, ReportComponent> components;
+ ComponentDto project;
+
+ ComputeEngineIssueStorage sut;
+
+ @Before
+ public void setUp() throws Exception {
+ System2 system = mock(System2.class);
+ when(system.now()).thenReturn(2000000000L);
+ dbClient = new DbClient(getDatabase(), getMyBatis(),
+ new ComponentDao(system),
+ new IssueDao(getMyBatis()),
+ new ComponentDao(system));
+ dbSession = dbClient.openSession(false);
+ components = new HashMap<>();
+ project = new ComponentDto();
+
+ sut = new ComputeEngineIssueStorage(getMyBatis(), dbClient, new FakeRuleFinder(), project);
+ }
+
+ @Test
+ public void should_get_component_id_set_in_issue() throws Exception {
+ DefaultIssue issue = new DefaultIssue().setComponentId(123L);
+
+ long componentId = sut.componentId(dbSession, issue);
+
+ assertThat(componentId).isEqualTo(123L);
+ }
+
+ @Test
+ public void should_load_component_id_from_db() throws Exception {
+ setupData("should_load_component_id_from_db");
+
+ long componentId = sut.componentId(dbSession, new DefaultIssue().setComponentKey("struts:Action.java"));
+
+ assertThat(componentId).isEqualTo(123);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void should_fail_to_load_component_id_if_unknown_component() throws Exception {
+ setupData("should_fail_to_load_component_id_if_unknown_component");
+
+ sut.componentId(dbSession, new DefaultIssue().setComponentKey("struts:Action.java"));
+ }
+
+ @Test
+ public void should_load_project_id() throws Exception {
+ project.setId(100L);
+
+ long projectId = sut.projectId();
+
+ assertThat(projectId).isEqualTo(100);
+ }
+
+ @Test
+ public void should_insert_new_issues() throws Exception {
+ setupData("should_insert_new_issues");
+ project.setId(10L).setKey("struts");
+
+ DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
+ // override generated key
+ comment.setKey("FGHIJ");
+
+ Date date = DateUtils.parseDate("2013-05-18");
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setNew(true)
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+ .setLine(5000)
+ .setDebt(Duration.create(10L))
+ .setReporter("emmerik")
+ .setResolution("OPEN")
+ .setStatus("OPEN")
+ .setSeverity("BLOCKER")
+ .setAttribute("foo", "bar")
+ .addComment(comment)
+ .setCreationDate(date)
+ .setUpdateDate(date)
+ .setCloseDate(date)
+
+ .setComponentKey("struts:Action");
+
+ sut.save(issue);
+
+ checkTables("should_insert_new_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
+ }
+
+ @Test
+ public void should_update_issues() throws Exception {
+ setupData("should_update_issues");
+
+ IssueChangeContext context = IssueChangeContext.createUser(new Date(), "emmerik");
+
+ project.setId(10L).setKey("struts");
+
+ DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
+ // override generated key
+ comment.setKey("FGHIJ");
+
+ Date date = DateUtils.parseDate("2013-05-18");
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setNew(false)
+ .setChanged(true)
+
+ // updated fields
+ .setLine(5000)
+ .setDebt(Duration.create(10L))
+ .setChecksum("FFFFF")
+ .setAuthorLogin("simon")
+ .setAssignee("loic")
+ .setFieldChange(context, "severity", "INFO", "BLOCKER")
+ .setReporter("emmerik")
+ .setResolution("FIXED")
+ .setStatus("RESOLVED")
+ .setSeverity("BLOCKER")
+ .setAttribute("foo", "bar")
+ .addComment(comment)
+ .setCreationDate(date)
+ .setUpdateDate(date)
+ .setCloseDate(date)
+
+ // unmodifiable fields
+ .setRuleKey(RuleKey.of("xxx", "unknown"))
+ .setComponentKey("not:a:component");
+
+ sut.save(issue);
+
+ checkTables("should_update_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
+ }
+
+ @Test
+ public void should_resolve_conflicts_on_updates() throws Exception {
+ setupData("should_resolve_conflicts_on_updates");
+
+ project.setId(10L).setKey("struts");
+
+ Date date = DateUtils.parseDate("2013-05-18");
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setNew(false)
+ .setChanged(true)
+ .setCreationDate(DateUtils.parseDate("2005-05-12"))
+ .setUpdateDate(date)
+ .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
+ .setComponentKey("struts:Action")
+
+ // issue in database has been updated in 2015, after the loading by scan
+ .setSelectedAt(1400000000000L)
+
+ // fields to be updated
+ .setLine(444)
+ .setSeverity("BLOCKER")
+ .setChecksum("FFFFF")
+ .setAttribute("JIRA", "http://jira.com")
+
+ // fields overridden by end-user -> do not save
+ .setAssignee("looser")
+ .setResolution(null)
+ .setStatus("REOPEN");
+
+ sut.save(issue);
+
+ checkTables("should_resolve_conflicts_on_updates", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues");
+ }
+
+ static class FakeRuleFinder implements RuleFinder {
+
+ @Override
+ public Rule findById(int ruleId) {
+ return null;
+ }
+
+ @Override
+ public Rule findByKey(String repositoryKey, String key) {
+ return null;
+ }
+
+ @Override
+ public Rule findByKey(RuleKey key) {
+ Rule rule = Rule.create().setRepositoryKey(key.repository()).setKey(key.rule());
+ rule.setId(200);
+ return rule;
+ }
+
+ @Override
+ public Rule find(RuleQuery query) {
+ return null;
+ }
+
+ @Override
+ public Collection<Rule> findAll(RuleQuery query) {
+ return null;
+ }
+ }
+}
sut.execute(mock(DbSession.class), context);
verify(projectCleaner).purge(any(DbSession.class), any(IdUuidPair.class));
- // verify(reportService).clean(any(File.class));
+ // verify(reportService).deleteDirectory(any(File.class));
}
}
+++ /dev/null
-<dataset>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <!-- NEW SNAPSHOT -->
- <snapshots id="1" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
- status="U" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <snapshots id="2" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
- status="U" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <snapshots id="3" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
- status="U" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <!-- PROJECT_ID = 3 – no last snapshot -->
- <snapshots id="4" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
- status="U" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <!-- Child of snapshot id=1 -->
- <snapshots id="5" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
- status="U" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
-
- <!-- LAST FLAGGED SNAPSHOT -->
- <snapshots id="21" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
- status="P" islast="[true]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <snapshots id="22" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
- status="P" islast="[true]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <snapshots id="23" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
- status="P" islast="[true]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <!-- PROJECT_ID = 3 – no last snapshot -->
- <snapshots id="24" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
- status="P" islast="[true]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <!-- Child of snapshot id=1 -->
- <snapshots id="25" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
- status="P" islast="[true]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
-
- <!-- OLD SNAPSHOT -->
- <snapshots id="46" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
- status="P" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <snapshots id="47" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
- status="P" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <snapshots id="48" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
- status="P" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <!-- PROJECT_ID = 3 – no last snapshot -->
- <snapshots id="49" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
- status="P" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
- <!-- Child of snapshot id=1 -->
- <snapshots id="50" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
- status="P" islast="[false]" purge_status="1"
- period1_mode="days1" period1_param="30" period1_date="2011-09-24"
- period2_mode="days2" period2_param="31" period2_date="2011-09-25"
- period3_mode="days3" period3_param="32" period3_date="2011-09-26"
- period4_mode="days4" period4_param="33" period4_date="2011-09-27"
- period5_mode="days5" period5_param="34" period5_date="2011-09-28"
- depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
- version="2.1-SNAPSHOT" path="1.2."/>
-</dataset>
--- /dev/null
+{
+ "analysisDate": "2012-12-12T00:00:00+0100",
+ "root": {
+ "batchId": 1,
+ "id": 11,
+ "snapshotId": 111,
+ "name": "Root project",
+ "type": "PRJ",
+ "children": [
+ {
+ "batchId": 2,
+ "id": 22,
+ "snapshotId": 222,
+ "path": "module1",
+ "name": "Module",
+ "type": "MOD",
+ "children": [
+ {
+ "batchId": 3,
+ "id": 33,
+ "snapshotId": 333,
+ "path": "src",
+ "name": "src",
+ "type": "DIR",
+ "children": [
+ {
+ "batchId": 4,
+ "id": 44,
+ "snapshotId": 444,
+ "path": "Foo.java",
+ "name": "Foo.java",
+ "type": "FIL",
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
--- /dev/null
+<dataset>
+
+</dataset>
--- /dev/null
+[
+ {
+ "isNew": false,
+ "key": "key",
+ "manualSeverity": false,
+ "assignee": "Assignee",
+ "attributes": "attributes",
+ "authorLogin": "login",
+ "isChanged": true,
+ "ruleKey": "ruleKey",
+ "ruleRepo": "local",
+ "severity": "INFO",
+ "message": "message",
+ "line": 25,
+ "effortToFix": 30,
+ "debtInMinutes": 25,
+ "status": "NEW",
+ "resolution": "Non Solved",
+ "reporter": "reporter",
+ "assignee": "assignee",
+ "checkSum": "checkSum",
+ "attributes": "toto=25",
+ "authorLogin": "author",
+ "actionPlanKey": "actionPlanKey",
+ "creationDate": "2014-12-19T00:03:14+0100",
+ "updateDate": "2014-12-19T00:03:14+0100",
+ "closeDate": "2014-12-19T00:03:14+0100",
+ "currentChange": "coucou,c'est,nous",
+ "isChange": false,
+ "selectAt": 564897564
+ },
+ {
+ "isNew": false,
+ "key": "key",
+ "manualSeverity": false,
+ "assignee": "Assignee",
+ "attributes": "attributes",
+ "authorLogin": "login",
+ "isChanged": true,
+ "ruleKey": "ruleKey",
+ "ruleRepo": "local",
+ "severity": "INFO",
+ "message": "message",
+ "line": 25,
+ "effortToFix": 30,
+ "debtInMinutes": 25,
+ "status": "NEW",
+ "resolution": "Non Solved",
+ "reporter": "reporter",
+ "assignee": "assignee",
+ "checkSum": "checkSum",
+ "attributes": "toto=25",
+ "authorLogin": "author",
+ "actionPlanKey": "actionPlanKey",
+ "creationDate": "2014-12-19T00:03:14+0100",
+ "updateDate": "2014-12-19T00:03:14+0100",
+ "closeDate": "2014-12-19T00:03:14+0100",
+ "currentChange": "coucou,c'est,nous",
+ "isChange": false,
+ "selectAt": 564897564
+ },
+ {
+ "isNew": false,
+ "key": "key",
+ "manualSeverity": false,
+ "assignee": "Assignee",
+ "attributes": "attributes",
+ "authorLogin": "login",
+ "isChanged": true,
+ "ruleKey": "ruleKey",
+ "ruleRepo": "local",
+ "severity": "INFO",
+ "message": "message",
+ "line": 25,
+ "effortToFix": 30,
+ "debtInMinutes": 25,
+ "status": "NEW",
+ "resolution": "Non Solved",
+ "reporter": "reporter",
+ "assignee": "assignee",
+ "checkSum": "checkSum",
+ "attributes": "toto=25",
+ "authorLogin": "author",
+ "actionPlanKey": "actionPlanKey",
+ "creationDate": "2014-12-19T00:03:14+0100",
+ "updateDate": "2014-12-19T00:03:14+0100",
+ "closeDate": "2014-12-19T00:03:14+0100",
+ "currentChange": "coucou,c'est,nous",
+ "isChange": false,
+ "selectAt": 564897564
+ },
+ {
+ "isNew": false,
+ "key": "key",
+ "manualSeverity": false,
+ "assignee": "Assignee",
+ "attributes": "attributes",
+ "authorLogin": "login",
+ "isChanged": true,
+ "ruleKey": "ruleKey",
+ "ruleRepo": "local",
+ "severity": "INFO",
+ "message": "message",
+ "line": 25,
+ "effortToFix": 30,
+ "debtInMinutes": 25,
+ "status": "NEW",
+ "resolution": "Non Solved",
+ "reporter": "reporter",
+ "assignee": "assignee",
+ "checkSum": "checkSum",
+ "attributes": "toto=25",
+ "authorLogin": "author",
+ "actionPlanKey": "actionPlanKey",
+ "creationDate": "2014-12-19T00:03:14+0100",
+ "updateDate": "2014-12-19T00:03:14+0100",
+ "closeDate": "2014-12-19T00:03:14+0100",
+ "currentChange": "coucou,c'est,nous",
+ "isChange": false,
+ "selectAt": 564897564
+ },
+ {
+ "isNew": false,
+ "key": "key",
+ "manualSeverity": false,
+ "assignee": "Assignee",
+ "attributes": "attributes",
+ "authorLogin": "login",
+ "isChanged": true,
+ "ruleKey": "ruleKey",
+ "ruleRepo": "local",
+ "severity": "INFO",
+ "message": "message",
+ "line": 25,
+ "effortToFix": 30,
+ "debtInMinutes": 25,
+ "status": "NEW",
+ "resolution": "Non Solved",
+ "reporter": "reporter",
+ "assignee": "assignee",
+ "checkSum": "checkSum",
+ "attributes": "toto=25",
+ "authorLogin": "author",
+ "actionPlanKey": "actionPlanKey",
+ "creationDate": "2014-12-19T00:03:14+0100",
+ "updateDate": "2014-12-19T00:03:14+0100",
+ "closeDate": "2014-12-19T00:03:14+0100",
+ "currentChange": "coucou,c'est,nous",
+ "isChange": false,
+ "selectAt": 564897564
+ },
+ {
+ "isNew": false,
+ "key": "key",
+ "manualSeverity": false,
+ "assignee": "Assignee",
+ "attributes": "attributes",
+ "authorLogin": "login",
+ "isChanged": true,
+ "ruleKey": "ruleKey",
+ "ruleRepo": "local",
+ "severity": "INFO",
+ "message": "message",
+ "line": 25,
+ "effortToFix": 30,
+ "debtInMinutes": 25,
+ "status": "NEW",
+ "resolution": "Non Solved",
+ "reporter": "reporter",
+ "assignee": "assignee",
+ "checkSum": "checkSum",
+ "attributes": "toto=25",
+ "authorLogin": "author",
+ "actionPlanKey": "actionPlanKey",
+ "creationDate": "2014-12-19T00:03:14+0100",
+ "updateDate": "2014-12-19T00:03:14+0100",
+ "closeDate": "2014-12-19T00:03:14+0100",
+ "currentChange": "coucou,c'est,nous",
+ "isChange": false,
+ "selectAt": 564897564
+ }
+]
\ No newline at end of file
--- /dev/null
+<dataset>
+
+ <!-- NEW SNAPSHOT -->
+ <snapshots id="1" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+ status="U" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <snapshots id="2" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+ status="U" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <snapshots id="3" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+ status="U" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <!-- PROJECT_ID = 3 – no last snapshot -->
+ <snapshots id="4" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+ status="U" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <!-- Child of snapshot id=1 -->
+ <snapshots id="5" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+ status="U" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+
+ <!-- LAST FLAGGED SNAPSHOT -->
+ <snapshots id="21" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+ status="P" islast="[true]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <snapshots id="22" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+ status="P" islast="[true]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <snapshots id="23" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+ status="P" islast="[true]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <!-- PROJECT_ID = 3 – no last snapshot -->
+ <snapshots id="24" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+ status="P" islast="[true]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <!-- Child of snapshot id=1 -->
+ <snapshots id="25" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+ status="P" islast="[true]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+
+ <!-- OLD SNAPSHOT -->
+ <snapshots id="46" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+ status="P" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <snapshots id="47" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+ status="P" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <snapshots id="48" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+ status="P" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <!-- PROJECT_ID = 3 – no last snapshot -->
+ <snapshots id="49" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+ status="P" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+ <!-- Child of snapshot id=1 -->
+ <snapshots id="50" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+ status="P" islast="[false]" purge_status="1"
+ period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+ period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+ period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+ period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+ period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+ depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+ version="2.1-SNAPSHOT" path="1.2."/>
+</dataset>
--- /dev/null
+<dataset></dataset>
\ No newline at end of file
--- /dev/null
+<dataset>
+ <issues id="1" kee="ABCDE" resolution="OPEN" status="OPEN" severity="BLOCKER" manual_severity="[false]"
+ assignee="[null]"
+ author_login="[null]"
+ checksum="[null]"
+ effort_to_fix="[null]"
+ technical_debt="10"
+ message="[null]"
+ line="5000"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ created_at="[null]"
+ updated_at="[null]"
+ reporter="emmerik"
+ issue_attributes="foo=bar"
+ tags="[null]"
+ action_plan_key="[null]"
+ issue_creation_date="2013-05-18"
+ issue_update_date="2013-05-18"
+ issue_close_date="2013-05-18"
+ />
+
+ <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik" change_data="the comment"
+ created_at="[null]" updated_at="[null]" issue_change_creation_date="[null]" />
+
+</dataset>
--- /dev/null
+<dataset>
+ <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+ <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+</dataset>
--- /dev/null
+<dataset>
+ <projects id="123" kee="struts:Action.java" uuid="ABCD"/>
+</dataset>
--- /dev/null
+<dataset>
+ <rules tags="[null]" system_tags="[null]" id="200" name="Avoid Cycles" plugin_rule_key="AvoidCycles"
+ plugin_config_key="[null]" plugin_name="squid"/>
+
+ <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+ <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+
+ <issues id="1"
+ kee="ABCDE"
+ resolution="FIXED"
+ status="RESOLVED"
+ severity="BLOCKER"
+ manual_severity="[false]"
+ assignee="winner"
+ author_login="[null]"
+ checksum="FFFFF"
+ effort_to_fix="[null]"
+ technical_debt="[null]"
+ message="[null]"
+ line="444"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ reporter="[null]"
+ issue_attributes="JIRA=http://jira.com"
+ tags="[null]"
+ action_plan_key="[null]"
+ created_at="1400000000000"
+ updated_at="1400000000000"
+ issue_creation_date="2005-05-12 00:00:00.0"
+ issue_update_date="2013-05-18 00:00:00.0"
+ issue_close_date="[null]"
+ />
+</dataset>
--- /dev/null
+<dataset>
+
+ <rules tags="[null]" system_tags="[null]" id="200" name="Avoid Cycles" plugin_rule_key="AvoidCycles"
+ plugin_config_key="[null]" plugin_name="squid" />
+
+ <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+ <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+
+ <issues id="1"
+ kee="ABCDE"
+ assignee="winner"
+ resolution="FIXED"
+ status="RESOLVED"
+ severity="MAJOR"
+ manual_severity="[false]"
+ author_login="[null]"
+ checksum="FFFFF"
+ effort_to_fix="[null]"
+ technical_debt="[null]"
+ message="[null]"
+ line="1"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ reporter="[null]"
+ issue_attributes=""
+ action_plan_key="[null]"
+ created_at="1400000000000"
+ updated_at="1500000000000"
+ issue_creation_date="2005-05-12 00:00:00.0"
+ issue_update_date="2013-05-18 00:00:00.0"
+ issue_close_date="[null]"
+ />
+</dataset>
--- /dev/null
+<dataset>
+ <issues id="1"
+ kee="ABCDE"
+ resolution="FIXED"
+ status="RESOLVED"
+ severity="BLOCKER"
+ manual_severity="[false]"
+ assignee="loic"
+ author_login="simon"
+ checksum="FFFFF"
+ effort_to_fix="[null]"
+ technical_debt="10"
+ message="[null]"
+ line="5000"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ created_at="1400000000000"
+ updated_at="1400000000000"
+ reporter="emmerik"
+ issue_attributes="foo=bar"
+ tags="[null]"
+ action_plan_key="[null]"
+ issue_creation_date="2013-05-18 00:00:00.0"
+ issue_update_date="2013-05-18 00:00:00.0"
+ issue_close_date="2013-05-18 00:00:00.0"
+ />
+
+ <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik"
+ change_data="the comment" created_at="[null]" updated_at="[null]" issue_change_creation_date="[null]"/>
+ <issue_changes id="2" kee="[null]" issue_key="ABCDE" change_type="diff" user_login="emmerik"
+ change_data="severity=INFO|BLOCKER" created_at="[null]" updated_at="[null]" issue_change_creation_date="[null]"/>
+</dataset>
--- /dev/null
+<dataset>
+
+ <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+ <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+
+ <issues id="1"
+ kee="ABCDE"
+ resolution="OPEN"
+ status="OPEN"
+ severity="BLOCKER"
+ manual_severity="[false]"
+ assignee="loic"
+ author_login="simon"
+ checksum="FFFFF"
+ effort_to_fix="[null]"
+ technical_debt="[null]"
+ message="[null]"
+ line="3000"
+ component_id="100"
+ root_component_id="10"
+ rule_id="200"
+ created_at="1400000000000"
+ updated_at="1400000000000"
+ reporter="emmerik"
+ issue_attributes="foo=bar"
+ action_plan_key="[null]"
+ issue_creation_date="2010-01-01"
+ issue_update_date="2010-02-02"
+ issue_close_date="[null]"
+ />
+</dataset>
ref.addFileData("foo", "src/main/java/Foo.java", new FileData("xyz", "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin"));
ref.addFileData("foo", "src/main/java/Foo2.java", new FileData("xyz", "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin"));
- System.out.println(ref.toJson());
JSONAssert
.assertEquals(
"{timestamp:10,"
return;
}
Iterable<DefaultIssue> issues = issueCache.all();
- storage.save(issues);
+ // storage.save(issues);
}
}
import java.util.Arrays;
import java.util.List;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
public class IssuePersisterTest extends AbstractDaoTestCase {
}
@Test
- public void should_persist_all_issues() throws Exception {
+ public void should_not_persist_issues_anymore() throws Exception {
persister.persist();
- verify(storage, times(1)).save(issues);
+ verify(storage, never()).save(issues);
}
@Test
.setResolution(issue.resolution())
.setStatus(issue.status())
.setSeverity(issue.severity())
- .setChecksum(issue.checksum())
.setManualSeverity(issue.manualSeverity())
+ .setChecksum(issue.checksum())
.setReporter(issue.reporter())
.setAssignee(issue.assignee())
.setRuleId(ruleId)
.setIssueUpdateDate(issue.updateDate())
.setSelectedAt(issue.selectedAt())
- // technical dates
+ // technical dates
.setCreatedAt(now)
.setUpdatedAt(now);
}
// Batch session can not be used for updates. It does not return the number of updated rows,
// required for detecting conflicts.
long now = System.currentTimeMillis();
- List<DefaultIssue> toBeUpdated = batchInsert(session, issues, now);
+ List<DefaultIssue> toBeUpdated = batchInsertAndReturnIssuesToUpdate(session, issues, now);
update(toBeUpdated, now);
doAfterSave();
}
// overridden on server-side to index ES
}
- private List<DefaultIssue> batchInsert(DbSession session, Iterable<DefaultIssue> issues, long now) {
+ private List<DefaultIssue> batchInsertAndReturnIssuesToUpdate(DbSession session, Iterable<DefaultIssue> issues, long now) {
List<DefaultIssue> toBeUpdated = newArrayList();
int count = 0;
IssueChangeMapper issueChangeMapper = session.getMapper(IssueChangeMapper.class);
import javax.annotation.Nullable;
import java.io.Serializable;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import static com.google.common.collect.Lists.newArrayList;
return this;
}
+ public DefaultIssue setCurrentChange(FieldDiffs currentChange) {
+ this.currentChange = currentChange;
+ addChange(currentChange);
+ return this;
+ }
+
@CheckForNull
public FieldDiffs currentChange() {
return currentChange;