Browse Source

SONAR-10283 Fail fast at startup when a language is missing a default built in quality profile

tags/7.5
Duarte Meneses 6 years ago
parent
commit
03692a7dee

+ 18
- 6
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java View File

@@ -20,15 +20,19 @@
package org.sonar.server.qualityprofile;

import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
@@ -76,6 +80,7 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository
}
Map<String, Map<String, BuiltInQualityProfile>> rulesProfilesByLanguage = validateAndClean(context);
this.qProfiles = toFlatList(rulesProfilesByLanguage);
ensureAllLanguagesHaveAtLeastOneBuiltInQP();
profiler.stopDebug();
}

@@ -86,22 +91,29 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository
return qProfiles;
}

private void ensureAllLanguagesHaveAtLeastOneBuiltInQP() {
Set<String> languagesWithBuiltInQProfiles = qProfiles.stream().map(BuiltInQProfile::getLanguage).collect(Collectors.toSet());
Set<String> languagesWithoutBuiltInQProfiles = Arrays.stream(languages.all())
.map(Language::getKey)
.filter(key -> !languagesWithBuiltInQProfiles.contains(key))
.collect(Collectors.toSet());

checkState(languagesWithoutBuiltInQProfiles.isEmpty(), "The following languages have no built-in quality profiles: %s",
languagesWithoutBuiltInQProfiles.stream().collect(Collectors.joining()));
}

private Map<String, Map<String, BuiltInQualityProfile>> validateAndClean(BuiltInQualityProfilesDefinition.Context context) {
Map<String, Map<String, BuiltInQualityProfile>> profilesByLanguageAndName = context.profilesByLanguageAndName();
profilesByLanguageAndName.entrySet()
.removeIf(entry -> {
String language = entry.getKey();
if (languages.get(language) == null) {
LOGGER.info("Language {} is not installed, related Quality profiles are ignored", language);
return true;
}
Collection<BuiltInQualityProfile> profiles = entry.getValue().values();
if (profiles.isEmpty()) {
LOGGER.warn("No Quality profiles defined for language: {}", language);
LOGGER.info("Language {} is not installed, related quality profiles are ignored", language);
return true;
}
return false;
});

return profilesByLanguageAndName;
}


+ 4
- 3
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java View File

@@ -71,12 +71,13 @@ public class BuiltInQProfileRepositoryImplTest {
}

@Test
public void initialize_creates_no_BuiltInQProfile_when_there_is_no_definition() {
public void initialize_throws_ISE_if_language_has_no_builtin_qp() {
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(FOO_LANGUAGE));

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("The following languages have no built-in quality profiles: foo");
underTest.initialize();

assertThat(underTest.get()).isEmpty();
}

@Test

+ 1
- 0
settings.gradle View File

@@ -44,6 +44,7 @@ include 'tests:plugins:fake-governance-plugin'
include 'tests:plugins:foo-plugin-v1'
include 'tests:plugins:foo-plugin-v2'
include 'tests:plugins:foo-plugin-v3'
include 'tests:plugins:foo-plugin-without-qprofile'
include 'tests:plugins:global-property-change-plugin'
include 'tests:plugins:issue-filter-plugin'
include 'tests:plugins:l10n-fr-pack'

+ 1
- 0
tests/build.gradle View File

@@ -24,6 +24,7 @@ def pluginsForITs = [
':tests:plugins:foo-plugin-v1',
':tests:plugins:foo-plugin-v2',
':tests:plugins:foo-plugin-v3',
':tests:plugins:foo-plugin-without-qprofile',
':tests:plugins:global-property-change-plugin',
':tests:plugins:issue-filter-plugin',
':tests:plugins:l10n-fr-pack',

+ 29
- 0
tests/plugins/foo-plugin-without-qprofile/build.gradle View File

@@ -0,0 +1,29 @@
sonarqube {
skipProject = true
}

dependencies {
compile 'com.google.guava:guava'
compile 'commons-io:commons-io'
compile 'commons-lang:commons-lang'
compileOnly 'com.google.code.findbugs:jsr305'
compileOnly project(path: ':sonar-plugin-api', configuration: 'shadow')
}

jar {
manifest {
attributes(
'Plugin-Key': 'foo',
'Plugin-Version': version,
'Plugin-Class': 'org.sonar.foo.FooPlugin',
'Plugin-ChildFirstClassLoader': 'false',
'Sonar-Version': version,
'SonarLint-Supported': 'false',
'Plugin-Name': 'Foo',
'Plugin-License': 'GNU LGPL 3'
)
}
into('META-INF/lib') {
from configurations.compile
}
}

+ 43
- 0
tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/Foo.java View File

@@ -0,0 +1,43 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.foo;

import org.sonar.api.resources.Language;

public class Foo implements Language {

public static final String KEY = "foo";
public static final String NAME = "Foo";

@Override
public String getKey() {
return KEY;
}

@Override
public String getName() {
return NAME;
}

@Override
public String[] getFileSuffixes() {
return new String[0];
}
}

+ 35
- 0
tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/FooPlugin.java View File

@@ -0,0 +1,35 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.foo;

import org.sonar.api.Plugin;

/**
* Plugin entry-point, as declared in pom.xml.
*/
public class FooPlugin implements Plugin {

@Override
public void define(Context context) {
context.addExtension(
Foo.class);
}

}

+ 23
- 0
tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/package-info.java View File

@@ -0,0 +1,23 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.
*/
@ParametersAreNonnullByDefault
package org.sonar.foo;

import javax.annotation.ParametersAreNonnullByDefault;

+ 2
- 0
tests/src/test/java/org/sonarqube/tests/Category5Suite.java View File

@@ -28,6 +28,7 @@ import org.sonarqube.tests.issue.IssueCreationDatePluginChangedTest;
import org.sonarqube.tests.marketplace.UpdateCenterTest;
import org.sonarqube.tests.qualityProfile.ActiveRuleEsResilienceTest;
import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest;
import org.sonarqube.tests.qualityProfile.PluginWithoutBuiltinQualityProfile;
import org.sonarqube.tests.rule.RuleEsResilienceTest;
import org.sonarqube.tests.serverSystem.BlueGreenTest;
import org.sonarqube.tests.serverSystem.RestartTest;
@@ -64,6 +65,7 @@ import org.sonarqube.tests.user.UserEsResilienceTest;
HttpHeadersAuthenticationTest.class,
OnboardingTest.class,
BuiltInQualityProfilesNotificationTest.class,
PluginWithoutBuiltinQualityProfile.class,
ActiveRuleEsResilienceTest.class,
AnalysisEsResilienceTest.class,
RuleEsResilienceTest.class,

+ 58
- 0
tests/src/test/java/org/sonarqube/tests/qualityProfile/PluginWithoutBuiltinQualityProfile.java View File

@@ -0,0 +1,58 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.sonarqube.tests.qualityProfile;

import com.sonar.orchestrator.Orchestrator;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static util.ItUtils.newOrchestratorBuilder;
import static util.ItUtils.pluginArtifact;

public class PluginWithoutBuiltinQualityProfile {
private static Orchestrator orchestrator;

@Test
public void should_fail_if_plugin_defines_language_and_no_builtin_qprofile() throws IOException {
orchestrator = newOrchestratorBuilder()
.addPlugin(pluginArtifact("foo-plugin-without-qprofile"))
.build();

try {
orchestrator.start();
fail("Expected to fail to start");
} catch (IllegalStateException e) {
String logs = FileUtils.readFileToString(orchestrator.getServer().getWebLogs(), StandardCharsets.UTF_8);
assertThat(logs).contains("java.lang.IllegalStateException: The following languages have no built-in quality profiles: foo");
}
}

@After
public void after() {
if (orchestrator != null) {
orchestrator.stop();
}
}
}

Loading…
Cancel
Save