Browse Source

Extract SonarQube Scanner as a separate project

tags/2.5-rc1
Julien HENRY 8 years ago
parent
commit
5a8d95da69
100 changed files with 127 additions and 7713 deletions
  1. 0
    0
      assembly.xml
  2. 127
    95
      pom.xml
  3. 0
    215
      sonar-runner-api/pom.xml
  4. 0
    78
      sonar-runner-api/src/main/java/org/sonar/runner/api/Dirs.java
  5. 0
    299
      sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java
  6. 0
    290
      sonar-runner-api/src/main/java/org/sonar/runner/api/Issue.java
  7. 0
    24
      sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListener.java
  8. 0
    55
      sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListenerAdapter.java
  9. 0
    29
      sonar-runner-api/src/main/java/org/sonar/runner/api/LogOutput.java
  10. 0
    61
      sonar-runner-api/src/main/java/org/sonar/runner/api/LoggerAdapter.java
  11. 0
    45
      sonar-runner-api/src/main/java/org/sonar/runner/api/RunnerProperties.java
  12. 0
    48
      sonar-runner-api/src/main/java/org/sonar/runner/api/RunnerVersion.java
  13. 0
    79
      sonar-runner-api/src/main/java/org/sonar/runner/api/ScanProperties.java
  14. 0
    39
      sonar-runner-api/src/main/java/org/sonar/runner/api/StdOutLogOutput.java
  15. 0
    123
      sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java
  16. 0
    24
      sonar-runner-api/src/main/java/org/sonar/runner/api/package-info.java
  17. 0
    84
      sonar-runner-api/src/main/java/org/sonar/runner/cache/DeleteFileOnCloseInputStream.java
  18. 0
    106
      sonar-runner-api/src/main/java/org/sonar/runner/cache/DirectoryLock.java
  19. 0
    159
      sonar-runner-api/src/main/java/org/sonar/runner/cache/FileCache.java
  20. 0
    60
      sonar-runner-api/src/main/java/org/sonar/runner/cache/FileCacheBuilder.java
  21. 0
    73
      sonar-runner-api/src/main/java/org/sonar/runner/cache/FileHashes.java
  22. 0
    34
      sonar-runner-api/src/main/java/org/sonar/runner/cache/Logger.java
  23. 0
    281
      sonar-runner-api/src/main/java/org/sonar/runner/cache/PersistentCache.java
  24. 0
    110
      sonar-runner-api/src/main/java/org/sonar/runner/cache/PersistentCacheBuilder.java
  25. 0
    27
      sonar-runner-api/src/main/java/org/sonar/runner/cache/PersistentCacheInvalidation.java
  26. 0
    48
      sonar-runner-api/src/main/java/org/sonar/runner/cache/TTLCacheInvalidation.java
  27. 0
    25
      sonar-runner-api/src/main/java/org/sonar/runner/cache/package-info.java
  28. 0
    62
      sonar-runner-api/src/main/java/org/sonar/runner/impl/ClassloadRules.java
  29. 0
    28
      sonar-runner-api/src/main/java/org/sonar/runner/impl/InternalProperties.java
  30. 0
    109
      sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedClassloader.java
  31. 0
    105
      sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java
  32. 0
    86
      sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherProxy.java
  33. 0
    42
      sonar-runner-api/src/main/java/org/sonar/runner/impl/JarDownloader.java
  34. 0
    41
      sonar-runner-api/src/main/java/org/sonar/runner/impl/JarExtractor.java
  35. 0
    110
      sonar-runner-api/src/main/java/org/sonar/runner/impl/Jars.java
  36. 0
    28
      sonar-runner-api/src/main/java/org/sonar/runner/impl/RunnerException.java
  37. 0
    218
      sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java
  38. 0
    113
      sonar-runner-api/src/main/java/org/sonar/runner/impl/SimulatedLauncher.java
  39. 0
    66
      sonar-runner-api/src/main/java/org/sonar/runner/impl/TempCleaning.java
  40. 0
    41
      sonar-runner-api/src/main/java/org/sonar/runner/impl/VersionUtils.java
  41. 0
    22
      sonar-runner-api/src/main/java/org/sonar/runner/impl/package-info.java
  42. 0
    1
      sonar-runner-api/src/main/resources/org/sonar/runner/api/version.txt
  43. 0
    95
      sonar-runner-api/src/test/java/org/sonar/runner/api/DirsTest.java
  44. 0
    326
      sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java
  45. 0
    57
      sonar-runner-api/src/test/java/org/sonar/runner/api/IssueListenerAdapterTest.java
  46. 0
    76
      sonar-runner-api/src/test/java/org/sonar/runner/api/LoggerAdapterTest.java
  47. 0
    34
      sonar-runner-api/src/test/java/org/sonar/runner/api/RunnerVersionTest.java
  48. 0
    40
      sonar-runner-api/src/test/java/org/sonar/runner/api/StdOutLogOutputTest.java
  49. 0
    128
      sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java
  50. 0
    94
      sonar-runner-api/src/test/java/org/sonar/runner/cache/DirectoryLockTest.java
  51. 0
    60
      sonar-runner-api/src/test/java/org/sonar/runner/cache/FileCacheBuilderTest.java
  52. 0
    117
      sonar-runner-api/src/test/java/org/sonar/runner/cache/FileCacheTest.java
  53. 0
    127
      sonar-runner-api/src/test/java/org/sonar/runner/cache/FileHashesTest.java
  54. 0
    78
      sonar-runner-api/src/test/java/org/sonar/runner/cache/PersistentCacheBuilderTest.java
  55. 0
    145
      sonar-runner-api/src/test/java/org/sonar/runner/cache/PersistentCacheTest.java
  56. 0
    55
      sonar-runner-api/src/test/java/org/sonar/runner/cache/TTLCacheInvalidationTest.java
  57. 0
    106
      sonar-runner-api/src/test/java/org/sonar/runner/impl/ClassloadRulesTest.java
  58. 0
    110
      sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedClassloaderTest.java
  59. 0
    96
      sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java
  60. 0
    77
      sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherProxyTest.java
  61. 0
    47
      sonar-runner-api/src/test/java/org/sonar/runner/impl/JarDownloaderTest.java
  62. 0
    48
      sonar-runner-api/src/test/java/org/sonar/runner/impl/JarExtractorTest.java
  63. 0
    103
      sonar-runner-api/src/test/java/org/sonar/runner/impl/JarsTest.java
  64. 0
    123
      sonar-runner-api/src/test/java/org/sonar/runner/impl/MockHttpServer.java
  65. 0
    54
      sonar-runner-api/src/test/java/org/sonar/runner/impl/MockHttpServerInterceptor.java
  66. 0
    52
      sonar-runner-api/src/test/java/org/sonar/runner/impl/NetworkUtil.java
  67. 0
    261
      sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java
  68. 0
    142
      sonar-runner-api/src/test/java/org/sonar/runner/impl/SimulatedLauncherTest.java
  69. 0
    66
      sonar-runner-api/src/test/java/org/sonar/runner/impl/TempCleaningTest.java
  70. 0
    39
      sonar-runner-api/src/test/java/org/sonar/runner/impl/VersionUtilsTest.java
  71. 0
    1
      sonar-runner-api/src/test/resources/fake.jar
  72. 0
    2
      sonar-runner-api/src/test/resources/org/sonar/runner/impl/BatchLauncherMainTest/props.properties
  73. 0
    4
      sonar-runner-api/src/test/scripts/echo.bat
  74. 0
    6
      sonar-runner-api/src/test/scripts/echo.sh
  75. 0
    6
      sonar-runner-api/src/test/scripts/forever.bat
  76. 0
    6
      sonar-runner-api/src/test/scripts/forever.sh
  77. 0
    5
      sonar-runner-api/src/test/scripts/output.bat
  78. 0
    6
      sonar-runner-api/src/test/scripts/output.sh
  79. 0
    1
      sonar-runner-batch-interface/.gitignore
  80. 0
    12
      sonar-runner-batch-interface/pom.xml
  81. 0
    41
      sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java
  82. 0
    163
      sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IssueListener.java
  83. 0
    33
      sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/LogOutput.java
  84. 0
    20
      sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/package-info.java
  85. 0
    5
      sonar-runner-batch-interface/src/test/java_sample/sonar-project.properties
  86. 0
    0
      sonar-runner-batch-interface/src/test/java_sample/src/Sample.java
  87. 0
    91
      sonar-runner-batch/pom.xml
  88. 0
    143
      sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
  89. 0
    178
      sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/IssueListener.java
  90. 0
    33
      sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/LogOutput.java
  91. 0
    23
      sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/package-info.java
  92. 0
    30
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchFactory.java
  93. 0
    117
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java
  94. 0
    87
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/Compatibility.java
  95. 0
    49
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/DefaultBatchFactory.java
  96. 0
    20
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/package-info.java
  97. 0
    128
      sonar-runner-batch/src/test/java/org/sonar/runner/batch/BatchIsolatedLauncherTest.java
  98. 0
    120
      sonar-runner-batch/src/test/java/org/sonar/runner/batch/CompatibilityTest.java
  99. 0
    44
      sonar-runner-batch/src/test/java/org/sonar/runner/batch/DefaultBatchFactoryTest.java
  100. 0
    0
      sonar-runner-batch/src/test/java_sample/sonar-project.properties

sonar-runner-cli/assembly.xml → assembly.xml View File


+ 127
- 95
pom.xml View File

@@ -6,21 +6,14 @@
<version>23</version>
</parent>

<groupId>org.sonarsource.sonar-runner</groupId>
<artifactId>sonar-runner</artifactId>
<groupId>org.sonarsource.scanner</groupId>
<artifactId>sonar-scanner</artifactId>
<version>2.5-SNAPSHOT</version>
<packaging>pom</packaging>
<name>SonarQube Runner</name>
<url>http://docs.codehaus.org/display/SONAR/Analyzing+with+SonarQube+Runner</url>
<packaging>jar</packaging>
<name>SonarQube Scanner</name>
<url>http://docs.sonarqube.org/display/SONAR/Analyzing+with+SonarQube+Scanner</url>
<inceptionYear>2011</inceptionYear>

<modules>
<module>sonar-runner-api</module>
<module>sonar-runner-batch</module>
<module>sonar-runner-batch-interface</module>
<module>sonar-runner-cli</module>
</modules>

<organization>
<name>SonarSource</name>
<url>http://www.sonarsource.com</url>
@@ -35,103 +28,142 @@
</licenses>

<scm>
<connection>scm:git:git@github.com:SonarSource/sonar-runner.git</connection>
<developerConnection>scm:git:git@github.com:SonarSource/sonar-runner.git</developerConnection>
<url>https://github.com/SonarSource/sonar-runner</url>
<connection>scm:git:git@github.com:SonarSource/sonar-scanner-cli.git</connection>
<developerConnection>scm:git:git@github.com:SonarSource/sonar-scanner-cli.git</developerConnection>
<url>https://github.com/SonarSource/sonar-scanner-cli</url>
<tag>HEAD</tag>
</scm>

<issueManagement>
<system>JIRA</system>
<url>http://jira.codehaus.org/browse/SONARPLUGINS/component/14640</url>
<url>https://jira.sonarsource.com/browse/SONARSCANNER</url>
</issueManagement>

<properties>
<maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>
</properties>

<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.sonarsource.sonar-runner</groupId>
<artifactId>sonar-runner-api</artifactId>
<version>2.5-RC1</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.github.kevinsawicki</groupId>
<artifactId>http-request</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
<!-- Unit tests -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>com.jayway.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>1.6.3</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>org/sonar/runner/commonsio/*</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>false</addClasspath>
<mainClass>org.sonar.runner.cli.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>sonar-runner-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<escapeString>\</escapeString>
<descriptors>
<descriptor>${project.basedir}/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-distribution-size</id>
<goals>
<goal>enforce</goal>
</goals>
<phase>verify</phase>
<configuration>
<rules>
<requireFilesSize>
<minsize>160000</minsize>
<maxsize>185000</maxsize>
<files>
<file>${project.build.directory}/sonar-runner-${project.version}.zip</file>
</files>
</requireFilesSize>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

+ 0
- 215
sonar-runner-api/pom.xml View File

@@ -1,215 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonarsource.sonar-runner</groupId>
<artifactId>sonar-runner</artifactId>
<version>2.5-SNAPSHOT</version>
</parent>

<artifactId>sonar-runner-api</artifactId>
<name>SonarQube Runner - API</name>

<dependencies>
<!-- Dependencies with scope "compile" are shaded and removed from transitive dependencies-->
<dependency>
<groupId>com.github.kevinsawicki</groupId>
<artifactId>http-request</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-runner-batch</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-runner-batch-interface</artifactId>
<version>${project.version}</version>
</dependency>

<!-- unit tests -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<!-- used to compare results -->
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<!-- Use the MANIFEST generated by maven-bundle-plugin -->
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>process-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-runner-batch</artifactId>
<version>${project.version}</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<destFileName>sonar-runner-batch.jar</destFileName>
</artifactItem>
</artifactItems>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>com.github.kevinsawicki.http</pattern>
<shadedPattern>org.sonar.runner.kevinsawicki</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.io</pattern>
<shadedPattern>org.sonar.runner.commonsio</shadedPattern>
</relocation>
<relocation>
<pattern>org.sonar.home</pattern>
<shadedPattern>org.sonar.runner.home</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>!*</Import-Package>
<Export-Package>!.,org.sonar.runner.api</Export-Package>
<Bundle-RequiredExecutionEnvironment>JavaSE-1.7</Bundle-RequiredExecutionEnvironment>
</instructions>
</configuration>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<releaseProfiles>sign</releaseProfiles>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>sign</id>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<alias>sonarsource-codesign-2015-2017</alias>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

+ 0
- 78
sonar-runner-api/src/main/java/org/sonar/runner/api/Dirs.java View File

@@ -1,78 +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;

import org.sonar.runner.cache.Logger;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;


class Dirs {

private final Logger logger;

Dirs(Logger logger) {
this.logger = logger;
}

void init(Properties p) {
boolean onProject = Utils.taskRequiresProject(p);
if (onProject) {
initProjectDirs(p);
} else {
initTaskDirs(p);
}
}

private void initProjectDirs(Properties p) {
String pathString = p.getProperty(ScanProperties.PROJECT_BASEDIR, "");
Path absoluteProjectPath = Paths.get(pathString).toAbsolutePath().normalize();
if (!Files.isDirectory(absoluteProjectPath)) {
throw new IllegalStateException("Project home must be an existing directory: " + pathString);
}
p.setProperty(ScanProperties.PROJECT_BASEDIR, absoluteProjectPath.toString());

Path workDirPath;
pathString = p.getProperty(RunnerProperties.WORK_DIR, "");
if ("".equals(pathString.trim())) {
workDirPath = absoluteProjectPath.resolve(".sonar");
} else {
workDirPath = Paths.get(pathString);
if (!workDirPath.isAbsolute()) {
workDirPath = absoluteProjectPath.resolve(pathString);
}
}
p.setProperty(RunnerProperties.WORK_DIR, workDirPath.normalize().toString());
logger.debug("Work directory: " + workDirPath.normalize().toString());
}

/**
* Non-scan task
*/
private static void initTaskDirs(Properties p) {
String path = p.getProperty(RunnerProperties.WORK_DIR, ".");
File workDir = new File(path);
p.setProperty(RunnerProperties.WORK_DIR, workDir.getAbsolutePath());
}
}

+ 0
- 299
sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java View File

@@ -1,299 +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;

import org.sonar.runner.cache.Logger;

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;

import org.sonar.runner.batch.IsolatedLauncher;
import org.sonar.runner.impl.InternalProperties;
import org.sonar.runner.impl.IsolatedLauncherFactory;
import org.sonar.runner.impl.VersionUtils;

/**
* Entry point to run SonarQube analysis programmatically.
* @since 2.2
*/
public class EmbeddedRunner {
private final IsolatedLauncherFactory launcherFactory;
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) {
Logger logger = new LoggerAdapter(logOutput);
return new EmbeddedRunner(new IsolatedLauncherFactory(logger), logger, logOutput);
}

public Properties globalProperties() {
Properties clone = new Properties();
clone.putAll(globalProperties);
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)
*/
public EmbeddedRunner addGlobalProperties(Properties p) {
globalProperties.putAll(p);
return this;
}

/**
* 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
*/
public EmbeddedRunner setGlobalProperty(String key, String value) {
globalProperties.setProperty(key, value);
return this;
}

public String globalProperty(String key, @Nullable String defaultValue) {
return globalProperties.getProperty(key, defaultValue);
}

/**
* User-agent used in the HTTP requests to the SonarQube server
*/
public EmbeddedRunner setApp(String app, String version) {
setGlobalProperty(InternalProperties.RUNNER_APP, app);
setGlobalProperty(InternalProperties.RUNNER_APP_VERSION, version);
return this;
}

public String app() {
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);
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())) {
throw new IllegalStateException("not supported in current SonarQube version: " + launcher.getVersion());
}
launcher.syncProject(projectKey);
}

public void start() {
start(false);
}

public void start(boolean preferCache) {
initGlobalDefaultValues();
doStart(preferCache);
}

/**
* 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()}
*/
@Deprecated
public final void execute() {
start();
runAnalysis(new Properties());
stop();
}

private void initGlobalDefaultValues() {
setGlobalDefaultValue(RunnerProperties.HOST_URL, "http://localhost:9000");
setGlobalDefaultValue(InternalProperties.RUNNER_APP, "SonarQubeRunner");
setGlobalDefaultValue(InternalProperties.RUNNER_APP_VERSION, RunnerVersion.version());
}

private void initAnalysisProperties(Properties p) {
initSourceEncoding(p);
new Dirs(logger).init(p);
}

void initSourceEncoding(Properties p) {
boolean onProject = Utils.taskRequiresProject(p);
if (onProject) {
String sourceEncoding = p.getProperty(ScanProperties.PROJECT_SOURCE_ENCODING, "");
boolean platformDependent = false;
if ("".equals(sourceEncoding)) {
sourceEncoding = Charset.defaultCharset().name();
platformDependent = true;
p.setProperty(ScanProperties.PROJECT_SOURCE_ENCODING, sourceEncoding);
}
logger.info("Default locale: \"" + Locale.getDefault() + "\", source code encoding: \"" + sourceEncoding + "\""
+ (platformDependent ? " (analysis is platform dependent)" : ""));
}
}

private void setGlobalDefaultValue(String key, String value) {
if (!globalProperties.containsKey(key)) {
setGlobalProperty(key, value);
}
}

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

@Override
public void log(String formattedMessage, Level level) {
logOutput.log(formattedMessage, LogOutput.Level.valueOf(level.name()));
}

}, preferCache);
}
}

protected void doStop() {
if (VersionUtils.isAtLeast52(launcher.getVersion())) {
launcher.stop();
launcher = null;
}
}

protected void doExecute(Properties analysisProperties, @Nullable IssueListener issueListener) {
if (VersionUtils.isAtLeast52(launcher.getVersion())) {
if (issueListener != null) {
launcher.execute(analysisProperties, new IssueListenerAdapter(issueListener));
} else {
launcher.execute(analysisProperties);
}
} else {
if (issueListener != null) {
throw new InvalidParameterException("Issue listeners not supported in current version: " + launcher.getVersion());
}
Properties prop = new Properties();
prop.putAll(globalProperties());
prop.putAll(analysisProperties);
launcher.executeOldVersion(prop, extensions);
}
}

private void checkLauncherExists() {
if (launcher == null) {
throw new IllegalStateException("not started");
}
}

private void checkLauncherDoesntExist() {
if (launcher != null) {
throw new IllegalStateException("already started");
}
}
}

+ 0
- 290
sonar-runner-api/src/main/java/org/sonar/runner/api/Issue.java View File

@@ -1,290 +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;

import javax.annotation.concurrent.Immutable;

@Immutable
public final class Issue {
private final String key;
private final String componentKey;
private final String message;
private final String ruleKey;
private final String ruleName;
private final String status;
private final String resolution;
private final boolean isNew;
private final String assigneeLogin;
private final String assigneeName;
private final String severity;
private final Integer startLine;
private final Integer startLineOffset;
private final Integer endLine;
private final Integer endLineOffset;

private Issue(String key, String componentKey, String message, String ruleKey, String ruleName, String status, String resolution, boolean isNew,
String assigneeLogin, String assigneeName, String severity, Integer startLine, Integer startLineOffset, Integer endLine, Integer endLineOffset) {
super();
this.key = key;
this.componentKey = componentKey;
this.message = message;
this.ruleKey = ruleKey;
this.ruleName = ruleName;
this.status = status;
this.resolution = resolution;
this.isNew = isNew;
this.assigneeLogin = assigneeLogin;
this.assigneeName = assigneeName;
this.severity = severity;
this.startLine = startLine;
this.startLineOffset = startLineOffset;
this.endLine = endLine;
this.endLineOffset = endLineOffset;
}

public static class Builder {
private String key;
private String componentKey;
private String message;
private String ruleKey;
private String ruleName;
private String status;
private String resolution;
private boolean isNew;
private String assigneeLogin;
private String assigneeName;
private String severity;
private Integer startLine;
private Integer startLineOffset;
private Integer endLine;
private Integer endLineOffset;

public Integer getStartLine() {
return startLine;
}

public Builder setStartLine(Integer startLine) {
this.startLine = startLine;
return this;
}

public Integer getStartLineOffset() {
return startLineOffset;
}

public Builder setStartLineOffset(Integer startLineOffset) {
this.startLineOffset = startLineOffset;
return this;
}

public Integer getEndLine() {
return endLine;
}

public Builder setEndLine(Integer endLine) {
this.endLine = endLine;
return this;
}

public Integer getEndLineOffset() {
return endLineOffset;
}

public Builder setEndLineOffset(Integer endLineOffset) {
this.endLineOffset = endLineOffset;
return this;
}

public String getKey() {
return key;
}

public Builder setKey(String key) {
this.key = key;
return this;
}

public String getComponentKey() {
return componentKey;
}

public Builder setComponentKey(String componentKey) {
this.componentKey = componentKey;
return this;
}

public String getMessage() {
return message;
}

public Builder setMessage(String message) {
this.message = message;
return this;
}

public String getRuleKey() {
return ruleKey;
}

public Builder setRuleKey(String ruleKey) {
this.ruleKey = ruleKey;
return this;
}

public String getRuleName() {
return ruleKey;
}

public Builder setRuleName(String ruleName) {
this.ruleName = ruleName;
return this;
}

public String getStatus() {
return status;
}

public Builder setStatus(String status) {
this.status = status;
return this;
}

public String getResolution() {
return resolution;
}

public Builder setResolution(String resolution) {
this.resolution = resolution;
return this;
}

public boolean isNew() {
return isNew;
}

public Builder setNew(boolean isNew) {
this.isNew = isNew;
return this;
}

public String getAssigneeLogin() {
return assigneeLogin;
}

public Builder setAssigneeLogin(String assigneeLogin) {
this.assigneeLogin = assigneeLogin;
return this;
}

public String getAssigneeName() {
return assigneeName;
}

public Builder setAssigneeName(String assigneeName) {
this.assigneeName = assigneeName;
return this;
}

public String getSeverity() {
return severity;
}

public Builder setSeverity(String severity) {
this.severity = severity;
return this;
}

public Issue build() {
return new Issue(key, componentKey, message, ruleKey, ruleName, status, resolution, isNew, assigneeLogin,
assigneeName, severity, startLine, startLineOffset, endLine, endLineOffset);
}
}

public static Builder builder() {
return new Builder();
}

public String getKey() {
return key;
}

public String getComponentKey() {
return componentKey;
}

public Integer getStartLine() {
return startLine;
}

/**
* @return <code>null</code> if it isn't supported by the sonar-batch being used (< 5.3).
*/
public Integer getStartLineOffset() {
return startLineOffset;
}

public Integer getEndLine() {
return endLine;
}

/**
* @return <code>null</code> if it isn't supported by the sonar-batch being used (< 5.3).
*/
public Integer getEndLineOffset() {
return endLineOffset;
}

public String getMessage() {
return message;
}

public String getRuleKey() {
return ruleKey;
}

public String getRuleName() {
return ruleName;
}

public String getStatus() {
return status;
}

public String getResolution() {
return resolution;
}

public boolean isNew() {
return isNew;
}

public String getAssigneeLogin() {
return assigneeLogin;
}

public String getAssigneeName() {
return assigneeName;
}

public String getSeverity() {
return severity;
}

}

+ 0
- 24
sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListener.java View File

@@ -1,24 +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;

public interface IssueListener {
void handle(Issue issue);
}

+ 0
- 55
sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListenerAdapter.java View File

@@ -1,55 +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;

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.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());
issueBuilder.setStartLine(batchIssue.getStartLine());
issueBuilder.setStartLineOffset(batchIssue.getStartLineOffset());
issueBuilder.setEndLine(batchIssue.getEndLine());
issueBuilder.setEndLineOffset(batchIssue.getEndLineOffset());

return issueBuilder.build();
}
}

+ 0
- 29
sonar-runner-api/src/main/java/org/sonar/runner/api/LogOutput.java View File

@@ -1,29 +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;

public interface LogOutput {
void log(String formattedMessage, Level level);
enum Level {
ERROR, WARN, INFO, DEBUG, TRACE;
}
}

+ 0
- 61
sonar-runner-api/src/main/java/org/sonar/runner/api/LoggerAdapter.java View File

@@ -1,61 +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;


import org.sonar.runner.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
- 45
sonar-runner-api/src/main/java/org/sonar/runner/api/RunnerProperties.java View File

@@ -1,45 +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;

/**
* Mostly used properties that can be passed to {@link EmbeddedRunner#addGlobalProperties(java.util.Properties)}.
* See <a href="http://docs.sonarqube.org/display/SONAR/Analysis+Parameters">documentation</a> for more properties.
*
* @since 2.2
*/
public interface RunnerProperties {
/**
* HTTP URL of Sonar server, "http://localhost:9000" by default
*/
String HOST_URL = "sonar.host.url";

/**
* Task to execute, "scan" by default
* @deprecated since 2.5 No more task starting from SQ 5.2
*/
@Deprecated
String TASK = "sonar.task";

/**
* Working directory containing generated reports and temporary data.
*/
String WORK_DIR = "sonar.working.directory";
}

+ 0
- 48
sonar-runner-api/src/main/java/org/sonar/runner/api/RunnerVersion.java View File

@@ -1,48 +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;

import java.util.Scanner;

/**
* Version of this sonar-runner API.
*
* @since 2.2
*/
public enum RunnerVersion {

INSTANCE;

private String version;

private RunnerVersion() {
Scanner scanner = new Scanner(getClass().getResourceAsStream("/org/sonar/runner/api/version.txt"), "UTF-8");
try {
this.version = scanner.next();
} finally {
scanner.close();
}
}

public static String version() {
return INSTANCE.version;
}

}

+ 0
- 79
sonar-runner-api/src/main/java/org/sonar/runner/api/ScanProperties.java View File

@@ -1,79 +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;

/**
* Most commonly used properties for a SonarQube analysis. These properties are passed to {@link EmbeddedRunner#runAnalysis(java.util.Properties)}.
* See <a href="http://docs.sonarqube.org/display/SONAR/Analysis+Parameters">documentation</a> for more properties.
*
* @since 2.2
*/
public interface ScanProperties {

/**
* Default task
*
* @see RunnerProperties#TASK
* @deprecated since 2.5 No more task since SQ 5.2
*/
@Deprecated
String SCAN_TASK = "scan";

/**
* Required project key
*/
String PROJECT_KEY = "sonar.projectKey";

/**
* Used to define the exact key of each module. If {@link #PROJECT_KEY} is used instead on a module, then final key of the module will be <parent module key>:<PROJECT_KEY>.
* @since SonarQube 4.1
*/
String MODULE_KEY = "sonar.moduleKey";

String PROJECT_NAME = "sonar.projectName";

String PROJECT_VERSION = "sonar.projectVersion";

/**
* Optional description
*/
String PROJECT_DESCRIPTION = "sonar.projectDescription";

/**
* Required paths to source directories, separated by commas, for example: "srcDir1,srcDir2"
*/
String PROJECT_SOURCE_DIRS = "sonar.sources";

/**
* Optional paths to test directories, separated by commas, for example: "testDir1,testDir2"
*/
String PROJECT_TEST_DIRS = "sonar.tests";

/**
* Property used to specify the base directory of the project to analyse. Default is ".".
*/
String PROJECT_BASEDIR = "sonar.projectBaseDir";

/**
* Encoding of source and test files. By default it's the platform encoding.
*/
String PROJECT_SOURCE_ENCODING = "sonar.sourceEncoding";

}

+ 0
- 39
sonar-runner-api/src/main/java/org/sonar/runner/api/StdOutLogOutput.java View File

@@ -1,39 +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;

import java.io.PrintStream;

public class StdOutLogOutput implements LogOutput {
private PrintStream stdOut;

public StdOutLogOutput() {
this(System.out);
}

StdOutLogOutput(PrintStream stdOut) {
this.stdOut = stdOut;
}

@Override
public void log(String formattedMessage, org.sonar.runner.api.LogOutput.Level level) {
stdOut.println(level.name() + ": " + formattedMessage);
}
}

+ 0
- 123
sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java View File

@@ -1,123 +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;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;

import javax.annotation.Nullable;

class Utils {
private Utils() {
// only util static methods
}

/**
* Similar to org.apache.commons.lang.StringUtils#join()
*/
static String join(String[] array, String delimiter) {
StringBuilder sb = new StringBuilder();
Iterator<String> it = Arrays.asList(array).iterator();
while (it.hasNext()) {
sb.append(it.next());
if (!it.hasNext()) {
break;
}
sb.append(delimiter);
}
return sb.toString();
}

static boolean taskRequiresProject(Properties props) {
Object task = props.get(RunnerProperties.TASK);
return task == null || ScanProperties.SCAN_TASK.equals(task);
}

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

static void deleteQuietly(File f) {
try {
Files.walkFileTree(f.toPath(), new DeleteQuietlyFileVisitor());
} catch (IOException e) {
// ignore
}
}

private static class DeleteQuietlyFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
try {
Files.delete(file);
} catch (IOException e) {
// ignore
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
try {
Files.delete(file);
} catch (IOException e) {
// ignore
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
try {
Files.delete(dir);
} catch (IOException e) {
// ignore
}
return FileVisitResult.CONTINUE;
}
}

static void closeQuietly(@Nullable Closeable c) {
if (c == null) {
return;
}

try {
c.close();
} catch (IOException e) {
// ignore
}
}
}

+ 0
- 24
sonar-runner-api/src/main/java/org/sonar/runner/api/package-info.java View File

@@ -1,24 +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
*/
@ParametersAreNonnullByDefault
package org.sonar.runner.api;

import javax.annotation.ParametersAreNonnullByDefault;


+ 0
- 84
sonar-runner-api/src/main/java/org/sonar/runner/cache/DeleteFileOnCloseInputStream.java View File

@@ -1,84 +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.cache;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;

public class DeleteFileOnCloseInputStream extends InputStream {
private final InputStream is;
private final Path p;

public DeleteFileOnCloseInputStream(InputStream stream, Path p) {
this.is = stream;
this.p = p;
}

@Override
public int read() throws IOException {
return is.read();
}

@Override
public int read(byte[] b) throws IOException {
return is.read(b);
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
return is.read(b, off, len);
}

@Override
public long skip(long n) throws IOException {
return is.skip(n);
}

@Override
public synchronized void mark(int readlimit) {
is.mark(readlimit);
}

@Override
public synchronized void reset() throws IOException {
is.reset();
}

@Override
public int available() throws IOException {
return is.available();
}

@Override
public boolean markSupported() {
return is.markSupported();
}

@Override
public void close() throws IOException {
try {
super.close();
} finally {
Files.delete(p);
}
}
}

+ 0
- 106
sonar-runner-api/src/main/java/org/sonar/runner/cache/DirectoryLock.java View File

@@ -1,106 +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.cache;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
import java.nio.file.Path;

public class DirectoryLock {
static final String LOCK_FILE_NAME = ".sonar_lock";
private final Path lockFilePath;
private final Logger logger;

private RandomAccessFile lockRandomAccessFile;
private FileChannel lockChannel;
private FileLock lockFile;

public DirectoryLock(Path directory, Logger logger) {
this.logger = logger;
this.lockFilePath = directory.resolve(LOCK_FILE_NAME).toAbsolutePath();
}

public String getFileLockName() {
return LOCK_FILE_NAME;
}
public void lock() {
try {
lockRandomAccessFile = new RandomAccessFile(lockFilePath.toFile(), "rw");
lockChannel = lockRandomAccessFile.getChannel();
lockFile = lockChannel.lock(0, 1024, false);
} catch (IOException e) {
throw new IllegalStateException("Failed to create lock in " + lockFilePath.toString(), e);
}
}
public boolean tryLock() {
try {
lockRandomAccessFile = new RandomAccessFile(lockFilePath.toFile(), "rw");
lockChannel = lockRandomAccessFile.getChannel();
lockFile = lockChannel.tryLock(0, 1024, false);

return lockFile != null;
} catch (IOException e) {
throw new IllegalStateException("Failed to create lock in " + lockFilePath.toString(), e);
}
}

public void unlock() {
if (lockFile != null) {
try {
lockFile.release();
lockFile = null;
} catch (IOException e) {
logger.error("Error releasing lock", e);
}
}
if (lockChannel != null) {
try {
lockChannel.close();
lockChannel = null;
} catch (IOException e) {
logger.error("Error closing file channel", e);
}
}
if (lockRandomAccessFile != null) {
try {
lockRandomAccessFile.close();
lockRandomAccessFile = null;
} catch (IOException e) {
logger.error("Error closing file", e);
}
}

try {
Files.delete(lockFilePath);
} catch (IOException e) {
// ignore, as an error happens if another process just started to acquire the same lock
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
logger.debug("Couldn't delete lock file: " + lockFilePath.toString() + " " + errors.toString());
}
}
}

+ 0
- 159
sonar-runner-api/src/main/java/org/sonar/runner/cache/FileCache.java View File

@@ -1,159 +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.cache;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.annotation.CheckForNull;

/**
* This class is responsible for managing Sonar batch file cache. You can put file into cache and
* later try to retrieve them. MD5 is used to differentiate files (name is not secure as files may come
* from different Sonar servers and have same name but be actually different, and same for SNAPSHOTs).
*/
public class FileCache {

/** Maximum loop count when creating temp directories. */
private static final int TEMP_DIR_ATTEMPTS = 10000;

private final File dir;
private final File tmpDir;
private final FileHashes hashes;
private final Logger logger;

FileCache(File dir, FileHashes fileHashes, Logger logger) {
this.hashes = fileHashes;
this.logger = logger;
this.dir = createDir(dir, "user cache");
logger.info(String.format("User cache: %s", dir.getAbsolutePath()));
this.tmpDir = createDir(new File(dir, "_tmp"), "temp dir");
}

static FileCache create(File dir, Logger logger) {
return new FileCache(dir, new FileHashes(), logger);
}

public File getDir() {
return dir;
}

/**
* Look for a file in the cache by its filename and md5 checksum. If the file is not
* present then return null.
*/
@CheckForNull
public File get(String filename, String hash) {
File cachedFile = new File(new File(dir, hash), filename);
if (cachedFile.exists()) {
return cachedFile;
}
logger.debug(String.format("No file found in the cache with name %s and hash %s", filename, hash));
return null;
}

public interface Downloader {
void download(String filename, File toFile) throws IOException;
}

public File get(String filename, String hash, Downloader downloader) {
// Does not fail if another process tries to create the directory at the same time.
File hashDir = hashDir(hash);
File targetFile = new File(hashDir, filename);
if (!targetFile.exists()) {
File tempFile = newTempFile();
download(downloader, filename, tempFile);
String downloadedHash = hashes.of(tempFile);
if (!hash.equals(downloadedHash)) {
throw new IllegalStateException("INVALID HASH: File " + tempFile.getAbsolutePath() + " was expected to have hash " + hash
+ " but was downloaded with hash " + downloadedHash);
}
mkdirQuietly(hashDir);
renameQuietly(tempFile, targetFile);
}
return targetFile;
}

private void download(Downloader downloader, String filename, File tempFile) {
try {
downloader.download(filename, tempFile);
} catch (IOException e) {
throw new IllegalStateException("Fail to download " + filename + " to " + tempFile, e);
}
}

private void renameQuietly(File sourceFile, File targetFile) {
boolean rename = sourceFile.renameTo(targetFile);
// Check if the file was cached by another process during download
if (!rename && !targetFile.exists()) {
logger.warn(String.format("Unable to rename %s to %s", sourceFile.getAbsolutePath(), targetFile.getAbsolutePath()));
logger.warn("A copy/delete will be tempted but with no guarantee of atomicity");
try {
Files.move(sourceFile.toPath(), targetFile.toPath());
} catch (IOException e) {
throw new IllegalStateException("Fail to move " + sourceFile.getAbsolutePath() + " to " + targetFile, e);
}
}
}

private File hashDir(String hash) {
return new File(dir, hash);
}

private static void mkdirQuietly(File hashDir) {
try {
Files.createDirectories(hashDir.toPath());
} catch (IOException e) {
throw new IllegalStateException("Fail to create cache directory: " + hashDir, e);
}
}

private File newTempFile() {
try {
return File.createTempFile("fileCache", null, tmpDir);
} catch (IOException e) {
throw new IllegalStateException("Fail to create temp file in " + tmpDir, e);
}
}

public File createTempDir() {
String baseName = System.currentTimeMillis() + "-";

for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
File tempDir = new File(tmpDir, baseName + counter);
if (tempDir.mkdir()) {
return tempDir;
}
}
throw new IllegalStateException("Failed to create directory in " + tmpDir);
}

private File createDir(File dir, String debugTitle) {
if (!dir.isDirectory() || !dir.exists()) {
logger.debug("Create : " + dir.getAbsolutePath());
try {
Files.createDirectories(dir.toPath());
} catch (IOException e) {
throw new IllegalStateException("Unable to create " + debugTitle + dir.getAbsolutePath(), e);
}
}
return dir;
}
}

+ 0
- 60
sonar-runner-api/src/main/java/org/sonar/runner/cache/FileCacheBuilder.java View File

@@ -1,60 +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.cache;

import java.io.File;

import javax.annotation.Nullable;

public class FileCacheBuilder {
private final Logger logger;
private File userHome;

public FileCacheBuilder(Logger logger) {
this.logger = logger;
}

public FileCacheBuilder setUserHome(File d) {
this.userHome = d;
return this;
}

public FileCacheBuilder setUserHome(@Nullable String path) {
this.userHome = (path == null) ? null : new File(path);
return this;
}

public FileCache build() {
if (userHome == null) {
userHome = findHome();
}
File cacheDir = new File(userHome, "cache");
return FileCache.create(cacheDir, logger);
}
private static File findHome() {
String path = System.getenv("SONAR_USER_HOME");
if (path == null) {
// Default
path = System.getProperty("user.home") + File.separator + ".sonar";
}
return new File(path);
}
}

+ 0
- 73
sonar-runner-api/src/main/java/org/sonar/runner/cache/FileHashes.java View File

@@ -1,73 +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.cache;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;

/**
* Hashes used to store files in the cache directory.
*
* @since 3.5
*/
class FileHashes {

private static final int STREAM_BUFFER_LENGTH = 1024;

String of(File file) {
try {
return of(new FileInputStream(file));
} catch (IOException e) {
throw new IllegalStateException("Fail to compute hash of: " + file.getAbsolutePath(), e);
}
}

/**
* Computes the hash of given stream. The stream is closed by this method.
*/
String of(InputStream input) {
try(InputStream is = input) {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] hash = digest(is, digest);
return toHex(hash);
} catch (Exception e) {
throw new IllegalStateException("Fail to compute hash", e);
}
}

private static byte[] digest(InputStream input, MessageDigest digest) throws IOException {
final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
int read = input.read(buffer, 0, STREAM_BUFFER_LENGTH);
while (read > -1) {
digest.update(buffer, 0, read);
read = input.read(buffer, 0, STREAM_BUFFER_LENGTH);
}
return digest.digest();
}

static String toHex(byte[] bytes) {
BigInteger bi = new BigInteger(1, bytes);
return String.format("%0" + (bytes.length << 1) + "x", bi);
}
}

+ 0
- 34
sonar-runner-api/src/main/java/org/sonar/runner/cache/Logger.java View File

@@ -1,34 +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.cache;

public interface Logger {

void debug(String msg);

void info(String msg);

void warn(String msg);

void error(String msg);

void error(String msg, Throwable t);

}

+ 0
- 281
sonar-runner-api/src/main/java/org/sonar/runner/cache/PersistentCache.java View File

@@ -1,281 +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.cache;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;

public class PersistentCache {
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
private static final Charset ENCODING = StandardCharsets.UTF_8;
private static final String DIGEST_ALGO = "MD5";

private final PersistentCacheInvalidation invalidation;
private final Logger logger;
private final Path dir;
private DirectoryLock lock;

PersistentCache(Path dir, PersistentCacheInvalidation invalidation, Logger logger, DirectoryLock lock) {
this.dir = dir;
this.invalidation = invalidation;
this.logger = logger;
this.lock = lock;

reconfigure();
logger.debug("cache: " + dir);
}

public synchronized void reconfigure() {
try {
Files.createDirectories(dir);
} catch (IOException e) {
throw new IllegalStateException("failed to create cache dir", e);
}
}

public Path getDirectory() {
return dir;
}

@CheckForNull
public synchronized String getString(@Nonnull String obj) throws IOException {
byte[] cached = get(obj);

if (cached == null) {
return null;
}

return new String(cached, ENCODING);
}

@CheckForNull
public synchronized InputStream getStream(@Nonnull String obj) throws IOException {
String key = getKey(obj);

try {
lock();
Path path = getCacheCopy(key);
if (path == null) {
return null;
}
return new DeleteFileOnCloseInputStream(new FileInputStream(path.toFile()), path);

} finally {
unlock();
}
}

@CheckForNull
public synchronized byte[] get(@Nonnull String obj) throws IOException {
String key = getKey(obj);

try {
lock();

byte[] cached = getCache(key);

if (cached != null) {
logger.debug("cache hit for " + obj + " -> " + key);
return cached;
}

logger.debug("cache miss for " + obj + " -> " + key);
} finally {
unlock();
}

return null;
}

public synchronized void put(@Nonnull String obj, @Nonnull InputStream stream) throws IOException {
String key = getKey(obj);
try {
lock();
putCache(key, stream);
} finally {
unlock();
}
}

public synchronized void put(@Nonnull String obj, @Nonnull byte[] value) throws IOException {
String key = getKey(obj);
try {
lock();
putCache(key, value);
} finally {
unlock();
}
}

/**
* Deletes all cache entries
*/
public synchronized void clear() {
logger.info("cache: clearing");
try {
lock();
deleteCacheEntries(new DirectoryClearFilter());
} catch (IOException e) {
logger.error("Error clearing cache", e);
} finally {
unlock();
}
}

/**
* Deletes cache entries that are no longer valid according to the default expiration time period.
*/
public synchronized void clean() {
logger.info("cache: cleaning");
try {
lock();
deleteCacheEntries(new DirectoryCleanFilter());
} catch (IOException e) {
logger.error("Error cleaning cache", e);
} finally {
unlock();
}
}

private void lock() throws IOException {
lock.lock();
}

private void unlock() {
lock.unlock();
}

private static String getKey(String uri) {
try {
String key = uri;
MessageDigest digest = MessageDigest.getInstance(DIGEST_ALGO);
digest.update(key.getBytes(StandardCharsets.UTF_8));
return byteArrayToHex(digest.digest());
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Couldn't create hash", e);
}
}

private void deleteCacheEntries(DirectoryStream.Filter<Path> filter) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
for (Path p : stream) {
try {
Files.delete(p);
} catch (Exception e) {
logger.error("Error deleting " + p, e);
}
}
}
}

private class DirectoryClearFilter implements DirectoryStream.Filter<Path> {
@Override
public boolean accept(Path entry) throws IOException {
return !lock.getFileLockName().equals(entry.getFileName().toString());
}
}

private class DirectoryCleanFilter implements DirectoryStream.Filter<Path> {
@Override
public boolean accept(Path entry) throws IOException {
if (lock.getFileLockName().equals(entry.getFileName().toString())) {
return false;
}

return invalidation.test(entry);
}
}

private void putCache(String key, byte[] value) throws IOException {
Path cachePath = getCacheEntryPath(key);
Files.write(cachePath, value, CREATE, WRITE, TRUNCATE_EXISTING);
}

private void putCache(String key, InputStream stream) throws IOException {
Path cachePath = getCacheEntryPath(key);
Files.copy(stream, cachePath, StandardCopyOption.REPLACE_EXISTING);
}

private byte[] getCache(String key) throws IOException {
Path cachePath = getCacheEntryPath(key);

if (!validateCacheEntry(cachePath)) {
return null;
}

return Files.readAllBytes(cachePath);
}

private Path getCacheCopy(String key) throws IOException {
Path cachePath = getCacheEntryPath(key);

if (!validateCacheEntry(cachePath)) {
return null;
}

Path temp = Files.createTempFile("sonar_cache", null);
Files.copy(cachePath, temp, StandardCopyOption.REPLACE_EXISTING);
return temp;
}

private boolean validateCacheEntry(Path cacheEntryPath) throws IOException {
if (!Files.exists(cacheEntryPath)) {
return false;
}

if (invalidation.test(cacheEntryPath)) {
logger.debug("cache: evicting entry");
Files.delete(cacheEntryPath);
return false;
}

return true;
}

private Path getCacheEntryPath(String key) {
return dir.resolve(key);
}

public static String byteArrayToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}

+ 0
- 110
sonar-runner-api/src/main/java/org/sonar/runner/cache/PersistentCacheBuilder.java View File

@@ -1,110 +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.cache;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;

/**
* Cache files will be placed in 3 areas:
* <pre>
* &lt;sonar_home&gt;/ws_cache/&lt;server_url&gt;-&lt;version&gt;/projects/&lt;project&gt;/
* &lt;sonar_home&gt;/ws_cache/&lt;server_url&gt;-&lt;version&gt;/global/
* &lt;sonar_home&gt;/ws_cache/&lt;server_url&gt;-&lt;version&gt;/local/
* </pre>
*/
public class PersistentCacheBuilder {
private static final long DEFAULT_EXPIRE_DURATION = TimeUnit.MILLISECONDS.convert(9999L, TimeUnit.DAYS);
private static final String DIR_NAME = "ws_cache";

private Path cacheBasePath;
private Path relativePath;
private final Logger logger;

public PersistentCacheBuilder(Logger logger) {
this.logger = logger;
}

public PersistentCacheBuilder setAreaForProject(String serverUrl, String serverVersion, String projectKey) {
relativePath = Paths.get(sanitizeFilename(serverUrl))
.resolve(sanitizeFilename(serverVersion))
.resolve("projects")
.resolve(sanitizeFilename(projectKey));
return this;
}

public PersistentCacheBuilder setAreaForGlobal(String serverUrl) {
relativePath = Paths.get(sanitizeFilename(serverUrl))
.resolve("global");
return this;
}

public PersistentCacheBuilder setAreaForLocalProject(String serverUrl, String serverVersion) {
relativePath = Paths.get(sanitizeFilename(serverUrl))
.resolve(sanitizeFilename(serverVersion))
.resolve("local");
return this;
}

public PersistentCacheBuilder setSonarHome(@Nullable Path p) {
if (p != null) {
this.cacheBasePath = p.resolve(DIR_NAME);
}
return this;
}

public PersistentCache build() {
if (relativePath == null) {
throw new IllegalStateException("area must be set before building");
}
if (cacheBasePath == null) {
setSonarHome(findHome());
}
Path cachePath = cacheBasePath.resolve(relativePath);
DirectoryLock lock = new DirectoryLock(cacheBasePath, logger);
PersistentCacheInvalidation criteria = new TTLCacheInvalidation(DEFAULT_EXPIRE_DURATION);
return new PersistentCache(cachePath, criteria, logger, lock);
}

private static Path findHome() {
String home = System.getenv("SONAR_USER_HOME");

if (home != null) {
return Paths.get(home);
}

home = System.getProperty("user.home");
return Paths.get(home, ".sonar");
}

private static String sanitizeFilename(String name) {
try {
return URLEncoder.encode(name, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Couldn't sanitize filename: " + name, e);
}
}
}

+ 0
- 27
sonar-runner-api/src/main/java/org/sonar/runner/cache/PersistentCacheInvalidation.java View File

@@ -1,27 +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.cache;

import java.io.IOException;
import java.nio.file.Path;

public interface PersistentCacheInvalidation {
boolean test(Path cacheEntryPath) throws IOException;
}

+ 0
- 48
sonar-runner-api/src/main/java/org/sonar/runner/cache/TTLCacheInvalidation.java View File

@@ -1,48 +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.cache;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;

class TTLCacheInvalidation implements PersistentCacheInvalidation {
private final long durationToExpireMs;

TTLCacheInvalidation(long durationToExpireMs) {
this.durationToExpireMs = durationToExpireMs;
}
@Override
public boolean test(Path cacheEntryPath) throws IOException {
BasicFileAttributes attr = Files.readAttributes(cacheEntryPath, BasicFileAttributes.class);
long modTime = attr.lastModifiedTime().toMillis();

long age = System.currentTimeMillis() - modTime;

if (age > durationToExpireMs) {
return true;
}

return false;
}

}

+ 0
- 25
sonar-runner-api/src/main/java/org/sonar/runner/cache/package-info.java View File

@@ -1,25 +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
*/

@ParametersAreNonnullByDefault
package org.sonar.runner.cache;

import javax.annotation.ParametersAreNonnullByDefault;


+ 0
- 62
sonar-runner-api/src/main/java/org/sonar/runner/impl/ClassloadRules.java View File

@@ -1,62 +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.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;
}
}

+ 0
- 28
sonar-runner-api/src/main/java/org/sonar/runner/impl/InternalProperties.java View File

@@ -1,28 +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.impl;

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";
}

+ 0
- 109
sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedClassloader.java View File

@@ -1,109 +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.impl;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
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, ClassloadRules rules) {
super(new URL[0], parent);
this.rules = rules;
}

void addFiles(List<File> files) {
try {
for (File file : files) {
addURL(file.toURI().toURL());
}
} catch (MalformedURLException e) {
throw new IllegalStateException("Fail to create classloader", e);
}
}

/**
* Same behavior as in {@link java.net.URLClassLoader#loadClass(String, boolean)}, except loading from parent.
*/
@Override
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// Load from parent
if (getParent() != null && rules.canLoad(name)) {
c = getParent().loadClass(name);
} else {

// Load from system

// I don't know for other vendors, but for Oracle JVM :
// - ClassLoader.getSystemClassLoader() is sun.misc.Launcher$AppClassLoader. It contains app classpath.
// - ClassLoader.getSystemClassLoader().getParent() is sun.misc.Launcher$ExtClassLoader. It contains core JVM
ClassLoader systemClassLoader = getSystemClassLoader();
if (systemClassLoader.getParent() != null) {
systemClassLoader = systemClassLoader.getParent();
}
c = systemClassLoader.loadClass(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}

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

/**
* Unlike {@link java.net.URLClassLoader#getResources(String)} don't return resources from parent.
* See http://jira.codehaus.org/browse/SONAR-2276
*/
@Override
public Enumeration<URL> getResources(String name) throws IOException {
return findResources(name);
}

}

+ 0
- 105
sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java View File

@@ -1,105 +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.impl;

import org.sonar.runner.batch.IsolatedLauncher;
import org.sonar.runner.cache.Logger;
import org.sonar.runner.cache.PersistentCache;
import org.sonar.runner.cache.PersistentCacheBuilder;

import java.io.File;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import java.util.Properties;

public class IsolatedLauncherFactory {
static final String ISOLATED_LAUNCHER_IMPL = "org.sonar.runner.batch.BatchIsolatedLauncher";
private final TempCleaning tempCleaning;
private final String launcherImplClassName;
private final Logger logger;

/**
* For unit tests
*/
IsolatedLauncherFactory(String isolatedLauncherClassName, TempCleaning tempCleaning, Logger logger) {
this.tempCleaning = tempCleaning;
this.launcherImplClassName = isolatedLauncherClassName;
this.logger = logger;
}

public IsolatedLauncherFactory(Logger logger) {
this(ISOLATED_LAUNCHER_IMPL, new TempCleaning(logger), logger);
}

private PersistentCache getCache(Properties props) {
PersistentCacheBuilder builder = new PersistentCacheBuilder(logger);
String serverUrl = props.getProperty("sonar.host.url");
String home = props.getProperty("sonar.userHome");

builder.setAreaForGlobal(serverUrl);
if (home != null) {
builder.setSonarHome(Paths.get(home));
}
return builder.build();
}

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, ClassloadRules rules, boolean preferCache) {
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, preferCache);
JarDownloader jarDownloader = new JarDownloader(serverConnection, logger, props);

return createLauncher(jarDownloader, rules);
}

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, rules);
IsolatedLauncher objProxy = IsolatedLauncherProxy.create(cl, IsolatedLauncher.class, launcherImplClassName, logger);
tempCleaning.clean();

return objProxy;
} catch (Exception e) {
// Catch all other exceptions, which relates to reflection
throw new RunnerException("Unable to execute SonarQube", e);
}
}
});
}
}

+ 0
- 86
sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherProxy.java View File

@@ -1,86 +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.impl;

import org.sonar.runner.cache.Logger;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public class IsolatedLauncherProxy implements InvocationHandler {
private final Object proxied;
private final ClassLoader cl;
private final Logger logger;

private IsolatedLauncherProxy(ClassLoader cl, Object proxied, Logger logger) {
this.cl = cl;
this.proxied = proxied;
this.logger = logger;
}

public static <T> T create(ClassLoader cl, Class<T> interfaceClass, String proxiedClassName, Logger logger) throws ReflectiveOperationException {
Object proxied = createProxiedObject(cl, proxiedClassName);
// interfaceClass needs to be loaded with a parent ClassLoader (common to both ClassLoaders)
// In addition, Proxy.newProxyInstance checks if the target ClassLoader sees the same class as the one given
Class<?> loadedInterfaceClass = cl.loadClass(interfaceClass.getName());
return (T) create(cl, proxied, loadedInterfaceClass, logger);
}

public static <T> T create(ClassLoader cl, Object proxied, Class<T> interfaceClass, Logger logger) {
Class<?>[] c = {interfaceClass};
return (T) Proxy.newProxyInstance(cl, c, new IsolatedLauncherProxy(cl, proxied, logger));
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ClassLoader initialContextClassLoader = Thread.currentThread().getContextClassLoader();

try {
Thread.currentThread().setContextClassLoader(cl);
logger.debug("Execution " + method.getName());
return method.invoke(proxied, args);
} catch (UndeclaredThrowableException | InvocationTargetException e) {
throw unwrapException(e);
} finally {
Thread.currentThread().setContextClassLoader(initialContextClassLoader);
}
}

private static Throwable unwrapException(Throwable e) {
Throwable cause = e;

while (cause.getCause() != null) {
if (cause instanceof UndeclaredThrowableException || cause instanceof InvocationTargetException) {
cause = cause.getCause();
} else {
break;
}
}
return cause;
}

private static Object createProxiedObject(ClassLoader cl, String proxiedClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> proxiedClass = cl.loadClass(proxiedClassName);
return proxiedClass.newInstance();
}
}

+ 0
- 42
sonar-runner-api/src/main/java/org/sonar/runner/impl/JarDownloader.java View File

@@ -1,42 +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.impl;

import org.sonar.runner.cache.Logger;

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

class JarDownloader {
private final ServerConnection serverConnection;
private final Logger logger;
private final Properties props;

JarDownloader(ServerConnection conn, Logger logger, Properties props) {
this.serverConnection = conn;
this.logger = logger;
this.props = props;
}

List<File> download() {
return new Jars(serverConnection, new JarExtractor(), logger, props).download();
}
}

+ 0
- 41
sonar-runner-api/src/main/java/org/sonar/runner/impl/JarExtractor.java View File

@@ -1,41 +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.impl;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.net.URL;

public class JarExtractor {

public File extractToTemp(String filenameWithoutSuffix) {
String filename = filenameWithoutSuffix + ".jar";
URL url = getClass().getResource("/" + filename);
try {
File copy = File.createTempFile(filenameWithoutSuffix, ".jar");
FileUtils.copyURLToFile(url, copy);
return copy;
} catch (Exception e) {
throw new IllegalStateException("Fail to extract " + filename, e);
}
}
}


+ 0
- 110
sonar-runner-api/src/main/java/org/sonar/runner/impl/Jars.java View File

@@ -1,110 +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.impl;

import org.sonar.runner.cache.FileCache;
import org.sonar.runner.cache.FileCacheBuilder;
import org.sonar.runner.cache.Logger;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

class Jars {
private static final String BOOTSTRAP_INDEX_PATH = "/batch_bootstrap/index";
static final String BATCH_PATH = "/batch/";

private final FileCache fileCache;
private final ServerConnection connection;
private final JarExtractor jarExtractor;
private final Logger logger;

Jars(ServerConnection conn, JarExtractor jarExtractor, Logger logger, Properties props) {
this.logger = logger;
this.fileCache = new FileCacheBuilder(logger)
.setUserHome(props.getProperty("sonar.userHome"))
.build();
this.connection = conn;
this.jarExtractor = jarExtractor;
}

/**
* For unit tests
*/
Jars(FileCache fileCache, ServerConnection conn, JarExtractor jarExtractor, Logger logger) {
this.logger = logger;
this.fileCache = fileCache;
this.connection = conn;
this.jarExtractor = jarExtractor;
}

/**
* For unit tests
*/
FileCache getFileCache() {
return fileCache;
}

List<File> download() {
List<File> files = new ArrayList<File>();
logger.debug("Extract sonar-runner-batch in temp...");
files.add(jarExtractor.extractToTemp("sonar-runner-batch"));
files.addAll(dowloadFiles());
return files;
}

private List<File> dowloadFiles() {
try {
List<File> files = new ArrayList<File>();
logger.debug("Get bootstrap index...");
String libs = connection.loadString(BOOTSTRAP_INDEX_PATH);
logger.debug("Get bootstrap completed");
String[] lines = libs.split("[\r\n]+");
BatchFileDownloader batchFileDownloader = new BatchFileDownloader(connection);
for (String line : lines) {
line = line.trim();
if (!"".equals(line)) {
String[] libAndHash = line.split("\\|");
String filename = libAndHash[0];
String hash = libAndHash.length > 0 ? libAndHash[1] : "";
files.add(fileCache.get(filename, hash, batchFileDownloader));
}
}
return files;
} catch (Exception e) {
throw new IllegalStateException("Fail to download libraries from server", e);
}
}

static class BatchFileDownloader implements FileCache.Downloader {
private final ServerConnection connection;

BatchFileDownloader(ServerConnection conn) {
this.connection = conn;
}

@Override
public void download(String filename, File toFile) throws IOException {
connection.download(BATCH_PATH + filename, toFile);
}
}
}

+ 0
- 28
sonar-runner-api/src/main/java/org/sonar/runner/impl/RunnerException.java View File

@@ -1,28 +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.impl;

public class RunnerException extends RuntimeException {

public RunnerException(String message, Throwable cause) {
super(message, cause);
}

}

+ 0
- 218
sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java View File

@@ -1,218 +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.impl;

import com.github.kevinsawicki.http.HttpRequest;
import com.github.kevinsawicki.http.HttpRequest.HttpRequestException;
import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.sonar.runner.cache.Logger;
import org.sonar.runner.cache.PersistentCache;

class ServerConnection {

private static final String SONAR_SERVER_CAN_NOT_BE_REACHED = "SonarQube server ''{0}'' can not be reached";
private static final String STATUS_RETURNED_BY_URL_IS_INVALID = "Status returned by url : ''{0}'' is invalid : {1}";
static final int CONNECT_TIMEOUT_MILLISECONDS = 5000;
static final int READ_TIMEOUT_MILLISECONDS = 60000;
private static final Pattern CHARSET_PATTERN = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)");

private final String serverUrl;
private final String userAgent;

private final PersistentCache wsCache;
private final boolean preferCache;
private final Logger logger;
private final boolean isCacheEnabled;

private ServerConnection(String serverUrl, String app, String appVersion, boolean preferCache, boolean cacheEnabled, PersistentCache cache, Logger logger) {
this.isCacheEnabled = cacheEnabled;
this.logger = logger;
this.serverUrl = removeEndSlash(serverUrl);
this.userAgent = app + "/" + appVersion;
this.wsCache = cache;
this.preferCache = preferCache;
}

private static String removeEndSlash(String url) {
return url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
}

static ServerConnection create(Properties properties, PersistentCache cache, Logger logger, boolean preferCache) {
String serverUrl = properties.getProperty("sonar.host.url");
String app = properties.getProperty(InternalProperties.RUNNER_APP);
String appVersion = properties.getProperty(InternalProperties.RUNNER_APP_VERSION);
boolean enableCache = isCacheEnabled(properties);

return new ServerConnection(serverUrl, app, appVersion, preferCache, enableCache, cache, logger);
}

private static boolean isCacheEnabled(Properties properties) {
String analysisMode = properties.getProperty("sonar.analysis.mode");
return "issues".equalsIgnoreCase(analysisMode);
}

/**
*
* @throws HttpRequestException If there is an underlying IOException related to the connection
* @throws IOException If the HTTP response code is != 200
*/
private String downloadString(String url, boolean saveCache) throws HttpRequestException, IOException {
logger.debug("Download: " + url);
HttpRequest httpRequest = null;
try {
httpRequest = newHttpRequest(new URL(url));
String charset = getCharsetFromContentType(httpRequest.contentType());
if (charset == null || "".equals(charset)) {
charset = "UTF-8";
}
if (!httpRequest.ok()) {
throw new IOException(MessageFormat.format(STATUS_RETURNED_BY_URL_IS_INVALID, url, httpRequest.code()));
}

byte[] body = httpRequest.bytes();
if (saveCache) {
try {
wsCache.put(url, body);
} catch (IOException e) {
logger.warn("Failed to cache WS call: " + e.getMessage());
}
}
return new String(body, charset);
} finally {
if (httpRequest != null) {
httpRequest.disconnect();
}
}
}

void download(String path, File toFile) {
String fullUrl = serverUrl + path;
try {
logger.debug("Download " + fullUrl + " to " + toFile.getAbsolutePath());
HttpRequest httpRequest = newHttpRequest(new URL(fullUrl));
if (!httpRequest.ok()) {
throw new IOException(MessageFormat.format(STATUS_RETURNED_BY_URL_IS_INVALID, fullUrl, httpRequest.code()));
}
httpRequest.receive(toFile);

} catch (Exception e) {
if (isCausedByConnection(e)) {
logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl));
}
FileUtils.deleteQuietly(toFile);
throw new IllegalStateException("Fail to download: " + fullUrl, e);
}
}

/**
* Tries to fetch from cache and server. If both attempts fail, it throws the exception linked to the server connection failure.
*/
String loadString(String path) throws IOException {
String fullUrl = serverUrl + path;

if (isCacheEnabled && preferCache) {
return tryCacheFirst(fullUrl);
} else {
return tryServerFirst(fullUrl, isCacheEnabled);
}

}

private String tryCacheFirst(String fullUrl) throws IOException {
String cached = getFromCache(fullUrl);
if (cached != null) {
return cached;
}

try {
return downloadString(fullUrl, preferCache);
} catch (Exception e) {
logger.error(MessageFormat.format("Data is not cached and " + SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl));
throw e;
}
}

private String tryServerFirst(String fullUrl, boolean cacheEnabled) throws IOException {
try {
return downloadString(fullUrl, cacheEnabled);
} catch (HttpRequest.HttpRequestException e) {
if (cacheEnabled && isCausedByConnection(e)) {
logger.info(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED + ", trying cache", serverUrl));
String cached = getFromCache(fullUrl);
if (cached != null) {
return cached;
}
logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED + " and data is not cached", serverUrl));
throw e;
}

logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl));
throw e;
}
}

private static boolean isCausedByConnection(Exception e) {
return e.getCause() instanceof ConnectException || e.getCause() instanceof UnknownHostException ||
e.getCause() instanceof java.net.SocketTimeoutException;
}

private String getFromCache(String fullUrl) {
try {
return wsCache.getString(fullUrl);
} catch (IOException e) {
throw new IllegalStateException("Failed to access cache", e);
}
}

private HttpRequest newHttpRequest(URL url) {
HttpRequest request = HttpRequest.get(url);
request.trustAllCerts().trustAllHosts();
request.acceptGzipEncoding().uncompress(true);
request.connectTimeout(CONNECT_TIMEOUT_MILLISECONDS).readTimeout(READ_TIMEOUT_MILLISECONDS);
request.userAgent(userAgent);
return request;
}

/**
* Parse out a charset from a content type header.
*
* @param contentType e.g. "text/html; charset=EUC-JP"
* @return "EUC-JP", or null if not found. Charset is trimmed and upper-cased.
*/
static String getCharsetFromContentType(String contentType) {
if (contentType == null) {
return null;
}
Matcher m = CHARSET_PATTERN.matcher(contentType);
if (m.find()) {
return m.group(1).trim().toUpperCase();
}
return null;
}
}

+ 0
- 113
sonar-runner-api/src/main/java/org/sonar/runner/impl/SimulatedLauncher.java View File

@@ -1,113 +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.impl;

import org.sonar.runner.batch.IsolatedLauncher;
import org.sonar.runner.batch.IssueListener;
import org.sonar.runner.batch.LogOutput;
import org.sonar.runner.cache.Logger;

import javax.annotation.Nullable;

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

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 preferCache) {
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;
}

}

+ 0
- 66
sonar-runner-api/src/main/java/org/sonar/runner/impl/TempCleaning.java View File

@@ -1,66 +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.impl;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AgeFileFilter;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.PrefixFileFilter;
import org.sonar.runner.cache.Logger;

import java.io.File;
import java.util.Collection;

/**
* The file sonar-runner-batch.jar is locked by the classloader on Windows and can't be dropped at the end of the execution.
* See {@link IsolatedLauncherFactory}
*/
class TempCleaning {
static final int ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;

final File tempDir;

private final Logger logger;

TempCleaning(Logger logger) {
this(new File(System.getProperty("java.io.tmpdir")), logger);
}

/**
* For unit tests
*/
TempCleaning(File tempDir, Logger logger) {
this.logger = logger;
this.tempDir = tempDir;
}

void clean() {
logger.debug("Start temp cleaning...");
long cutoff = System.currentTimeMillis() - ONE_DAY_IN_MILLISECONDS;
Collection<File> files = FileUtils.listFiles(tempDir, new AndFileFilter(
new PrefixFileFilter("sonar-runner-batch"),
new AgeFileFilter(cutoff)), null);

for (File file : files) {
FileUtils.deleteQuietly(file);
}
logger.debug("Temp cleaning done");
}
}

+ 0
- 41
sonar-runner-api/src/main/java/org/sonar/runner/impl/VersionUtils.java View File

@@ -1,41 +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.impl;

public class VersionUtils {
private VersionUtils() {
// only util static methods
}

public static boolean isAtLeast52(String version) {
// it can be snapshot (5.2-SNAPSHOT)
if (version == null) {
return false;
}

int endIndex = Math.min(3, version.length());
try {
return Double.parseDouble(version.substring(0, endIndex)) >= 5.2;
} catch (NumberFormatException e) {
return false;
}
}

}

+ 0
- 22
sonar-runner-api/src/main/java/org/sonar/runner/impl/package-info.java View File

@@ -1,22 +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
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.runner.impl;


+ 0
- 1
sonar-runner-api/src/main/resources/org/sonar/runner/api/version.txt View File

@@ -1 +0,0 @@
${project.version}

+ 0
- 95
sonar-runner-api/src/test/java/org/sonar/runner/api/DirsTest.java View File

@@ -1,95 +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;

import org.sonar.runner.cache.Logger;

import java.io.File;
import java.util.Properties;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class DirsTest {

Properties p = new Properties();

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void should_init_default_task_work_dir() throws Exception {
p.setProperty("sonar.task", "views");
new Dirs(mock(Logger.class)).init(p);

File workDir = new File(p.getProperty(RunnerProperties.WORK_DIR, null));
assertThat(workDir).isNotNull().isDirectory();
assertThat(workDir.getCanonicalPath()).isEqualTo(new File(".").getCanonicalPath());
}

@Test
public void should_use_parameterized_task_work_dir() throws Exception {
p.setProperty("sonar.task", "views");
p.setProperty(RunnerProperties.WORK_DIR, "generated/reports");
new Dirs(mock(Logger.class)).init(p);

File workDir = new File(p.getProperty(RunnerProperties.WORK_DIR, null));
assertThat(workDir).isNotNull();
// separators from windows to unix
assertThat(workDir.getCanonicalPath().replace("\\", "/")).contains("generated/reports");
}

@Test
public void should_init_default_project_dirs() throws Exception {
p.setProperty("sonar.task", "scan");
new Dirs(mock(Logger.class)).init(p);

File projectDir = new File(p.getProperty(ScanProperties.PROJECT_BASEDIR, null));
File workDir = new File(p.getProperty(RunnerProperties.WORK_DIR, null));

assertThat(projectDir).isNotNull().isDirectory();
assertThat(workDir).isNotNull();

assertThat(projectDir.getCanonicalPath()).isEqualTo(new File(".").getCanonicalPath());
assertThat(workDir.getName()).isEqualTo(".sonar");
assertThat(workDir.getParentFile()).isEqualTo(projectDir);
}

@Test
public void should_set_relative_path_to_project_work_dir() throws Exception {
File initialProjectDir = temp.getRoot();
p.setProperty("sonar.task", "scan");
p.setProperty(RunnerProperties.WORK_DIR, "relative/path");
p.setProperty(ScanProperties.PROJECT_BASEDIR, initialProjectDir.getAbsolutePath());
new Dirs(mock(Logger.class)).init(p);

File projectDir = new File(p.getProperty(ScanProperties.PROJECT_BASEDIR, null));
File workDir = new File(p.getProperty(RunnerProperties.WORK_DIR, null));

assertThat(projectDir).isNotNull().isDirectory();
assertThat(projectDir.getCanonicalPath()).isEqualTo(initialProjectDir.getCanonicalPath());

assertThat(workDir).isNotNull();
assertThat(workDir.getCanonicalPath()).isEqualTo(new File(projectDir, "relative/path").getCanonicalPath());
}
}

+ 0
- 326
sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java View File

@@ -1,326 +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;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentMatcher;
import org.sonar.runner.batch.IsolatedLauncher;
import org.sonar.runner.cache.Logger;
import org.sonar.runner.impl.ClassloadRules;
import org.sonar.runner.impl.IsolatedLauncherFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import static org.mockito.Matchers.anyBoolean;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class EmbeddedRunnerTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void should_create() {
assertThat(EmbeddedRunner.create(mock(LogOutput.class))).isNotNull().isInstanceOf(EmbeddedRunner.class);
}

private IsolatedLauncherFactory batchLauncher;
private IsolatedLauncher launcher;
private EmbeddedRunner runner;

@Before
public void setUp() {
batchLauncher = mock(IsolatedLauncherFactory.class);
launcher = mock(IsolatedLauncher.class);
when(launcher.getVersion()).thenReturn("5.2");
when(batchLauncher.createLauncher(any(Properties.class), any(ClassloadRules.class), anyBoolean())).thenReturn(launcher);
runner = new EmbeddedRunner(batchLauncher, mock(Logger.class), mock(LogOutput.class));
}

@Test
public void test_sync_project() {
String projectKey = "proj";
runner.start();
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());
}

@Test
public void test_fail_project_sync_old_sq() {
when(launcher.getVersion()).thenReturn("5.0");

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("version");

runner.setGlobalProperty("sonar.projectKey", "foo");
runner.start();
runner.syncProject("foo");
}

@Test
public void test_app() {
EmbeddedRunner runner = EmbeddedRunner.create(mock(LogOutput.class)).setApp("Eclipse", "3.1");
assertThat(runner.app()).isEqualTo("Eclipse");
assertThat(runner.appVersion()).isEqualTo("3.1");
}

@Test
public void test_back_compatibility() {
when(launcher.getVersion()).thenReturn("4.5");

Properties analysisProps = new Properties();
analysisProps.put("sonar.dummy", "summy");

runner.setGlobalProperty("sonar.projectKey", "foo");
runner.start();
runner.runAnalysis(analysisProps);
runner.stop();

verify(batchLauncher).createLauncher(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}), any(ClassloadRules.class), anyBoolean());

// it should have added a few properties to analysisProperties, and have merged global props
final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir",
"sonar.projectKey", "sonar.dummy"};

verify(launcher).executeOldVersion(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
Properties m = (Properties) o;
for (String s : mustHaveKeys) {
if (!m.containsKey(s)) {
return false;
}
}
return true;
}
}), eq(new LinkedList<>()));
}

@Test
public void should_set_properties() {
EmbeddedRunner runner = EmbeddedRunner.create(mock(LogOutput.class));
runner.setGlobalProperty("sonar.projectKey", "foo");
runner.addGlobalProperties(new Properties() {
{
setProperty("sonar.login", "admin");
setProperty("sonar.password", "gniark");
}
});

assertThat(runner.globalProperty("sonar.projectKey", null)).isEqualTo("foo");
assertThat(runner.globalProperty("sonar.login", null)).isEqualTo("admin");
assertThat(runner.globalProperty("sonar.password", null)).isEqualTo("gniark");
assertThat(runner.globalProperty("not.set", "this_is_default")).isEqualTo("this_is_default");
}

@Test
public void should_launch_batch() {
runner.setGlobalProperty("sonar.projectKey", "foo");
runner.start();
runner.runAnalysis(new Properties());
runner.stop();

verify(batchLauncher).createLauncher(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}), any(ClassloadRules.class), anyBoolean());

// it should have added a few properties to analysisProperties
final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir"};

verify(launcher).execute(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
Properties m = (Properties) o;
for (String s : mustHaveKeys) {
if (!m.containsKey(s)) {
return false;
}
}
return true;
}
}));
}

@Test
public void test_issue_adapter() {
final List<Issue> issuesRecorded = new LinkedList<>();
IssueListener apiIssueListener = new IssueListener() {
@Override
public void handle(Issue issue) {
issuesRecorded.add(issue);
}
};
IssueListenerAdapter adapter = new IssueListenerAdapter(apiIssueListener);

org.sonar.runner.batch.IssueListener.Issue batchIssue = new org.sonar.runner.batch.IssueListener.Issue();
batchIssue.setAssigneeName("assignee");
adapter.handle(batchIssue);

assertThat(issuesRecorded).hasSize(1);
assertThat(issuesRecorded.get(0).getAssigneeName()).isEqualTo("assignee");
}

@Test(expected = IllegalArgumentException.class)
public void reject_issue_listener_old_version() {
when(launcher.getVersion()).thenReturn("4.5");
launch_with_issue_listener();
}

@Test
public void launch_with_issue_listener() {
runner.start();
runner.runAnalysis(mock(Properties.class), mock(IssueListener.class));
runner.stop();

verify(launcher).execute(any(Properties.class), any(org.sonar.runner.batch.IssueListener.class));
}

@Test
public void should_launch_batch_analysisProperties() {
runner.setGlobalProperty("sonar.projectKey", "foo");
runner.start();

Properties analysisProperties = new Properties();
analysisProperties.put("sonar.projectKey", "value1");
runner.runAnalysis(analysisProperties);
runner.stop();

verify(batchLauncher).createLauncher(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}), any(ClassloadRules.class), anyBoolean());

verify(launcher).execute(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
return "value1".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}));
}

@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");
runner.setGlobalProperty("sonarRunner.dumpToFile", dump.getAbsolutePath());
runner.start();
runner.runAnalysis(p);
runner.stop();

Properties props = new Properties();
props.load(new FileInputStream(dump));

assertThat(props.getProperty("sonar.projectKey")).isEqualTo("foo");
}

@Test
public void should_set_default_platform_encoding() throws Exception {
Properties p = new Properties();
p.setProperty("sonar.task", "scan");
runner.initSourceEncoding(p);
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();
p.setProperty("sonar.task", "scan");
p.setProperty("sonar.sourceEncoding", "THE_ISO_1234");
runner.initSourceEncoding(p);
assertThat(p.getProperty("sonar.sourceEncoding", null)).isEqualTo("THE_ISO_1234");
}

@Test
public void should_not_init_encoding_if_not_project_task() throws Exception {
Properties p = new Properties();
p.setProperty("sonar.task", "views");
runner.initSourceEncoding(p);
assertThat(p.getProperty("sonar.sourceEncoding", null)).isNull();
}

}

+ 0
- 57
sonar-runner-api/src/test/java/org/sonar/runner/api/IssueListenerAdapterTest.java View File

@@ -1,57 +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;

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");
issue.setStartLineOffset(2);
adapter.handle(issue);

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

Issue i = argument.getValue();

assertThat(i.getAssigneeName()).isEqualTo("dummy");
assertThat(i.getStartLineOffset()).isEqualTo(2);
}
}

+ 0
- 76
sonar-runner-api/src/test/java/org/sonar/runner/api/LoggerAdapterTest.java View File

@@ -1,76 +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;

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);
}
}

+ 0
- 34
sonar-runner-api/src/test/java/org/sonar/runner/api/RunnerVersionTest.java View File

@@ -1,34 +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;

import org.junit.Test;

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

public class RunnerVersionTest {

@Test
public void should_load_version() {
String version = RunnerVersion.version();
assertThat(version).isNotEmpty().contains(".").doesNotContain("$");
}

}

+ 0
- 40
sonar-runner-api/src/test/java/org/sonar/runner/api/StdOutLogOutputTest.java View File

@@ -1,40 +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;

import org.junit.Test;
import org.sonar.runner.api.LogOutput.Level;

import java.io.PrintStream;

import static org.mockito.Mockito.verify;

import static org.mockito.Mockito.mock;

public class StdOutLogOutputTest {
private PrintStream stdOut = mock(PrintStream.class);
private StdOutLogOutput logOutput = new StdOutLogOutput(stdOut);

@Test
public void test() {
logOutput.log("msg", Level.INFO);
verify(stdOut).println("INFO: msg");
}
}

+ 0
- 128
sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java View File

@@ -1,128 +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;

import org.junit.Rule;
import org.junit.rules.TemporaryFolder;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;

import org.junit.Test;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class UtilsTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void should_join_strings() {
assertThat(Utils.join(new String[] {}, ",")).isEqualTo("");
assertThat(Utils.join(new String[] {"foo"}, ",")).isEqualTo("foo");
assertThat(Utils.join(new String[] {"foo", "bar"}, ",")).isEqualTo("foo,bar");
}

@Test
public void task_should_require_project() {
Properties props = new Properties();
assertThat(Utils.taskRequiresProject(props)).isTrue();

props.setProperty("sonar.task", "scan");
assertThat(Utils.taskRequiresProject(props)).isTrue();
}

@Test
public void write_properties() throws IOException {
File f = temp.newFile();
Properties p = new Properties();
p.put("key", "value");
Utils.writeProperties(f, p);
assertThat(Files.readAllLines(f.toPath(), StandardCharsets.UTF_8)).contains("key=value");
}

@Test
public void task_should_not_require_project() {
Properties props = new Properties();
props.setProperty("sonar.task", "views");
assertThat(Utils.taskRequiresProject(props)).isFalse();
}

@Test
public void close_quietly_error() throws IOException {
Closeable c = mock(Closeable.class);
doThrow(IOException.class).when(c).close();
Utils.closeQuietly(c);
verify(c).close();
}

@Test
public void close_quietly_null() throws IOException {
Utils.closeQuietly(null);
}

@Test
public void close_quietly() throws IOException {
Closeable c = mock(Closeable.class);
Utils.closeQuietly(c);
verify(c).close();
}
@Test
public void delete_quietly() {
File f = mock(File.class);
doThrow(IOException.class).when(f).toPath();
Utils.deleteQuietly(f);
}

@Test
public void delete_non_empty_directory() throws IOException {
/*-
* Create test structure:
* tmp
* |-folder1
* |- file1
* |- folder2
* |- file2
*/
Path tmpDir = Files.createTempDirectory("junit");
Path folder1 = tmpDir.resolve("folder1");
Files.createDirectories(folder1);
Path file1 = folder1.resolve("file1");
Files.write(file1, "test1".getBytes());

Path folder2 = folder1.resolve("folder2");
Files.createDirectories(folder2);
Path file2 = folder1.resolve("file2");
Files.write(file2, "test2".getBytes());

// delete it
assertThat(tmpDir.toFile()).exists();
Utils.deleteQuietly(tmpDir.toFile());
assertThat(tmpDir.toFile()).doesNotExist();
}
}

+ 0
- 94
sonar-runner-api/src/test/java/org/sonar/runner/cache/DirectoryLockTest.java View File

@@ -1,94 +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.cache;

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

import org.junit.rules.ExpectedException;

import java.nio.channels.OverlappingFileLockException;
import java.nio.file.Paths;

import org.junit.Test;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;

public class DirectoryLockTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Rule
public ExpectedException exception = ExpectedException.none();
private DirectoryLock lock;

@Before
public void setUp() {
lock = new DirectoryLock(temp.getRoot().toPath(), mock(Logger.class));
}

@Test
public void lock() {
assertThat(temp.getRoot().list()).isEmpty();
lock.lock();
assertThat(temp.getRoot().toPath().resolve(".sonar_lock")).exists();
lock.unlock();
assertThat(temp.getRoot().list()).isEmpty();
}

@Test
public void tryLock() {
assertThat(temp.getRoot().list()).isEmpty();
lock.tryLock();
assertThat(temp.getRoot().toPath().resolve(".sonar_lock")).exists();
lock.unlock();
assertThat(temp.getRoot().list()).isEmpty();
}

@Test(expected = OverlappingFileLockException.class)
public void error_2locks() {
assertThat(temp.getRoot().list()).isEmpty();
lock.lock();
lock.lock();
}

@Test
public void unlockWithoutLock() {
lock.unlock();
}

@Test
public void errorCreatingLock() {
lock = new DirectoryLock(Paths.get("non", "existing", "path"), mock(Logger.class));

exception.expect(IllegalStateException.class);
exception.expectMessage("Failed to create lock");
lock.lock();
}

@Test
public void errorTryLock() {
lock = new DirectoryLock(Paths.get("non", "existing", "path"), mock(Logger.class));

exception.expect(IllegalStateException.class);
exception.expectMessage("Failed to create lock");
lock.tryLock();
}
}

+ 0
- 60
sonar-runner-api/src/test/java/org/sonar/runner/cache/FileCacheBuilderTest.java View File

@@ -1,60 +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.cache;

import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

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

public class FileCacheBuilderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void setUserHome() throws Exception {
File userHome = temp.newFolder();
FileCache cache = new FileCacheBuilder(mock(Logger.class)).setUserHome(userHome).build();

assertThat(cache.getDir()).isDirectory().exists();
assertThat(cache.getDir().getName()).isEqualTo("cache");
assertThat(cache.getDir().getParentFile()).isEqualTo(userHome);
}

@Test
public void user_home_property_can_be_null() {
FileCache cache = new FileCacheBuilder(mock(Logger.class)).setUserHome((String) null).build();

// does not fail. It uses default path or env variable
assertThat(cache.getDir()).isDirectory().exists();
assertThat(cache.getDir().getName()).isEqualTo("cache");
}

@Test
public void use_default_path_or_env_variable() {
FileCache cache = new FileCacheBuilder(mock(Logger.class)).build();

assertThat(cache.getDir()).isDirectory().exists();
assertThat(cache.getDir().getName()).isEqualTo("cache");
}
}

+ 0
- 117
sonar-runner-api/src/test/java/org/sonar/runner/cache/FileCacheTest.java View File

@@ -1,117 +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.cache;

import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class FileCacheTest {
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void not_in_cache() throws IOException {
FileCache cache = FileCache.create(tempFolder.newFolder(), mock(Logger.class));
assertThat(cache.get("sonar-foo-plugin-1.5.jar", "ABCDE")).isNull();
}

@Test
public void found_in_cache() throws IOException {
FileCache cache = FileCache.create(tempFolder.newFolder(), mock(Logger.class));

// populate the cache. Assume that hash is correct.
File cachedFile = new File(new File(cache.getDir(), "ABCDE"), "sonar-foo-plugin-1.5.jar");
FileUtils.write(cachedFile, "body");

assertThat(cache.get("sonar-foo-plugin-1.5.jar", "ABCDE")).isNotNull().exists().isEqualTo(cachedFile);
}

@Test
public void download_and_add_to_cache() throws IOException {
FileHashes hashes = mock(FileHashes.class);
FileCache cache = new FileCache(tempFolder.newFolder(), hashes, mock(Logger.class));
when(hashes.of(any(File.class))).thenReturn("ABCDE");

FileCache.Downloader downloader = new FileCache.Downloader() {
public void download(String filename, File toFile) throws IOException {
FileUtils.write(toFile, "body");
}
};
File cachedFile = cache.get("sonar-foo-plugin-1.5.jar", "ABCDE", downloader);
assertThat(cachedFile).isNotNull().exists().isFile();
assertThat(cachedFile.getName()).isEqualTo("sonar-foo-plugin-1.5.jar");
assertThat(cachedFile.getParentFile().getParentFile()).isEqualTo(cache.getDir());
assertThat(FileUtils.readFileToString(cachedFile)).isEqualTo("body");
}

@Test
public void download_corrupted_file() throws IOException {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("INVALID HASH");

FileHashes hashes = mock(FileHashes.class);
FileCache cache = new FileCache(tempFolder.newFolder(), hashes, mock(Logger.class));
when(hashes.of(any(File.class))).thenReturn("VWXYZ");

FileCache.Downloader downloader = new FileCache.Downloader() {
public void download(String filename, File toFile) throws IOException {
FileUtils.write(toFile, "corrupted body");
}
};
cache.get("sonar-foo-plugin-1.5.jar", "ABCDE", downloader);
}

@Test
public void concurrent_download() throws IOException {
FileHashes hashes = mock(FileHashes.class);
when(hashes.of(any(File.class))).thenReturn("ABCDE");
final FileCache cache = new FileCache(tempFolder.newFolder(), hashes, mock(Logger.class));

FileCache.Downloader downloader = new FileCache.Downloader() {
public void download(String filename, File toFile) throws IOException {
// Emulate a concurrent download that adds file to cache before
File cachedFile = new File(new File(cache.getDir(), "ABCDE"), "sonar-foo-plugin-1.5.jar");
FileUtils.write(cachedFile, "downloaded by other");

FileUtils.write(toFile, "downloaded by me");
}
};

// do not fail
File cachedFile = cache.get("sonar-foo-plugin-1.5.jar", "ABCDE", downloader);
assertThat(cachedFile).isNotNull().exists().isFile();
assertThat(cachedFile.getName()).isEqualTo("sonar-foo-plugin-1.5.jar");
assertThat(cachedFile.getParentFile().getParentFile()).isEqualTo(cache.getDir());
assertThat(FileUtils.readFileToString(cachedFile)).contains("downloaded by");
}
}

+ 0
- 127
sonar-runner-api/src/test/java/org/sonar/runner/cache/FileHashesTest.java View File

@@ -1,127 +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.cache;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.SecureRandom;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class FileHashesTest {

SecureRandom secureRandom = new SecureRandom();

@Rule
public ExpectedException thrown = ExpectedException.none();

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void test_md5_hash() {
assertThat(hash("sonar")).isEqualTo("d85e336d61f5344395c42126fac239bc");

// compare results with commons-codec
for (int index = 0; index < 100; index++) {
String random = randomString();
assertThat(hash(random)).as(random).isEqualTo(
DigestUtils.md5Hex(random).toLowerCase()
);
}
}

@Test
public void test_hash_file() throws IOException {
File f = temp.newFile();
Files.write(f.toPath(), "sonar".getBytes(StandardCharsets.UTF_8));
assertThat(hashFile(f)).isEqualTo("d85e336d61f5344395c42126fac239bc");
}

@Test
public void test_toHex() {
// lower-case
assertThat(FileHashes.toHex("aloa_bi_bop_a_loula".getBytes())).isEqualTo("616c6f615f62695f626f705f615f6c6f756c61");

// compare results with commons-codec
for (int index = 0; index < 100; index++) {
String random = randomString();
assertThat(FileHashes.toHex(random.getBytes())).as(random).isEqualTo(
Hex.encodeHexString(random.getBytes()).toLowerCase()
);
}
}

@Test
public void fail_if_file_does_not_exist() throws IOException {
File file = temp.newFile("does_not_exist");
FileUtils.forceDelete(file);

thrown.expect(IllegalStateException.class);
thrown.expectMessage("Fail to compute hash of: " + file.getAbsolutePath());

new FileHashes().of(file);
}

@Test
public void fail_if_stream_is_closed() throws Exception {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Fail to compute hash");

InputStream input = mock(InputStream.class);
when(input.read(any(byte[].class), anyInt(), anyInt())).thenThrow(new IllegalThreadStateException());
new FileHashes().of(input);
}

private String randomString() {
return new BigInteger(130, secureRandom).toString(32);
}

private String hash(String s) {
InputStream in = new ByteArrayInputStream(s.getBytes());
try {
return new FileHashes().of(in);
} finally {
IOUtils.closeQuietly(in);
}
}

private String hashFile(File f) {
return new FileHashes().of(f);
}
}

+ 0
- 78
sonar-runner-api/src/test/java/org/sonar/runner/cache/PersistentCacheBuilderTest.java View File

@@ -1,78 +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.cache;

import java.nio.file.Files;
import java.nio.file.Paths;

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

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.mockito.Mockito.mock;

public class PersistentCacheBuilderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void user_home_property_can_be_null() {
PersistentCache cache = new PersistentCacheBuilder(mock(Logger.class)).setSonarHome(null).setAreaForGlobal("url").build();
assertTrue(Files.isDirectory(cache.getDirectory()));
assertThat(cache.getDirectory()).endsWith(Paths.get("url", "global"));
}

@Test
public void set_user_home() {
PersistentCache cache = new PersistentCacheBuilder(mock(Logger.class)).setSonarHome(temp.getRoot().toPath()).setAreaForGlobal("url").build();

assertThat(cache.getDirectory()).isDirectory();
assertThat(cache.getDirectory()).startsWith(temp.getRoot().toPath());
assertTrue(Files.isDirectory(cache.getDirectory()));
}

@Test
public void read_system_env() {
assumeTrue(System.getenv("SONAR_USER_HOME") == null);

System.setProperty("user.home", temp.getRoot().getAbsolutePath());

PersistentCache cache = new PersistentCacheBuilder(mock(Logger.class)).setAreaForGlobal("url").build();
assertTrue(Files.isDirectory(cache.getDirectory()));
assertThat(cache.getDirectory()).startsWith(temp.getRoot().toPath());
}

@Test
public void directories() {
System.setProperty("user.home", temp.getRoot().getAbsolutePath());

PersistentCache cache = new PersistentCacheBuilder(mock(Logger.class)).setAreaForProject("url", "0", "proj").build();
assertThat(cache.getDirectory()).endsWith(Paths.get(".sonar", "ws_cache", "url", "0", "projects", "proj"));

cache = new PersistentCacheBuilder(mock(Logger.class)).setAreaForLocalProject("url", "0").build();
assertThat(cache.getDirectory()).endsWith(Paths.get(".sonar", "ws_cache", "url", "0", "local"));

cache = new PersistentCacheBuilder(mock(Logger.class)).setAreaForGlobal("url").build();
assertThat(cache.getDirectory()).endsWith(Paths.get(".sonar", "ws_cache", "url", "global"));
}
}

+ 0
- 145
sonar-runner-api/src/test/java/org/sonar/runner/cache/PersistentCacheTest.java View File

@@ -1,145 +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.cache;

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.mockito.Matchers.any;

import static org.mockito.Mockito.when;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class PersistentCacheTest {
private final static String URI = "key1";
private final static String VALUE = "cache content";
private PersistentCache cache = null;
private DirectoryLock lock = null;
private PersistentCacheInvalidation invalidation = null;

@Rule
public TemporaryFolder tmp = new TemporaryFolder();

@Before
public void setUp() throws IOException {
invalidation = mock(PersistentCacheInvalidation.class);
when(invalidation.test(any(Path.class))).thenReturn(false);
lock = mock(DirectoryLock.class);
when(lock.getFileLockName()).thenReturn("lock");
cache = new PersistentCache(tmp.getRoot().toPath(), invalidation, mock(Logger.class), lock);
}

@Test
public void testCacheMiss() throws Exception {
assertCacheHit(false);
}

@Test
public void testClean() throws Exception {
Path lockFile = cache.getDirectory().resolve("lock");
// puts entry
cache.put(URI, VALUE.getBytes(StandardCharsets.UTF_8));
Files.write(lockFile, "test".getBytes(StandardCharsets.UTF_8));
assertCacheHit(true);
when(invalidation.test(any(Path.class))).thenReturn(true);
cache.clean();
when(invalidation.test(any(Path.class))).thenReturn(false);
assertCacheHit(false);
// lock file should not get deleted
assertThat(new String(Files.readAllBytes(lockFile), StandardCharsets.UTF_8)).isEqualTo("test");
}

@Test
public void testStream() throws IOException {
cache.put("id", "test".getBytes());
InputStream stream = cache.getStream("id");
assertThat(IOUtils.toString(stream)).isEqualTo("test");

assertThat(cache.getStream("non existing")).isNull();
}

@Test
public void testClear() throws Exception {
Path lockFile = cache.getDirectory().resolve("lock");
cache.put(URI, VALUE.getBytes(StandardCharsets.UTF_8));
Files.write(lockFile, "test".getBytes(StandardCharsets.UTF_8));
assertCacheHit(true);
cache.clear();
assertCacheHit(false);
// lock file should not get deleted
assertThat(new String(Files.readAllBytes(lockFile), StandardCharsets.UTF_8)).isEqualTo("test");
}

@Test
public void testCacheHit() throws Exception {
cache.put(URI, VALUE.getBytes(StandardCharsets.UTF_8));
assertCacheHit(true);
}

@Test
public void testReconfigure() throws Exception {
assertCacheHit(false);
cache.put(URI, VALUE.getBytes(StandardCharsets.UTF_8));
assertCacheHit(true);

File root = tmp.getRoot();
FileUtils.deleteQuietly(root);

// should re-create cache directory and start using the cache
cache.reconfigure();
assertThat(root).exists();

assertCacheHit(false);
cache.put(URI, VALUE.getBytes(StandardCharsets.UTF_8));
assertCacheHit(true);
}

@Test
public void testExpiration() throws Exception {
when(invalidation.test(any(Path.class))).thenReturn(true);
cache.put(URI, VALUE.getBytes(StandardCharsets.UTF_8));
assertCacheHit(false);
}

private void assertCacheHit(boolean hit) throws Exception {
assertCacheHit(cache, hit);
}

private void assertCacheHit(PersistentCache pCache, boolean hit) throws Exception {
String expected = hit ? VALUE : null;
assertThat(pCache.getString(URI)).isEqualTo(expected);
verify(lock, atLeast(1)).unlock();
}

}

+ 0
- 55
sonar-runner-api/src/test/java/org/sonar/runner/cache/TTLCacheInvalidationTest.java View File

@@ -1,55 +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.cache;

import org.junit.Before;

import java.io.IOException;
import java.nio.file.Path;

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

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

public class TTLCacheInvalidationTest {
private Path testFile;

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Before
public void setUp() throws IOException {
testFile = temp.newFile().toPath();
}

@Test
public void testExpired() throws IOException {
TTLCacheInvalidation invalidation = new TTLCacheInvalidation(-100);
assertThat(invalidation.test(testFile)).isEqualTo(true);
}

@Test
public void testValid() throws IOException {
TTLCacheInvalidation invalidation = new TTLCacheInvalidation(100_000);
assertThat(invalidation.test(testFile)).isEqualTo(false);
}
}

+ 0
- 106
sonar-runner-api/src/test/java/org/sonar/runner/impl/ClassloadRulesTest.java View File

@@ -1,106 +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.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();
}
}

+ 0
- 110
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedClassloaderTest.java View File

@@ -1,110 +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.impl;

import org.junit.Before;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;

import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.fest.assertions.Assertions.assertThat;

public class IsolatedClassloaderTest {
@Rule
public ExpectedException thrown = ExpectedException.none();

private IsolatedClassloader classLoader;

@Before
public void setUp() {
ClassLoader parent = getClass().getClassLoader();
classLoader = new IsolatedClassloader(parent, new ClassloadRules(new HashSet<String>(), new HashSet<String>()));
}

@Test
public void should_use_isolated_system_classloader_when_parent_is_excluded() throws ClassNotFoundException, IOException {
thrown.expect(ClassNotFoundException.class);
thrown.expectMessage("org.junit.Test");

// 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();
classLoader.loadClass("org.junit.Test", false);
classLoader.close();
}

@Test
public void should_use_parent_to_load() throws ClassNotFoundException, IOException {
ClassloadRules rules = mock(ClassloadRules.class);
when(rules.canLoad("org.junit.Test")).thenReturn(true);
classLoader = new IsolatedClassloader(getClass().getClassLoader(), rules);
assertThat(classLoader.loadClass("org.junit.Test", false)).isNotNull();
}

@Test
public void add_jars() throws MalformedURLException {
File f = new File("dummy");
File[] files = {f};
classLoader.addFiles(Arrays.asList(files));

assertThat(classLoader.getURLs()).contains(f.toURI().toURL());
}

@Test
public void error_add_jars() {
File f = mock(File.class);
when(f.toURI()).thenThrow(MalformedURLException.class);
File[] files = {f};

thrown.expect(IllegalStateException.class);
thrown.expectMessage("Fail to create classloader");

classLoader.addFiles(Arrays.asList(files));
}

@Test
public void dont_get_resource_from_parent() {
URL resource2 = classLoader.getParent().getResource("fake.jar");
assertThat(resource2).isNotNull();

// should not find resource through parent classloader
URL resource = classLoader.getResource("fake.jar");
assertThat(resource).isNull();
}

@Test
public void dont_get_resources_from_parent() throws IOException {
Enumeration<URL> resource2 = classLoader.getParent().getResources("fake.jar");
assertThat(resource2.hasMoreElements()).isTrue();

// should not find resource through parent classloader
Enumeration<URL> resource = classLoader.getResources("fake.jar");
assertThat(resource.hasMoreElements()).isFalse();
}
}

+ 0
- 96
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java View File

@@ -1,96 +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.impl;

import org.junit.Before;
import org.junit.Test;
import org.sonar.runner.batch.IsolatedLauncher;
import org.sonar.runner.batch.IssueListener;
import org.sonar.runner.batch.LogOutput;
import org.sonar.runner.cache.Logger;

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

import static org.fest.assertions.Fail.fail;
import static org.mockito.Mockito.mock;

public class IsolatedLauncherFactoryTest {
IsolatedLauncherFactory factory;
Properties props;
TempCleaning tempCleaning;
JarDownloader jarDownloader;

@Before
public void setUp() {
tempCleaning = mock(TempCleaning.class);
factory = new IsolatedLauncherFactory(FakeIsolatedLauncher.class.getName(), tempCleaning, mock(Logger.class));
props = new Properties();
jarDownloader = mock(JarDownloader.class);
}

@Test
public void should_use_isolated_classloader() {
try {
factory.createLauncher(jarDownloader, new ClassloadRules(new HashSet<String>(), new HashSet<String>()));
fail();
} catch (RunnerException e) {
// success
}
}

public static class FakeIsolatedLauncher implements IsolatedLauncher {
public static Properties props = null;
public static IssueListener listener = null;

@Override
public void start(Properties properties, LogOutput logger, boolean preferCache) {
}

@Override
public void stop() {
}

@Override
public void execute(Properties properties) {
FakeIsolatedLauncher.props = properties;
}

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

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

@Override
public void execute(Properties properties, IssueListener listener) {
FakeIsolatedLauncher.props = properties;
FakeIsolatedLauncher.listener = listener;
}

@Override
public void syncProject(String projectKey) {
}
}
}

+ 0
- 77
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherProxyTest.java View File

@@ -1,77 +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.impl;

import org.junit.Before;
import org.junit.Test;
import org.sonar.runner.batch.BatchIsolatedLauncher;
import org.sonar.runner.cache.Logger;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.Callable;

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

public class IsolatedLauncherProxyTest {
BatchIsolatedLauncher laucherProxy = null;
ClassLoader cl = null;

@Before
public void setUp() {
cl = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
}

@Test
public void delegate_proxied() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String str = "test";
CharSequence s = IsolatedLauncherProxy.create(cl, str, CharSequence.class, mock(Logger.class));
assertThat(s).isEqualTo(str);
}

@Test(expected = IllegalStateException.class)
public void exceptions_unwrapped() throws ReflectiveOperationException {
Runnable r = IsolatedLauncherProxy.create(cl, Runnable.class, ExceptionThrower.class.getName(), mock(Logger.class));
r.run();
}

@Test
public void create_proxied() throws Exception {
Callable<?> c = IsolatedLauncherProxy.create(cl, Callable.class, SimpleClass.class.getName(), mock(Logger.class));
assertThat(c.getClass().getClassLoader()).isEqualTo(cl);
assertThat(c.getClass().getClassLoader()).isNotEqualTo(Thread.currentThread().getContextClassLoader());
assertThat(c.call()).isEqualTo(URLClassLoader.class.getSimpleName());
}

public static class ExceptionThrower implements Runnable {
@Override
public void run() {
throw new IllegalStateException("message");
}
}

public static class SimpleClass implements Callable<String> {
@Override
public String call() throws Exception {
return Thread.currentThread().getContextClassLoader().getClass().getSimpleName();
}
}
}

+ 0
- 47
sonar-runner-api/src/test/java/org/sonar/runner/impl/JarDownloaderTest.java View File

@@ -1,47 +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.impl;

import org.junit.Test;
import org.sonar.runner.cache.Logger;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;

public class JarDownloaderTest {

ServerConnection serverConnection = mock(ServerConnection.class);
Properties props = new Properties();
JarDownloader downloader = spy(new JarDownloader(serverConnection, mock(Logger.class), props));

@Test
public void should_download_jar_files() {
doReturn(new ArrayList<File>()).when(downloader).download();
List<File> jarFiles = downloader.download();
assertThat(jarFiles).isNotNull();
}
}

+ 0
- 48
sonar-runner-api/src/test/java/org/sonar/runner/impl/JarExtractorTest.java View File

@@ -1,48 +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.impl;

import org.apache.commons.io.FileUtils;
import org.junit.Test;

import java.io.File;

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

public class JarExtractorTest {
@Test
public void test_extract() throws Exception {
File jarFile = new JarExtractor().extractToTemp("fake");
assertThat(jarFile).isFile().exists();
assertThat(FileUtils.readFileToString(jarFile, "UTF-8")).isEqualTo("Fake jar for unit tests");
assertThat(jarFile.toURI().toURL().toString()).doesNotContain("jar:file");
}

@Test
public void should_fail_to_extract() throws Exception {
try {
new JarExtractor().extractToTemp("unknown");
fail();
} catch (IllegalStateException e) {
assertThat(e).hasMessage("Fail to extract unknown.jar");
}
}
}

+ 0
- 103
sonar-runner-api/src/test/java/org/sonar/runner/impl/JarsTest.java View File

@@ -1,103 +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.impl;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.runner.cache.FileCache;
import org.sonar.runner.cache.Logger;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

public class JarsTest {
ServerConnection connection = mock(ServerConnection.class);
JarExtractor jarExtractor = mock(JarExtractor.class);
FileCache fileCache = mock(FileCache.class);

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void should_download_jar_files() throws Exception {
File batchJar = temp.newFile("sonar-runner-batch.jar");
when(jarExtractor.extractToTemp("sonar-runner-batch")).thenReturn(batchJar);
// index of the files to download
when(connection.loadString("/batch_bootstrap/index")).thenReturn(
"cpd.jar|CA124VADFSDS\n" +
"squid.jar|34535FSFSDF\n");

Jars jars35 = new Jars(fileCache, connection, jarExtractor, mock(Logger.class));
List<File> files = jars35.download();

assertThat(files).isNotNull();
verify(connection, times(1)).loadString("/batch_bootstrap/index");
verifyNoMoreInteractions(connection);
verify(fileCache, times(1)).get(eq("cpd.jar"), eq("CA124VADFSDS"), any(FileCache.Downloader.class));
verify(fileCache, times(1)).get(eq("squid.jar"), eq("34535FSFSDF"), any(FileCache.Downloader.class));
verifyNoMoreInteractions(fileCache);
}

@Test
public void should_honor_sonarUserHome() throws IOException {
Properties props = new Properties();
File f = temp.newFolder();
props.put("sonar.userHome", f.getAbsolutePath());
Jars jars = new Jars(connection, jarExtractor, mock(Logger.class), props);
assertThat(jars.getFileCache().getDir()).isEqualTo(new File(f, "cache"));
}

@Test
public void should_fail_to_download_files() throws Exception {
File batchJar = temp.newFile("sonar-runner-batch.jar");
when(jarExtractor.extractToTemp("sonar-runner-batch")).thenReturn(batchJar);
// index of the files to download
when(connection.loadString("/batch_bootstrap/index")).thenThrow(new IllegalStateException());

Jars jars35 = new Jars(fileCache, connection, jarExtractor, mock(Logger.class));
try {
jars35.download();
fail();
} catch (RuntimeException e) {
assertThat(e).hasMessage("Fail to download libraries from server");
}
}

@Test
public void test_jar_downloader() throws Exception {
Jars.BatchFileDownloader downloader = new Jars.BatchFileDownloader(connection);
File toFile = temp.newFile();
downloader.download("squid.jar", toFile);
verify(connection).download("/batch/squid.jar", toFile);
}
}

+ 0
- 123
sonar-runner-api/src/test/java/org/sonar/runner/impl/MockHttpServer.java View File

@@ -1,123 +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.impl;

import org.apache.commons.io.IOUtils;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.HttpException;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.apache.commons.io.IOUtils.write;

class MockHttpServer {
private Server server;
private String responseBody;
private String requestBody;
private String mockResponseData;
private int mockResponseStatus = SC_OK;

public void start() throws Exception {
// 0 is random available port
server = new Server(0);
server.setHandler(getMockHandler());
server.start();
}

/**
* Creates an {@link AbstractHandler handler} returning an arbitrary String as a response.
*
* @return never <code>null</code>.
*/
public Handler getMockHandler() {
Handler handler = new AbstractHandler() {

public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException {
// SONARPLUGINS-3061
if (target.startsWith("//")) {
throw new HttpException(404, "Not found");
}
Request baseRequest = request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
setResponseBody(getMockResponseData());
setRequestBody(IOUtils.toString(baseRequest.getInputStream()));
response.setStatus(mockResponseStatus);
response.setContentType("text/xml;charset=utf-8");
write(getResponseBody(), response.getOutputStream());
baseRequest.setHandled(true);
}
};
return handler;
}

public void stop() {
try {
if (server != null) {
server.stop();
}
} catch (Exception e) {
throw new IllegalStateException("Fail to stop HTTP server", e);
}
}

public void setResponseBody(String responseBody) {
this.responseBody = responseBody;
}

public String getResponseBody() {
return responseBody;
}

public void setRequestBody(String requestBody) {
this.requestBody = requestBody;
}

public String getRequestBody() {
return requestBody;
}

public void setMockResponseData(String mockResponseData) {
this.mockResponseData = mockResponseData;
}

public void setMockResponseStatus(int status) {
this.mockResponseStatus = status;
}

public String getMockResponseData() {
return mockResponseData;
}

public int getPort() {
return server.getConnectors()[0].getLocalPort();
}

public String getUrl() {
return "http://" + server.getConnectors()[0].getName();
}
}

+ 0
- 54
sonar-runner-api/src/test/java/org/sonar/runner/impl/MockHttpServerInterceptor.java View File

@@ -1,54 +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.impl;

import org.junit.rules.ExternalResource;

public class MockHttpServerInterceptor extends ExternalResource {

private MockHttpServer server;

@Override
protected final void before() throws Throwable {
server = new MockHttpServer();
server.start();
}

@Override
protected void after() {
server.stop();
}

public void setMockResponseData(String data) {
server.setMockResponseData(data);
}

public void setMockResponseStatus(int status) {
server.setMockResponseStatus(status);
}

public String url() {
return server.getUrl();
}

public int getPort() {
return server.getPort();
}
}

+ 0
- 52
sonar-runner-api/src/test/java/org/sonar/runner/impl/NetworkUtil.java View File

@@ -1,52 +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.impl;


import java.io.IOException;
import java.net.ServerSocket;
import java.util.Arrays;
import java.util.List;

class NetworkUtil {
static int getNextAvailablePort() {
for (int index = 0; index < 5; index++) {
try {
ServerSocket socket = new ServerSocket(0);
int unusedPort = socket.getLocalPort();
socket.close();
if (isValidPort(unusedPort)) {
return unusedPort;
}

} catch (IOException e) {
throw new IllegalStateException("Can not find an open network port", e);
}
}
throw new IllegalStateException("Can not find an open network port");
}

// Firefox blocks some reserverd ports : http://www-archive.mozilla.org/projects/netlib/PortBanning.html
private static final List<Integer> BLOCKED_PORTS = Arrays.asList(2049, 4045, 6000);

static boolean isValidPort(int port) {
return port > 1023 && !BLOCKED_PORTS.contains(port);
}
}

+ 0
- 261
sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java View File

@@ -1,261 +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.impl;

import com.github.kevinsawicki.http.HttpRequest;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.runner.cache.Logger;
import org.sonar.runner.cache.PersistentCache;
import org.sonar.runner.cache.PersistentCacheBuilder;

import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.Properties;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.startsWith;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class ServerConnectionTest {

@Rule
public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor();

@Rule
public TemporaryFolder temp = new TemporaryFolder();

private PersistentCache cache;
private Logger logger;

@Before
public void setUp() {
cache = new PersistentCacheBuilder(mock(Logger.class))
.setAreaForGlobal("server")
.setSonarHome(temp.getRoot().toPath())
.build();
logger = mock(Logger.class);
}

@Test
public void continue_if_cache_put_fails() throws Exception {
cache = mock(PersistentCache.class);
doThrow(IOException.class).when(cache).put(anyString(), any(byte[].class));
ServerConnection connection = createSimpleServerConnection(httpServer.url(), null, true, false);
String response = connection.loadString("/batch/index.txt");

assertThat(response).isEqualTo("abcde");
verify(logger).warn(startsWith("Failed to cache WS call:"));
}

@Test
public void should_download_to_string() throws Exception {
ServerConnection connection = createSimpleServerConnection(httpServer.url(), null);
String response = connection.loadString("/batch/index.txt");

assertThat(response).isEqualTo("abcde");
}
@Test
public void test_prefer_cache() throws IOException {
File cacheDir = cache.getDirectory().toFile();

ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true, true);

//not cached
assertThat(cacheDir.list().length).isEqualTo(0);
String str = connection.loadString("/batch/index.txt");

//cached
assertThat(str).isEqualTo("abcde");
assertThat(cacheDir.list().length).isEqualTo(1);

httpServer.setMockResponseData("request2");
//got response in cached
str = connection.loadString("/batch/index.txt");
assertThat(str).isEqualTo("abcde");
}
@Test
public void test_dont_prefer_cache() throws IOException {
File cacheDir = cache.getDirectory().toFile();

ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true, false);

//not cached
assertThat(cacheDir.list().length).isEqualTo(0);
String str = connection.loadString("/batch/index.txt");

//cached
assertThat(str).isEqualTo("abcde");
assertThat(cacheDir.list().length).isEqualTo(1);

httpServer.setMockResponseData("request2");
//got response in cached
str = connection.loadString("/batch/index.txt");
assertThat(str).isEqualTo("request2");
httpServer.after();
str = connection.loadString("/batch/index.txt");
assertThat(str).isEqualTo("request2");
}

@Test
public void should_download_to_file() throws Exception {
ServerConnection connection = createSimpleServerConnection(httpServer.url(), null);
File toFile = temp.newFile();
connection.download("/batch/index.txt", toFile);

assertThat(FileUtils.readFileToString(toFile)).isEqualTo("abcde");
}

@Test
public void should_throw_connection_exception_fallback_to_cache() throws IOException {
cache = mock(PersistentCache.class);
ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort(),
true, false);

try {
connection.loadString("/batch/index.txt");
fail();
} catch (HttpRequest.HttpRequestException e) {
verify(cache).getString(anyString());
assertThat(e.getCause()).isInstanceOf(ConnectException.class);
}
}

@Test
public void should_cache_jar_list() throws Exception {
File cacheDir = cache.getDirectory().toFile();

ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true, false);

assertThat(cacheDir.list().length).isEqualTo(0);
String str = connection.loadString("/batch/index.txt");

assertThat(str).isEqualTo("abcde");
assertThat(cacheDir.list().length).isEqualTo(1);

httpServer.after();
str = connection.loadString("/batch/index.txt");
assertThat(str).isEqualTo("abcde");
}

@Test
public void should_throw_connection_exception() throws IOException {
File cacheDir = cache.getDirectory().toFile();
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null);

assertThat(cacheDir.list().length).isEqualTo(0);
String str = connection.loadString("/batch/index.txt");
assertThat(str).isEqualTo("abcde");

httpServer.after();

try {
connection.loadString("/batch/index.txt");
fail("exception expected");
} catch (HttpRequest.HttpRequestException e) {
// expected
assertTrue((e.getCause() instanceof ConnectException) || (e.getCause() instanceof SocketTimeoutException));

// cache never used
assertThat(cacheDir.list().length).isEqualTo(0);
}

}

@Test
public void should_not_cache_not_issues_mode() throws Exception {
File cacheDir = cache.getDirectory().toFile();
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null);

assertThat(cacheDir.list().length).isEqualTo(0);
String str = connection.loadString("/batch/index.txt");

assertThat(str).isEqualTo("abcde");
assertThat(cacheDir.list().length).isEqualTo(0);

httpServer.setMockResponseData("request2");
str = connection.loadString("/batch/index.txt");
assertThat(str).isEqualTo("request2");
}

// SONARPLUGINS-3061
@Test
public void should_support_trailing_slash() throws Exception {
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null);
File toFile = temp.newFile();
connection.download("/batch/index.txt", toFile);

assertThat(FileUtils.readFileToString(toFile)).isEqualTo("abcde");
}

@Test
public void should_not_download_file_when_host_is_down() throws Exception {
ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort());

File toFile = temp.newFile();
try {
connection.download("/batch/index.txt", toFile);
fail();
} catch (Exception e) {
// success
}
}

@Test
public void should_not_download_string_when_host_is_down() throws Exception {
ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort());

try {
connection.loadString("/batch/index.txt");
fail();
} catch (Exception e) {
// success
}
}

private ServerConnection createSimpleServerConnection(String url, Integer port) {
return createSimpleServerConnection(url, port, false, false);
}

private ServerConnection createSimpleServerConnection(String url, Integer port, boolean issuesMode, boolean preferCache) {
httpServer.setMockResponseData("abcde");
String fullUrl = port == null ? url : url + ":" + port;
Properties props = new Properties();
props.setProperty("sonar.host.url", fullUrl);
if (issuesMode) {
props.setProperty("sonar.analysis.mode", "issues");
}
return ServerConnection.create(props, cache, logger, preferCache);
}
}

+ 0
- 142
sonar-runner-api/src/test/java/org/sonar/runner/impl/SimulatedLauncherTest.java View File

@@ -1,142 +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.impl;

import org.sonar.runner.batch.IssueListener;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.runner.cache.Logger;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;

import static org.mockito.Mockito.doThrow;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class SimulatedLauncherTest {
private static final String VERSION = "5.2";
private SimulatedLauncher launcher;
private Logger logger;
private String filename;

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Before
public void setUp() {
logger = mock(Logger.class);
launcher = new SimulatedLauncher(VERSION, logger);
filename = new File(temp.getRoot(), "props").getAbsolutePath();
}

@Test
public void testDump() throws IOException {
Properties global = new Properties();
global.putAll(createProperties(true));
Properties analysis = new Properties();
analysis.putAll(createProperties(false));

launcher.start(global, null, false);
launcher.execute(analysis);
assertDump(global, analysis);
}

@Test
public void testDump_with_issue_listener() throws IOException {
Properties global = new Properties();
global.putAll(createProperties(true));
Properties analysis = new Properties();
analysis.putAll(createProperties(false));

launcher.start(global, null, false);
launcher.execute(analysis, mock(IssueListener.class));
assertDump(global, analysis);
}

@Test(expected = IllegalStateException.class)
public void error_if_no_dump_file() {
launcher.execute(new Properties());
}

@Test(expected = IllegalStateException.class)
public void error_dump() throws IOException {
Properties p = mock(Properties.class);
doThrow(IOException.class).when(p).store(any(OutputStream.class), anyString());
launcher.execute(p);
}

@Test
public void no_ops() {
launcher.syncProject(null);
}

@Test
public void testOldExecute() {
Properties global = new Properties();
global.putAll(createProperties(true));
Properties analysis = new Properties();
analysis.putAll(createProperties(false));

launcher.start(global, null, false);
launcher.executeOldVersion(analysis, null);

}

private Properties createProperties(boolean global) {
Properties prop = new Properties();
prop.put("key1_" + global, "value1");
prop.put("key2_" + global, "value2");
prop.put(InternalProperties.RUNNER_DUMP_TO_FILE, filename);
return prop;
}

@Test
public void version() {
assertThat(launcher.getVersion()).isEqualTo(VERSION);
}

private void assertDump(Properties global, Properties analysis) throws IOException {
if (analysis != null) {
Properties p = new Properties();
p.load(new FileInputStream(new File(filename)));
assertThat(p).isEqualTo(analysis);
} else {
assertThat(new File(filename)).doesNotExist();
}

if (global != null) {
Properties p = new Properties();
p.load(new FileInputStream(new File(filename + ".global")));
assertThat(p).isEqualTo(global);
} else {
assertThat(new File(filename + ".global")).doesNotExist();
}
}

}

+ 0
- 66
sonar-runner-api/src/test/java/org/sonar/runner/impl/TempCleaningTest.java View File

@@ -1,66 +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.impl;

import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.runner.cache.Logger;

import java.io.File;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class TempCleaningTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void should_clean_jvm_tmp_dir() {
TempCleaning cleaning = new TempCleaning(mock(Logger.class));
assertThat(cleaning.tempDir).isDirectory().exists();
}

@Test
public void should_clean() throws Exception {
File dir = temp.newFolder();
File oldBatch = new File(dir, "sonar-runner-batch656.jar");
FileUtils.write(oldBatch, "foo");
oldBatch.setLastModified(System.currentTimeMillis() - 3 * TempCleaning.ONE_DAY_IN_MILLISECONDS);

File youngBatch = new File(dir, "sonar-runner-batch123.jar");
FileUtils.write(youngBatch, "foo");

File doNotDelete = new File(dir, "jacoco.txt");
FileUtils.write(doNotDelete, "foo");

assertThat(oldBatch).exists();
assertThat(youngBatch).exists();
assertThat(doNotDelete).exists();
new TempCleaning(dir, mock(Logger.class)).clean();

assertThat(oldBatch).doesNotExist();
assertThat(youngBatch).exists();
assertThat(doNotDelete).exists();
}
}

+ 0
- 39
sonar-runner-api/src/test/java/org/sonar/runner/impl/VersionUtilsTest.java View File

@@ -1,39 +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.impl;

import org.junit.Test;

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

public class VersionUtilsTest {

@Test
public void parse_version() {
assertThat(VersionUtils.isAtLeast52("5.2")).isTrue();
assertThat(VersionUtils.isAtLeast52(null)).isFalse();
assertThat(VersionUtils.isAtLeast52("52")).isTrue();
assertThat(VersionUtils.isAtLeast52("5.0")).isFalse();
assertThat(VersionUtils.isAtLeast52("")).isFalse();
assertThat(VersionUtils.isAtLeast52("trash")).isFalse();
assertThat(VersionUtils.isAtLeast52("6.0.0")).isTrue();
assertThat(VersionUtils.isAtLeast52("5.2-SNAPSHOT")).isTrue();
}
}

+ 0
- 1
sonar-runner-api/src/test/resources/fake.jar View File

@@ -1 +0,0 @@
Fake jar for unit tests

+ 0
- 2
sonar-runner-api/src/test/resources/org/sonar/runner/impl/BatchLauncherMainTest/props.properties View File

@@ -1,2 +0,0 @@
sonar.login=foo
sonar.password=bar

+ 0
- 4
sonar-runner-api/src/test/scripts/echo.bat View File

@@ -1,4 +0,0 @@
@ECHO OFF
@ECHO %CD% > echo.log
@ECHO Parameter: %1 >> echo.log
@ECHO Environment variable: %ENVVAR% >> echo.log

+ 0
- 6
sonar-runner-api/src/test/scripts/echo.sh View File

@@ -1,6 +0,0 @@
#!/bin/sh

WORKING_DIR=`pwd`
echo $WORKING_DIR > echo.log
echo "Parameter: $1" >> echo.log
echo "Environment variable: $ENVVAR" >> echo.log

+ 0
- 6
sonar-runner-api/src/test/scripts/forever.bat View File

@@ -1,6 +0,0 @@
@ECHO OFF

:LOOP
@rem Next line may lead to freeze of build process on Windows 7 due to non-terminated ping-processes
@rem ping 1.1.1.1 -n 2 -w 60000 > nul
GOTO LOOP

+ 0
- 6
sonar-runner-api/src/test/scripts/forever.sh View File

@@ -1,6 +0,0 @@
#!/bin/sh

while test "notempty"
do
sleep 1
done

+ 0
- 5
sonar-runner-api/src/test/scripts/output.bat View File

@@ -1,5 +0,0 @@
@ECHO OFF
@ECHO stdOut: first line
@ECHO stdOut: second line
@ECHO stdErr: first line 1>&2
@ECHO stdErr: second line 1>&2

+ 0
- 6
sonar-runner-api/src/test/scripts/output.sh View File

@@ -1,6 +0,0 @@
#!/bin/sh

echo stdOut: first line
echo stdOut: second line
echo stdErr: first line 1>&2
echo stdErr: second line 1>&2

+ 0
- 1
sonar-runner-batch-interface/.gitignore View File

@@ -1 +0,0 @@
/target/

+ 0
- 12
sonar-runner-batch-interface/pom.xml View File

@@ -1,12 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonarsource.sonar-runner</groupId>
<artifactId>sonar-runner</artifactId>
<version>2.5-SNAPSHOT</version>
</parent>

<artifactId>sonar-runner-batch-interface</artifactId>
<name>SonarQube Runner - Batch Interface</name>
</project>

+ 0
- 41
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java View File

@@ -1,41 +0,0 @@
/*
* SonarQube Runner - Batch Interface
* 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.batch;

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

public interface IsolatedLauncher {

void start(Properties properties, LogOutput logOutput, boolean preferCache);

void stop();

void execute(Properties properties);
void execute(Properties properties, IssueListener listener);
void syncProject(String projectKey);
void executeOldVersion(Properties properties, List<Object> extensions);

String getVersion();

}

+ 0
- 163
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IssueListener.java View File

@@ -1,163 +0,0 @@
/*
* SonarQube Runner - Batch Interface
* 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.batch;

public interface IssueListener {
void handle(Issue issue);

class Issue {
private Integer startLine;
private Integer startLineOffset;
private Integer endLine;
private Integer endLineOffset;

private String key;
private String componentKey;
private String message;
private String ruleKey;
private String ruleName;
private String status;
private String resolution;
private boolean isNew;
private String assigneeLogin;
private String assigneeName;
private String severity;

public String getSeverity() {
return severity;
}

public void setSeverity(String severity) {
this.severity = severity;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public String getComponentKey() {
return componentKey;
}

public void setComponentKey(String componentKey) {
this.componentKey = componentKey;
}

public Integer getStartLine() {
return startLine;
}

public void setStartLine(Integer startLine) {
this.startLine = startLine;
}

public Integer getStartLineOffset() {
return startLineOffset;
}

public void setStartLineOffset(Integer startLineOffset) {
this.startLineOffset = startLineOffset;
}

public Integer getEndLine() {
return endLine;
}

public void setEndLine(Integer endLine) {
this.endLine = endLine;
}

public Integer getEndLineOffset() {
return endLineOffset;
}

public void setEndLineOffset(Integer endLineOffset) {
this.endLineOffset = endLineOffset;
}
public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getRuleKey() {
return ruleKey;
}

public void setRuleKey(String ruleKey) {
this.ruleKey = ruleKey;
}

public String getRuleName() {
return ruleName;
}

public void setRuleName(String ruleName) {
this.ruleName = ruleName;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getResolution() {
return resolution;
}

public void setResolution(String resolution) {
this.resolution = resolution;
}

public boolean isNew() {
return isNew;
}

public void setNew(boolean isNew) {
this.isNew = isNew;
}

public String getAssigneeLogin() {
return assigneeLogin;
}

public void setAssigneeLogin(String assigneeLogin) {
this.assigneeLogin = assigneeLogin;
}

public String getAssigneeName() {
return assigneeName;
}

public void setAssigneeName(String assigneeName) {
this.assigneeName = assigneeName;
}
}
}

+ 0
- 33
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/LogOutput.java View File

@@ -1,33 +0,0 @@
/*
* SonarQube Runner - Batch Interface
* 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.batch;

/**
* Allow to redirect batch logs to a custom output. By defaults logs are written to System.out
* @since 5.2
*/
public interface LogOutput {

void log(String formattedMessage, Level level);

enum Level {
ERROR, WARN, INFO, DEBUG, TRACE;
}
}

+ 0
- 20
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/package-info.java View File

@@ -1,20 +0,0 @@
/*
* SonarQube Runner - Batch Interface
* 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.batch;

+ 0
- 5
sonar-runner-batch-interface/src/test/java_sample/sonar-project.properties View File

@@ -1,5 +0,0 @@
sonar.projectKey=sample
sonar.projectName=Sample
sonar.projectVersion=1.0-SNAPSHOT
sonar.projectDescription=Sample description
sonar.sources=src

+ 0
- 0
sonar-runner-batch-interface/src/test/java_sample/src/Sample.java View File


+ 0
- 91
sonar-runner-batch/pom.xml View File

@@ -1,91 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonarsource.sonar-runner</groupId>
<artifactId>sonar-runner</artifactId>
<version>2.5-SNAPSHOT</version>
</parent>

<artifactId>sonar-runner-batch</artifactId>
<name>SonarQube Runner - Batch</name>

<properties>
<sonarBatchVersion>4.5.1</sonarBatchVersion>
</properties>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-runner-batch-interface</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-batch</artifactId>
<version>${sonarBatchVersion}</version>
<scope>provided</scope>
</dependency>

<!-- Unit tests -->
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-testing-harness</artifactId>
<version>${sonarBatchVersion}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-configuration</artifactId>
<groupId>commons-configuration</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/org/sonar/batch/bootstrapper/*</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

+ 0
- 143
sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java View File

@@ -1,143 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch.bootstrapper;

import java.util.List;
import java.util.Map;
import org.picocontainer.annotations.Nullable;

/**
* Entry point for sonar-runner 2.1.
*
* @since 2.14
*/
public class Batch {

private Batch(Builder builder) {
}

public LoggingConfiguration getLoggingConfiguration() {
return null;
}

/**
* @deprecated since 4.4 use {@link #start()}, {@link #executeTask(Map)} and then {@link #stop()}
*/
@Deprecated
public synchronized Batch execute() {
return this;
}

/**
* @since 4.4
*/
public synchronized Batch start() {
return start(false);
}

public synchronized Batch start(boolean preferCache) {
return this;
}

/**
* @since 4.4
*/
public Batch executeTask(Map<String, String> analysisProperties, Object... components) {
return this;
}

/**
* @since 5.2
*/
public Batch executeTask(Map<String, String> analysisProperties, IssueListener issueListener) {
return this;
}

/**
* @since 5.2
*/
public Batch syncProject(String projectKey) {
return this;
}

/**
* @since 4.4
*/
public synchronized void stop() {
}

public static Builder builder() {
return new Builder();
}

public static final class Builder {

private Builder() {
}

public Builder setEnvironment(EnvironmentInformation env) {
return this;
}

public Builder setComponents(List<Object> l) {
return this;
}

public Builder setLogOutput(@Nullable LogOutput logOutput) {
return this;
}

/**
* @deprecated since 3.7 use {@link #setBootstrapProperties(Map)}
*/
@Deprecated
public Builder setGlobalProperties(Map<String, String> globalProperties) {
return this;
}

public Builder setBootstrapProperties(Map<String, String> bootstrapProperties) {
return this;
}

public Builder addComponents(Object... components) {
return this;
}

public Builder addComponent(Object component) {
return this;
}

public boolean isEnableLoggingConfiguration() {
return false;
}

/**
* Logback is configured by default. It can be disabled, but n this case the batch bootstrapper must provide its
* own implementation of SLF4J.
*/
public Builder setEnableLoggingConfiguration(boolean b) {
return this;
}

public Batch build() {
return new Batch(this);
}
}
}

+ 0
- 178
sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/IssueListener.java View File

@@ -1,178 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch.bootstrapper;

public interface IssueListener {
void handle(Issue issue);

class Issue {
/** @since 5.3 */
private Integer startLine;
/** @since 5.3 */
private Integer startLineOffset;
/** @since 5.3 */
private Integer endLine;
/** @since 5.3 */
private Integer endLineOffset;

/** no longer exists since 5.3 */
private Integer line;

private String key;
private String componentKey;
private String message;
private String ruleKey;
private String ruleName;
private String status;
private String resolution;
private boolean isNew;
private String assigneeLogin;
private String assigneeName;
private String severity;

public String getSeverity() {
return severity;
}

public void setSeverity(String severity) {
this.severity = severity;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public String getComponentKey() {
return componentKey;
}

public void setComponentKey(String componentKey) {
this.componentKey = componentKey;
}

public Integer getStartLine() {
return startLine;
}

public void setStartLine(Integer startLine) {
this.startLine = startLine;
}

public Integer getStartLineOffset() {
return startLineOffset;
}

public void setStartLineOffset(Integer startLineOffset) {
this.startLineOffset = startLineOffset;
}

public Integer getEndLine() {
return endLine;
}

public void setEndLine(Integer endLine) {
this.endLine = endLine;
}

public Integer getEndLineOffset() {
return endLineOffset;
}

public void setEndLineOffset(Integer endLineOffset) {
this.endLineOffset = endLineOffset;
}

public Integer getLine() {
return line;
}

public void setLine(Integer line) {
this.line = line;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getRuleKey() {
return ruleKey;
}

public void setRuleKey(String ruleKey) {
this.ruleKey = ruleKey;
}

public String getRuleName() {
return ruleName;
}

public void setRuleName(String ruleName) {
this.ruleName = ruleName;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getResolution() {
return resolution;
}

public void setResolution(String resolution) {
this.resolution = resolution;
}

public boolean isNew() {
return isNew;
}

public void setNew(boolean isNew) {
this.isNew = isNew;
}

public String getAssigneeLogin() {
return assigneeLogin;
}

public void setAssigneeLogin(String assigneeLogin) {
this.assigneeLogin = assigneeLogin;
}

public String getAssigneeName() {
return assigneeName;
}

public void setAssigneeName(String assigneeName) {
this.assigneeName = assigneeName;
}
}
}

+ 0
- 33
sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/LogOutput.java View File

@@ -1,33 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch.bootstrapper;

/**
* Allow to redirect batch logs to a custom output. By defaults logs are written to System.out
* @since 5.2
*/
public interface LogOutput {

void log(String formattedMessage, Level level);

enum Level {
ERROR, WARN, INFO, DEBUG, TRACE;
}
}

+ 0
- 23
sonar-runner-batch/src/main/java/org/sonar/batch/bootstrapper/package-info.java View File

@@ -1,23 +0,0 @@
/*
* SonarQube Runner - Batch
* 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
*/
/**
* This package contains duplicated classes to avoid a dependency on SQ batch
*/
package org.sonar.batch.bootstrapper;

+ 0
- 30
sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchFactory.java View File

@@ -1,30 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import org.picocontainer.annotations.Nullable;
import org.sonar.batch.bootstrapper.Batch;

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

interface BatchFactory {
Batch createBatch(Properties properties, @Nullable final org.sonar.runner.batch.LogOutput logOutput, @Nullable List<Object> extensions);
}

+ 0
- 117
sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java View File

@@ -1,117 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import java.io.BufferedReader;
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 java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.sonar.batch.bootstrapper.Batch;

/**
* This class is executed within the classloader provided by the server. It contains the installed plugins and
* the same version of sonar-batch as the server.
*/
public class BatchIsolatedLauncher implements IsolatedLauncher {
private static final String VERSION_FORMAT = "^(\\d+)\\.(\\d+)";
private Batch batch = null;
private final BatchFactory factory;
private final Pattern versionPattern;

public BatchIsolatedLauncher() {
this(new DefaultBatchFactory());
}

public BatchIsolatedLauncher(BatchFactory factory) {
this.factory = factory;
this.versionPattern = Pattern.compile(VERSION_FORMAT);
}

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

@Override
public void stop() {
batch.stop();
}

@Override
public void execute(Properties properties) {
batch.executeTask((Map) properties);
}

@Override
public void execute(Properties properties, IssueListener listener) {
org.sonar.batch.bootstrapper.IssueListener batchIssueListener = Compatibility.getBatchIssueListener(listener, hasPreciseIssueLocation(getVersion()));
batch.executeTask((Map) properties, batchIssueListener);
}

@Override
public void syncProject(String projectKey) {
batch.syncProject(projectKey);
}

/**
* This method exists for backward compatibility with SonarQube < 5.2.
*/
@Override
public void executeOldVersion(Properties properties, List<Object> extensions) {
factory.createBatch(properties, null, extensions).execute();
}

boolean hasPreciseIssueLocation(String version) {
if (version == null) {
return false;
}

Matcher matcher = versionPattern.matcher(version);
if (!matcher.find() || matcher.groupCount() < 2) {
return false;
}

Integer major = Integer.parseInt(matcher.group(1));
Integer minor = Integer.parseInt(matcher.group(2));

return major > 5 || (major == 5 && minor >= 3);
}

@Override
public String getVersion() {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sq-version.txt");
if (is == null) {
return null;
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
return br.readLine();
} catch (IOException e) {
return null;
}
}
}

+ 0
- 87
sonar-runner-batch/src/main/java/org/sonar/runner/batch/Compatibility.java View File

@@ -1,87 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.LogOutput;

public class Compatibility {
private Compatibility() {
// Utility class
}

static void setLogOutputFor5dot2(Batch.Builder builder, final org.sonar.runner.batch.LogOutput logOutput) {
builder.setLogOutput(new LogOutput() {

@Override
public void log(String formattedMessage, Level level) {
logOutput.log(formattedMessage, org.sonar.runner.batch.LogOutput.Level.valueOf(level.name()));
}

});
}

static org.sonar.batch.bootstrapper.IssueListener getBatchIssueListener(IssueListener listener, boolean hasPreciseLocation) {
return new IssueListenerAdapter(listener, hasPreciseLocation);
}

static class IssueListenerAdapter implements org.sonar.batch.bootstrapper.IssueListener {
private IssueListener listener;
private boolean hasPreciseLocation;

public IssueListenerAdapter(IssueListener listener, boolean hasPreciseLocation) {
this.listener = listener;
this.hasPreciseLocation = hasPreciseLocation;
}

@Override
public void handle(Issue issue) {
listener.handle(transformIssue(issue));
}

private IssueListener.Issue transformIssue(Issue batchIssue) {
IssueListener.Issue newIssue = new IssueListener.Issue();

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

if (hasPreciseLocation) {
newIssue.setStartLine(batchIssue.getStartLine());
newIssue.setStartLineOffset(batchIssue.getStartLineOffset());
newIssue.setEndLine(batchIssue.getEndLine());
newIssue.setEndLineOffset(batchIssue.getEndLineOffset());
} else {
newIssue.setStartLine(batchIssue.getLine());
newIssue.setEndLine(batchIssue.getLine());
}

return newIssue;
}
}
}

+ 0
- 49
sonar-runner-batch/src/main/java/org/sonar/runner/batch/DefaultBatchFactory.java View File

@@ -1,49 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import org.picocontainer.annotations.Nullable;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;

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

class DefaultBatchFactory implements BatchFactory {
@Override
public 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);
}

return builder.build();
}
}

+ 0
- 20
sonar-runner-batch/src/main/java/org/sonar/runner/batch/package-info.java View File

@@ -1,20 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

+ 0
- 128
sonar-runner-batch/src/test/java/org/sonar/runner/batch/BatchIsolatedLauncherTest.java View File

@@ -1,128 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import org.junit.Before;
import org.junit.Test;
import org.sonar.batch.bootstrapper.Batch;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

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

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

public class BatchIsolatedLauncherTest {
private Batch batch;
private BatchFactory factory;
private BatchIsolatedLauncher launcher;

@Before
public void setUp() {
factory = mock(BatchFactory.class);
batch = mock(Batch.class);
when(factory.createBatch(any(Properties.class), any(LogOutput.class), anyListOf(Object.class))).thenReturn(batch);
launcher = new BatchIsolatedLauncher(factory);
}

@Test
public void supportsPreciseLocation() {
assertThat(launcher.hasPreciseIssueLocation("5.2.9")).isFalse();
assertThat(launcher.hasPreciseIssueLocation("5.2")).isFalse();
assertThat(launcher.hasPreciseIssueLocation("5.")).isFalse();
assertThat(launcher.hasPreciseIssueLocation(null)).isFalse();
assertThat(launcher.hasPreciseIssueLocation("4.5")).isFalse();
assertThat(launcher.hasPreciseIssueLocation("4.5-SNAPSHOT")).isFalse();
assertThat(launcher.hasPreciseIssueLocation("4-RC1")).isFalse();
assertThat(launcher.hasPreciseIssueLocation("6")).isFalse();
assertThat(launcher.hasPreciseIssueLocation("e6.0")).isFalse();

assertThat(launcher.hasPreciseIssueLocation("5.3")).isTrue();
assertThat(launcher.hasPreciseIssueLocation("5.10.1")).isTrue();
assertThat(launcher.hasPreciseIssueLocation("5.3.1")).isTrue();
assertThat(launcher.hasPreciseIssueLocation("6.0")).isTrue();
assertThat(launcher.hasPreciseIssueLocation("5.3-SNAPSHOT")).isTrue();
assertThat(launcher.hasPreciseIssueLocation("5.3-RC1")).isTrue();
}

@Test
public void executeOld() {
Properties prop = new Properties();
List<Object> list = new LinkedList<>();

launcher.executeOldVersion(prop, list);

verify(factory).createBatch(prop, null, list);
verify(batch).execute();

verifyNoMoreInteractions(batch);
verifyNoMoreInteractions(factory);
}

@Test(expected = NullPointerException.class)
public void executeWithoutStart() {
IssueListener issueListener = mock(IssueListener.class);
Properties prop = new Properties();
launcher.execute(prop, issueListener);
}

@Test
public void executeWithListener() {
IssueListener issueListener = mock(IssueListener.class);
Properties prop = new Properties();

launcher.start(null, null, true);
launcher.execute(prop, issueListener);

verify(batch).start(true);
verify(batch).executeTask(eq((Map) prop), any(org.sonar.batch.bootstrapper.IssueListener.class));

verifyNoMoreInteractions(batch);
}

@Test
public void proxy() {
Properties prop = new Properties();

launcher.start(prop, null, true);
launcher.syncProject("proj");
launcher.execute(prop);
launcher.stop();

verify(factory).createBatch(any(Properties.class), any(LogOutput.class), anyListOf(Object.class));
verify(batch).start(true);
verify(batch).syncProject("proj");
verify(batch).executeTask((Map) prop);
verify(batch).stop();

verifyNoMoreInteractions(batch);
verifyNoMoreInteractions(factory);
}

}

+ 0
- 120
sonar-runner-batch/src/test/java/org/sonar/runner/batch/CompatibilityTest.java View File

@@ -1,120 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import static org.mockito.Mockito.times;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class CompatibilityTest {
private IssueListener issueListener;

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

@Test
public void test() {
org.sonar.batch.bootstrapper.IssueListener.Issue batchIssue = new org.sonar.batch.bootstrapper.IssueListener.Issue();
setIssue(batchIssue);

org.sonar.batch.bootstrapper.IssueListener adaptedIssueListener = Compatibility.getBatchIssueListener(issueListener, false);

adaptedIssueListener.handle(batchIssue);

ArgumentCaptor<IssueListener.Issue> arg = ArgumentCaptor.forClass(IssueListener.Issue.class);
verify(issueListener).handle(arg.capture());
assertIssue(arg.getValue(), false);
}

@Test
public void testPrecise() {
org.sonar.batch.bootstrapper.IssueListener.Issue batchIssue = new org.sonar.batch.bootstrapper.IssueListener.Issue();
setIssue(batchIssue);

org.sonar.batch.bootstrapper.IssueListener adaptedIssueListener = Compatibility.getBatchIssueListener(issueListener, true);

adaptedIssueListener.handle(batchIssue);

ArgumentCaptor<IssueListener.Issue> arg = ArgumentCaptor.forClass(IssueListener.Issue.class);
verify(issueListener).handle(arg.capture());
assertIssue(arg.getValue(), true);
}

@Test
public void preciseIssueLocationCompatibility() {
org.sonar.batch.bootstrapper.IssueListener.Issue batchIssue = mock(org.sonar.batch.bootstrapper.IssueListener.Issue.class);

org.sonar.batch.bootstrapper.IssueListener adaptedIssueListener = Compatibility.getBatchIssueListener(issueListener, false);
adaptedIssueListener.handle(batchIssue);

verify(batchIssue, times(0)).getEndLine();
verify(batchIssue, times(0)).getStartLine();
verify(batchIssue, times(0)).getStartLineOffset();
verify(batchIssue, times(0)).getEndLineOffset();
}

private static void setIssue(org.sonar.batch.bootstrapper.IssueListener.Issue issue) {
issue.setAssigneeName("name");
issue.setRuleName("rule");
issue.setRuleKey("key");
issue.setMessage("msg");
issue.setAssigneeLogin("login");
issue.setLine(10);
issue.setStartLine(5);
issue.setEndLine(6);
issue.setStartLineOffset(1);
issue.setEndLineOffset(2);
issue.setComponentKey("component");
issue.setSeverity("severity");
issue.setNew(true);
issue.setStatus("status");
}

private static void assertIssue(IssueListener.Issue issue, boolean precise) {
assertThat(issue.getAssigneeName()).isEqualTo("name");
assertThat(issue.getRuleName()).isEqualTo("rule");
assertThat(issue.getRuleKey()).isEqualTo("key");
assertThat(issue.getMessage()).isEqualTo("msg");
assertThat(issue.getAssigneeLogin()).isEqualTo("login");
assertThat(issue.getComponentKey()).isEqualTo("component");
assertThat(issue.getSeverity()).isEqualTo("severity");
assertThat(issue.isNew()).isEqualTo(true);
assertThat(issue.getStatus()).isEqualTo("status");

if (precise) {
assertThat(issue.getStartLine()).isEqualTo(5);
assertThat(issue.getEndLine()).isEqualTo(6);
assertThat(issue.getStartLineOffset()).isEqualTo(1);
assertThat(issue.getEndLineOffset()).isEqualTo(2);
} else {
assertThat(issue.getStartLine()).isEqualTo(10);
assertThat(issue.getEndLine()).isEqualTo(10);
assertThat(issue.getStartLineOffset()).isEqualTo(null);
assertThat(issue.getEndLineOffset()).isEqualTo(null);
}
}
}

+ 0
- 44
sonar-runner-batch/src/test/java/org/sonar/runner/batch/DefaultBatchFactoryTest.java View File

@@ -1,44 +0,0 @@
/*
* SonarQube Runner - Batch
* 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.batch;

import java.util.Properties;
import org.junit.Test;
import org.sonar.batch.bootstrapper.Batch;

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

public class DefaultBatchFactoryTest {

private Properties props = new Properties();
private BatchFactory factory = new DefaultBatchFactory();

@Test
public void should_create_batch() {
props.setProperty("sonar.projectBaseDir", "src/test/java_sample");
props.setProperty("sonar.projectKey", "sample");
props.setProperty("sonar.projectName", "Sample");
props.setProperty("sonar.projectVersion", "1.0");
props.setProperty("sonar.sources", "src");
Batch batch = factory.createBatch(props, null, null);

assertThat(batch).isNotNull();
}
}

+ 0
- 0
sonar-runner-batch/src/test/java_sample/sonar-project.properties View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save