/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT 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 02110-1301, USA.
*/
package org.sonar.scanner.mediumtest.fs;
import com.google.common.collect.ImmutableMap;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Random;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.scanner.mediumtest.LogOutputRecorder;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.TaskResult;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.rule.XooRulesDefinition;
import java.io.File;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
public class FileSystemMediumTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Rule
public ExpectedException thrown = ExpectedException.none();
private LogOutputRecorder logs = new LogOutputRecorder();
private ScannerMediumTester tester;
private File baseDir;
private ImmutableMap.Builder<String, String> builder;
@Before
public void prepare() throws IOException {
tester = ScannerMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.setLogOutput(logs)
.build();
tester.start();
baseDir = temp.getRoot();
builder = ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.projectName", "Foo Project")
.put("sonar.projectVersion", "1.0-SNAPSHOT")
.put("sonar.projectDescription", "Description of Foo Project");
}
@After
public void stop() {
if (tester != null) {
tester.stop();
tester = null;
}
logs = new LogOutputRecorder();
}
private ImmutableMap.Builder<String, String> createBuilder() {
return ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.verbose", "true")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.projectVersion", "1.0-SNAPSHOT")
.put("sonar.projectDescription", "Description of Foo Project");
}
@Test
public void scanProjectWithoutProjectName() throws IOException {
builder = createBuilder();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
int ref = result.getReportReader().readMetadata().getRootComponentRef();
assertThat(result.getReportReader().readComponent(ref).getName()).isEmpty();
assertThat(result.inputFiles()).hasSize(1);
assertThat(result.inputDirs()).hasSize(1);
DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
InputDir dir = result.inputDir("src");
assertThat(file.type()).isEqualTo(InputFile.Type.MAIN);
assertThat(file.relativePath()).isEqualTo("src/sample.xoo");
assertThat(file.language()).isEqualTo("xoo");
assertThat(dir.relativePath()).isEqualTo("src");
// file and dirs were published, since language matched xoo
assertThat(file.publish()).isTrue();
assertThat(result.getReportComponent(dir.key())).isNotNull();
assertThat(result.getReportComponent(file.key())).isNotNull();
}
@Test
public void logProjectKeyAndOrganizationKey() throws IOException {
builder = createBuilder();
builder.put("sonar.organization", "my org");
builder.put("sonar.branch", "");
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
assertThat(logs.getAllAsString()).contains("Organization key: my org");
assertThat(logs.getAllAsString()).doesNotContain("Branch key");
}
@Test
public void logBranchKey() throws IOException {
builder = createBuilder();
builder.put("sonar.branch", "my-branch");
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
assertThat(logs.getAllAsString()).contains("Branch key: my-branch");
}
@Test
public void dontLogInvalidOrganization() throws IOException {
builder = createBuilder();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
assertThat(logs.getAllAsString()).doesNotContain("Organization key");
assertThat(logs.getAllAsString()).doesNotContain("Branch key");
}
@Test
public void onlyGenerateMetadataIfNeeded() throws IOException {
builder = createBuilder();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent");
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).contains("2 files indexed");
assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
assertThat(logs.getAllAsString()).doesNotContain("'src/sample.java' generated metadata");
}
@Test
public void preloadFileMetadata() throws IOException {
builder = createBuilder()
.put("sonar.preloadFileMetadata", "true");
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent");
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).contains("2 files indexed");
assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
assertThat(logs.getAllAsString()).contains("'src/sample.java' generated metadata");
}
@Test
public void dontPublishFilesWithoutDetectedLanguage() throws IOException {
builder = createBuilder();
Path mainDir = baseDir.toPath().resolve("src").resolve("main");
Files.createDirectories(mainDir);
Path testDir = baseDir.toPath().resolve("src").resolve("test");
Files.createDirectories(testDir);
Path testXooFile = testDir.resolve("sample.java");
Files.write(testXooFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));
Path xooFile = mainDir.resolve("sample.xoo");
Files.write(xooFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));
Path javaFile = mainDir.resolve("sample.java");
Files.write(javaFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src/main")
.put("sonar.tests", "src/test")
.build())
.start();
assertThat(logs.getAllAsString()).contains("3 files indexed");
assertThat(logs.getAllAsString()).contains("'src/main/sample.xoo' generated metadata");
assertThat(logs.getAllAsString()).doesNotContain("'src/main/sample.java' generated metadata");
assertThat(logs.getAllAsString()).doesNotContain("'src/test/sample.java' generated metadata");
DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");
assertThat(result.getReportComponent(javaInputFile.key())).isNull();
}
@Test
public void createIssueOnAnyFile() throws IOException {
LogOutputRecorder logs = new LogOutputRecorder();
stop();
tester = ScannerMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addRules(new XooRulesDefinition())
.setLogOutput(logs)
.addActiveRule("xoo", "OneIssuePerUnknownFile", null, "OneIssuePerUnknownFile", "MAJOR", null, "xoo")
.build();
tester.start();
builder = createBuilder();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.unknown");
FileUtils.write(xooFile, "Sample xoo\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).contains("1 file indexed");
assertThat(logs.getAllAsString()).contains("'src/sample.unknown' indexed with language 'null'");
assertThat(logs.getAllAsString()).contains("'src/sample.unknown' generated metadata");
DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
assertThat(result.getReportComponent(inputFile.key())).isNotNull();
}
@Test
public void lazyIssueExclusion() throws IOException {
tester.stop();
LogOutputRecorder logs = new LogOutputRecorder();
tester = ScannerMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addRules(new XooRulesDefinition())
.setLogOutput(logs)
.addActiveRule("xoo", "OneIssuePerFile", null, "OneIssuePerFile", "MAJOR", null, "xoo")
.build();
tester.start();
builder = createBuilder();
builder.put("sonar.issue.ignore.allfile", "1")
.put("sonar.issue.ignore.allfile.1.fileRegexp", "pattern");
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
File unknownFile = new File(srcDir, "myfile.binary");
byte[] b = new byte[512];
new Random().nextBytes(b);
FileUtils.writeByteArrayToFile(unknownFile, b);
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' indexed with language 'null'");
assertThat(logs.getAllAsString()).doesNotContain("'src/myfile.binary' generating issue exclusions");
assertThat(logs.getAllAsString()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
}
@Test
public void preloadIssueExclusions() throws IOException {
builder = createBuilder();
builder.put("sonar.issue.ignore.allfile", "1")
.put("sonar.issue.ignore.allfile.1.fileRegexp", "pattern")
.put("sonar.preloadFileMetadata", "true");
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\npattern");
File unknownFile = new File(srcDir, "myfile.binary");
FileUtils.write(unknownFile, "some text");
tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(logs.getAllAsString()).containsOnlyOnce("- Exclusion pattern 'pattern'");
assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
}
@Test
public void publishFilesWithIssues() throws IOException {
stop();
tester = ScannerMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addRules(new XooRulesDefinition())
.addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")
.build();
tester.start();
builder = createBuilder();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
InputDir dir = result.inputDir("src");
assertThat(file.publish()).isTrue();
assertThat(result.getReportComponent(dir.key())).isNotNull();
assertThat(result.getReportComponent(file.key())).isNotNull();
}
@Test
public void publishDirsWithIssues() throws IOException {
stop();
tester = ScannerMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addRules(new XooRulesDefinition())
.addActiveRule("xoo", "OneIssuePerDirectory", null, "OneIssuePerDirectory", "MAJOR", null, "xoo")
.build();
tester.start();
builder = ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.verbose", "true")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.projectVersion", "1.0-SNAPSHOT")
.put("sonar.projectDescription", "Description of Foo Project");
Path unknownRelative = Paths.get("src", "unknown", "file.notanalyzed");
Path unknown = baseDir.toPath().resolve(unknownRelative);
Files.createDirectories(unknown.getParent());
Files.write(unknown, "dummy content".getBytes());
Path emptyDirRelative = Paths.get("src", "emptydir");
Files.createDirectories(emptyDirRelative);
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
DefaultInputFile unknownInputFile = (DefaultInputFile) result.inputFile("src/unknown/file.notanalyzed");
InputDir unknownInputDir = result.inputDir("src/unknown");
assertThat(unknownInputFile.publish()).isFalse();
assertThat(result.getReportComponent(unknownInputDir.key())).isNotNull();
// no issues on empty dir
InputDir emptyInputDir = result.inputDir(emptyDirRelative.toString());
assertThat(emptyInputDir).isNull();
// no issues on parent dir
InputDir parentInputDir = result.inputDir(unknownRelative.getParent().getParent().toString());
assertThat(parentInputDir).isNull();
}
@Test
public void scanProjectWithSourceDir() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(result.inputFiles()).hasSize(1);
assertThat(result.inputDirs()).hasSize(1);
assertThat(result.inputFile("src/sample.xoo").type()).isEqualTo(InputFile.Type.MAIN);
assertThat(result.inputFile("src/sample.xoo").relativePath()).isEqualTo("src/sample.xoo");
assertThat(result.inputDir("src").relativePath()).isEqualTo("src");
}
@Test
public void scanBigProject() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
int nbFiles = 100;
int ruleCount = 100000;
for (int nb = 1; nb <= nbFiles; nb++) {
File xooFile = new File(srcDir, "sample" + nb + ".xoo");
FileUtils.write(xooFile, StringUtils.repeat(StringUtils.repeat("a", 100) + "\n", ruleCount / 1000));
}
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(result.inputFiles()).hasSize(100);
assertThat(result.inputDirs()).hasSize(1);
}
@Test
public void scanProjectWithTestDir() throws IOException {
File test = new File(baseDir, "test");
test.mkdir();
File xooFile = new File(test, "sampleTest.xoo");
FileUtils.write(xooFile, "Sample test xoo\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "")
.put("sonar.tests", "test")
.build())
.start();
assertThat(result.inputFiles()).hasSize(1);
assertThat(result.inputFile("test/sampleTest.xoo").type()).isEqualTo(InputFile.Type.TEST);
}
/**
* SONAR-5419
*/
@Test
public void scanProjectWithMixedSourcesAndTests() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
File xooFile2 = new File(baseDir, "another.xoo");
FileUtils.write(xooFile2, "Sample xoo 2\ncontent");
File testDir = new File(baseDir, "test");
testDir.mkdir();
File xooTestFile = new File(baseDir, "sampleTest2.xoo");
FileUtils.write(xooTestFile, "Sample test xoo\ncontent");
File xooTestFile2 = new File(testDir, "sampleTest.xoo");
FileUtils.write(xooTestFile2, "Sample test xoo 2\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src,another.xoo")
.put("sonar.tests", "test,sampleTest2.xoo")
.build())
.start();
assertThat(result.inputFiles()).hasSize(4);
assertThat(result.inputDirs()).hasSize(3);
}
@Test
public void fileInclusionsExclusions() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
File xooFile2 = new File(baseDir, "another.xoo");
FileUtils.write(xooFile2, "Sample xoo 2\ncontent");
File testDir = new File(baseDir, "test");
testDir.mkdir();
File xooTestFile = new File(baseDir, "sampleTest2.xoo");
FileUtils.write(xooTestFile, "Sample test xoo\ncontent");
File xooTestFile2 = new File(testDir, "sampleTest.xoo");
FileUtils.write(xooTestFile2, "Sample test xoo 2\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src,another.xoo")
.put("sonar.tests", "test,sampleTest2.xoo")
.put("sonar.inclusions", "src/**")
.put("sonar.exclusions", "**/another.*")
.put("sonar.test.inclusions", "**/sampleTest*.*")
.put("sonar.test.exclusions", "**/sampleTest2.xoo")
.build())
.start();
assertThat(result.inputFiles()).hasSize(2);
}
@Test
public void failForDuplicateInputFile() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
thrown.expect(MessageException.class);
thrown.expectMessage("can't be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files");
tester.newTask()
.properties(builder
.put("sonar.sources", "src,src/sample.xoo")
.build())
.start();
}
// SONAR-5330
@Test
public void scanProjectWithSourceSymlink() {
if (!System2.INSTANCE.isOsWindows()) {
File projectDir = new File("src/test/resources/mediumtest/xoo/sample-with-symlink");
TaskResult result = tester
.newScanTask(new File(projectDir, "sonar-project.properties"))
.start();
assertThat(result.inputFiles()).hasSize(3);
// check that symlink was not resolved to target
assertThat(result.inputFiles()).extractingResultOf("path").toString().startsWith(projectDir.toString());
}
}
// SONAR-6719
@Test
public void scanProjectWithWrongCase() {
if (System2.INSTANCE.isOsWindows()) {
File projectDir = new File("src/test/resources/mediumtest/xoo/sample");
TaskResult result = tester
.newScanTask(new File(projectDir, "sonar-project.properties"))
.property("sonar.sources", "XOURCES")
.property("sonar.tests", "TESTX")
.start();
assertThat(result.inputFiles()).hasSize(3);
assertThat(result.inputFiles()).extractingResultOf("relativePath").containsOnly(
"xources/hello/HelloJava.xoo",
"xources/hello/helloscala.xoo",
"testx/ClassOneTest.xoo");
}
}
@Test
public void indexAnyFile() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "Sample xoo\ncontent");
File otherFile = new File(srcDir, "sample.other");
FileUtils.write(otherFile, "Sample other\ncontent");
TaskResult result = tester.newTask()
.properties(builder
.put("sonar.sources", "src")
.build())
.start();
assertThat(result.inputFiles()).hasSize(2);
assertThat(result.inputFile("src/sample.other").type()).isEqualTo(InputFile.Type.MAIN);
assertThat(result.inputFile("src/sample.other").relativePath()).isEqualTo("src/sample.other");
assertThat(result.inputFile("src/sample.other").language()).isNull();
}
@Test
public void scanMultiModuleProject() {
File projectDir = new File("src/test/resources/mediumtest/xoo/multi-modules-sample");
TaskResult result = tester
.newScanTask(new File(projectDir, "sonar-project.properties"))
.start();
assertThat(result.inputFiles()).hasSize(4);
assertThat(result.inputDirs()).hasSize(4);
}
}