]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13272 fix issue with setting some properties through env variables
authorMichal Duda <michal.duda@sonarsource.com>
Wed, 8 Apr 2020 17:38:02 +0000 (19:38 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 14 Apr 2020 20:04:04 +0000 (20:04 +0000)
54 files changed:
server/sonar-auth-github/src/test/java/org/sonar/auth/github/GitHubSettingsTest.java
server/sonar-auth-github/src/test/java/org/sonar/auth/github/IntegrationTest.java
server/sonar-auth-github/src/test/java/org/sonar/auth/github/UserIdentityFactoryImplTest.java
server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabSettingsTest.java
server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlIdentityProviderTest.java
server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlSettingsTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/RatingSettingsTest.java
server/sonar-main/src/main/java/org/sonar/application/command/CommandFactoryImpl.java
server/sonar-main/src/main/java/org/sonar/application/config/AppSettingsLoaderImpl.java
server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java
server/sonar-main/src/test/java/org/sonar/application/config/AppSettingsLoaderImplTest.java
server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java
server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java
server/sonar-process/src/main/java/org/sonar/process/logging/LogLevelConfig.java
server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java
server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/UrlSettings.java
server/sonar-server-common/src/main/java/org/sonar/server/setting/ThreadLocalSettings.java
server/sonar-server-common/src/test/java/org/sonar/server/config/ConfigurationProviderTest.java
server/sonar-server-common/src/test/java/org/sonar/server/platform/UrlSettingsTest.java
server/sonar-server-common/src/test/java/org/sonar/server/setting/ChildSettingsTest.java
server/sonar-server-common/src/test/java/org/sonar/server/setting/ThreadLocalSettingsTest.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/user/SystemPasscodeImpl.java
server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationMediumTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/monitoring/SettingsSectionTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/startup/RenameDeprecatedPropertyKeysTest.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/InfoAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/PauseAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ResumeAction.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/LiveMeasureComputerImplTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ListDefinitionsActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ResetActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SetActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsUpdaterTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java
server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatConnectors.java
server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatContexts.java
sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
sonar-core/src/main/java/org/sonar/core/util/SettingFormatter.java
sonar-core/src/test/java/org/sonar/core/util/SettingFormatterTest.java
sonar-plugin-api-impl/src/main/java/org/sonar/api/config/internal/MapSettings.java
sonar-plugin-api-impl/src/test/java/org/sonar/api/config/internal/MapSettingsTest.java
sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java
sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalConfigurationProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/config/DefaultConfigurationTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericCoverageSensorTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/genericcoverage/GenericTestExecutionSensorTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java

index b960bdd81ff57f8f061ead636f62e207167fee75..f15933e922a6b171481da5079cd5376b2f1b0685 100644 (file)
@@ -22,12 +22,13 @@ package org.sonar.auth.github;
 import org.junit.Test;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class GitHubSettingsTest {
 
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(GitHubSettings.definitions()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitHubSettings.definitions()));
 
   private GitHubSettings underTest = new GitHubSettings(settings.asConfig());
 
index 780213bd459dca6638fbd39bc921d2d10c4656ef..6c134d5be6a5bd22be86fd214effbdc1dcec2dcf 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.server.authentication.OAuth2IdentityProvider;
 import org.sonar.api.server.authentication.UnauthorizedException;
 import org.sonar.api.server.authentication.UserIdentity;
+import org.sonar.api.utils.System2;
 
 import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -52,7 +53,7 @@ public class IntegrationTest {
   public MockWebServer github = new MockWebServer();
 
   // load settings with default values
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(GitHubSettings.definitions()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitHubSettings.definitions()));
   private GitHubSettings gitHubSettings = new GitHubSettings(settings.asConfig());
   private UserIdentityFactoryImpl userIdentityFactory = new UserIdentityFactoryImpl();
   private ScribeGitHubApi scribeApi = new ScribeGitHubApi(gitHubSettings);
index 0913d1ee808e0b594953165bbddd4f1bd93317f9..7e3cd01ceebb5202fba359af795a83e6fed288da 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.server.authentication.UserIdentity;
+import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -33,7 +34,7 @@ public class UserIdentityFactoryImplTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(GitHubSettings.definitions()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitHubSettings.definitions()));
   private UserIdentityFactoryImpl underTest = new UserIdentityFactoryImpl();
 
   @Test
index 0517f0e55c958f74298bf24740951baed1fb28a3..523594dc7dcd1ed15987dad13610512e292a1975 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.auth.gitlab.GitLabSettings.GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP;
@@ -44,7 +45,7 @@ public class GitLabSettingsTest {
 
   @Before
   public void prepare() {
-    settings = new MapSettings(new PropertyDefinitions(GitLabSettings.definitions()));
+    settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, GitLabSettings.definitions()));
     config = new GitLabSettings(settings.asConfig());
   }
 
@@ -55,7 +56,6 @@ public class GitLabSettingsTest {
     settings.setProperty(GITLAB_AUTH_URL, "https://gitlab.com/api/");
     assertThat(config.url()).isEqualTo("https://gitlab.com/api");
 
-
     settings.setProperty(GITLAB_AUTH_URL, "https://gitlab.com/api");
     assertThat(config.url()).isEqualTo("https://gitlab.com/api");
 
index 6f285db5456a1f620cc90c3271cb36f477849d07..58f3e87a0ab6ba1fa5f79372ee153013b6de2d28 100644 (file)
@@ -27,15 +27,16 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
-import org.apache.commons.io.IOUtils;
 import org.sonar.api.server.authentication.OAuth2IdentityProvider;
 import org.sonar.api.server.authentication.UnauthorizedException;
 import org.sonar.api.server.authentication.UserIdentity;
+import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -48,7 +49,7 @@ public class SamlIdentityProviderTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(SamlSettings.definitions()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, SamlSettings.definitions()));
 
   private SamlIdentityProvider underTest = new SamlIdentityProvider(new SamlSettings(settings.asConfig()));
 
index b0cdf4e45394956eb07296646dc2d834367e3064..5968416ea3aa2a5df23ba32994a72aaed61c9317 100644 (file)
@@ -28,6 +28,7 @@ import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -37,7 +38,7 @@ public class SamlSettingsTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(SamlSettings.definitions()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, SamlSettings.definitions()));
 
   private SamlSettings underTest = new SamlSettings(settings.asConfig());
 
index d79e1e397395a578fb9040759f24b2f1aa8daf5a..f725b0056fa5ea0a082dba051d9c922df3004d72 100644 (file)
@@ -21,9 +21,9 @@ package org.sonar.ce.task.projectanalysis.purge;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.CoreProperties;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 import org.sonar.core.config.PurgeConstants;
 import org.sonar.core.config.PurgeProperties;
 import org.sonar.db.DbSession;
@@ -34,9 +34,7 @@ import org.sonar.db.purge.period.DefaultPeriodCleaner;
 
 import static java.util.Collections.emptySet;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 public class ProjectCleanerTest {
@@ -46,7 +44,7 @@ public class ProjectCleanerTest {
   private PurgeProfiler profiler = mock(PurgeProfiler.class);
   private DefaultPeriodCleaner periodCleaner = mock(DefaultPeriodCleaner.class);
   private PurgeListener purgeListener = mock(PurgeListener.class);
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(PurgeProperties.all()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, PurgeProperties.all()));
 
   @Before
   public void before() {
index b866b4237834f6175cf52b7467a5d04b36b83fdc..8ba5bd1041b6182427f92f9c7b2c9081a3479108 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.System2;
 import org.sonar.core.config.CorePropertyDefinitions;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -37,7 +38,7 @@ import static org.sonar.api.CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS
 
 public class RatingSettingsTest {
 
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all()));
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
index 13f0b3a610115fac782222090156abd4dab517af..2ad11760b3de5fd7ce81e87afd590ed47cbc80db 100644 (file)
@@ -39,7 +39,7 @@ import static org.sonar.process.ProcessProperties.Property.CE_JAVA_ADDITIONAL_OP
 import static org.sonar.process.ProcessProperties.Property.CE_JAVA_OPTS;
 import static org.sonar.process.ProcessProperties.Property.HTTPS_PROXY_HOST;
 import static org.sonar.process.ProcessProperties.Property.HTTPS_PROXY_PORT;
-import static org.sonar.process.ProcessProperties.Property.HTTP_AUTH_NLM_DOMAN;
+import static org.sonar.process.ProcessProperties.Property.HTTP_AUTH_NTLM_DOMAIN;
 import static org.sonar.process.ProcessProperties.Property.HTTP_NON_PROXY_HOSTS;
 import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_HOST;
 import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_PORT;
@@ -65,7 +65,7 @@ public class CommandFactoryImpl implements CommandFactory {
     HTTP_NON_PROXY_HOSTS.getKey(),
     HTTPS_PROXY_HOST.getKey(),
     HTTPS_PROXY_PORT.getKey(),
-    HTTP_AUTH_NLM_DOMAN.getKey(),
+    HTTP_AUTH_NTLM_DOMAIN.getKey(),
     SOCKS_PROXY_HOST.getKey(),
     SOCKS_PROXY_PORT.getKey()};
 
index 3ba85f8e60668f8868c86faf18617bd88f80d0c6..d3124e4aa20a3ffef5a4a9cc9c3b879852bc51c3 100644 (file)
@@ -25,7 +25,7 @@ import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.net.URISyntaxException;
-import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.Set;
@@ -33,6 +33,7 @@ import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import org.slf4j.LoggerFactory;
 import org.sonar.core.extension.ServiceLoaderWrapper;
+import org.sonar.core.util.SettingFormatter;
 import org.sonar.process.ConfigurationUtils;
 import org.sonar.process.NetworkUtilsImpl;
 import org.sonar.process.ProcessProperties;
@@ -40,8 +41,11 @@ import org.sonar.process.Props;
 import org.sonar.process.System2;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Arrays.stream;
 import static java.util.Optional.ofNullable;
 import static org.sonar.core.util.SettingFormatter.fromJavaPropertyToEnvVariable;
+import static org.sonar.process.ProcessProperties.Property.LDAP_SERVERS;
+import static org.sonar.process.ProcessProperties.Property.MULTI_SERVER_LDAP_SETTINGS;
 import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
 
 public class AppSettingsLoaderImpl implements AppSettingsLoader {
@@ -73,7 +77,37 @@ public class AppSettingsLoaderImpl implements AppSettingsLoader {
   @Override
   public AppSettings load() {
     Properties p = loadPropertiesFile(homeDir);
-    fetchSettingsFromEnvironment(system, p);
+    Set<String> keysOverridableFromEnv = stream(ProcessProperties.Property.values()).map(ProcessProperties.Property::getKey)
+      .collect(Collectors.toSet());
+    keysOverridableFromEnv.addAll(p.stringPropertyNames());
+
+    // 1st pass to load static properties
+    Props staticProps = reloadProperties(keysOverridableFromEnv, p);
+    keysOverridableFromEnv.addAll(getDynamicPropertiesKeys(staticProps));
+
+    // 2nd pass to load dynamic properties like `ldap.*.url` or `ldap.*.baseDn` which keys depend on values of static
+    // properties loaded in 1st step
+    Props props = reloadProperties(keysOverridableFromEnv, p);
+
+    new ProcessProperties(serviceLoaderWrapper).completeDefaults(props);
+    stream(consumers).forEach(c -> c.accept(props));
+    return new AppSettingsImpl(props);
+  }
+
+  private static Set<String> getDynamicPropertiesKeys(Props p) {
+    Set<String> dynamicPropertiesKeys = new HashSet<>();
+    String ldapServersValue = p.value(LDAP_SERVERS.getKey());
+    if (ldapServersValue != null) {
+      stream(SettingFormatter.getStringArrayBySeparator(ldapServersValue, ",")).forEach(
+        ldapServer -> MULTI_SERVER_LDAP_SETTINGS.forEach(
+          multiLdapSetting -> dynamicPropertiesKeys.add(multiLdapSetting.replace("*", ldapServer))));
+    }
+
+    return dynamicPropertiesKeys;
+  }
+
+  private Props reloadProperties(Set<String> keysOverridableFromEnv, Properties p) {
+    loadPropertiesFromEnvironment(system, p, keysOverridableFromEnv);
     p.putAll(CommandLineParser.parseArguments(cliArguments));
     p.setProperty(PATH_HOME.getKey(), homeDir.getAbsolutePath());
     p = ConfigurationUtils.interpolateVariables(p, system.getenv());
@@ -81,18 +115,11 @@ public class AppSettingsLoaderImpl implements AppSettingsLoader {
     // the difference between Properties and Props is that the latter
     // supports decryption of values, so it must be used when values
     // are accessed
-    Props props = new Props(p);
-    new ProcessProperties(serviceLoaderWrapper).completeDefaults(props);
-    Arrays.stream(consumers).forEach(c -> c.accept(props));
-
-    return new AppSettingsImpl(props);
+    return new Props(p);
   }
 
-  private static void fetchSettingsFromEnvironment(System2 system, Properties properties) {
-    Set<String> possibleSettings = Arrays.stream(ProcessProperties.Property.values()).map(ProcessProperties.Property::getKey)
-      .collect(Collectors.toSet());
-    possibleSettings.addAll(properties.stringPropertyNames());
-    possibleSettings.forEach(key -> {
+  private static void loadPropertiesFromEnvironment(System2 system, Properties properties, Set<String> overridableSettings) {
+    overridableSettings.forEach(key -> {
       String environmentVarName = fromJavaPropertyToEnvVariable(key);
       Optional<String> envVarValue = ofNullable(system.getenv(environmentVarName));
       envVarValue.ifPresent(value -> properties.put(key, value));
index d6c4aa8f9c515c876124d54a0c8169c5cd4d0e49..d66029f6ec9d604ee68a5e873980b499ba0c61a6 100644 (file)
@@ -23,15 +23,16 @@ import ch.qos.logback.classic.Level;
 import java.io.File;
 import java.util.Properties;
 import org.sonar.process.ProcessId;
+import org.sonar.process.ProcessProperties;
 import org.sonar.process.Props;
 import org.sonar.process.logging.Log4JPropertiesBuilder;
 import org.sonar.process.logging.LogLevelConfig;
 import org.sonar.process.logging.RootLoggerConfig;
 
+import static org.sonar.process.ProcessProperties.Property.LOG_CONSOLE;
 import static org.sonar.process.logging.RootLoggerConfig.newRootLoggerConfigBuilder;
 
 public class EsLogging {
-  private static final String ALL_LOGS_TO_CONSOLE_PROPERTY = "sonar.log.console";
 
   public Properties createProperties(Props props, File logDir) {
     Log4JPropertiesBuilder log4JPropertiesBuilder = new Log4JPropertiesBuilder(props);
@@ -51,12 +52,11 @@ public class EsLogging {
     return log4JPropertiesBuilder.get();
   }
 
-
   /**
    * Finds out whether we are in testing environment (usually ITs) and logs of all processes must be forward to
-   * App's System.out. This is specified by the value of property {@link #ALL_LOGS_TO_CONSOLE_PROPERTY}.
+   * App's System.out. This is specified by the value of property {@link ProcessProperties.Property#LOG_CONSOLE}.
    */
   private static boolean isAllLogsToConsoleEnabled(Props props) {
-    return props.valueAsBoolean(ALL_LOGS_TO_CONSOLE_PROPERTY, false);
+    return props.valueAsBoolean(LOG_CONSOLE.getKey(), false);
   }
 }
index 988107a61501d45ef5e54ba3fb06f86931c24a1a..db8aa65047cb57a15c8c167a1dad20b3e5ac915f 100644 (file)
@@ -87,6 +87,27 @@ public class AppSettingsLoaderImplTest {
       entry("sonar.embeddedDatabase.port", "8765"));
   }
 
+  @Test
+  public void load_multi_ldap_settings() throws IOException {
+    when(system.getenv()).thenReturn(ImmutableMap.of(
+      "LDAP_FOO_URL", "url1",
+      "LDAP_RANDOM_PROP", "5"));
+    when(system.getenv("LDAP_FOO_URL")).thenReturn("url1");
+    when(system.getenv("LDAP_RANDOM_PROP")).thenReturn("5");
+    File homeDir = temp.newFolder();
+    File propsFile = new File(homeDir, "conf/sonar.properties");
+    FileUtils.write(propsFile, "ldap.servers=foo,bar\n" +
+      "ldap.bar.url=url2", UTF_8);
+    AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(system, new String[0], homeDir, serviceLoaderWrapper);
+
+    AppSettings settings = underTest.load();
+
+    assertThat(settings.getProps().rawProperties()).contains(
+      entry("ldap.servers", "foo,bar"),
+      entry("ldap.foo.url", "url1"),
+      entry("ldap.bar.url", "url2"));
+  }
+
   @Test
   public void throws_ISE_if_file_fails_to_be_loaded() throws Exception {
     File homeDir = temp.newFolder();
index f643c4a744c3088378fe31c78b106c72dde5bcc3..45d01f448f2fd9cb6ef8cf467c4b0213c3d27eb3 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.process;
 
+import com.google.common.collect.ImmutableSet;
 import java.net.InetAddress;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -62,10 +63,14 @@ public class ProcessProperties {
     PATH_TEMP("sonar.path.temp", "temp"),
     PATH_WEB("sonar.path.web", "web"),
 
+    LOG_LEVEL("sonar.log.level"),
     LOG_LEVEL_APP("sonar.log.level.app"),
     LOG_LEVEL_WEB("sonar.log.level.web"),
     LOG_LEVEL_CE("sonar.log.level.ce"),
     LOG_LEVEL_ES("sonar.log.level.es"),
+    LOG_ROLLING_POLICY("sonar.log.rollingPolicy"),
+    LOG_MAX_FILES("sonar.log.maxFiles"),
+    LOG_CONSOLE("sonar.log.console"),
 
     SEARCH_HOST("sonar.search.host", InetAddress.getLoopbackAddress().getHostAddress()),
     SEARCH_PORT("sonar.search.port", "9001"),
@@ -76,10 +81,19 @@ public class ProcessProperties {
     SEARCH_MINIMUM_MASTER_NODES("sonar.search.minimumMasterNodes"),
     SEARCH_INITIAL_STATE_TIMEOUT("sonar.search.initialStateTimeout"),
 
+    WEB_HOST("sonar.web.host"),
     WEB_JAVA_OPTS("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"),
     WEB_JAVA_ADDITIONAL_OPTS("sonar.web.javaAdditionalOpts", ""),
+    WEB_CONTEXT("sonar.web.context"),
     WEB_PORT("sonar.web.port"),
     WEB_GRACEFUL_STOP_TIMEOUT("sonar.web.gracefulStopTimeOutInMs", "" + 4 * 60 * 1_000L),
+    WEB_HTTP_MIN_THREADS("sonar.web.http.minThreads"),
+    WEB_HTTP_MAX_THREADS("sonar.web.http.maxThreads"),
+    WEB_HTTP_ACCEPT_COUNT("sonar.web.http.acceptCount"),
+    WEB_SESSION_TIMEOUT_IN_MIN("sonar.web.sessionTimeoutInMinutes"),
+    WEB_SYSTEM_PASS_CODE("sonar.web.systemPasscode"),
+    WEB_ACCESSLOGS_ENABLE("sonar.web.accessLogs.enable"),
+    WEB_ACCESSLOGS_PATTERN("sonar.web.accessLogs.pattern"),
 
     CE_JAVA_OPTS("sonar.ce.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"),
     CE_JAVA_ADDITIONAL_OPTS("sonar.ce.javaAdditionalOpts", ""),
@@ -92,7 +106,7 @@ public class ProcessProperties {
     HTTP_PROXY_USER("http.proxyUser"),
     HTTP_PROXY_PASSWORD("http.proxyPassword"),
     HTTP_NON_PROXY_HOSTS("http.nonProxyHosts", "localhost|127.*|[::1]"),
-    HTTP_AUTH_NLM_DOMAN("http.auth.ntlm.domain"),
+    HTTP_AUTH_NTLM_DOMAIN("http.auth.ntlm.domain"),
     SOCKS_PROXY_HOST("socksProxyHost"),
     SOCKS_PROXY_PORT("socksProxyPort"),
 
@@ -116,6 +130,23 @@ public class ProcessProperties {
     SONAR_SECURITY_REALM("sonar.security.realm"),
     SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE("sonar.authenticator.ignoreStartupFailure", "false"),
 
+    LDAP_SERVERS("ldap.servers"),
+    LDAP_URL("ldap.url"),
+    LDAP_BIND_DN("ldap.bindDn"),
+    LDAP_BIND_PASSWORD("ldap.bindPassword"),
+    LDAP_AUTHENTICATION("ldap.authentication"),
+    LDAP_REALM("ldap.realm"),
+    LDAP_CONTEXT_FACTORY_CLASS("ldap.contextFactoryClass"),
+    LDAP_START_TLS("ldap.StartTLS"),
+    LDAP_FOLLOW_REFERRALS("ldap.followReferrals"),
+    LDAP_USER_BASE_DN("ldap.user.baseDn"),
+    LDAP_USER_REQUEST("ldap.user.request"),
+    LDAP_USER_REAL_NAME_ATTRIBUTE("ldap.user.realNameAttribute"),
+    LDAP_USER_EMAIL_ATTRIBUTE("ldap.user.emailAttribute"),
+    LDAP_GROUP_BASE_DN("ldap.group.baseDn"),
+    LDAP_GROUP_REQUEST("ldap.group.request"),
+    LDAP_GROUP_ID_ATTRIBUTE("ldap.group.idAttribute"),
+
     SONAR_TELEMETRY_ENABLE("sonar.telemetry.enable", "true"),
     SONAR_TELEMETRY_URL("sonar.telemetry.url", "https://telemetry.sonarsource.com/sonarqube"),
     SONAR_TELEMETRY_FREQUENCY_IN_SECONDS("sonar.telemetry.frequencyInSeconds", "21600"),
@@ -136,6 +167,26 @@ public class ProcessProperties {
     // whether the blue/green deployment of server is enabled
     BLUE_GREEN_ENABLED("sonar.blueGreenEnabled", "false");
 
+    /**
+     * Properties that are defined for each LDAP server from the `ldap.servers` property
+     */
+    public static final Set<String> MULTI_SERVER_LDAP_SETTINGS = ImmutableSet.of(
+      "ldap.*.url",
+      "ldap.*.bindDn",
+      "ldap.*.bindPassword",
+      "ldap.*.authentication",
+      "ldap.*.realm",
+      "ldap.*.contextFactoryClass",
+      "ldap.*.StartTLS",
+      "ldap.*.followReferrals",
+      "ldap.*.user.baseDn",
+      "ldap.*.user.request",
+      "ldap.*.user.realNameAttribute",
+      "ldap.*.user.emailAttribute",
+      "ldap.*.group.baseDn",
+      "ldap.*.group.request",
+      "ldap.*.group.idAttribute");
+
     private final String key;
     private final String defaultValue;
 
index 87ca0edb8bed1a416a84a745e68ddd854aa80f9f..e2f256a751c8cbc3662bfb23447bb297b6c5ebc8 100644 (file)
@@ -28,9 +28,6 @@ import static java.lang.String.format;
 
 public abstract class AbstractLogHelper {
   static final Level[] ALLOWED_ROOT_LOG_LEVELS = new Level[] {Level.TRACE, Level.DEBUG, Level.INFO};
-  static final String SONAR_LOG_LEVEL_PROPERTY = "sonar.log.level";
-  static final String ROLLING_POLICY_PROPERTY = "sonar.log.rollingPolicy";
-  static final String MAX_FILES_PROPERTY = "sonar.log.maxFiles";
 
   private static final String PROCESS_NAME_PLACEHOLDER = "XXXX";
   private static final String THREAD_ID_PLACEHOLDER = "ZZZZ";
index fe5e7f9845b35a02c245585eaf50eb253da003bc..d7dde9b2974f8997229b2b6cdd9c7614b88d9d78 100644 (file)
@@ -28,10 +28,14 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.process.MessageException;
+import org.sonar.process.ProcessProperties;
 import org.sonar.process.Props;
 
 import static java.lang.String.format;
 import static java.lang.String.valueOf;
+import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL;
+import static org.sonar.process.ProcessProperties.Property.LOG_MAX_FILES;
+import static org.sonar.process.ProcessProperties.Property.LOG_ROLLING_POLICY;
 
 public class Log4JPropertiesBuilder extends AbstractLogHelper {
   private static final String ROOT_LOGGER_NAME = "rootLogger";
@@ -70,8 +74,8 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper {
    * <p>
    * <ul>
    * <li>the file's name will use the prefix defined in {@link RootLoggerConfig#getProcessId()#getLogFilenamePrefix()}.</li>
-   * <li>the file will follow the rotation policy defined in property {@link #ROLLING_POLICY_PROPERTY} and
-   * the max number of files defined in property {@link #MAX_FILES_PROPERTY}</li>
+   * <li>the file will follow the rotation policy defined in property {@link ProcessProperties.Property#LOG_ROLLING_POLICY} and
+   * the max number of files defined in property {@link org.sonar.process.ProcessProperties.Property#LOG_MAX_FILES}</li>
    * <li>the logs will follow the specified log pattern</li>
    * </ul>
    * </p>
@@ -106,8 +110,8 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper {
   }
 
   private RollingPolicy createRollingPolicy(File logDir, String filenamePrefix) {
-    String rollingPolicy = props.value(ROLLING_POLICY_PROPERTY, "time:yyyy-MM-dd");
-    int maxFiles = props.valueAsInt(MAX_FILES_PROPERTY, 7);
+    String rollingPolicy = props.value(LOG_ROLLING_POLICY.getKey(), "time:yyyy-MM-dd");
+    int maxFiles = props.valueAsInt(LOG_MAX_FILES.getKey(), 7);
     if (maxFiles <= 0) {
       maxFiles = UNLIMITED_MAX_FILES;
     }
@@ -119,7 +123,7 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper {
     } else if ("none".equals(rollingPolicy)) {
       return new NoRollingPolicy(filenamePrefix, logDir);
     } else {
-      throw new MessageException(format("Unsupported value for property %s: %s", ROLLING_POLICY_PROPERTY, rollingPolicy));
+      throw new MessageException(format("Unsupported value for property %s: %s", LOG_ROLLING_POLICY.getKey(), rollingPolicy));
     }
   }
 
@@ -128,7 +132,7 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper {
       throw new IllegalArgumentException("Value of LogLevelConfig#rootLoggerName must be \"" + ROOT_LOGGER_NAME + "\"");
     }
 
-    Level propertyValueAsLevel = getPropertyValueAsLevel(props, SONAR_LOG_LEVEL_PROPERTY);
+    Level propertyValueAsLevel = getPropertyValueAsLevel(props, LOG_LEVEL.getKey());
     boolean traceGloballyEnabled = propertyValueAsLevel == Level.TRACE;
 
     List<String> loggerNames = Stream.of(
index 8e508f8fd06adfe28e83587efe1c897fc0357a6f..c130f06cc2f1a5596c635251db1a73f87ee71e90 100644 (file)
@@ -32,11 +32,12 @@ import java.util.stream.Stream;
 import org.sonar.process.ProcessId;
 
 import static java.util.Objects.requireNonNull;
+import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL;
 
 public final class LogLevelConfig {
-  private static final String SONAR_LOG_LEVEL_PROPERTY = "sonar.log.level";
+  private static final String SONAR_LOG_LEVEL_PROPERTY = LOG_LEVEL.getKey();
   private static final String PROCESS_NAME_PLACEHOLDER = "XXXX";
-  private static final String SONAR_PROCESS_LOG_LEVEL_PROPERTY = "sonar.log.level." + PROCESS_NAME_PLACEHOLDER;
+  private static final String SONAR_PROCESS_LOG_LEVEL_PROPERTY = SONAR_LOG_LEVEL_PROPERTY + "." + PROCESS_NAME_PLACEHOLDER;
 
   private final Map<String, List<String>> configuredByProperties;
   private final Map<String, Level> configuredByHardcodedLevel;
index 785730b78ac16b3fcc4b86c19e0cfc87fe5f2cf0..85bb1a407794bd252a4e5c24c15e9805800fe31a 100644 (file)
@@ -47,10 +47,15 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.LoggerFactory;
 import org.slf4j.bridge.SLF4JBridgeHandler;
 import org.sonar.process.MessageException;
+import org.sonar.process.ProcessProperties;
 import org.sonar.process.Props;
 
 import static java.lang.String.format;
 import static org.slf4j.Logger.ROOT_LOGGER_NAME;
+import static org.sonar.process.ProcessProperties.Property.LOG_CONSOLE;
+import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL;
+import static org.sonar.process.ProcessProperties.Property.LOG_MAX_FILES;
+import static org.sonar.process.ProcessProperties.Property.LOG_ROLLING_POLICY;
 import static org.sonar.process.ProcessProperties.Property.PATH_LOGS;
 
 /**
@@ -58,7 +63,6 @@ import static org.sonar.process.ProcessProperties.Property.PATH_LOGS;
  */
 public class LogbackHelper extends AbstractLogHelper {
 
-  private static final String ALL_LOGS_TO_CONSOLE_PROPERTY = "sonar.log.console";
   private static final String LOGBACK_LOGGER_NAME_PATTERN = "%logger{20}";
 
   public LogbackHelper() {
@@ -118,7 +122,7 @@ public class LogbackHelper extends AbstractLogHelper {
     LoggerContext rootContext = getRootContext();
     logLevelConfig.getConfiguredByProperties().forEach((key, value) -> applyLevelByProperty(props, rootContext.getLogger(key), value));
     logLevelConfig.getConfiguredByHardcodedLevel().forEach((key, value) -> applyHardcodedLevel(rootContext, key, value));
-    Level propertyValueAsLevel = getPropertyValueAsLevel(props, SONAR_LOG_LEVEL_PROPERTY);
+    Level propertyValueAsLevel = getPropertyValueAsLevel(props, LOG_LEVEL.getKey());
     boolean traceGloballyEnabled = propertyValueAsLevel == Level.TRACE;
     logLevelConfig.getOffUnlessTrace().forEach(logger -> applyHardUnlessTrace(rootContext, logger, traceGloballyEnabled));
     return rootContext;
@@ -169,8 +173,8 @@ public class LogbackHelper extends AbstractLogHelper {
    * <p>
    * <ul>
    * <li>the file's name will use the prefix defined in {@link RootLoggerConfig#getProcessId()#getLogFilenamePrefix()}.</li>
-   * <li>the file will follow the rotation policy defined in property {@link #ROLLING_POLICY_PROPERTY} and
-   * the max number of files defined in property {@link #MAX_FILES_PROPERTY}</li>
+   * <li>the file will follow the rotation policy defined in property {@link ProcessProperties.Property#LOG_ROLLING_POLICY} and
+   * the max number of files defined in property {@link org.sonar.process.ProcessProperties.Property#LOG_MAX_FILES}</li>
    * <li>the logs will follow the specified log encoder</li>
    * </ul>
    * </p>
@@ -204,10 +208,10 @@ public class LogbackHelper extends AbstractLogHelper {
 
   /**
    * Finds out whether we are in testing environment (usually ITs) and logs of all processes must be forward to
-   * App's System.out. This is specified by the value of property {@link #ALL_LOGS_TO_CONSOLE_PROPERTY}.
+   * App's System.out. This is specified by the value of property {@link ProcessProperties.Property#LOG_CONSOLE}.
    */
   public boolean isAllLogsToConsoleEnabled(Props props) {
-    return props.valueAsBoolean(ALL_LOGS_TO_CONSOLE_PROPERTY, false);
+    return props.valueAsBoolean(LOG_CONSOLE.getKey(), false);
   }
 
   public Level getLoggerLevel(String loggerName) {
@@ -241,8 +245,8 @@ public class LogbackHelper extends AbstractLogHelper {
   }
 
   public RollingPolicy createRollingPolicy(Context ctx, Props props, String filenamePrefix) {
-    String rollingPolicy = props.value(ROLLING_POLICY_PROPERTY, "time:yyyy-MM-dd");
-    int maxFiles = props.valueAsInt(MAX_FILES_PROPERTY, 7);
+    String rollingPolicy = props.value(LOG_ROLLING_POLICY.getKey(), "time:yyyy-MM-dd");
+    int maxFiles = props.valueAsInt(LOG_MAX_FILES.getKey(), 7);
     File logsDir = props.nonNullValueAsFile(PATH_LOGS.getKey());
 
     if (rollingPolicy.startsWith("time:")) {
@@ -255,7 +259,7 @@ public class LogbackHelper extends AbstractLogHelper {
       return new NoRollingPolicy(ctx, filenamePrefix, logsDir, maxFiles);
 
     } else {
-      throw new MessageException(format("Unsupported value for property %s: %s", ROLLING_POLICY_PROPERTY, rollingPolicy));
+      throw new MessageException(format("Unsupported value for property %s: %s", LOG_ROLLING_POLICY.getKey(), rollingPolicy));
     }
   }
 
index 5f6abff54c633f72d538ed08ed74a5a6a1302632..6603260c9ad19032915f392c280fa0959d869ce4 100644 (file)
@@ -502,7 +502,7 @@ public class LogbackHelperTest {
     assertThat(encoder).isInstanceOf(LayoutWrappingEncoder.class);
     Layout layout = ((LayoutWrappingEncoder) encoder).getLayout();
     assertThat(layout).isInstanceOf(LogbackJsonLayout.class);
-    assertThat(((LogbackJsonLayout)layout).getProcessKey()).isEqualTo("web");
+    assertThat(((LogbackJsonLayout) layout).getProcessKey()).isEqualTo("web");
   }
 
   private LogLevelConfig.Builder newLogLevelConfig() {
@@ -531,6 +531,25 @@ public class LogbackHelperTest {
     };
   }
 
+  @Test
+  public void log_to_console_setting_missing() {
+    assertThat(underTest.isAllLogsToConsoleEnabled(new Props(new Properties()))).isFalse();
+  }
+
+  @Test
+  public void log_to_console_setting_enabled() {
+    Properties properties = new Properties();
+    properties.setProperty("sonar.log.console", "true");
+    assertThat(underTest.isAllLogsToConsoleEnabled(new Props(properties))).isTrue();
+  }
+
+  @Test
+  public void log_to_console_setting_disabled() {
+    Properties properties = new Properties();
+    properties.setProperty("sonar.log.console", "false");
+    assertThat(underTest.isAllLogsToConsoleEnabled(new Props(properties))).isFalse();
+  }
+
   public static class MemoryAppender extends AppenderBase<ILoggingEvent> {
     private static final List<ILoggingEvent> LOGS = new ArrayList<>();
 
index 559c251bc36454e0e4f39edf4058c0c9774f0a71..efd7254f7e164cd47175f4d4215bd0854bc8a4e2 100644 (file)
@@ -27,12 +27,12 @@ import org.sonar.api.server.ServerSide;
 import static org.apache.commons.lang.StringUtils.isEmpty;
 import static org.apache.commons.lang.StringUtils.isNotEmpty;
 import static org.sonar.api.CoreProperties.SERVER_BASE_URL;
+import static org.sonar.process.ProcessProperties.Property.WEB_CONTEXT;
+import static org.sonar.process.ProcessProperties.Property.WEB_HOST;
 
 @ComputeEngineSide
 @ServerSide
 public class UrlSettings {
-  private static final String PROPERTY_CONTEXT = "sonar.web.context";
-
   private static final int DEFAULT_PORT = 9000;
   private static final int DEFAULT_HTTP_PORT = 80;
   private static final String ALL_IPS_HOST = "0.0.0.0";
@@ -43,7 +43,7 @@ public class UrlSettings {
 
   public UrlSettings(Configuration config) {
     this.config = config;
-    this.contextPath = config.get(PROPERTY_CONTEXT).orElse("")
+    this.contextPath = config.get(WEB_CONTEXT.getKey()).orElse("")
       // Remove trailing slashes
       .replaceFirst("(\\/+)$", "");
   }
@@ -66,9 +66,9 @@ public class UrlSettings {
   }
 
   private String computeBaseUrl() {
-    String host = config.get("sonar.web.host").orElse("");
+    String host = config.get(WEB_HOST.getKey()).orElse("");
     int port = config.getInt("sonar.web.port").orElse(0);
-    String context = config.get(PROPERTY_CONTEXT).orElse("");
+    String context = config.get(WEB_CONTEXT.getKey()).orElse("");
 
     StringBuilder res = new StringBuilder();
     res.append("http://");
index 74c7affdf532f6a4f4194d7a71167b6e949c3649..0b55727ce58b88efbdfadbf7e5bffb4c487af589 100644 (file)
 package org.sonar.server.setting;
 
 import com.google.common.annotations.VisibleForTesting;
-import java.util.AbstractMap;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import org.apache.ibatis.exceptions.PersistenceException;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.config.internal.Encryption;
-import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
 import org.sonar.api.config.internal.Settings;
 import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.SettingFormatter;
 
 import static java.util.Collections.unmodifiableMap;
 import static java.util.Objects.requireNonNull;
@@ -61,24 +55,19 @@ import static java.util.Objects.requireNonNull;
 @ServerSide
 public class ThreadLocalSettings extends Settings {
   private final Properties systemProps = new Properties();
-  private final Properties corePropsFromEnvVariables = new Properties();
   private static final ThreadLocal<Map<String, String>> CACHE = new ThreadLocal<>();
   private Map<String, String> getPropertyDbFailureCache = Collections.emptyMap();
   private Map<String, String> getPropertiesDbFailureCache = Collections.emptyMap();
   private SettingLoader settingLoader;
-  private System2 system2;
 
-  public ThreadLocalSettings(System2 system2, PropertyDefinitions definitions, Properties props) {
-    this(system2, definitions, props, new NopSettingLoader());
+  public ThreadLocalSettings(PropertyDefinitions definitions, Properties props) {
+    this(definitions, props, new NopSettingLoader());
   }
 
   @VisibleForTesting
-  ThreadLocalSettings(System2 system2, PropertyDefinitions definitions, Properties props, SettingLoader settingLoader) {
+  ThreadLocalSettings(PropertyDefinitions definitions, Properties props, SettingLoader settingLoader) {
     super(definitions, new Encryption(null));
-    this.system2 = system2;
     this.settingLoader = settingLoader;
-
-    resolveCorePropertiesFromEnvironment();
     props.forEach((k, v) -> systemProps.put(k, v == null ? null : v.toString().trim()));
 
     // TODO something wrong about lifecycle here. It could be improved
@@ -107,9 +96,9 @@ public class ThreadLocalSettings extends Settings {
       return Optional.of(value);
     }
 
-    value = corePropsFromEnvVariables.getProperty(key);
-    if (value != null) {
-      return Optional.of(value);
+    Optional<String> envVal = getDefinitions().getValueFromEnv(key);
+    if (envVal.isPresent()) {
+      return envVal;
     }
 
     Map<String, String> dbProps = CACHE.get();
@@ -183,7 +172,7 @@ public class ThreadLocalSettings extends Settings {
   public Map<String, String> getProperties() {
     Map<String, String> result = new HashMap<>();
     loadAll(result);
-    corePropsFromEnvVariables.forEach((k, v) -> result.put((String) k, (String) v));
+    getDefinitions().getAllPropertiesSetInEnv().forEach(result::put);
     systemProps.forEach((key, value) -> result.put((String) key, (String) value));
     return unmodifiableMap(result);
   }
@@ -197,20 +186,4 @@ public class ThreadLocalSettings extends Settings {
       appendTo.putAll(getPropertiesDbFailureCache);
     }
   }
-
-  private void resolveCorePropertiesFromEnvironment() {
-    corePropsFromEnvVariables.putAll(this.getDefinitions().getAll()
-      .stream()
-      .map(PropertyDefinition::key)
-      .flatMap(p -> {
-        String envVar = SettingFormatter.fromJavaPropertyToEnvVariable(p);
-        String envVarValue = system2.envVariable(envVar);
-        if (envVarValue != null) {
-          return Stream.of(new AbstractMap.SimpleEntry<>(p, envVarValue));
-        } else {
-          return Stream.empty();
-        }
-      })
-      .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)));
-  }
 }
index 833f447f52de6e56491924472477ba089db04860..29957eaa22d98f79332e0db6cd3c6fe6d72f8c69 100644 (file)
@@ -28,6 +28,7 @@ import org.junit.runner.RunWith;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.config.PropertyDefinition.builder;
@@ -38,7 +39,7 @@ public class ConfigurationProviderTest {
   private final String nonDeclaredKey = RandomStringUtils.randomAlphabetic(3);
   private final String nonMultivalueKey = RandomStringUtils.randomAlphabetic(3);
   private final String multivalueKey = RandomStringUtils.randomAlphabetic(3);
-  private final MapSettings settings = new MapSettings(new PropertyDefinitions(
+  private final MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE,
     builder(nonMultivalueKey).multiValues(false).build(),
     builder(multivalueKey).multiValues(true).build()));
 
index 1a2c451d6336fc0084edba2a4777b7c02b11321e..ea842bc515b452b1528d92ec663a8b261bb9bb5d 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 import org.sonar.core.config.CorePropertyDefinitions;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -38,7 +39,7 @@ public class UrlSettingsTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all()));
+  private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all()));
 
   @Test
   public void use_default_context_path() {
index 2964925628ea76e14a0cfdd1135216c93a225271..4e2858e70dd49ee5dfe616c7f59b151d7db36d44 100644 (file)
@@ -29,6 +29,7 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -46,7 +47,7 @@ public class ChildSettingsTest {
   public void childSettings_should_retrieve_parent_settings() {
     String multipleValuesKey = randomAlphanumeric(19);
     PropertyDefinition multipleValues = PropertyDefinition.builder(multipleValuesKey).multiValues(true).build();
-    MapSettings parent = new MapSettings(new PropertyDefinitions(Collections.singletonList(multipleValues)));
+    MapSettings parent = new MapSettings(new PropertyDefinitions(System2.INSTANCE, Collections.singletonList(multipleValues)));
     ChildSettings underTest = new ChildSettings(parent);
 
     parent.setProperty(randomAlphanumeric(10), randomAlphanumeric(20));
index 90624314c4a1c5edaa20235f283bb7aa1cd4ae7a..859c0ae4c2068e61b5fbc1e933e56497e2df67bb 100644 (file)
@@ -33,6 +33,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.Property;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.utils.System2;
 import org.sonar.core.config.CorePropertyDefinitions;
@@ -70,7 +71,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void can_not_add_property_if_no_cache() {
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
 
     underTest.set("foo", "wiz");
 
@@ -79,7 +80,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void can_not_remove_system_property_if_no_cache() {
-    underTest = create(ImmutableMap.of("foo", "bar"));
+    underTest = create(system, ImmutableMap.of("foo", "bar"));
 
     underTest.remove("foo");
 
@@ -88,7 +89,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void add_property_to_cache() {
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
 
     underTest.load();
     underTest.set("foo", "bar");
@@ -101,7 +102,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void remove_property_from_cache() {
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
 
     underTest.load();
     underTest.set("foo", "bar");
@@ -120,7 +121,7 @@ public class ThreadLocalSettingsTest {
   @Test
   public void getProperties_does_not_fail_on_duplicated_key() {
     insertPropertyIntoDb("foo", "from_db");
-    underTest = create(ImmutableMap.of("foo", "from_system"));
+    underTest = create(system, ImmutableMap.of("foo", "from_system"));
 
     assertThat(underTest.get("foo")).hasValue("from_system");
     assertThat(underTest.getProperties().get("foo")).isEqualTo("from_system");
@@ -130,27 +131,31 @@ public class ThreadLocalSettingsTest {
   public void load_encryption_secret_key_from_system_properties() throws Exception {
     File secretKey = temp.newFile();
 
-    underTest = create(ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", secretKey.getAbsolutePath()));
+    underTest = create(system, ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", secretKey.getAbsolutePath()));
 
     assertThat(underTest.getEncryption().hasSecretKey()).isTrue();
   }
 
   @Test
   public void encryption_secret_key_is_undefined_by_default() {
-    underTest = create(ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", "unknown/path/to/sonar-secret.txt"));
+    underTest = create(system, ImmutableMap.of("foo", "bar", "sonar.secretKeyPath", "unknown/path/to/sonar-secret.txt"));
 
     assertThat(underTest.getEncryption().hasSecretKey()).isFalse();
   }
 
-  private ThreadLocalSettings create(Map<String, String> systemProps) {
+  private ThreadLocalSettings create(System2 system, Map<String, String> systemProps) {
+    PropertyDefinitions definitions = new PropertyDefinitions(system);
+    definitions.addComponents(CorePropertyDefinitions.all());
+    definitions.addComponent(new AnnotatedTestClass());
+
     Properties p = new Properties();
     p.putAll(systemProps);
-    return new ThreadLocalSettings(system, new PropertyDefinitions(CorePropertyDefinitions.all()), p, dbSettingLoader);
+    return new ThreadLocalSettings(definitions, p, dbSettingLoader);
   }
 
   @Test
   public void load_system_properties() {
-    underTest = create(ImmutableMap.of("foo", "1", "bar", "2"));
+    underTest = create(system, ImmutableMap.of("foo", "1", "bar", "2"));
 
     assertThat(underTest.get("foo")).hasValue("1");
     assertThat(underTest.get("missing")).isNotPresent();
@@ -160,17 +165,19 @@ public class ThreadLocalSettingsTest {
   @Test
   public void load_core_properties_from_environment() {
     when(system.envVariable("SONAR_FORCEAUTHENTICATION")).thenReturn("true");
-    underTest = create(ImmutableMap.of());
+    when(system.envVariable("SONAR_ANNOTATION_TEST_PROP")).thenReturn("113");
+    underTest = create(system, ImmutableMap.of());
 
     assertThat(underTest.get("sonar.forceAuthentication")).hasValue("true");
+    assertThat(underTest.get("sonar.annotation.test.prop")).hasValue("113");
     assertThat(underTest.get("missing")).isNotPresent();
-    assertThat(underTest.getProperties()).containsOnly(entry("sonar.forceAuthentication", "true"));
+    assertThat(underTest.getProperties()).containsOnly(entry("sonar.forceAuthentication", "true"), entry("sonar.annotation.test.prop", "113"));
   }
 
   @Test
   public void database_properties_are_not_cached_by_default() {
     insertPropertyIntoDb("foo", "from db");
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
 
     assertThat(underTest.get("foo")).hasValue("from db");
 
@@ -182,7 +189,7 @@ public class ThreadLocalSettingsTest {
   @Test
   public void system_settings_have_precedence_over_database() {
     insertPropertyIntoDb("foo", "from db");
-    underTest = create(ImmutableMap.of("foo", "from system"));
+    underTest = create(system, ImmutableMap.of("foo", "from system"));
 
     assertThat(underTest.get("foo")).hasValue("from system");
   }
@@ -191,7 +198,7 @@ public class ThreadLocalSettingsTest {
   public void getProperties_are_all_properties_with_value() {
     insertPropertyIntoDb("db", "from db");
     insertPropertyIntoDb("empty", "");
-    underTest = create(ImmutableMap.of("system", "from system"));
+    underTest = create(system, ImmutableMap.of("system", "from system"));
 
     assertThat(underTest.getProperties()).containsOnly(entry("system", "from system"), entry("db", "from db"), entry("empty", ""));
   }
@@ -199,7 +206,7 @@ public class ThreadLocalSettingsTest {
   @Test
   public void getProperties_is_not_cached_in_thread_cache() {
     insertPropertyIntoDb("foo", "bar");
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
     underTest.load();
 
     assertThat(underTest.getProperties())
@@ -219,7 +226,7 @@ public class ThreadLocalSettingsTest {
   public void load_creates_a_thread_specific_cache() throws InterruptedException {
     insertPropertyIntoDb(A_KEY, "v1");
 
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
     underTest.load();
 
     assertThat(underTest.get(A_KEY)).hasValue("v1");
@@ -239,7 +246,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void load_invalidates_cache_if_unload_has_not_been_called() {
-    underTest = create(emptyMap());
+    underTest = create(system, emptyMap());
     underTest.load();
     underTest.set("foo", "bar");
     // unload() is not called
@@ -250,7 +257,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void keep_in_thread_cache_the_fact_that_a_property_is_not_in_db() {
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
     underTest.load();
     assertThat(underTest.get(A_KEY)).isNotPresent();
 
@@ -263,7 +270,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void change_setting_loader() {
-    underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties());
+    underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties());
 
     assertThat(underTest.getSettingLoader()).isNotNull();
 
@@ -274,7 +281,7 @@ public class ThreadLocalSettingsTest {
 
   @Test
   public void cache_db_calls_if_property_is_not_persisted() {
-    underTest = create(Collections.emptyMap());
+    underTest = create(system, Collections.emptyMap());
     underTest.load();
     assertThat(underTest.get(A_KEY)).isNotPresent();
     assertThat(underTest.get(A_KEY)).isNotPresent();
@@ -286,7 +293,7 @@ public class ThreadLocalSettingsTest {
     SettingLoader settingLoaderMock = mock(SettingLoader.class);
     PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB");
     doThrow(toBeThrown).when(settingLoaderMock).loadAll();
-    underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock);
+    underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock);
 
     assertThat(underTest.getProperties())
       .isEmpty();
@@ -297,7 +304,7 @@ public class ThreadLocalSettingsTest {
     SettingLoader settingLoaderMock = mock(SettingLoader.class);
     PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB");
     doThrow(toBeThrown).when(settingLoaderMock).loadAll();
-    underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock);
+    underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock);
     underTest.load();
 
     assertThat(underTest.getProperties())
@@ -316,7 +323,7 @@ public class ThreadLocalSettingsTest {
       .doAnswer(invocationOnMock -> ImmutableMap.of(key, value2))
       .when(settingLoaderMock)
       .loadAll();
-    underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock);
+    underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock);
 
     underTest.load();
     assertThat(underTest.getProperties())
@@ -340,7 +347,7 @@ public class ThreadLocalSettingsTest {
     PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB");
     String key = randomAlphanumeric(3);
     doThrow(toBeThrown).when(settingLoaderMock).load(key);
-    underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock);
+    underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock);
 
     assertThat(underTest.get(key)).isEmpty();
   }
@@ -351,7 +358,7 @@ public class ThreadLocalSettingsTest {
     PersistenceException toBeThrown = new PersistenceException("Faking an error connecting to DB");
     String key = randomAlphanumeric(3);
     doThrow(toBeThrown).when(settingLoaderMock).load(key);
-    underTest = new ThreadLocalSettings(system, new PropertyDefinitions(), new Properties(), settingLoaderMock);
+    underTest = new ThreadLocalSettings(new PropertyDefinitions(system), new Properties(), settingLoaderMock);
     underTest.load();
 
     assertThat(underTest.get(key)).isEmpty();
@@ -417,4 +424,14 @@ public class ThreadLocalSettingsTest {
       return unmodifiableMap(map);
     }
   }
+
+  @org.sonar.api.Properties({
+    @Property(
+      key = "sonar.annotation.test.prop",
+      defaultValue = "60",
+      name = "Test annotation property",
+      global = false)
+  })
+  class AnnotatedTestClass {
+  }
 }
index 9c9eb212450192a9a4696243717566e8dd6c550e..a46245a0ab04f3cc1ebebaadeaf019e048c4fdae 100644 (file)
@@ -40,13 +40,12 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 import static org.apache.commons.lang.StringUtils.isEmpty;
 import static org.apache.commons.lang.time.DateUtils.addSeconds;
+import static org.sonar.process.ProcessProperties.Property.WEB_SESSION_TIMEOUT_IN_MIN;
 import static org.sonar.server.authentication.Cookies.findCookie;
 import static org.sonar.server.authentication.Cookies.newCookieBuilder;
 
 @ServerSide
 public class JwtHttpHandler {
-
-  private static final String SESSION_TIMEOUT_IN_MINUTES_PROPERTY = "sonar.web.sessionTimeoutInMinutes";
   private static final int SESSION_TIMEOUT_DEFAULT_VALUE_IN_MINUTES = 3 * 24 * 60;
   private static final int MAX_SESSION_TIMEOUT_IN_MINUTES = 3 * 30 * 24 * 60;
 
@@ -175,10 +174,11 @@ public class JwtHttpHandler {
   }
 
   private static int getSessionTimeoutInSeconds(Configuration config) {
-    int minutes = config.getInt(SESSION_TIMEOUT_IN_MINUTES_PROPERTY).orElse(SESSION_TIMEOUT_DEFAULT_VALUE_IN_MINUTES);
-    checkArgument(minutes > 0, "Property %s must be strictly positive. Got %s", SESSION_TIMEOUT_IN_MINUTES_PROPERTY, minutes);
-    checkArgument(minutes <= MAX_SESSION_TIMEOUT_IN_MINUTES, "Property %s must not be greater than 3 months (%s minutes). Got %s minutes",
-      SESSION_TIMEOUT_IN_MINUTES_PROPERTY, MAX_SESSION_TIMEOUT_IN_MINUTES, minutes);
+    int minutes = config.getInt(WEB_SESSION_TIMEOUT_IN_MIN.getKey()).orElse(SESSION_TIMEOUT_DEFAULT_VALUE_IN_MINUTES);
+    checkArgument(minutes > 0, "Property %s must be strictly positive. Got %s", WEB_SESSION_TIMEOUT_IN_MIN.getKey(), minutes);
+    checkArgument(minutes <= MAX_SESSION_TIMEOUT_IN_MINUTES,
+      "Property %s must not be greater than 3 months (%s minutes). Got %s minutes", WEB_SESSION_TIMEOUT_IN_MIN.getKey(),
+      MAX_SESSION_TIMEOUT_IN_MINUTES, minutes);
     return minutes * 60;
   }
 
index 43c4551e4e54034f62fec4b0b17456e8f86f8cbe..8511de7a7ac6b590056768ed9e540528fcc0f9aa 100644 (file)
@@ -27,11 +27,12 @@ import org.sonar.api.server.ServerSide;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.utils.log.Loggers;
 
+import static org.sonar.process.ProcessProperties.Property.WEB_SYSTEM_PASS_CODE;
+
 @ServerSide
 public class SystemPasscodeImpl implements SystemPasscode, Startable {
 
   public static final String PASSCODE_HTTP_HEADER = "X-Sonar-Passcode";
-  public static final String PASSCODE_CONF_PROPERTY = "sonar.web.systemPasscode";
 
   private final Configuration configuration;
   private String configuredPasscode;
@@ -52,7 +53,7 @@ public class SystemPasscodeImpl implements SystemPasscode, Startable {
 
   @Override
   public void start() {
-    Optional<String> passcodeOpt = configuration.get(PASSCODE_CONF_PROPERTY)
+    Optional<String> passcodeOpt = configuration.get(WEB_SYSTEM_PASS_CODE.getKey())
       // if present, result is never empty string
       .map(StringUtils::trimToNull);
 
index 8eca155c47d221ea3d6aa43ee45edddd8b40b01c..794863787712fd9dea3b8ebfbbf6eebcc8814058 100644 (file)
@@ -28,6 +28,7 @@ import org.mockito.verification.Timeout;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.notifications.Notification;
+import org.sonar.api.utils.System2;
 
 import static java.util.Collections.singleton;
 import static org.mockito.ArgumentMatchers.anyCollection;
@@ -43,7 +44,7 @@ public class NotificationDaemonTest {
 
   @Before
   public void setUp() {
-    MapSettings settings = new MapSettings(new PropertyDefinitions(NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L);
+    MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L);
 
     underTest = new NotificationDaemon(settings.asConfig(), manager, notificationService);
     inOrder = Mockito.inOrder(notificationService);
index fb8b5001af559872165a5a3cfe0346c7d1b9f3e1..39a67cee288da2523fc3adbd830e077723afb9dd 100644 (file)
@@ -23,10 +23,11 @@ import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.Settings;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.config.internal.Settings;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -68,7 +69,7 @@ public class NotificationMediumTest {
     when(qualityGateChange.getType()).thenReturn("qgate-changes");
     when(manager.getFromQueue()).thenReturn(notification).thenReturn(null);
 
-    MapSettings settings = new MapSettings(new PropertyDefinitions(NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L);
+    MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L);
 
     underTest = new NotificationDaemon(settings.asConfig(), manager, service);
   }
index 3790efa3c017c6c62fc54a20a1b3963478a36e18..b9f9252341b8dbf981f126b9475ae5d1f1318e0f 100644 (file)
@@ -23,8 +23,9 @@ import org.junit.Test;
 import org.sonar.api.PropertyType;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.Settings;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.config.internal.Settings;
+import org.sonar.api.utils.System2;
 import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
 
 import static org.apache.commons.lang.StringUtils.repeat;
@@ -36,7 +37,7 @@ public class SettingsSectionTest {
 
   private static final String PASSWORD_PROPERTY = "sonar.password";
 
-  private PropertyDefinitions defs = new PropertyDefinitions(PropertyDefinition.builder(PASSWORD_PROPERTY).type(PropertyType.PASSWORD).build());
+  private PropertyDefinitions defs = new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder(PASSWORD_PROPERTY).type(PropertyType.PASSWORD).build());
   private Settings settings = new MapSettings(defs);
   private SettingsSection underTest = new SettingsSection(settings);
 
index fd68ea0a0c30e9f1be8a6dcc0764e58b908bd59f..5ed9547504a5a5601241f598584f375ed9abe2f0 100644 (file)
@@ -23,15 +23,18 @@ import org.junit.Test;
 import org.sonar.api.Properties;
 import org.sonar.api.Property;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
 import org.sonar.db.property.PropertiesDao;
 
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 public class RenameDeprecatedPropertyKeysTest {
   @Test
   public void should_rename_deprecated_keys() {
     PropertiesDao dao = mock(PropertiesDao.class);
-    PropertyDefinitions definitions = new PropertyDefinitions(FakeExtension.class);
+    PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE, FakeExtension.class);
     RenameDeprecatedPropertyKeys task = new RenameDeprecatedPropertyKeys(dao, definitions);
     task.start();
 
index 04867d6b08c8adc6e84483f658c014b320d2671b..532698f147904e95eb1f72edfa338774d4e917aa 100644 (file)
@@ -23,9 +23,9 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.ce.queue.CeQueue;
+import org.sonar.process.ProcessProperties;
 import org.sonar.server.user.AbstractUserSession;
 import org.sonar.server.user.SystemPasscode;
-import org.sonar.server.user.SystemPasscodeImpl;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.WsUtils;
 import org.sonarqube.ws.Ce;
@@ -46,7 +46,7 @@ public class InfoAction implements CeWsAction {
   public void define(WebService.NewController controller) {
     controller.createAction("info")
       .setDescription("Gets information about Compute Engine. Requires the system administration permission or " +
-        "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).")
+        "system passcode (see " + ProcessProperties.Property.WEB_SYSTEM_PASS_CODE + " in sonar.properties).")
       .setSince("7.2")
       .setInternal(true)
       .setHandler(this)
index 66ea01bebbcd8e879056667ad59a9f67c438d39c..22d1ceb18523721762b750dd9a3db169edc5bd3a 100644 (file)
@@ -23,9 +23,9 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.ce.queue.CeQueue;
+import org.sonar.process.ProcessProperties;
 import org.sonar.server.user.AbstractUserSession;
 import org.sonar.server.user.SystemPasscode;
-import org.sonar.server.user.SystemPasscodeImpl;
 import org.sonar.server.user.UserSession;
 
 public class PauseAction implements CeWsAction {
@@ -44,7 +44,7 @@ public class PauseAction implements CeWsAction {
   public void define(WebService.NewController controller) {
     controller.createAction("pause")
       .setDescription("Requests pause of Compute Engine workers. Requires the system administration permission or " +
-        "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).")
+        "system passcode (see " + ProcessProperties.Property.WEB_SYSTEM_PASS_CODE + " in sonar.properties).")
       .setSince("7.2")
       .setInternal(true)
       .setHandler(this)
index 41955dcd95b403d5e6ddf378d04682b8764e0452..0599e9ab03b00994d93cc83776fcd2012e2bacb5 100644 (file)
@@ -23,9 +23,9 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.ce.queue.CeQueue;
+import org.sonar.process.ProcessProperties;
 import org.sonar.server.user.AbstractUserSession;
 import org.sonar.server.user.SystemPasscode;
-import org.sonar.server.user.SystemPasscodeImpl;
 import org.sonar.server.user.UserSession;
 
 public class ResumeAction implements CeWsAction {
@@ -44,7 +44,7 @@ public class ResumeAction implements CeWsAction {
   public void define(WebService.NewController controller) {
     controller.createAction("resume")
       .setDescription("Resumes pause of Compute Engine workers. Requires the system administration permission or " +
-        "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).")
+        "system passcode (see " + ProcessProperties.Property.WEB_SYSTEM_PASS_CODE + " in sonar.properties).")
       .setSince("7.2")
       .setInternal(true)
       .setHandler(this)
index 9a64112913c814dfe6cdd3f529cde43b82ea36bf..29a13e098648735c536570717d0a48a8f13f5f85 100644 (file)
@@ -39,6 +39,7 @@ import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.utils.System2;
 import org.sonar.core.config.CorePropertyDefinitions;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
@@ -399,7 +400,7 @@ public class LiveMeasureComputerImplTest {
     when(qGateComputer.getMetricsRelatedTo(qualityGate)).thenReturn(singleton(CoreMetrics.ALERT_STATUS_KEY));
     when(qGateComputer.refreshGateStatus(eq(project), same(qualityGate), any(MeasureMatrix.class)))
       .thenReturn(newQualityGate);
-    MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all()));
+    MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all()));
     ProjectConfigurationLoader configurationLoader = new TestProjectConfigurationLoader(settings.asConfig());
 
     LiveMeasureComputerImpl underTest = new LiveMeasureComputerImpl(db.getDbClient(), formulaFactory, qGateComputer, configurationLoader, projectIndexer);
index 841248d8618cf5179ba8ccd85a2befd961508ca2..e724e52cd7225c4a2283ef64c754692bcd30ac98 100644 (file)
@@ -85,7 +85,7 @@ public class ListDefinitionsActionTest {
   private DbClient dbClient = db.getDbClient();
   private ComponentDbTester componentDb = new ComponentDbTester(db);
   private ComponentDto project;
-  private PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
+  private PropertyDefinitions propertyDefinitions = new PropertyDefinitions(System2.INSTANCE);
   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
   private SettingsWsSupport support = new SettingsWsSupport(defaultOrganizationProvider, userSession);
   private WsActionTester ws = new WsActionTester(
index f44cebed3f9d2a48dade5b32c5b8dd8e15a77889..6fc1b274231ee02614fe8bd853782caf990eaeeb 100644 (file)
@@ -81,7 +81,7 @@ public class ResetActionTest {
   private DbClient dbClient = db.getDbClient();
   private DbSession dbSession = db.getSession();
   private ComponentFinder componentFinder = TestComponentFinder.from(db);
-  private PropertyDefinitions definitions = new PropertyDefinitions();
+  private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE);
   private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions);
   private SettingValidations settingValidations = new SettingValidations(definitions, dbClient, i18n);
   private ComponentDto project;
index c25c8bb11d21c64b4ba19650be3427d42c6596cf..734869d66f9ebb8398ad8bdc45e6e246571c6e63 100644 (file)
@@ -91,7 +91,7 @@ public class SetActionTest {
   private ComponentFinder componentFinder = TestComponentFinder.from(db);
 
   private I18nRule i18n = new I18nRule();
-  private PropertyDefinitions definitions = new PropertyDefinitions();
+  private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE);
   private FakeSettingsNotifier settingsChangeNotifier = new FakeSettingsNotifier(dbClient);
   private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions);
   private SettingValidations validations = new SettingValidations(definitions, dbClient, i18n);
index bf12663030e93b66e3e7b57a9a0db514a9974ed2..f41c559f670cc2b1829149ee1a99748ebc8f3069 100644 (file)
@@ -59,7 +59,7 @@ public class SettingsUpdaterTest {
   PropertyDbTester propertyDb = new PropertyDbTester(db);
   ComponentDbTester componentDb = new ComponentDbTester(db);
 
-  PropertyDefinitions definitions = new PropertyDefinitions();
+  PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE);
   ComponentDto project;
 
   SettingsUpdater underTest= new SettingsUpdater(dbClient, definitions);
index 48f8a7a73f3fa1793287abe81df177d681de46ef..efb439b13d29454863d4716e07b3cd0ce1366059 100644 (file)
@@ -89,7 +89,7 @@ public class ValuesActionTest {
   private DbClient dbClient = db.getDbClient();
   private PropertyDbTester propertyDb = new PropertyDbTester(db);
   private ComponentDbTester componentDb = new ComponentDbTester(db);
-  private PropertyDefinitions definitions = new PropertyDefinitions();
+  private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE);
   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
   private SettingsWsSupport support = new SettingsWsSupport(defaultOrganizationProvider, userSession);
   private ComponentDto project;
index 5a43767f460db50b468ee0d59064a8ed9f96015f..dc55d7bbd9ca3e0e30a47fd4529436f16ba42499 100644 (file)
@@ -25,6 +25,10 @@ import org.apache.catalina.startup.Tomcat;
 import org.sonar.process.Props;
 
 import static java.lang.String.format;
+import static org.sonar.process.ProcessProperties.Property.WEB_HOST;
+import static org.sonar.process.ProcessProperties.Property.WEB_HTTP_ACCEPT_COUNT;
+import static org.sonar.process.ProcessProperties.Property.WEB_HTTP_MAX_THREADS;
+import static org.sonar.process.ProcessProperties.Property.WEB_HTTP_MIN_THREADS;
 
 /**
  * Configuration of Tomcat connectors
@@ -53,7 +57,7 @@ class TomcatConnectors {
 
     Connector connector = new Connector(HTTP_PROTOCOL);
     connector.setURIEncoding("UTF-8");
-    connector.setProperty("address", props.value("sonar.web.host", "0.0.0.0"));
+    connector.setProperty("address", props.value(WEB_HOST.getKey(), "0.0.0.0"));
     connector.setProperty("socket.soReuseAddress", "true");
     // see https://tomcat.apache.org/tomcat-8.5-doc/config/http.html
     connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
@@ -75,9 +79,9 @@ class TomcatConnectors {
 
   private static void configurePool(Props props, Connector connector) {
     connector.setProperty("acceptorThreadCount", String.valueOf(2));
-    connector.setProperty("minSpareThreads", String.valueOf(props.valueAsInt("sonar.web.http.minThreads", 5)));
-    connector.setProperty("maxThreads", String.valueOf(props.valueAsInt("sonar.web.http.maxThreads", 50)));
-    connector.setProperty("acceptCount", String.valueOf(props.valueAsInt("sonar.web.http.acceptCount", 25)));
+    connector.setProperty("minSpareThreads", String.valueOf(props.valueAsInt(WEB_HTTP_MIN_THREADS.getKey(), 5)));
+    connector.setProperty("maxThreads", String.valueOf(props.valueAsInt(WEB_HTTP_MAX_THREADS.getKey(), 50)));
+    connector.setProperty("acceptCount", String.valueOf(props.valueAsInt(WEB_HTTP_ACCEPT_COUNT.getKey(), 25)));
   }
 
   private static void configureCompression(Connector connector) {
index 48eb59b495bd35a1e95332a6989097617b837e69..b1afee1dd83e9183dc21b8dcaa41ac14f23aae91 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.process.Props;
 import static java.lang.String.format;
 import static org.sonar.process.ProcessProperties.Property.PATH_DATA;
 import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
+import static org.sonar.process.ProcessProperties.Property.WEB_CONTEXT;
 
 /**
  * Configures Tomcat contexts:
@@ -41,8 +42,6 @@ import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
  * </ul>
  */
 public class TomcatContexts {
-
-  private static final String PROPERTY_CONTEXT = "sonar.web.context";
   private static final String WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR = "web/deploy";
 
   private final Fs fs;
@@ -68,11 +67,11 @@ public class TomcatContexts {
   }
 
   static String getContextPath(Props props) {
-    String context = props.value(PROPERTY_CONTEXT, "");
+    String context = props.value(WEB_CONTEXT.getKey(), "");
     if ("/".equals(context)) {
       context = "";
     } else if (!"".equals(context) && context != null && !context.startsWith("/")) {
-      throw MessageException.of(format("Value of '%s' must start with a forward slash: '%s'", PROPERTY_CONTEXT, context));
+      throw MessageException.of(format("Value of '%s' must start with a forward slash: '%s'", WEB_CONTEXT.getKey(), context));
     }
     return context;
   }
index 71b214b4684d9bc746cc7a28dd0c0c5c8d46e0b9..98e952f52db99b547f8e9c6c0cc617a43202f79c 100644 (file)
@@ -40,6 +40,7 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.scanner.ScannerSide;
 import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.System2;
 
 import static com.google.common.collect.ImmutableList.copyOf;
 import static java.util.Objects.requireNonNull;
@@ -88,7 +89,7 @@ public class ComponentContainer implements ContainerPopulator.Container {
   }
 
   protected ComponentContainer(MutablePicoContainer picoContainer) {
-    this(picoContainer, new PropertyDefinitions());
+    this(picoContainer, new PropertyDefinitions(System2.INSTANCE));
   }
 
   protected ComponentContainer(MutablePicoContainer picoContainer, PropertyDefinitions propertyDefinitions) {
index 7233a79cbbba948a71ef7697eeac9afaa976574d..74b3eb0688637fdefd60b2d7edd6f4aa3b5616a7 100644 (file)
@@ -20,6 +20,9 @@
 package org.sonar.core.util;
 
 import java.util.Locale;
+import org.apache.commons.lang.StringUtils;
+
+import static org.apache.commons.lang.StringUtils.trim;
 
 public final class SettingFormatter {
   private SettingFormatter() {
@@ -29,4 +32,16 @@ public final class SettingFormatter {
   public static String fromJavaPropertyToEnvVariable(String property) {
     return property.toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_');
   }
+
+  /**
+   * Value is split and trimmed.
+   */
+  public static String[] getStringArrayBySeparator(String value, String separator) {
+    String[] strings = StringUtils.splitByWholeSeparator(value, separator);
+    String[] result = new String[strings.length];
+    for (int index = 0; index < strings.length; index++) {
+      result[index] = trim(strings[index]);
+    }
+    return result;
+  }
 }
index d9aed76edf9b6bfd791964cf3160426e5f78edcc..608e4c5ed56e624ea658fda44bf0d92216c8a98b 100644 (file)
@@ -30,4 +30,16 @@ public class SettingFormatterTest {
     String output = SettingFormatter.fromJavaPropertyToEnvVariable("some.randomProperty-123.test");
     assertThat(output).isEqualTo("SOME_RANDOMPROPERTY_123_TEST");
   }
+
+  @Test
+  public void test_getStringArrayBySeparator_on_input_with_separator() {
+    String[] result = SettingFormatter.getStringArrayBySeparator(" abc, DeF  , ghi", ",");
+    assertThat(result).containsExactly("abc", "DeF", "ghi");
+  }
+
+  @Test
+  public void test_getStringArrayBySeparator_on_input_without_separator() {
+    String[] result = SettingFormatter.getStringArrayBySeparator(" abc, DeF  , ghi", ";");
+    assertThat(result).containsExactly("abc, DeF  , ghi");
+  }
 }
index 764eef2812dccdb5ad495af5347412f5ad3f85a0..4ca59b06733f7863a1d18e6cdda6ea27da7b23ef 100644 (file)
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.Optional;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
 
 import static java.util.Collections.unmodifiableMap;
 import static java.util.Objects.requireNonNull;
@@ -42,7 +43,7 @@ public class MapSettings extends Settings {
   private final ConfigurationBridge configurationBridge;
 
   public MapSettings() {
-    this(new PropertyDefinitions());
+    this(new PropertyDefinitions(System2.INSTANCE));
   }
 
   public MapSettings(PropertyDefinitions definitions) {
index 89845b01dbb5a41aad8833791bf292d16a723886..6cf2c86c021b4da2612731c5f0a48943f8cddb0a 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.api.PropertyType;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
 
 import static java.util.Collections.singletonList;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
@@ -75,7 +76,7 @@ public class MapSettingsTest {
 
   @Before
   public void init_definitions() {
-    definitions = new PropertyDefinitions();
+    definitions = new PropertyDefinitions(System2.INSTANCE);
     definitions.addComponent(Init.class);
   }
 
@@ -129,7 +130,7 @@ public class MapSettingsTest {
   public void set_property_string_throws_NPE_if_key_is_null() {
     String key = randomAlphanumeric(3);
 
-    Settings underTest = new MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
+    Settings underTest = new MapSettings(new PropertyDefinitions(System2.INSTANCE, singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
 
     expectKeyNullNPE();
 
@@ -160,7 +161,7 @@ public class MapSettingsTest {
   public void set_property_string_array_trims_key() {
     String key = randomAlphanumeric(3);
 
-    Settings underTest = new MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
+    Settings underTest = new MapSettings(new PropertyDefinitions(System2.INSTANCE, singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
 
     Random random = new Random();
     String blankBefore = blank(random);
index f76de7ebae3703a29da6a201cdf0f2f845d4f2cb..2bc87e5451062d60060e229dc70b3f4f825196ef 100644 (file)
@@ -23,19 +23,23 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.Properties;
 import org.sonar.api.Property;
-import org.sonar.api.scanner.ScannerSide;
 import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.scanner.ScannerSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.AnnotationUtils;
+import org.sonar.api.utils.System2;
 
 import static java.util.Objects.requireNonNull;
+import static java.util.Optional.ofNullable;
 
 /**
  * Metadata of all the properties declared by plugins
@@ -48,17 +52,22 @@ import static java.util.Objects.requireNonNull;
 public final class PropertyDefinitions {
 
   private final Map<String, PropertyDefinition> definitions = new HashMap<>();
+  private final Map<String, String> propertyValueFromEnvironment = new HashMap<>();
   private final Map<String, Category> categories = new HashMap<>();
   private final Map<String, SubCategory> subcategories = new HashMap<>();
 
   // deprecated key -> new key
   private final Map<String, String> deprecatedKeys = new HashMap<>();
 
-  public PropertyDefinitions(Object... components) {
+  private final System2 system;
+
+  public PropertyDefinitions(System2 system, Object... components) {
+    this.system = system;
     addComponents(Arrays.asList(components));
   }
 
-  public PropertyDefinitions(Collection<PropertyDefinition> components) {
+  public PropertyDefinitions(System2 system, Collection<PropertyDefinition> components) {
+    this.system = system;
     addComponents(components);
   }
 
@@ -108,6 +117,8 @@ public final class PropertyDefinitions {
   private PropertyDefinitions add(PropertyDefinition definition, String defaultCategory) {
     if (!definitions.containsKey(definition.key())) {
       definitions.put(definition.key(), definition);
+      String envVar = definition.key().toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_');
+      ofNullable(system.envVariable(envVar)).ifPresent(value -> propertyValueFromEnvironment.put(definition.key(), value));
       String category = StringUtils.defaultIfBlank(definition.category(), defaultCategory);
       categories.put(definition.key(), new Category(category));
       String subcategory = StringUtils.defaultIfBlank(definition.subCategory(), category);
@@ -124,6 +135,14 @@ public final class PropertyDefinitions {
     return definitions.get(validKey(key));
   }
 
+  public Optional<String> getValueFromEnv(String key) {
+    return ofNullable(propertyValueFromEnvironment.get(key));
+  }
+
+  public Map<String, String> getAllPropertiesSetInEnv() {
+    return new HashMap<>(propertyValueFromEnvironment);
+  }
+
   public Collection<PropertyDefinition> getAll() {
     return definitions.values();
   }
index d7555cc37010284bfc1058adb389770846c33f32..fa915935f0f635a18d35f3d5064d477a27b62b33 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.api.config;
 
+import com.google.common.collect.ImmutableMap;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
@@ -30,9 +31,12 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.Properties;
 import org.sonar.api.Property;
 import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.utils.System2;
 
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class PropertyDefinitionsTest {
   @Rule
@@ -44,14 +48,14 @@ public class PropertyDefinitionsTest {
       PropertyDefinition.builder("foo").name("Foo").build(),
       PropertyDefinition.builder("one").name("One").build(),
       PropertyDefinition.builder("two").name("Two").defaultValue("2").build());
-    PropertyDefinitions def = new PropertyDefinitions(list);
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, list);
 
     assertProperties(def);
   }
 
   @Test
   public void should_inspect_plugin_objects() {
-    PropertyDefinitions def = new PropertyDefinitions(
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE,
       PropertyDefinition.builder("foo").name("Foo").build(),
       PropertyDefinition.builder("one").name("One").build(),
       PropertyDefinition.builder("two").name("Two").defaultValue("2").build());
@@ -61,21 +65,21 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void should_inspect_annotation_plugin_objects() {
-    PropertyDefinitions def = new PropertyDefinitions(new PluginWithProperty(), new PluginWithProperties());
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, new PluginWithProperty(), new PluginWithProperties());
 
     assertProperties(def);
   }
 
   @Test
   public void should_inspect_plugin_classes() {
-    PropertyDefinitions def = new PropertyDefinitions(PluginWithProperty.class, PluginWithProperties.class);
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, PluginWithProperty.class, PluginWithProperties.class);
 
     assertProperties(def);
   }
 
   @Test
   public void test_categories() {
-    PropertyDefinitions def = new PropertyDefinitions(
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE,
       PropertyDefinition.builder("inCateg").name("In Categ").category("categ").build(),
       PropertyDefinition.builder("noCateg").name("No categ").build());
 
@@ -85,7 +89,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void test_categories_on_annotation_plugin() {
-    PropertyDefinitions def = new PropertyDefinitions(Categories.class);
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, Categories.class);
 
     assertThat(def.getCategory("inCateg")).isEqualTo("categ");
     assertThat(def.getCategory("noCateg")).isEqualTo("");
@@ -93,7 +97,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void test_default_category() {
-    PropertyDefinitions def = new PropertyDefinitions();
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE);
     def.addComponent(PropertyDefinition.builder("inCateg").name("In Categ").category("categ").build(), "default");
     def.addComponent(PropertyDefinition.builder("noCateg").name("No categ").build(), "default");
 
@@ -103,7 +107,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void test_default_category_on_annotation_plugin() {
-    PropertyDefinitions def = new PropertyDefinitions();
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE);
     def.addComponent(Categories.class, "default");
     assertThat(def.getCategory("inCateg")).isEqualTo("categ");
     assertThat(def.getCategory("noCateg")).isEqualTo("default");
@@ -111,7 +115,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void should_return_special_categories() {
-    PropertyDefinitions def = new PropertyDefinitions();
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE);
 
     assertThat(def.propertiesByCategory(null).get(new Category("general")).keySet()).containsOnly(new SubCategory("email"));
     assertThat(def.propertiesByCategory(null).get(new Category("general")).keySet().iterator().next().isSpecial()).isTrue();
@@ -123,7 +127,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void should_group_by_category() {
-    PropertyDefinitions def = new PropertyDefinitions(
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE,
       PropertyDefinition.builder("global1").name("Global1").category("catGlobal1").build(),
       PropertyDefinition.builder("global2").name("Global2").category("catGlobal1").build(),
       PropertyDefinition.builder("global3").name("Global3").category("catGlobal2").build(),
@@ -142,7 +146,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void should_group_by_subcategory() {
-    PropertyDefinitions def = new PropertyDefinitions(
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE,
       PropertyDefinition.builder("global1").name("Global1").category("catGlobal1").subCategory("sub1").build(),
       PropertyDefinition.builder("global2").name("Global2").category("catGlobal1").subCategory("sub2").build(),
       PropertyDefinition.builder("global3").name("Global3").category("catGlobal1").build(),
@@ -155,7 +159,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void should_group_by_category_on_annotation_plugin() {
-    PropertyDefinitions def = new PropertyDefinitions(ByCategory.class);
+    PropertyDefinitions def = new PropertyDefinitions(System2.INSTANCE, ByCategory.class);
 
     assertThat(def.propertiesByCategory(null).keySet()).contains(new Category("catglobal1"), new Category("catglobal2"));
     assertThat(def.propertiesByCategory(Qualifiers.PROJECT).keySet()).containsOnly(new Category("catproject"));
@@ -176,7 +180,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void validKey_throws_NPE_if_key_is_null() {
-    PropertyDefinitions underTest = new PropertyDefinitions();
+    PropertyDefinitions underTest = new PropertyDefinitions(System2.INSTANCE);
 
     expectedException.expect(NullPointerException.class);
     expectedException.expectMessage("key can't be null");
@@ -186,7 +190,7 @@ public class PropertyDefinitionsTest {
 
   @Test
   public void get_throws_NPE_if_key_is_null() {
-    PropertyDefinitions underTest = new PropertyDefinitions();
+    PropertyDefinitions underTest = new PropertyDefinitions(System2.INSTANCE);
 
     expectedException.expect(NullPointerException.class);
     expectedException.expectMessage("key can't be null");
@@ -199,15 +203,15 @@ public class PropertyDefinitionsTest {
     Random random = new Random();
     String key = RandomStringUtils.randomAlphanumeric(4);
     String deprecatedKey = RandomStringUtils.randomAlphanumeric(4);
-    PropertyDefinitions underTest = new PropertyDefinitions(singletonList(
+    PropertyDefinitions underTest = new PropertyDefinitions(System2.INSTANCE, singletonList(
       PropertyDefinition.builder(key)
         .deprecatedKey(deprecatedKey)
         .build()));
 
     String untrimmedKey = blank(random) + deprecatedKey + blank(random);
     assertThat(underTest.get(untrimmedKey).key())
-        .describedAs("expecting key %s being returned for get(%s)", key, untrimmedKey)
-        .isEqualTo(key);
+      .describedAs("expecting key %s being returned for get(%s)", key, untrimmedKey)
+      .isEqualTo(key);
   }
 
   private static String blank(Random random) {
@@ -216,6 +220,33 @@ public class PropertyDefinitionsTest {
     return b.toString();
   }
 
+  @Test
+  public void get_value_from_env() {
+    System2 system = mock(System2.class);
+    when(system.envVariable("FOO")).thenReturn("777");
+    when(system.envVariable("ONE")).thenReturn("888");
+    when(system.envVariable("SOME_COMPLETELY_RANDOM_ENV_VAR")).thenReturn("999");
+
+    PropertyDefinitions underTest = new PropertyDefinitions(system, new PluginWithProperty(), new PluginWithProperties());
+
+    assertThat(underTest.getValueFromEnv("foo")).hasValue("777");
+    assertThat(underTest.getValueFromEnv("one")).hasValue("888");
+    assertThat(underTest.getValueFromEnv("two")).isEmpty();
+    assertThat(underTest.getValueFromEnv("some.unrecognizable.prop")).isEmpty();
+  }
+
+  @Test
+  public void get_all_properties_set_in_env() {
+    System2 system = mock(System2.class);
+    when(system.envVariable("FOO")).thenReturn("777");
+    when(system.envVariable("ONE")).thenReturn("888");
+    when(system.envVariable("SOME_COMPLETELY_RANDOM_ENV_VAR")).thenReturn("999");
+
+    PropertyDefinitions underTest = new PropertyDefinitions(system, new PluginWithProperty(), new PluginWithProperties());
+
+    assertThat(underTest.getAllPropertiesSetInEnv()).containsExactlyInAnyOrderEntriesOf(ImmutableMap.of("foo", "777", "one", "888"));
+  }
+
   @Property(key = "foo", name = "Foo")
   static final class PluginWithProperty {
   }
index 1ec4a238abb63ef46d9b0f29df05d980d44dc7e9..2b57667e5014ca0aa0a32cf8e4098a5bae4cc632 100644 (file)
@@ -26,6 +26,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.LogTester;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -34,7 +35,6 @@ import static org.mockito.Mockito.when;
 
 public class GlobalConfigurationProviderTest {
 
-  public static final String SOME_VALUE = "some_value";
   @Rule
   public ExpectedException thrown = ExpectedException.none();
   @Rule
@@ -53,7 +53,7 @@ public class GlobalConfigurationProviderTest {
   public void should_load_global_settings() {
     when(globalServerSettings.properties()).thenReturn(ImmutableMap.of("sonar.cpd.cross", "true"));
 
-    GlobalConfiguration globalConfig = new GlobalConfigurationProvider().provide(globalServerSettings, scannerProps, new PropertyDefinitions());
+    GlobalConfiguration globalConfig = new GlobalConfigurationProvider().provide(globalServerSettings, scannerProps, new PropertyDefinitions(System2.INSTANCE));
 
     assertThat(globalConfig.get("sonar.cpd.cross")).hasValue("true");
   }
index 1646722b2ced31005f478c8b9c60abe7c7f7abf2..c840607ff7be422ba3fd5e423b799defc43b6eef 100644 (file)
@@ -24,13 +24,15 @@ import java.util.Arrays;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.Encryption;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.PropertyFieldDefinition;
+import org.sonar.api.config.internal.Encryption;
+import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
 
+import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
 
@@ -41,7 +43,7 @@ public class DefaultConfigurationTest {
 
   @Test
   public void accessingMultiValuedPropertiesShouldBeConsistentWithDeclaration() {
-    Configuration config = new DefaultConfiguration(new PropertyDefinitions(Arrays.asList(
+    Configuration config = new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, Arrays.asList(
       PropertyDefinition.builder("single").multiValues(false).build(),
       PropertyDefinition.builder("multiA").multiValues(true).build())), new Encryption(null),
       ImmutableMap.of("single", "foo", "multiA", "a,b", "notDeclared", "c,d")) {
@@ -68,7 +70,7 @@ public class DefaultConfigurationTest {
 
   @Test
   public void accessingPropertySetPropertiesShouldBeConsistentWithDeclaration() {
-    Configuration config = new DefaultConfiguration(new PropertyDefinitions(Arrays.asList(
+    Configuration config = new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, Arrays.asList(
       PropertyDefinition.builder("props").fields(PropertyFieldDefinition.build("foo1").name("Foo1").build(), PropertyFieldDefinition.build("foo2").name("Foo2").build()).build())),
       new Encryption(null),
       ImmutableMap.of("props", "1,2", "props.1.foo1", "a", "props.1.foo2", "b")) {
@@ -87,7 +89,7 @@ public class DefaultConfigurationTest {
 
   @Test
   public void getDefaultValues() {
-    Configuration config = new DefaultConfiguration(new PropertyDefinitions(Arrays.asList(
+    Configuration config = new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, Arrays.asList(
       PropertyDefinition.builder("single").multiValues(false).defaultValue("default").build(),
       PropertyDefinition.builder("multiA").multiValues(true).defaultValue("foo,bar").build())), new Encryption(null),
       ImmutableMap.of()) {
@@ -114,7 +116,7 @@ public class DefaultConfigurationTest {
     assertThat(getStringArray("a\n,b\n")).containsExactly("a", "b");
     assertThat(getStringArray("a\n,b\n,\"\"")).containsExactly("a", "b", "");
     assertThat(getStringArray("a\n,  \"  \"  ,b\n")).containsExactly("a", "  ", "b");
-    assertThat(getStringArray("  \" , ,, \", a\n,b\n")).containsExactly(" , ,, ", "a","b");
+    assertThat(getStringArray("  \" , ,, \", a\n,b\n")).containsExactly(" , ,, ", "a", "b");
     assertThat(getStringArray("a\n,,b\n")).containsExactly("a", "b");
     assertThat(getStringArray("a,\n\nb,c")).containsExactly("a", "b", "c");
     assertThat(getStringArray("a,b\n\nc,d")).containsExactly("a", "b\nc", "d");
@@ -127,7 +129,7 @@ public class DefaultConfigurationTest {
   }
 
   private String[] getStringArray(String value) {
-    return new DefaultConfiguration(new PropertyDefinitions(Arrays.asList(
+    return new DefaultConfiguration(new PropertyDefinitions(System2.INSTANCE, singletonList(
       PropertyDefinition.builder("multi").multiValues(true).build())), new Encryption(null),
       ImmutableMap.of("multi", value)) {
     }.getStringArray("multi");
index 4fde4372d755b076a40bec6318442a8df255f18b..a8073090a3352cf0cf65801f9cee885799375a14 100644 (file)
@@ -24,8 +24,9 @@ import java.util.Map;
 import java.util.Set;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonar.api.config.internal.Encryption;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
+import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.scanner.config.DefaultConfiguration;
 import org.sonar.scanner.scan.ProjectConfiguration;
@@ -41,7 +42,7 @@ public class GenericCoverageSensorTest {
   public void loadAllReportPaths() {
     Map<String, String> settings = new HashMap<>();
     settings.put(GenericCoverageSensor.REPORT_PATHS_PROPERTY_KEY, "report.xml,report2.xml");
-    PropertyDefinitions defs = new PropertyDefinitions(GenericCoverageSensor.properties());
+    PropertyDefinitions defs = new PropertyDefinitions(System2.INSTANCE, GenericCoverageSensor.properties());
     DefaultConfiguration config = new ProjectConfiguration(defs, new Encryption(null), settings);
 
     Set<String> reportPaths = new GenericCoverageSensor(config).loadReportPaths();
index c5e9427f88d7f27cd4c8297777a0cc377ec7c023..ed4802bc32143934bdb7ddc559df2ed93dde53de 100644 (file)
@@ -28,14 +28,15 @@ import org.apache.commons.io.FileUtils;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.Encryption;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
+import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.scanner.config.DefaultConfiguration;
 import org.sonar.scanner.deprecated.test.TestPlanBuilder;
 import org.sonar.scanner.scan.ProjectConfiguration;
-import org.sonar.api.batch.sensor.internal.SensorContextTester;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -57,7 +58,7 @@ public class GenericTestExecutionSensorTest {
 
     Map<String, String> settings = new HashMap<>();
     settings.put(GenericTestExecutionSensor.OLD_UNIT_TEST_REPORT_PATHS_PROPERTY_KEY, "report.xml");
-    PropertyDefinitions defs = new PropertyDefinitions(GenericTestExecutionSensor.properties());
+    PropertyDefinitions defs = new PropertyDefinitions(System2.INSTANCE, GenericTestExecutionSensor.properties());
     DefaultConfiguration config = new ProjectConfiguration(defs, new Encryption(null), settings);
 
     new GenericTestExecutionSensor(mock(TestPlanBuilder.class), config).execute(context);
index d29ffe745f796ea468d39945b764119603f14435..cbb6acfb10911e60fe9c73dba2430579824a0655 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Test;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.System2;
 import org.sonar.core.config.IssueExclusionProperties;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -34,7 +35,7 @@ public class IssueExclusionPatternInitializerTest {
 
   @Before
   public void init() {
-    settings = new MapSettings(new PropertyDefinitions(IssueExclusionProperties.all()));
+    settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, IssueExclusionProperties.all()));
   }
 
   @Test
index 5055af6b15d97bb4765a77db559a194615c42fce..4d1d6bb3387650ab02bcd75b22640566385780f0 100644 (file)
@@ -23,6 +23,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
 import org.sonar.core.config.IssueExclusionProperties;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -34,7 +35,7 @@ public class IssueInclusionPatternInitializerTest {
 
   @Before
   public void init() {
-    settings = new MapSettings(new PropertyDefinitions(IssueExclusionProperties.all()));
+    settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, IssueExclusionProperties.all()));
     patternsInitializer = new IssueInclusionPatternInitializer(settings.asConfig());
   }