]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10283 Fail fast at startup when a language is missing a default built in qualit...
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 7 Jun 2018 14:59:49 +0000 (16:59 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 11 Jun 2018 18:20:48 +0000 (20:20 +0200)
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java
settings.gradle
tests/build.gradle
tests/plugins/foo-plugin-without-qprofile/build.gradle [new file with mode: 0644]
tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/Foo.java [new file with mode: 0644]
tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/FooPlugin.java [new file with mode: 0644]
tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/package-info.java [new file with mode: 0644]
tests/src/test/java/org/sonarqube/tests/Category5Suite.java
tests/src/test/java/org/sonarqube/tests/qualityProfile/PluginWithoutBuiltinQualityProfile.java [new file with mode: 0644]

index bb8f4d2ac6ce7744db46cf78ff31ba83cac23d32..519730c11d3ac9483d70927a3c3989191cdec909 100644 (file)
 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;
   }
 
index 0d1a96835f9e67d1f962848e4a0d482dd352862e..fa6d2b5b6363c805549f95db8873ebb755e9a906 100644 (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
index f19d9e246a85f577990e9f1b1b3f15ad03bc40ea..ff20a6df26718961cffa4a3d4991ce7b97251a05 100644 (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'
index 0701f734a2cb691f91a50d6575c96794bdd341cc..3b357654511f6c728abc53aca82c87b78d07c7a9 100644 (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',
diff --git a/tests/plugins/foo-plugin-without-qprofile/build.gradle b/tests/plugins/foo-plugin-without-qprofile/build.gradle
new file mode 100644 (file)
index 0000000..a1eed2e
--- /dev/null
@@ -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
+  }
+}
diff --git a/tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/Foo.java b/tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/Foo.java
new file mode 100644 (file)
index 0000000..0fe6566
--- /dev/null
@@ -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];
+  }
+}
diff --git a/tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/FooPlugin.java b/tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/FooPlugin.java
new file mode 100644 (file)
index 0000000..7ee8868
--- /dev/null
@@ -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);
+  }
+
+}
diff --git a/tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/package-info.java b/tests/plugins/foo-plugin-without-qprofile/src/main/java/org/sonar/foo/package-info.java
new file mode 100644 (file)
index 0000000..7ebb0e1
--- /dev/null
@@ -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;
index b2a635e07039e9f3a60a387ad8c89fcfa7238eed..bf1b19e2517d31e829fc489458713cce671e621f 100644 (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,
diff --git a/tests/src/test/java/org/sonarqube/tests/qualityProfile/PluginWithoutBuiltinQualityProfile.java b/tests/src/test/java/org/sonarqube/tests/qualityProfile/PluginWithoutBuiltinQualityProfile.java
new file mode 100644 (file)
index 0000000..37fc176
--- /dev/null
@@ -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();
+    }
+  }
+}