diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2013-02-19 00:04:01 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2013-02-19 00:09:44 +0100 |
commit | 91cfedbfd44100916f813231c72d0b4202bef4ef (patch) | |
tree | 9535836350d4427e2b5439cc083767420f1ecd1c /sonar-batch/src | |
parent | 16fcb63b9884486db7b97f0aa0e9d0d00cb29266 (diff) | |
download | sonarqube-91cfedbfd44100916f813231c72d0b4202bef4ef.tar.gz sonarqube-91cfedbfd44100916f813231c72d0b4202bef4ef.zip |
SONAR-3317 download last analysis on dry run
Diffstat (limited to 'sonar-batch/src')
6 files changed, 261 insertions, 9 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java index 181f7703ab3..fda39f6c801 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java @@ -33,6 +33,7 @@ import org.sonar.api.utils.SonarException; import org.sonar.batch.bootstrapper.EnvironmentInformation; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -59,19 +60,23 @@ public class ServerClient implements BatchComponent { InputSupplier<InputStream> inputSupplier = doRequest(pathStartingWithSlash); Files.copy(inputSupplier, toFile); } catch (HttpDownloader.HttpException he) { - throw handleHttpException(he); - } catch (Exception e) { + throw handleHttpException(pathStartingWithSlash, he); + } catch (IOException e) { throw new SonarException(String.format("Unable to download '%s' to: %s", pathStartingWithSlash, toFile), e); } } public String request(String pathStartingWithSlash) { + return request(pathStartingWithSlash, true); + } + + public String request(String pathStartingWithSlash, boolean wrapHttpException) { InputSupplier<InputStream> inputSupplier = doRequest(pathStartingWithSlash); try { return IOUtils.toString(inputSupplier.getInput(), "UTF-8"); - } catch (HttpDownloader.HttpException he) { - throw handleHttpException(he); - } catch (Exception e) { + } catch (HttpDownloader.HttpException e) { + throw (wrapHttpException ? handleHttpException(pathStartingWithSlash, e) : e); + } catch (IOException e) { throw new SonarException(String.format("Unable to request: %s", pathStartingWithSlash), e); } } @@ -96,14 +101,14 @@ public class ServerClient implements BatchComponent { } } - private SonarException handleHttpException(HttpDownloader.HttpException he) { + private RuntimeException handleHttpException(String uri, HttpDownloader.HttpException he) { if (he.getResponseCode() == 401) { - throw new SonarException(String.format(getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD)); + return new SonarException(String.format(getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD)); } - throw new SonarException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he); + return new SonarException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he); } - private String getMessageWhenNotAuthorized(){ + private String getMessageWhenNotAuthorized() { String login = settings.getProperty(CoreProperties.LOGIN); String password = settings.getProperty(CoreProperties.PASSWORD); if (StringUtils.isEmpty(login) && StringUtils.isEmpty(password)) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java b/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java new file mode 100644 index 00000000000..490ce77ffea --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java @@ -0,0 +1,106 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan; + +import org.sonar.api.BatchComponent; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.database.model.SnapshotSource; +import org.sonar.api.resources.Resource; +import org.sonar.api.resources.ResourceUtils; +import org.sonar.api.utils.HttpDownloader; +import org.sonar.batch.bootstrap.ServerClient; + +import javax.annotation.CheckForNull; +import javax.persistence.Query; + +import java.util.Collections; +import java.util.List; + +public class LastSnapshots implements BatchComponent { + + private final Settings settings; + private final DatabaseSession session; + private final ServerClient server; + + public LastSnapshots(Settings settings, DatabaseSession session, ServerClient server) { + this.settings = settings; + this.session = session; + this.server = server; + } + + /** + * Return null if this is the first scan (no last scan). + */ + @CheckForNull + public List<RuleFailureModel> getViolations(Resource resource) { + Snapshot snapshot = getSnapshot(resource); + if (snapshot != null) { + return session.getResults(RuleFailureModel.class, "snapshotId", snapshot.getId()); + } + return null; + } + + public String getSource(Resource resource) { + String source = ""; + if (ResourceUtils.isFile(resource)) { + if (settings.getBoolean(CoreProperties.DRY_RUN)) { + source = loadSourceFromWs(resource); + } else { + source = loadSourceFromDb(resource); + } + } + return source; + } + + private String loadSourceFromWs(Resource resource) { + try { + return server.request("/api/sources?resource=" + resource.getEffectiveKey() + "&format=txt", false); + } catch (HttpDownloader.HttpException he) { + if (he.getResponseCode() == 404) { + return ""; + } + throw he; + } + } + + private String loadSourceFromDb(Resource resource) { + Snapshot snapshot = getSnapshot(resource); + if (snapshot != null) { + SnapshotSource source = session.getSingleResult(SnapshotSource.class, "snapshotId", snapshot.getId()); + if (source != null) { + return source.getData(); + } + } + return ""; + } + + private Snapshot getSnapshot(Resource resource) { + Query query = session.createQuery("from " + Snapshot.class.getSimpleName() + " s where s.last=:last and s.resourceId=(select r.id from " + + ResourceModel.class.getSimpleName() + " r where r.key=:key)"); + query.setParameter("key", resource.getEffectiveKey()); + query.setParameter("last", Boolean.TRUE); + return session.getSingleResult(query, null); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ScanContainer.java index dcb25cbdeaa..e898e87d53f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ScanContainer.java @@ -94,6 +94,7 @@ public class ScanContainer extends Container { } container.addSingleton(Languages.class); container.addSingleton(RulesDao.class); + container.addSingleton(LastSnapshots.class); // file system container.addSingleton(PathResolver.class); diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java new file mode 100644 index 00000000000..62e756b8c7d --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java @@ -0,0 +1,126 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan; + +import org.junit.Test; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.resources.File; +import org.sonar.api.utils.HttpDownloader; +import org.sonar.batch.bootstrap.ServerClient; +import org.sonar.jpa.test.AbstractDbUnitTestCase; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +public class LastSnapshotsTest extends AbstractDbUnitTestCase { + + @Test + public void should_return_null_violations_if_no_last_snapshot() { + setupData("no_last_snapshot"); + ServerClient server = mock(ServerClient.class); + + LastSnapshots lastSnapshots = new LastSnapshots(new Settings(), getSession(), server); + + assertThat(lastSnapshots.getViolations(new File("org/foo", "Bar.c"))).isNull(); + verifyZeroInteractions(server); + } + + @Test + public void should_get_violations_of_last_snapshot() { + setupData("last_snapshot"); + ServerClient server = mock(ServerClient.class); + + LastSnapshots lastSnapshots = new LastSnapshots(new Settings(), getSession(), server); + + List<RuleFailureModel> violations = lastSnapshots.getViolations(newFile()); + assertThat(violations).hasSize(1); + assertThat(violations.get(0).getChecksum()).isEqualTo("ABCDE"); + verifyZeroInteractions(server); + } + + @Test + public void should_get_source_of_last_snapshot() { + setupData("last_snapshot"); + ServerClient server = mock(ServerClient.class); + + LastSnapshots lastSnapshots = new LastSnapshots(new Settings(), getSession(), server); + + assertThat(lastSnapshots.getSource(newFile())).isEqualTo("this is bar"); + verifyZeroInteractions(server); + } + + @Test + public void should_return_empty_source_if_no_last_snapshot() { + setupData("no_last_snapshot"); + ServerClient server = mock(ServerClient.class); + + LastSnapshots lastSnapshots = new LastSnapshots(new Settings(), getSession(), server); + + assertThat(lastSnapshots.getSource(newFile())).isEqualTo(""); + verifyZeroInteractions(server); + } + + @Test + public void should_download_source_from_ws_if_dry_run() { + setupData("last_snapshot"); + ServerClient server = mock(ServerClient.class); + when(server.request(anyString(), eq(false))).thenReturn("downloaded source of Bar.c"); + + Settings settings = new Settings(); + settings.setProperty(CoreProperties.DRY_RUN, true); + LastSnapshots lastSnapshots = new LastSnapshots(settings, getSession(), server); + + String source = lastSnapshots.getSource(newFile()); + assertThat(source).isEqualTo("downloaded source of Bar.c"); + verify(server).request("/api/sources?resource=myproject:org/foo/Bar.c&format=txt", false); + } + + @Test + public void should_return_empty_source_if_dry_run_and_no_last_snapshot() throws URISyntaxException { + setupData("last_snapshot"); + ServerClient server = mock(ServerClient.class); + when(server.request(anyString(), eq(false))).thenThrow(new HttpDownloader.HttpException(new URI(""), 404)); + + Settings settings = new Settings(); + settings.setProperty(CoreProperties.DRY_RUN, true); + LastSnapshots lastSnapshots = new LastSnapshots(settings, getSession(), server); + + String source = lastSnapshots.getSource(newFile()); + assertThat(source).isEqualTo(""); + verify(server).request("/api/sources?resource=myproject:org/foo/Bar.c&format=txt", false); + } + + private File newFile() { + File file = new File("org/foo", "Bar.c"); + file.setEffectiveKey("myproject:org/foo/Bar.c"); + return file; + } +} diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/LastSnapshotsTest/last_snapshot.xml b/sonar-batch/src/test/resources/org/sonar/batch/scan/LastSnapshotsTest/last_snapshot.xml new file mode 100644 index 00000000000..6cc2ea5b8a5 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/scan/LastSnapshotsTest/last_snapshot.xml @@ -0,0 +1,11 @@ +<dataset> + <projects id="100" kee="myproject:org/foo/Bar.c" enabled="[true]" scope="FIL" qualifier="FIL" language="c"/> + <snapshots id="1000" project_id="100" status="P" islast="[false]" purge_status="[null]"/> + <snapshots id="1100" project_id="100" status="P" islast="[true]" purge_status="[null]"/> + <snapshot_sources ID="10000" SNAPSHOT_ID="1100" DATA="this is bar"/> + <rule_failures ID="1000000" SNAPSHOT_ID="1100" RULE_ID="1" + switched_off="[null]" permanent_id="[null]" FAILURE_LEVEL="2" + MESSAGE="msg1" LINE="[null]" COST="[null]" + created_at="2008-12-02 13:58:00.00" + checksum="ABCDE" person_id="[null]"/> +</dataset>
\ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/scan/LastSnapshotsTest/no_last_snapshot.xml b/sonar-batch/src/test/resources/org/sonar/batch/scan/LastSnapshotsTest/no_last_snapshot.xml new file mode 100644 index 00000000000..84d67a04385 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/scan/LastSnapshotsTest/no_last_snapshot.xml @@ -0,0 +1,3 @@ +<dataset> + +</dataset>
\ No newline at end of file |