*/
package org.sonar.scm.svn;
+import com.google.common.annotations.VisibleForTesting;
import java.util.List;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.tmatesoft.svn.core.SVNAuthenticationException;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNClientManager;
}
}
- private static void blame(SVNClientManager clientManager, InputFile inputFile, BlameOutput output) {
+ @VisibleForTesting
+ void blame(SVNClientManager clientManager, InputFile inputFile, BlameOutput output) {
String filename = inputFile.relativePath();
LOG.debug("Process file {}", filename);
SVNLogClient logClient = clientManager.getLogClient();
logClient.setDiffOptions(new SVNDiffOptions(true, true, true));
logClient.doAnnotate(inputFile.file(), SVNRevision.UNDEFINED, SVNRevision.create(1), SVNRevision.BASE, true, true, handler, null);
+ } catch (SVNAuthenticationException e) {
+ if(configuration.isEmpty()) {
+ LOG.warn("Authentication to SVN server is required but no authentication data was passed to the scanner");
+ }
+ throw new IllegalStateException("Authentication error when executing blame for file " + filename, e);
} catch (SVNException e) {
throw new IllegalStateException("Error when executing blame for file " + filename, e);
}
import org.junit.runners.Parameterized.Parameters;
import org.mockito.ArgumentCaptor;
import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.scm.BlameCommand.BlameInput;
import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.tmatesoft.svn.core.SVNAuthenticationException;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc2.compat.SvnCodec;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNClientManager;
+import org.tmatesoft.svn.core.wc.SVNLogClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc.SVNStatus;
+import org.tmatesoft.svn.core.wc.SVNStatusClient;
+import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
import org.tmatesoft.svn.core.wc2.SvnCheckout;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.eq;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
@Rule
public ExpectedException thrown = ExpectedException.none();
+ @Rule
+ public LogTester logTester = new LogTester();
+
private FileSystem fs;
private BlameInput input;
private String serverVersion;
verifyNoInteractions(blameResult);
}
+ @Test
+ public void blame_givenNoCredentials_logWarning() throws Exception {
+ BlameOutput output = mock(BlameOutput.class);
+ InputFile inputFile = mock(InputFile.class);
+ SvnBlameCommand svnBlameCommand = newSvnBlameCommand();
+
+ SVNClientManager clientManager = mock(SVNClientManager.class);
+ SVNLogClient logClient = mock(SVNLogClient.class);
+ SVNStatusClient statusClient = mock(SVNStatusClient.class);
+ SVNStatus status = mock(SVNStatus.class);
+
+ when(clientManager.getLogClient()).thenReturn(logClient);
+ when(clientManager.getStatusClient()).thenReturn(statusClient);
+ when(status.getContentsStatus()).thenReturn(SVNStatusType.STATUS_NORMAL);
+ when(inputFile.file()).thenReturn(mock(File.class));
+ when(statusClient.doStatus(any(File.class), anyBoolean())).thenReturn(status);
+
+ doThrow(SVNAuthenticationException.class).when(logClient).doAnnotate(any(File.class), any(SVNRevision.class),
+ any(SVNRevision.class), any(SVNRevision.class), anyBoolean(), anyBoolean(), any(AnnotationHandler.class),
+ eq(null));
+
+ assertThrows(IllegalStateException.class, () -> {
+ svnBlameCommand.blame(clientManager, inputFile, output);
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Authentication to SVN server is required but no " +
+ "authentication data was passed to the scanner");
+ });
+
+ }
+
+ @Test
+ public void blame_givenCredentialsSupplied_doNotlogWarning() throws Exception {
+ BlameOutput output = mock(BlameOutput.class);
+ InputFile inputFile = mock(InputFile.class);
+ SvnConfiguration properties = mock(SvnConfiguration.class);
+ SvnBlameCommand svnBlameCommand = new SvnBlameCommand(properties);
+
+ SVNClientManager clientManager = mock(SVNClientManager.class);
+ SVNLogClient logClient = mock(SVNLogClient.class);
+ SVNStatusClient statusClient = mock(SVNStatusClient.class);
+ SVNStatus status = mock(SVNStatus.class);
+
+ when(properties.isEmpty()).thenReturn(true);
+ when(clientManager.getLogClient()).thenReturn(logClient);
+ when(clientManager.getStatusClient()).thenReturn(statusClient);
+ when(status.getContentsStatus()).thenReturn(SVNStatusType.STATUS_NORMAL);
+ when(inputFile.file()).thenReturn(mock(File.class));
+ when(statusClient.doStatus(any(File.class), anyBoolean())).thenReturn(status);
+
+ doThrow(SVNAuthenticationException.class).when(logClient).doAnnotate(any(File.class), any(SVNRevision.class),
+ any(SVNRevision.class), any(SVNRevision.class), anyBoolean(), anyBoolean(), any(AnnotationHandler.class),
+ eq(null));
+
+ assertThrows(IllegalStateException.class, () -> {
+ svnBlameCommand.blame(clientManager, inputFile, output);
+ assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
+ });
+
+ }
+
private static void javaUnzip(File zip, File toDir) {
try {
try (ZipFile zipFile = new ZipFile(zip)) {
import static org.assertj.core.api.Assertions.fail;
public class SvnConfigurationTest {
+
@Rule
public TemporaryFolder temp = new TemporaryFolder();
assertThat(e).hasMessageContaining("Unable to read private key from ");
}
}
+
+ @Test
+ public void isEmpty_givenNullProperties_returnTrue() {
+ MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE));
+
+ SvnConfiguration svnConfiguration = new SvnConfiguration(settings.asConfig());
+
+ assertThat(svnConfiguration.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void isEmpty_givenNotNullProperties_returnFalse() {
+ MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE));
+ settings.setProperty("sonar.svn.username", "bob");
+
+ SvnConfiguration svnConfiguration = new SvnConfiguration(settings.asConfig());
+
+ assertThat(svnConfiguration.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void isEmpty_givenAllNotNullProperties_returnFalse() {
+ MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE));
+ settings.setProperty("sonar.svn.username", "bob");
+ settings.setProperty("sonar.svn.privateKeyPath", "bob");
+ settings.setProperty("sonar.svn.passphrase.secured", "bob");
+
+ SvnConfiguration svnConfiguration = new SvnConfiguration(settings.asConfig());
+
+ assertThat(svnConfiguration.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void isEmpty_givenHalfNotNullProperties_returnFalse() {
+ MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE));
+ settings.setProperty("sonar.svn.password.secured", "bob");
+ settings.setProperty("sonar.svn.passphrase.secured", "bob");
+
+ SvnConfiguration svnConfiguration = new SvnConfiguration(settings.asConfig());
+
+ assertThat(svnConfiguration.isEmpty()).isFalse();
+ }
}