瀏覽代碼

Back compatibility with SQ 4.5

tags/2.5-rc1
Duarte Meneses 8 年之前
父節點
當前提交
bbee5baf55
共有 19 個檔案被更改,包括 672 行新增150 行删除
  1. 72
    82
      sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java
  2. 52
    0
      sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListenerAdapter.java
  3. 60
    0
      sonar-runner-api/src/main/java/org/sonar/runner/api/LoggerAdapter.java
  4. 0
    33
      sonar-runner-api/src/main/java/org/sonar/runner/api/ProcessMonitor.java
  5. 1
    0
      sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java
  6. 62
    0
      sonar-runner-api/src/main/java/org/sonar/runner/impl/ClassloadRules.java
  7. 2
    0
      sonar-runner-api/src/main/java/org/sonar/runner/impl/InternalProperties.java
  8. 4
    6
      sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedClassloader.java
  9. 14
    6
      sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java
  10. 115
    0
      sonar-runner-api/src/main/java/org/sonar/runner/impl/SimulatedLauncher.java
  11. 34
    11
      sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java
  12. 53
    0
      sonar-runner-api/src/test/java/org/sonar/runner/api/IssueListenerAdapterTest.java
  13. 76
    0
      sonar-runner-api/src/test/java/org/sonar/runner/api/LoggerAdapterTest.java
  14. 106
    0
      sonar-runner-api/src/test/java/org/sonar/runner/impl/ClassloadRulesTest.java
  15. 3
    2
      sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedClassloaderTest.java
  16. 4
    2
      sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java
  17. 2
    1
      sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java
  18. 11
    6
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java
  19. 1
    1
      sonar-runner-batch/src/test/java/org/sonar/runner/batch/IsolatedLauncherTest.java

+ 72
- 82
sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java 查看文件

@@ -19,13 +19,17 @@
*/
package org.sonar.runner.api;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.sonar.runner.impl.ClassloadRules;

import java.nio.charset.Charset;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;

import javax.annotation.Nullable;

@@ -44,12 +48,16 @@ public class EmbeddedRunner {
private IsolatedLauncher launcher;
private final LogOutput logOutput;
private final Properties globalProperties = new Properties();
private final List<Object> extensions = new ArrayList<>();
private final Logger logger;
private final Set<String> classloaderMask = new HashSet<>();
private final Set<String> classloaderUnmask = new HashSet<>();

EmbeddedRunner(IsolatedLauncherFactory bl, Logger logger, LogOutput logOutput) {
this.logger = logger;
this.launcherFactory = bl;
this.logOutput = logOutput;
this.classloaderUnmask.add("org.sonar.runner.batch.");
}

public static EmbeddedRunner create(final LogOutput logOutput) {
@@ -63,8 +71,22 @@ public class EmbeddedRunner {
return clone;
}

public EmbeddedRunner unmask(String fqcnPrefix) {
checkLauncherDoesntExist();
classloaderUnmask.add(fqcnPrefix);
return this;
}

public EmbeddedRunner mask(String fqcnPrefix) {
checkLauncherDoesntExist();
classloaderMask.add(fqcnPrefix);
return this;
}

/**
* Declare Sonar properties, for example sonar.projectKey=>foo.
* These might be used at different stages (on {@link #start() or #runAnalysis(Properties)}, depending on the
* property and SQ version.
*
* @see #setProperty(String, String)
*/
@@ -75,6 +97,8 @@ public class EmbeddedRunner {

/**
* Declare a SonarQube property.
* These might be used at different stages (on {@link #start() or #runAnalysis(Properties)}, depending on the
* property and SQ version.
*
* @see RunnerProperties
* @see ScanProperties
@@ -101,30 +125,51 @@ public class EmbeddedRunner {
return globalProperty(InternalProperties.RUNNER_APP, null);
}

/**
* Add extensions to the batch's object container.
* Only supported until SQ 5.1. For more recent versions, an exception is thrown
* @param objs
*/
public EmbeddedRunner addExtensions(Object... objs) {
checkLauncherExists();
if (VersionUtils.isAtLeast52(launcher.getVersion())) {
throw new IllegalStateException("not supported in current SonarQube version: " + launcher.getVersion());
}

extensions.addAll(Arrays.asList(objs));
return this;
}

public String appVersion() {
return globalProperty(InternalProperties.RUNNER_APP_VERSION, null);
}

/**
* Launch an analysis.
* Runner must have been started - see {@link #start()}.
*/
public void runAnalysis(Properties analysisProperties) {
runAnalysis(analysisProperties, null);
}

/**
* Launch an analysis, providing optionally a issue listener.
* Runner must have been started - see {@link #start()}.
* Issue listener is supported starting in SQ 5.2. If a non-null listener is given for older versions, an exception is thrown
*/
public void runAnalysis(Properties analysisProperties, @Nullable IssueListener issueListener) {
checkLauncherExists();
Properties copy = new Properties();
copy.putAll(analysisProperties);
initAnalysisProperties(copy);

String dumpToFile = copy.getProperty(InternalProperties.RUNNER_DUMP_TO_FILE);
if (dumpToFile != null) {
File dumpFile = new File(dumpToFile);
Utils.writeProperties(dumpFile, copy);
logger.info("Simulation mode. Configuration written to " + dumpFile.getAbsolutePath());
} else {
doExecute(copy, issueListener);
}
doExecute(copy, issueListener);
}

/**
* Synchronizes the project's data in the local cache with the server, allowing analysis of the project to be done offline.
* Runner must have been started - see {@link #start()}.
* Only supported starting in SQ 5.2. For older versions, an exception is thrown
*/
public void syncProject(String projectKey) {
checkLauncherExists();
if (!VersionUtils.isAtLeast52(launcher.getVersion())) {
@@ -142,16 +187,19 @@ public class EmbeddedRunner {
doStart(forceSync);
}

/**
* Stops the batch.
* Only supported starting in SQ 5.2. For older versions, this is a no-op.
*/
public void stop() {
checkLauncherExists();
doStop();
}
public String serverVersion() {
checkLauncherExists();
return launcher.getVersion();
}

/**
* @deprecated since 2.5 use {@link #start()}, {@link #runAnalysis(Properties)} and then {@link #stop()}
@@ -196,7 +244,9 @@ public class EmbeddedRunner {
}

protected void doStart(boolean forceSync) {
launcher = launcherFactory.createLauncher(globalProperties());
checkLauncherDoesntExist();
ClassloadRules rules = new ClassloadRules(classloaderMask, classloaderUnmask);
launcher = launcherFactory.createLauncher(globalProperties(), rules);
if (VersionUtils.isAtLeast52(launcher.getVersion())) {
launcher.start(globalProperties(), new org.sonar.runner.batch.LogOutput() {

@@ -212,6 +262,7 @@ public class EmbeddedRunner {
protected void doStop() {
if (VersionUtils.isAtLeast52(launcher.getVersion())) {
launcher.stop();
launcher = null;
}
}

@@ -229,80 +280,19 @@ public class EmbeddedRunner {
Properties prop = new Properties();
prop.putAll(globalProperties());
prop.putAll(analysisProperties);
launcher.executeOldVersion(prop);
launcher.executeOldVersion(prop, extensions);
}
}
private void checkLauncherExists() {
if(launcher == null) {
if (launcher == null) {
throw new IllegalStateException("not started");
}
}

static class IssueListenerAdapter implements org.sonar.runner.batch.IssueListener {
private IssueListener apiIssueListener;

public IssueListenerAdapter(IssueListener apiIssueListener) {
this.apiIssueListener = apiIssueListener;
}

@Override
public void handle(org.sonar.runner.batch.IssueListener.Issue issue) {
apiIssueListener.handle(transformIssue(issue));
}

private static org.sonar.runner.api.Issue transformIssue(org.sonar.runner.batch.IssueListener.Issue batchIssue) {
org.sonar.runner.api.Issue.Builder issueBuilder = org.sonar.runner.api.Issue.builder();

issueBuilder.setAssigneeLogin(batchIssue.getAssigneeLogin());
issueBuilder.setAssigneeName(batchIssue.getAssigneeName());
issueBuilder.setComponentKey(batchIssue.getComponentKey());
issueBuilder.setKey(batchIssue.getKey());
issueBuilder.setLine(batchIssue.getLine());
issueBuilder.setMessage(batchIssue.getMessage());
issueBuilder.setNew(batchIssue.isNew());
issueBuilder.setResolution(batchIssue.getResolution());
issueBuilder.setRuleKey(batchIssue.getRuleKey());
issueBuilder.setRuleName(batchIssue.getRuleName());
issueBuilder.setSeverity(batchIssue.getSeverity());
issueBuilder.setStatus(batchIssue.getStatus());

return issueBuilder.build();
}
}

private static class LoggerAdapter implements Logger {
private LogOutput logOutput;

LoggerAdapter(LogOutput logOutput) {
this.logOutput = logOutput;
}

@Override
public void warn(String msg) {
logOutput.log(msg, LogOutput.Level.WARN);
}

@Override
public void info(String msg) {
logOutput.log(msg, LogOutput.Level.INFO);
}

@Override
public void error(String msg, Throwable t) {
StringWriter errors = new StringWriter();
t.printStackTrace(new PrintWriter(errors));
logOutput.log(msg + "\n" + errors.toString(), LogOutput.Level.ERROR);
}

@Override
public void error(String msg) {
logOutput.log(msg, LogOutput.Level.ERROR);
}

@Override
public void debug(String msg) {
logOutput.log(msg, LogOutput.Level.DEBUG);
private void checkLauncherDoesntExist() {
if (launcher != null) {
throw new IllegalStateException("already started");
}
}
}

+ 52
- 0
sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListenerAdapter.java 查看文件

@@ -0,0 +1,52 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.api;

class IssueListenerAdapter implements org.sonar.runner.batch.IssueListener {
private IssueListener apiIssueListener;

public IssueListenerAdapter(IssueListener apiIssueListener) {
this.apiIssueListener = apiIssueListener;
}

@Override
public void handle(org.sonar.runner.batch.IssueListener.Issue issue) {
apiIssueListener.handle(transformIssue(issue));
}

private static org.sonar.runner.api.Issue transformIssue(org.sonar.runner.batch.IssueListener.Issue batchIssue) {
org.sonar.runner.api.Issue.Builder issueBuilder = org.sonar.runner.api.Issue.builder();

issueBuilder.setAssigneeLogin(batchIssue.getAssigneeLogin());
issueBuilder.setAssigneeName(batchIssue.getAssigneeName());
issueBuilder.setComponentKey(batchIssue.getComponentKey());
issueBuilder.setKey(batchIssue.getKey());
issueBuilder.setLine(batchIssue.getLine());
issueBuilder.setMessage(batchIssue.getMessage());
issueBuilder.setNew(batchIssue.isNew());
issueBuilder.setResolution(batchIssue.getResolution());
issueBuilder.setRuleKey(batchIssue.getRuleKey());
issueBuilder.setRuleName(batchIssue.getRuleName());
issueBuilder.setSeverity(batchIssue.getSeverity());
issueBuilder.setStatus(batchIssue.getStatus());

return issueBuilder.build();
}
}

+ 60
- 0
sonar-runner-api/src/main/java/org/sonar/runner/api/LoggerAdapter.java 查看文件

@@ -0,0 +1,60 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.api;

import org.sonar.home.cache.Logger;

import java.io.PrintWriter;
import java.io.StringWriter;

class LoggerAdapter implements Logger {
private LogOutput logOutput;

LoggerAdapter(LogOutput logOutput) {
this.logOutput = logOutput;
}

@Override
public void warn(String msg) {
logOutput.log(msg, LogOutput.Level.WARN);
}

@Override
public void info(String msg) {
logOutput.log(msg, LogOutput.Level.INFO);
}

@Override
public void error(String msg, Throwable t) {
StringWriter errors = new StringWriter();
t.printStackTrace(new PrintWriter(errors));
logOutput.log(msg + "\n" + errors.toString(), LogOutput.Level.ERROR);
}

@Override
public void error(String msg) {
logOutput.log(msg, LogOutput.Level.ERROR);
}

@Override
public void debug(String msg) {
logOutput.log(msg, LogOutput.Level.DEBUG);
}
}

+ 0
- 33
sonar-runner-api/src/main/java/org/sonar/runner/api/ProcessMonitor.java 查看文件

@@ -1,33 +0,0 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.api;

/**
* To be used with {@link ForkedRunner}
* @since 2.3
*/
public interface ProcessMonitor {

/**
* {@link ForkedRunner} will poll this method periodically and if true is returned
* then forked SonarQube Runner process will be killed.
*/
boolean stop();
}

+ 1
- 0
sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java 查看文件

@@ -32,6 +32,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;

import javax.annotation.Nullable;

class Utils {

+ 62
- 0
sonar-runner-api/src/main/java/org/sonar/runner/impl/ClassloadRules.java 查看文件

@@ -0,0 +1,62 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.impl;

import javax.annotation.concurrent.Immutable;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Immutable
public class ClassloadRules {
private final List<String> mask;
private final List<String> unmask;

public ClassloadRules(Set<String> maskRules, Set<String> unmaskRules) {
this.mask = new ArrayList<>(maskRules);
this.unmask = new ArrayList<>(unmaskRules);
}

public boolean canLoad(String className) {
// if there is a tie -> block it
return unmaskSize(className) > maskSize(className);
}

private int maskSize(String className) {
return findBestMatch(mask, className);
}

private int unmaskSize(String className) {
return findBestMatch(unmask, className);
}

private static int findBestMatch(List<String> list, String name) {
// there can be a match of 0 ("")
int bestMatch = -1;
for (String s : list) {
if (name.startsWith(s) && s.length() > bestMatch) {
bestMatch = s.length();
}
}

return bestMatch;
}
}

+ 2
- 0
sonar-runner-api/src/main/java/org/sonar/runner/impl/InternalProperties.java 查看文件

@@ -23,4 +23,6 @@ public interface InternalProperties {
String RUNNER_APP = "sonarRunner.app";
String RUNNER_APP_VERSION = "sonarRunner.appVersion";
String RUNNER_DUMP_TO_FILE = "sonarRunner.dumpToFile";
String RUNNER_VERSION_SIMULATION = "sonarRunner.versionSimulation";
String RUNNER_MASK_RULES = "sonarRunner.maskRules";
}

+ 4
- 6
sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedClassloader.java 查看文件

@@ -31,12 +31,14 @@ import java.util.List;
* Special {@link java.net.URLClassLoader} to execute batch, which restricts loading from parent.
*/
class IsolatedClassloader extends URLClassLoader {
private final ClassloadRules rules;

/**
* The parent classloader is used only for loading classes and resources in unmasked packages
*/
IsolatedClassloader(ClassLoader parent) {
IsolatedClassloader(ClassLoader parent, ClassloadRules rules) {
super(new URL[0], parent);
this.rules = rules;
}

void addFiles(List<File> files) {
@@ -59,7 +61,7 @@ class IsolatedClassloader extends URLClassLoader {
if (c == null) {
try {
// Load from parent
if (getParent() != null && fromSonarBatchPackage(name)) {
if (getParent() != null && rules.canLoad(name)) {
c = getParent().loadClass(name);
} else {

@@ -86,10 +88,6 @@ class IsolatedClassloader extends URLClassLoader {
return c;
}

private static boolean fromSonarBatchPackage(String name) {
return name.startsWith("org.sonar.runner.batch");
}

/**
* Unlike {@link java.net.URLClassLoader#getResource(String)} don't return resource from parent.
* See http://jira.codehaus.org/browse/SONAR-2276

+ 14
- 6
sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java 查看文件

@@ -24,6 +24,7 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import java.util.Properties;

import org.sonar.home.cache.Logger;
import org.sonar.home.cache.PersistentCache;
import org.sonar.home.cache.PersistentCacheBuilder;
@@ -53,28 +54,35 @@ public class IsolatedLauncherFactory {
return builder.build();
}

private ClassLoader createClassLoader(List<File> jarFiles) {
IsolatedClassloader classloader = new IsolatedClassloader(getClass().getClassLoader());
private ClassLoader createClassLoader(List<File> jarFiles, ClassloadRules maskRules) {
IsolatedClassloader classloader = new IsolatedClassloader(getClass().getClassLoader(), maskRules);
classloader.addFiles(jarFiles);

return classloader;
}

public IsolatedLauncher createLauncher(Properties props) {
public IsolatedLauncher createLauncher(Properties props, ClassloadRules rules) {
if (props.containsKey(InternalProperties.RUNNER_DUMP_TO_FILE)) {
String version = props.getProperty(InternalProperties.RUNNER_VERSION_SIMULATION);
if (version == null) {
version = "5.2";
}
return new SimulatedLauncher(version, logger);
}
ServerConnection serverConnection = ServerConnection.create(props, getCache(props), logger);
JarDownloader jarDownloader = new JarDownloader(serverConnection, logger);

return createLauncher(jarDownloader);
return createLauncher(jarDownloader, rules);
}

IsolatedLauncher createLauncher(final JarDownloader jarDownloader) {
IsolatedLauncher createLauncher(final JarDownloader jarDownloader, final ClassloadRules rules) {
return AccessController.doPrivileged(new PrivilegedAction<IsolatedLauncher>() {
@Override
public IsolatedLauncher run() {
try {
List<File> jarFiles = jarDownloader.download();
logger.debug("Create isolated classloader...");
ClassLoader cl = createClassLoader(jarFiles);
ClassLoader cl = createClassLoader(jarFiles, rules);
IsolatedLauncher objProxy = IsolatedLauncherProxy.create(cl, IsolatedLauncher.class, launcherImplClassName, logger);
tempCleaning.clean();


+ 115
- 0
sonar-runner-api/src/main/java/org/sonar/runner/impl/SimulatedLauncher.java 查看文件

@@ -0,0 +1,115 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.impl;

import org.sonar.home.cache.Logger;

import javax.annotation.Nullable;

import org.sonar.runner.batch.IssueListener;
import org.sonar.runner.batch.LogOutput;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Properties;

import org.sonar.runner.batch.IsolatedLauncher;

public class SimulatedLauncher implements IsolatedLauncher {
private final String version;
private final Logger logger;
private Properties globalProperties;

SimulatedLauncher(String version, Logger logger) {
this.version = version;
this.logger = logger;
}

@Override
public void start(Properties properties, LogOutput logOutput, boolean forceSync) {
globalProperties = properties;
}

@Override
public void stop() {
globalProperties = null;
}

@Override
public void execute(Properties properties) {
dumpProperties(globalProperties, properties);
}

@Override
public void execute(Properties properties, IssueListener listener) {
dumpProperties(globalProperties, properties);
}

private void dumpProperties(@Nullable Properties global, Properties analysis) {
// for old versions, analysis will have global properties merged in it
String filePath;
String filePathGlobal = null;
if (global != null) {
filePath = global.getProperty(InternalProperties.RUNNER_DUMP_TO_FILE);
filePathGlobal = filePath + ".global";
} else {
filePath = analysis.getProperty(InternalProperties.RUNNER_DUMP_TO_FILE);
}

if (filePath == null) {
throw new IllegalStateException("No file to dump properties");
}

if (global != null) {
File dumpFileGlobal = new File(filePathGlobal);
writeProperties(dumpFileGlobal, global, "global properties");
}

File dumpFile = new File(filePath);
writeProperties(dumpFile, analysis, "analysis properties");
logger.info("Simulation mode. Configuration written to " + dumpFile.getAbsolutePath());
}

private static void writeProperties(File outputFile, Properties p, String comment) {
try (OutputStream output = new FileOutputStream(outputFile)) {
p.store(output, "Generated by sonar-runner - " + comment);
} catch (Exception e) {
throw new IllegalStateException("Fail to export sonar-runner properties", e);
}
}

@Override
public void syncProject(String projectKey) {
// no op
}

@Override
public void executeOldVersion(Properties properties, List<Object> extensions) {
dumpProperties(null, properties);
}

@Override
public String getVersion() {
return version;
}

}

+ 34
- 11
sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java 查看文件

@@ -19,9 +19,9 @@
*/
package org.sonar.runner.api;

import org.junit.rules.ExpectedException;
import org.sonar.runner.impl.ClassloadRules;

import org.sonar.runner.api.EmbeddedRunner.IssueListenerAdapter;
import org.junit.rules.ExpectedException;

import java.io.File;
import java.io.FileInputStream;
@@ -31,6 +31,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import static org.mockito.Matchers.eq;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -68,7 +69,7 @@ public class EmbeddedRunnerTest {
batchLauncher = mock(IsolatedLauncherFactory.class);
launcher = mock(IsolatedLauncher.class);
when(launcher.getVersion()).thenReturn("5.2");
when(batchLauncher.createLauncher(any(Properties.class))).thenReturn(launcher);
when(batchLauncher.createLauncher(any(Properties.class), any(ClassloadRules.class))).thenReturn(launcher);
runner = new EmbeddedRunner(batchLauncher, mock(Logger.class), mock(LogOutput.class));
}

@@ -79,18 +80,18 @@ public class EmbeddedRunnerTest {
runner.syncProject(projectKey);
verify(launcher).syncProject(projectKey);
}
@Test
public void test_server_version() {
runner.start();
assertThat(runner.serverVersion()).isEqualTo("5.2");
}
@Test
public void test_run_before_start() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("started");
runner.runAnalysis(new Properties());
}

@@ -130,7 +131,7 @@ public class EmbeddedRunnerTest {
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}));
}), any(ClassloadRules.class));

// it should have added a few properties to analysisProperties, and have merged global props
final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir",
@@ -147,7 +148,7 @@ public class EmbeddedRunnerTest {
}
return true;
}
}));
}), eq(new LinkedList<>()));
}

@Test
@@ -179,7 +180,7 @@ public class EmbeddedRunnerTest {
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}));
}), any(ClassloadRules.class));

// it should have added a few properties to analysisProperties
final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir"};
@@ -247,7 +248,7 @@ public class EmbeddedRunnerTest {
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}));
}), any(ClassloadRules.class));

verify(launcher).execute(argThat(new ArgumentMatcher<Properties>() {
@Override
@@ -259,11 +260,14 @@ public class EmbeddedRunnerTest {

@Test
public void should_launch_in_simulation_mode() throws IOException {
batchLauncher = new IsolatedLauncherFactory(mock(Logger.class));
runner = new EmbeddedRunner(batchLauncher, mock(Logger.class), mock(LogOutput.class));

File dump = temp.newFile();
Properties p = new Properties();

p.setProperty("sonar.projectKey", "foo");
p.setProperty("sonarRunner.dumpToFile", dump.getAbsolutePath());
runner.setGlobalProperty("sonarRunner.dumpToFile", dump.getAbsolutePath());
runner.start();
runner.runAnalysis(p);
runner.stop();
@@ -282,6 +286,25 @@ public class EmbeddedRunnerTest {
assertThat(p.getProperty("sonar.sourceEncoding", null)).isEqualTo(Charset.defaultCharset().name());
}

@Test
public void invalidate_after_stop() {
runner.start();
runner.stop();

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("started");
runner.runAnalysis(new Properties());
}
@Test
public void cannot_start_twice() {
runner.start();

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("started");
runner.start();
}

@Test
public void should_use_parameterized_encoding() throws Exception {
Properties p = new Properties();

+ 53
- 0
sonar-runner-api/src/test/java/org/sonar/runner/api/IssueListenerAdapterTest.java 查看文件

@@ -0,0 +1,53 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.api;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;

import org.mockito.ArgumentCaptor;

import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.mock;

public class IssueListenerAdapterTest {
private IssueListenerAdapter adapter;
private IssueListener issueListener;

@Before
public void setUp() {
issueListener = mock(IssueListener.class);
adapter = new IssueListenerAdapter(issueListener);
}

@Test
public void test() {
org.sonar.runner.batch.IssueListener.Issue issue = new org.sonar.runner.batch.IssueListener.Issue();

issue.setAssigneeName("dummy");
adapter.handle(issue);

ArgumentCaptor<Issue> argument = ArgumentCaptor.forClass(Issue.class);
verify(issueListener).handle(argument.capture());

assertThat(argument.getValue().getAssigneeName()).isEqualTo("dummy");
}
}

+ 76
- 0
sonar-runner-api/src/test/java/org/sonar/runner/api/LoggerAdapterTest.java 查看文件

@@ -0,0 +1,76 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.api;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Matchers.eq;

import static org.mockito.Matchers.startsWith;

import org.junit.Test;
import org.junit.Before;

public class LoggerAdapterTest {
private LoggerAdapter adapter;
private LogOutput logOutput;

@Before
public void setUp() {
logOutput = mock(LogOutput.class);
adapter = new LoggerAdapter(logOutput);
}

@Test
public void testDebug() {
adapter.debug("debug");
verify(logOutput).log("debug", LogOutput.Level.DEBUG);
verifyNoMoreInteractions(logOutput);
}
@Test
public void testInfo() {
adapter.info("info");
verify(logOutput).log("info", LogOutput.Level.INFO);
verifyNoMoreInteractions(logOutput);
}
@Test
public void testWarn() {
adapter.warn("warn");
verify(logOutput).log("warn", LogOutput.Level.WARN);
verifyNoMoreInteractions(logOutput);
}
@Test
public void testError() {
adapter.error("error");
verify(logOutput).log("error", LogOutput.Level.ERROR);
verifyNoMoreInteractions(logOutput);
}
@Test
public void testErrorThrowable() {
adapter.error("error", new IllegalStateException("error"));
verify(logOutput).log(startsWith("error\njava.lang.IllegalStateException: error"), eq(LogOutput.Level.ERROR));
verifyNoMoreInteractions(logOutput);
}
}

+ 106
- 0
sonar-runner-api/src/test/java/org/sonar/runner/impl/ClassloadRulesTest.java 查看文件

@@ -0,0 +1,106 @@
/*
* SonarQube Runner - API
* Copyright (C) 2011 SonarSource
* sonarqube@googlegroups.com
*
* This program 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.
*
* This program 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 02
*/
package org.sonar.runner.impl;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.HashSet;
import java.util.Set;

import org.junit.Test;
import org.junit.Before;

public class ClassloadRulesTest {
private ClassloadRules rules;
private Set<String> maskRules;
private Set<String> unmaskRules;

@Before
public void setUp() {
maskRules = new HashSet<>();
unmaskRules = new HashSet<>();
}

@Test
public void testUnmask() {
unmaskRules.add("org.apache.ant.");
rules = new ClassloadRules(maskRules, unmaskRules);

assertThat(rules.canLoad("org.sonar.runner.Foo")).isFalse();
assertThat(rules.canLoad("org.objectweb.asm.ClassVisitor")).isFalse();
assertThat(rules.canLoad("org.apache")).isFalse();

assertThat(rules.canLoad("org.apache.ant.Foo")).isTrue();
assertThat(rules.canLoad("org.apache.ant.project.Project")).isTrue();
}
@Test
public void testUnmaskAll() {
unmaskRules.add("");
rules = new ClassloadRules(maskRules, unmaskRules);
assertThat(rules.canLoad("org.sonar.runner.Foo")).isTrue();
assertThat(rules.canLoad("org.objectweb.asm.ClassVisitor")).isTrue();
assertThat(rules.canLoad("org.apache")).isTrue();

assertThat(rules.canLoad("org.apache.ant.Foo")).isTrue();
assertThat(rules.canLoad("org.apache.ant.project.Project")).isTrue();
}

@Test
public void testDefault() {
rules = new ClassloadRules(maskRules, unmaskRules);
assertThat(rules.canLoad("org.sonar.runner.Foo")).isFalse();
}

@Test
public void testMaskAndUnmask() throws ClassNotFoundException {
unmaskRules.add("org.apache.ant.");
maskRules.add("org.apache.ant.foo.");
rules = new ClassloadRules(maskRules, unmaskRules);

assertThat(rules.canLoad("org.apache.ant.something")).isTrue();
assertThat(rules.canLoad("org.apache.ant.foo.something")).isFalse();
assertThat(rules.canLoad("org.apache")).isFalse();
}
@Test
public void testUsedByMaven() {
maskRules.add( "org.slf4j.LoggerFactory" );
// Include slf4j Logger that is exposed by some Sonar components
unmaskRules.add( "org.slf4j.Logger" );
unmaskRules.add( "org.slf4j.ILoggerFactory" );
// Exclude other slf4j classes
// .unmask("org.slf4j.impl.")
maskRules.add( "org.slf4j." );
// Exclude logback
maskRules.add( "ch.qos.logback." );
maskRules.add( "org.sonar." );
unmaskRules.add("org.sonar.runner.batch.");
// Guava is not the same version in SonarQube classloader
maskRules.add( "com.google.common" );
// Include everything else
unmaskRules.add( "" );
rules = new ClassloadRules(maskRules, unmaskRules);
assertThat(rules.canLoad("org.sonar.runner.batch.IsolatedLauncher")).isTrue();
}
}

+ 3
- 2
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedClassloaderTest.java 查看文件

@@ -20,10 +20,11 @@
package org.sonar.runner.impl;

import java.io.IOException;
import java.util.HashSet;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.fest.assertions.Assertions.assertThat;

public class IsolatedClassloaderTest {
@@ -35,7 +36,7 @@ public class IsolatedClassloaderTest {
thrown.expect(ClassNotFoundException.class);
thrown.expectMessage("org.junit.Test");
ClassLoader parent = getClass().getClassLoader();
IsolatedClassloader classLoader = new IsolatedClassloader(parent);
IsolatedClassloader classLoader = new IsolatedClassloader(parent, new ClassloadRules(new HashSet<String>(), new HashSet<String>()));

// JUnit is available in the parent classloader (classpath used to execute this test) but not in the core JVM
assertThat(classLoader.loadClass("java.lang.String", false)).isNotNull();

+ 4
- 2
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java 查看文件

@@ -21,6 +21,8 @@ package org.sonar.runner.impl;

import org.sonar.runner.batch.IssueListener;

import java.util.HashSet;
import java.util.List;
import java.util.Properties;

import org.junit.Before;
@@ -48,7 +50,7 @@ public class IsolatedLauncherFactoryTest {
@Test
public void should_use_isolated_classloader() {
try {
factory.createLauncher(jarDownloader);
factory.createLauncher(jarDownloader, new ClassloadRules(new HashSet<String>(), new HashSet<String>()));
fail();
} catch (RunnerException e) {
// success
@@ -73,7 +75,7 @@ public class IsolatedLauncherFactoryTest {
}

@Override
public void executeOldVersion(Properties properties) {
public void executeOldVersion(Properties properties, List<Object> extensions) {
}

@Override

+ 2
- 1
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java 查看文件

@@ -19,6 +19,7 @@
*/
package org.sonar.runner.batch;

import java.util.List;
import java.util.Properties;

public interface IsolatedLauncher {
@@ -33,7 +34,7 @@ public interface IsolatedLauncher {
void syncProject(String projectKey);
void executeOldVersion(Properties properties);
void executeOldVersion(Properties properties, List<Object> extensions);

String getVersion();


+ 11
- 6
sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java 查看文件

@@ -24,8 +24,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.picocontainer.annotations.Nullable;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
@@ -35,12 +37,11 @@ import org.sonar.batch.bootstrapper.EnvironmentInformation;
* the same version of sonar-batch as the server.
*/
public class BatchIsolatedLauncher implements IsolatedLauncher {

private Batch batch = null;

@Override
public void start(Properties globalProperties, org.sonar.runner.batch.LogOutput logOutput, boolean forceSync) {
batch = createBatch(globalProperties, logOutput);
batch = createBatch(globalProperties, logOutput, null);
batch.start(forceSync);
}

@@ -65,12 +66,16 @@ public class BatchIsolatedLauncher implements IsolatedLauncher {
batch.syncProject(projectKey);
}

Batch createBatch(Properties properties, @Nullable final org.sonar.runner.batch.LogOutput logOutput) {
Batch createBatch(Properties properties, @Nullable final org.sonar.runner.batch.LogOutput logOutput, @Nullable List<Object> extensions) {
EnvironmentInformation env = new EnvironmentInformation(properties.getProperty("sonarRunner.app"), properties.getProperty("sonarRunner.appVersion"));
Batch.Builder builder = Batch.builder()
.setEnvironment(env)
.setBootstrapProperties((Map) properties);

if (extensions != null) {
builder.addComponents(extensions);
}

if (logOutput != null) {
// Do that is a separate class to avoid NoClassDefFoundError for org/sonar/batch/bootstrapper/LogOutput
Compatibility.setLogOutputFor5dot2(builder, logOutput);
@@ -83,10 +88,10 @@ public class BatchIsolatedLauncher implements IsolatedLauncher {
* This method exists for backward compatibility with SonarQube < 5.2.
*/
@Override
public void executeOldVersion(Properties properties) {
createBatch(properties, null).execute();
public void executeOldVersion(Properties properties, List<Object> extensions) {
createBatch(properties, null, extensions).execute();
}
@Override
public String getVersion() {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sq-version.txt");

+ 1
- 1
sonar-runner-batch/src/test/java/org/sonar/runner/batch/IsolatedLauncherTest.java 查看文件

@@ -37,7 +37,7 @@ public class IsolatedLauncherTest {
props.setProperty("sonar.projectName", "Sample");
props.setProperty("sonar.projectVersion", "1.0");
props.setProperty("sonar.sources", "src");
Batch batch = launcher.createBatch(props, null);
Batch batch = launcher.createBatch(props, null, null);

assertThat(batch).isNotNull();
}

Loading…
取消
儲存