From: Julien Lancelot Date: Wed, 16 Apr 2014 17:05:09 +0000 (+0200) Subject: Replacement injection of ServletContext by Properties in Platform X-Git-Tag: 4.4-RC1~1445^2~18 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8ea5c540ef2c1c9e22e06b717758a0d2dcb647a5;p=sonarqube.git Replacement injection of ServletContext by Properties in Platform --- diff --git a/sonar-application/pom.xml b/sonar-application/pom.xml index 3f6a630951b..34c0f89f99a 100644 --- a/sonar-application/pom.xml +++ b/sonar-application/pom.xml @@ -16,15 +16,27 @@ Package the standalone distribution + + commons-codec + commons-codec + commons-io commons-io + + commons-lang + commons-lang + com.google.code.findbugs jsr305 provided + + com.google.guava + guava + org.slf4j slf4j-api @@ -201,12 +213,6 @@ http-request test - - com.google.guava - guava - test - - diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties index 6c058aa3227..65954622bb9 100644 --- a/sonar-application/src/main/assembly/conf/sonar.properties +++ b/sonar-application/src/main/assembly/conf/sonar.properties @@ -82,7 +82,7 @@ sonar.jdbc.timeBetweenEvictionRunsMillis=30000 # Web context. When set, it must start with forward slash (for example /sonarqube). # The default value is root context (empty value). -#sonar.web.context= +#sonar.web.context=/ # TCP port for incoming HTTP connections. Disabled when value is -1. #sonar.web.port=9000 diff --git a/sonar-application/src/main/java/org/sonar/application/AesCipher.java b/sonar-application/src/main/java/org/sonar/application/AesCipher.java new file mode 100644 index 00000000000..d006146a7e6 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/AesCipher.java @@ -0,0 +1,138 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.application; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Throwables; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; + +import javax.annotation.Nullable; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import java.io.File; +import java.io.IOException; +import java.security.Key; +import java.security.SecureRandom; + +final class AesCipher extends Cipher { + + // Can't be increased because of Java 6 policy files : + // https://confluence.terena.org/display/~visser/No+256+bit+ciphers+for+Java+apps + // http://java.sun.com/javase/6/webnotes/install/jre/README + public static final int KEY_SIZE_IN_BITS = 128; + + private static final String CRYPTO_KEY = "AES"; + + /** + * Duplication from CoreProperties.ENCRYPTION_SECRET_KEY_PATH + */ + private static final String ENCRYPTION_SECRET_KEY_PATH = "sonar.secretKeyPath"; + + private String pathToSecretKey; + + AesCipher(@Nullable String pathToSecretKey) { + this.pathToSecretKey = pathToSecretKey; + } + + @Override + String encrypt(String clearText) { + try { + javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CRYPTO_KEY); + cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, loadSecretFile()); + return new String(Base64.encodeBase64(cipher.doFinal(clearText.getBytes("UTF-8")))); + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + @Override + String decrypt(String encryptedText) { + try { + javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CRYPTO_KEY); + cipher.init(javax.crypto.Cipher.DECRYPT_MODE, loadSecretFile()); + byte[] cipherData = cipher.doFinal(Base64.decodeBase64(StringUtils.trim(encryptedText))); + return new String(cipherData); + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + /** + * This method checks the existence of the file, but not the validity of the contained key. + */ + boolean hasSecretKey() { + String path = getPathToSecretKey(); + if (StringUtils.isNotBlank(path)) { + File file = new File(path); + return file.exists() && file.isFile(); + } + return false; + } + + private Key loadSecretFile() throws IOException { + String path = getPathToSecretKey(); + return loadSecretFileFromFile(path); + } + + @VisibleForTesting + Key loadSecretFileFromFile(@Nullable String path) throws IOException { + if (StringUtils.isBlank(path)) { + throw new IllegalStateException("Secret key not found. Please set the property " + ENCRYPTION_SECRET_KEY_PATH); + } + File file = new File(path); + if (!file.exists() || !file.isFile()) { + throw new IllegalStateException("The property " + ENCRYPTION_SECRET_KEY_PATH + " does not link to a valid file: " + path); + } + String s = FileUtils.readFileToString(file); + if (StringUtils.isBlank(s)) { + throw new IllegalStateException("No secret key in the file: " + path); + } + return new SecretKeySpec(Base64.decodeBase64(StringUtils.trim(s)), CRYPTO_KEY); + } + + String generateRandomSecretKey() { + try { + KeyGenerator keyGen = KeyGenerator.getInstance(CRYPTO_KEY); + keyGen.init(KEY_SIZE_IN_BITS, new SecureRandom()); + SecretKey secretKey = keyGen.generateKey(); + return new String(Base64.encodeBase64(secretKey.getEncoded())); + + } catch (Exception e) { + throw new IllegalStateException("Fail to generate secret key", e); + } + } + + @VisibleForTesting + String getPathToSecretKey() { + if (StringUtils.isBlank(pathToSecretKey)) { + pathToSecretKey = new File(FileUtils.getUserDirectoryPath(), ".sonar/sonar-secret.txt").getPath(); + } + return pathToSecretKey; + } + + public void setPathToSecretKey(@Nullable String pathToSecretKey) { + this.pathToSecretKey = pathToSecretKey; + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/Base64Cipher.java b/sonar-application/src/main/java/org/sonar/application/Base64Cipher.java new file mode 100644 index 00000000000..5abbeb85ac2 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Base64Cipher.java @@ -0,0 +1,35 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.application; + +import org.apache.commons.codec.binary.Base64; + +final class Base64Cipher extends Cipher { + @Override + String encrypt(String clearText) { + return new String(Base64.encodeBase64(clearText.getBytes())); + } + + @Override + String decrypt(String encryptedText) { + return new String(Base64.decodeBase64(encryptedText)); + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/Cipher.java b/sonar-application/src/main/java/org/sonar/application/Cipher.java new file mode 100644 index 00000000000..44abfbb3176 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Cipher.java @@ -0,0 +1,26 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.application; + +abstract class Cipher { + abstract String encrypt(String clearText); + abstract String decrypt(String encryptedText); +} diff --git a/sonar-application/src/main/java/org/sonar/application/ConfigurationUtils.java b/sonar-application/src/main/java/org/sonar/application/ConfigurationUtils.java new file mode 100644 index 00000000000..a5a563a168c --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/ConfigurationUtils.java @@ -0,0 +1,49 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.application; + +import org.apache.commons.lang.text.StrSubstitutor; + +import java.util.Enumeration; +import java.util.Map; +import java.util.Properties; + +public final class ConfigurationUtils { + + private ConfigurationUtils() { + // Utility class + } + + static Properties interpolateEnvVariables(Properties properties) { + return interpolateVariables(properties, System.getenv()); + } + + static Properties interpolateVariables(Properties properties, Map variables) { + Properties result = new Properties(); + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + String value = (String) properties.get(key); + String interpolatedValue = StrSubstitutor.replace(value, variables, "${env:", "}"); + result.setProperty(key, interpolatedValue); + } + return result; + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java b/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java index ddb1efad898..a677f8bcf11 100644 --- a/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java +++ b/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java @@ -65,6 +65,7 @@ class EmbeddedTomcat { tomcat.getHost().setDeployOnStartup(true); Props props = Props.create(env); + Logging.configure(tomcat, env, props); Connectors.configure(tomcat, props); Webapp.configure(tomcat, env, props); diff --git a/sonar-application/src/main/java/org/sonar/application/Encryption.java b/sonar-application/src/main/java/org/sonar/application/Encryption.java new file mode 100644 index 00000000000..60e732fc716 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Encryption.java @@ -0,0 +1,66 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.application; + +import com.google.common.collect.ImmutableMap; + +import javax.annotation.Nullable; + +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @since 3.0 + */ +public final class Encryption { + + private static final String BASE64_ALGORITHM = "b64"; + + private static final String AES_ALGORITHM = "aes"; + private final AesCipher aesCipher; + + private final Map ciphers; + private static final Pattern ENCRYPTED_PATTERN = Pattern.compile("\\{(.*?)\\}(.*)"); + + public Encryption(@Nullable String pathToSecretKey) { + aesCipher = new AesCipher(pathToSecretKey); + ciphers = ImmutableMap.of( + BASE64_ALGORITHM, new Base64Cipher(), + AES_ALGORITHM, aesCipher); + } + public boolean isEncrypted(String value) { + return value.indexOf('{') == 0 && value.indexOf('}') > 1; + } + + public String decrypt(String encryptedText) { + Matcher matcher = ENCRYPTED_PATTERN.matcher(encryptedText); + if (matcher.matches()) { + Cipher cipher = ciphers.get(matcher.group(1).toLowerCase(Locale.ENGLISH)); + if (cipher != null) { + return cipher.decrypt(matcher.group(2)); + } + } + return encryptedText; + } + +} diff --git a/sonar-application/src/main/java/org/sonar/application/Props.java b/sonar-application/src/main/java/org/sonar/application/Props.java index 7b33d918cc6..51a6cdfe49e 100644 --- a/sonar-application/src/main/java/org/sonar/application/Props.java +++ b/sonar-application/src/main/java/org/sonar/application/Props.java @@ -22,16 +22,14 @@ package org.sonar.application; import org.apache.commons.io.IOUtils; import javax.annotation.Nullable; + import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; -import java.io.IOException; +import java.util.Map; import java.util.Properties; -/** - * TODO support env substitution and encryption - */ class Props { + private final Properties props; Props(Properties props) { @@ -80,8 +78,18 @@ class Props { FileReader reader = null; try { reader = new FileReader(propsFile); + + // order is important : the last override the first p.load(reader); + p.putAll(System.getenv()); p.putAll(System.getProperties()); + + p = ConfigurationUtils.interpolateEnvVariables(p); + p = decrypt(p); + + // Set all properties as system properties to pass them to PlatformServletContextListener + System.setProperties(p); + return new Props(p); } catch (Exception e) { @@ -91,4 +99,19 @@ class Props { IOUtils.closeQuietly(reader); } } + + static Properties decrypt(Properties properties) { + Encryption encryption = new Encryption(null); + Properties result = new Properties(); + + for (Map.Entry entry : properties.entrySet()) { + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (encryption.isEncrypted(value)) { + value = encryption.decrypt(value); + } + result.setProperty(key, value); + } + return result; + } } diff --git a/sonar-application/src/test/java/org/sonar/application/AesCipherTest.java b/sonar-application/src/test/java/org/sonar/application/AesCipherTest.java new file mode 100644 index 00000000000..9f097093105 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/AesCipherTest.java @@ -0,0 +1,186 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.application; + +import com.google.common.io.Resources; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import javax.crypto.BadPaddingException; + +import java.io.File; +import java.security.InvalidKeyException; +import java.security.Key; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + + +public class AesCipherTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void generateRandomSecretKey() { + AesCipher cipher = new AesCipher(null); + + String key = cipher.generateRandomSecretKey(); + + assertThat(StringUtils.isNotBlank(key)).isTrue(); + assertThat(Base64.isArrayByteBase64(key.getBytes())).isTrue(); + } + + @Test + public void encrypt() throws Exception { + AesCipher cipher = new AesCipher(pathToSecretKey()); + + String encryptedText = cipher.encrypt("this is a secret"); + + assertThat(StringUtils.isNotBlank(encryptedText)).isTrue(); + assertThat(Base64.isArrayByteBase64(encryptedText.getBytes())).isTrue(); + } + + @Test + public void encrypt_bad_key() throws Exception { + thrown.expect(RuntimeException.class); + thrown.expectMessage("Invalid AES key"); + + AesCipher cipher = new AesCipher(getPath("bad_secret_key.txt")); + + cipher.encrypt("this is a secret"); + } + + @Test + public void decrypt() throws Exception { + AesCipher cipher = new AesCipher(pathToSecretKey()); + + // the following value has been encrypted with the key /org/sonar/api/config/AesCipherTest/aes_secret_key.txt + String clearText = cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY="); + + assertThat(clearText).isEqualTo("this is a secret"); + } + + @Test + public void decrypt_bad_key() throws Exception { + AesCipher cipher = new AesCipher(getPath("bad_secret_key.txt")); + + try { + cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY="); + fail(); + + } catch (RuntimeException e) { + assertThat(e.getCause()).isInstanceOf(InvalidKeyException.class); + } + } + + @Test + public void decrypt_other_key() throws Exception { + AesCipher cipher = new AesCipher(getPath("other_secret_key.txt")); + + try { + // text encrypted with another key + cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY="); + fail(); + + } catch (RuntimeException e) { + assertThat(e.getCause()).isInstanceOf(BadPaddingException.class); + } + } + + @Test + public void encryptThenDecrypt() throws Exception { + AesCipher cipher = new AesCipher(pathToSecretKey()); + + assertThat(cipher.decrypt(cipher.encrypt("foo"))).isEqualTo("foo"); + } + + @Test + public void testDefaultPathToSecretKey() { + AesCipher cipher = new AesCipher(null); + + String path = cipher.getPathToSecretKey(); + + assertThat(StringUtils.isNotBlank(path)).isTrue(); + assertThat(new File(path).getName()).isEqualTo("sonar-secret.txt"); + } + + @Test + public void loadSecretKeyFromFile() throws Exception { + AesCipher cipher = new AesCipher(null); + Key secretKey = cipher.loadSecretFileFromFile(pathToSecretKey()); + assertThat(secretKey.getAlgorithm()).isEqualTo("AES"); + assertThat(secretKey.getEncoded().length).isGreaterThan(10); + } + + @Test + public void loadSecretKeyFromFile_trim_content() throws Exception { + String path = getPath("non_trimmed_secret_key.txt"); + AesCipher cipher = new AesCipher(null); + + Key secretKey = cipher.loadSecretFileFromFile(path); + + assertThat(secretKey.getAlgorithm()).isEqualTo("AES"); + assertThat(secretKey.getEncoded().length).isGreaterThan(10); + } + + @Test + public void loadSecretKeyFromFile_file_does_not_exist() throws Exception { + thrown.expect(IllegalStateException.class); + + AesCipher cipher = new AesCipher(null); + cipher.loadSecretFileFromFile("/file/does/not/exist"); + } + + @Test + public void loadSecretKeyFromFile_no_property() throws Exception { + thrown.expect(IllegalStateException.class); + + AesCipher cipher = new AesCipher(null); + cipher.loadSecretFileFromFile(null); + } + + @Test + public void hasSecretKey() throws Exception { + AesCipher cipher = new AesCipher(pathToSecretKey()); + + assertThat(cipher.hasSecretKey()).isTrue(); + } + + @Test + public void doesNotHaveSecretKey() throws Exception { + AesCipher cipher = new AesCipher("/my/twitter/id/is/SimonBrandhof"); + + assertThat(cipher.hasSecretKey()).isFalse(); + } + + private static String getPath(String file){ + return Resources.getResource(AesCipherTest.class, "AesCipherTest/" + file).getPath(); + } + + private static String pathToSecretKey() throws Exception { + return getPath("aes_secret_key.txt"); + } + +} diff --git a/sonar-application/src/test/java/org/sonar/application/ConfigurationUtilsTest.java b/sonar-application/src/test/java/org/sonar/application/ConfigurationUtilsTest.java new file mode 100644 index 00000000000..29a722b9fad --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/ConfigurationUtilsTest.java @@ -0,0 +1,55 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.application; + +import com.google.common.collect.Maps; +import org.junit.Test; + +import java.util.Map; +import java.util.Properties; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class ConfigurationUtilsTest { + @Test + public void shouldInterpolateVariables() { + Properties input = new Properties(); + input.setProperty("hello", "world"); + input.setProperty("url", "${env:SONAR_JDBC_URL}"); + input.setProperty("do_not_change", "${SONAR_JDBC_URL}"); + Map variables = Maps.newHashMap(); + variables.put("SONAR_JDBC_URL", "jdbc:h2:mem"); + + Properties output = ConfigurationUtils.interpolateVariables(input, variables); + + assertThat(output.size(), is(3)); + assertThat(output.getProperty("hello"), is("world")); + assertThat(output.getProperty("url"), is("jdbc:h2:mem")); + assertThat(output.getProperty("do_not_change"), is("${SONAR_JDBC_URL}")); + + // input is not changed + assertThat(input.size(), is(3)); + assertThat(input.getProperty("hello"), is("world")); + assertThat(input.getProperty("url"), is("${env:SONAR_JDBC_URL}")); + assertThat(input.getProperty("do_not_change"), is("${SONAR_JDBC_URL}")); + } + +} diff --git a/sonar-application/src/test/java/org/sonar/application/EncryptionTest.java b/sonar-application/src/test/java/org/sonar/application/EncryptionTest.java new file mode 100644 index 00000000000..85b3c568a35 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/EncryptionTest.java @@ -0,0 +1,59 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.application; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class EncryptionTest { + + @Test + public void isEncrypted() { + Encryption encryption = new Encryption(null); + assertThat(encryption.isEncrypted("{aes}ADASDASAD"), is(true)); + assertThat(encryption.isEncrypted("{b64}ADASDASAD"), is(true)); + assertThat(encryption.isEncrypted("{abc}ADASDASAD"), is(true)); + + assertThat(encryption.isEncrypted("{}"), is(false)); + assertThat(encryption.isEncrypted("{foo"), is(false)); + assertThat(encryption.isEncrypted("foo{aes}"), is(false)); + } + + @Test + public void decrypt() { + Encryption encryption = new Encryption(null); + assertThat(encryption.decrypt("{b64}Zm9v"), is("foo")); + } + + @Test + public void decrypt_unknown_algorithm() { + Encryption encryption = new Encryption(null); + assertThat(encryption.decrypt("{xxx}Zm9v"), is("{xxx}Zm9v")); + } + + @Test + public void decrypt_uncrypted_text() { + Encryption encryption = new Encryption(null); + assertThat(encryption.decrypt("foo"), is("foo")); + } +} diff --git a/sonar-application/src/test/java/org/sonar/application/PropsTest.java b/sonar-application/src/test/java/org/sonar/application/PropsTest.java index 92091740301..46ca5e8dd26 100644 --- a/sonar-application/src/test/java/org/sonar/application/PropsTest.java +++ b/sonar-application/src/test/java/org/sonar/application/PropsTest.java @@ -19,6 +19,7 @@ */ package org.sonar.application; +import com.google.common.io.Resources; import org.apache.commons.io.FilenameUtils; import org.junit.Test; @@ -31,6 +32,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class PropsTest { + @Test public void of() throws Exception { Properties p = new Properties(); @@ -99,8 +101,10 @@ public class PropsTest { @Test public void load_file_and_system_properties() throws Exception { + System.setProperty("hello", "bar"); + Env env = mock(Env.class); - File propsFile = new File(getClass().getResource("/org/sonar/application/PropsTest/sonar.properties").toURI()); + File propsFile = new File(Resources.getResource(getClass(), "PropsTest/sonar.properties").getFile()); when(env.file("conf/sonar.properties")).thenReturn(propsFile); Props props = Props.create(env); @@ -109,7 +113,11 @@ public class PropsTest { assertThat(props.of("java.version")).isNotNull(); // system properties override file properties + assertThat(props.of("hello")).isEqualTo("bar"); assertThat(props.of("java.io.tmpdir")).isNotEmpty().isNotEqualTo("/should/be/overridden"); + + assertThat(System.getProperty("foo")).isEqualTo("bar"); + assertThat(System.getProperty("hello")).isEqualTo("bar"); } @Test diff --git a/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/aes_secret_key.txt b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/aes_secret_key.txt new file mode 100644 index 00000000000..65b98c522da --- /dev/null +++ b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/aes_secret_key.txt @@ -0,0 +1 @@ +0PZz+G+f8mjr3sPn4+AhHg== \ No newline at end of file diff --git a/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/bad_secret_key.txt b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/bad_secret_key.txt new file mode 100644 index 00000000000..b33e179e5c8 --- /dev/null +++ b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/bad_secret_key.txt @@ -0,0 +1 @@ +badbadbad== \ No newline at end of file diff --git a/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/non_trimmed_secret_key.txt b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/non_trimmed_secret_key.txt new file mode 100644 index 00000000000..ab83e4adc03 --- /dev/null +++ b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/non_trimmed_secret_key.txt @@ -0,0 +1,3 @@ + + 0PZz+G+f8mjr3sPn4+AhHg== + diff --git a/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/other_secret_key.txt b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/other_secret_key.txt new file mode 100644 index 00000000000..23f5ecf5104 --- /dev/null +++ b/sonar-application/src/test/resources/org/sonar/application/AesCipherTest/other_secret_key.txt @@ -0,0 +1 @@ +IBxEUxZ41c8XTxyaah1Qlg== \ No newline at end of file diff --git a/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties b/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties index b73be15411b..5c06e58a32e 100644 --- a/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties +++ b/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties @@ -1,2 +1,3 @@ +hello: world foo=bar java.io.tmpdir=/should/be/overridden diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerMetadata.java index cf664e315df..01d2b5915c1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerMetadata.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerMetadata.java @@ -27,6 +27,7 @@ import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; +import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; @@ -69,6 +70,21 @@ public class ServerMetadata extends Server implements BatchComponent { return null; } + @Override + public File getRootDir() { + return null; + } + + @Override + public File getDeployDir() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + @Override public String getURL() { return client.getURL(); diff --git a/sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java b/sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java deleted file mode 100644 index d3875f78846..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.core.config; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.text.StrSubstitutor; - -import javax.annotation.WillClose; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.Map; -import java.util.Properties; - -/** - * @since 2.12 - */ -public final class ConfigurationUtils { - - private ConfigurationUtils() { - } - - public static void copyProperties(Properties from, Map to) { - for (Map.Entry entry : from.entrySet()) { - String key = (String) entry.getKey(); - to.put(key, entry.getValue().toString()); - } - } - - public static Properties openProperties(File file) throws IOException { - FileInputStream input = FileUtils.openInputStream(file); - return readInputStream(input); - } - - /** - * Note that the input stream is closed in this method. - */ - public static Properties readInputStream(@WillClose InputStream input) throws IOException { - try { - Properties p = new Properties(); - p.load(input); - return p; - - } finally { - IOUtils.closeQuietly(input); - } - } - - public static Properties interpolateEnvVariables(Properties properties) { - return interpolateVariables(properties, System.getenv()); - } - - public static Properties interpolateVariables(Properties properties, Map variables) { - Properties result = new Properties(); - Enumeration keys = properties.keys(); - while (keys.hasMoreElements()) { - String key = (String) keys.nextElement(); - String value = (String) properties.get(key); - String interpolatedValue = StrSubstitutor.replace(value, variables, "${env:", "}"); - result.setProperty(key, interpolatedValue); - } - return result; - } -} diff --git a/sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java deleted file mode 100644 index 92452b2338e..00000000000 --- a/sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.core.config; - -import com.google.common.collect.Maps; -import org.junit.Test; - -import java.util.Map; -import java.util.Properties; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -public class ConfigurationUtilsTest { - @Test - public void shouldInterpolateVariables() { - Properties input = new Properties(); - input.setProperty("hello", "world"); - input.setProperty("url", "${env:SONAR_JDBC_URL}"); - input.setProperty("do_not_change", "${SONAR_JDBC_URL}"); - Map variables = Maps.newHashMap(); - variables.put("SONAR_JDBC_URL", "jdbc:h2:mem"); - - Properties output = ConfigurationUtils.interpolateVariables(input, variables); - - assertThat(output.size(), is(3)); - assertThat(output.getProperty("hello"), is("world")); - assertThat(output.getProperty("url"), is("jdbc:h2:mem")); - assertThat(output.getProperty("do_not_change"), is("${SONAR_JDBC_URL}")); - - // input is not changed - assertThat(input.size(), is(3)); - assertThat(input.getProperty("hello"), is("world")); - assertThat(input.getProperty("url"), is("${env:SONAR_JDBC_URL}")); - assertThat(input.getProperty("do_not_change"), is("${SONAR_JDBC_URL}")); - } - - @Test - public void shouldCopyProperties() { - Properties input = new Properties(); - input.setProperty("hello", "world"); - input.setProperty("foo", "bar"); - Map output = Maps.newHashMap(); - - ConfigurationUtils.copyProperties(input, output); - - assertThat(output.size(), is(2)); - assertThat(output.get("hello"), is("world")); - assertThat(output.get("foo"), is("bar")); - - // input is not changed - assertThat(input.size(), is(2)); - assertThat(input.getProperty("hello"), is("world")); - assertThat(input.getProperty("foo"), is("bar")); - } -} diff --git a/sonar-plugin-api/pom.xml b/sonar-plugin-api/pom.xml index 74f16c9a01e..2cd8b5bea82 100644 --- a/sonar-plugin-api/pom.xml +++ b/sonar-plugin-api/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -191,6 +192,14 @@ + + + + + src/main/resources + true + + diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java index d6c39401c2d..7fd8afd1b1e 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java @@ -22,6 +22,7 @@ package org.sonar.api.platform; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; +import java.io.File; import java.util.Date; /** @@ -35,6 +36,12 @@ public abstract class Server implements BatchComponent, ServerComponent { public abstract Date getStartedAt(); + public abstract File getRootDir(); + + public abstract File getDeployDir(); + + public abstract String getContextPath(); + /** * @return the server URL when executed from batch, else null. * @since 2.4 diff --git a/sonar-plugin-api/src/main/resources/sq-version.txt b/sonar-plugin-api/src/main/resources/sq-version.txt new file mode 100644 index 00000000000..ad96e7cf933 --- /dev/null +++ b/sonar-plugin-api/src/main/resources/sq-version.txt @@ -0,0 +1 @@ +${project.version} diff --git a/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java b/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java index 473fbd0e8f8..cf7a2d6ac0f 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java @@ -21,12 +21,12 @@ package org.sonar.server.platform; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.FileFilterUtils; -import org.apache.commons.lang.StringUtils; import org.picocontainer.Startable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; +import org.sonar.api.platform.Server; import org.sonar.api.platform.ServerFileSystem; import org.sonar.core.persistence.Database; @@ -47,26 +47,22 @@ public class DefaultServerFileSystem implements ServerFileSystem, Startable { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultServerFileSystem.class); private Database database; - private File deployDir; + private final Server server; private File homeDir; - public DefaultServerFileSystem(Database database, Settings settings) { + public DefaultServerFileSystem(Database database, Settings settings, Server server) { this.database = database; + this.server = server; this.homeDir = new File(settings.getString(CoreProperties.SONAR_HOME)); - - String deployPath = settings.getString(ServerSettings.DEPLOY_DIR); - if (StringUtils.isNotBlank(deployPath)) { - this.deployDir = new File(deployPath); - } } /** * for unit tests */ - public DefaultServerFileSystem(Database database, File homeDir, File deployDir) { + public DefaultServerFileSystem(Database database, File homeDir, Server server) { this.database = database; - this.deployDir = deployDir; this.homeDir = homeDir; + this.server = server; } @Override @@ -76,19 +72,19 @@ public class DefaultServerFileSystem implements ServerFileSystem, Startable { throw new IllegalStateException("SonarQube home directory does not exist"); } - if (deployDir == null) { - throw new IllegalStateException("The target directory to deploy libraries is not set"); - } - try { - LOGGER.info("Deploy dir: " + deployDir.getAbsolutePath()); - FileUtils.forceMkdir(deployDir); - for (File subDirectory : deployDir.listFiles((FileFilter) FileFilterUtils.directoryFileFilter())) { + if (getDeployDir() == null) { + throw new IllegalArgumentException("Web app directory does not exist: " + getDeployDir()); + } + + LOGGER.info("Deploy dir: " + getDeployDir().getAbsolutePath()); + FileUtils.forceMkdir(getDeployDir()); + for (File subDirectory : getDeployDir().listFiles((FileFilter) FileFilterUtils.directoryFileFilter())) { FileUtils.cleanDirectory(subDirectory); } } catch (IOException e) { - throw new IllegalStateException("The following directory can not be created: " + deployDir.getAbsolutePath(), e); + throw new IllegalStateException("The following directory can not be created: " + getDeployDir().getAbsolutePath(), e); } File deprecated = getDeprecatedPluginsDir(); @@ -117,15 +113,15 @@ public class DefaultServerFileSystem implements ServerFileSystem, Startable { } public File getDeployDir() { - return deployDir; + return server.getDeployDir(); } public File getDeployedJdbcDriverIndex() { - return new File(deployDir, "jdbc-driver.txt"); + return new File(getDeployDir(), "jdbc-driver.txt"); } public File getDeployedPluginsDir() { - return new File(deployDir, "plugins"); + return new File(getDeployDir(), "plugins"); } public File getDownloadedPluginsDir() { diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 353893e7d0b..510b3f6f620 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -25,7 +25,8 @@ import org.sonar.api.platform.Server; import org.sonar.core.persistence.DatabaseVersion; import javax.annotation.CheckForNull; -import javax.servlet.ServletContext; + +import java.util.Properties; /** * @since 2.2 @@ -40,7 +41,7 @@ public class Platform { private boolean dbConnected = false; private boolean started = false; - private Platform() { + public Platform() { } public static Platform getInstance() { @@ -65,8 +66,8 @@ public class Platform { return null; } - public void init(ServletContext servletContext) { - serverComponents = new ServerComponents(this, servletContext); + public void init(Properties properties) { + serverComponents = new ServerComponents(this, properties); if (!dbConnected) { startLevel1Container(); startLevel2Container(); diff --git a/sonar-server/src/main/java/org/sonar/server/platform/PlatformServletContextListener.java b/sonar-server/src/main/java/org/sonar/server/platform/PlatformServletContextListener.java index 6257c03551d..82e2e659596 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/PlatformServletContextListener.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/PlatformServletContextListener.java @@ -50,7 +50,7 @@ public final class PlatformServletContextListener implements ServletContextListe public void contextInitialized(ServletContextEvent event) { try { configureLogback(event); - Platform.getInstance().init(event.getServletContext()); + Platform.getInstance().init(System.getProperties()); Platform.getInstance().doStart(); } catch (Throwable t) { // Tomcat 7 "limitations": diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java index 79d4e11ac18..8ceb686e0a0 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java @@ -20,7 +20,9 @@ package org.sonar.server.platform; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; import com.google.common.base.Joiner; +import com.google.common.io.Resources; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.picocontainer.Startable; @@ -30,8 +32,10 @@ import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Properties; @@ -42,21 +46,24 @@ public final class ServerImpl extends Server implements Startable { private final Settings settings; private final Date startedAt; private final String buildProperties; - private final String pomProperties; + private final String versionPath; private String id; private String version; private String implementationBuild; + private String contextPath; + private File sonarHome; + private File deployDir; public ServerImpl(Settings settings) { - this(settings, "/build.properties", "/META-INF/maven/org.codehaus.sonar/sonar-plugin-api/pom.properties"); + this(settings, "/build.properties", "/sq-version.txt"); } @VisibleForTesting - ServerImpl(Settings settings, String buildProperties, String pomProperties) { + ServerImpl(Settings settings, String buildProperties, String versionPath) { this.settings = settings; this.startedAt = new Date(); this.buildProperties = buildProperties; - this.pomProperties = pomProperties; + this.versionPath = versionPath; } @Override @@ -64,13 +71,17 @@ public final class ServerImpl extends Server implements Startable { try { id = new SimpleDateFormat("yyyyMMddHHmmss").format(startedAt); - version = read(pomProperties).getProperty("version", ""); + version = readVersion(versionPath); implementationBuild = read(buildProperties).getProperty("Implementation-Build"); + contextPath = StringUtils.defaultIfBlank(settings.getString("sonar.web.context"), "/"); - if (StringUtils.isBlank(version)) { - throw new IllegalStateException("Unknown SonarQube version"); + sonarHome = new File(settings.getString(CoreProperties.SONAR_HOME)); + if (!sonarHome.isDirectory()) { + throw new IllegalStateException("SonarQube home directory is not valid"); } + deployDir = new File(sonarHome, "/web/deploy/"); + LOG.info("SonarQube {}", Joiner.on(" / ").skipNulls().join("Server", version, implementationBuild)); } catch (IOException e) { @@ -107,6 +118,32 @@ public final class ServerImpl extends Server implements Startable { return startedAt; } + @Override + public File getRootDir() { + return sonarHome; + } + + @Override + public File getDeployDir() { + return deployDir; + } + + @Override + public String getContextPath() { + return contextPath; + } + + private static String readVersion(String filename) throws IOException { + URL url = ServerImpl.class.getResource(filename); + if (url != null) { + String version = Resources.toString(url, Charsets.UTF_8); + if (!StringUtils.isBlank(version)) { + return StringUtils.deleteWhitespace(version); + } + } + throw new IllegalStateException("Unknown SonarQube version"); + } + private static Properties read(String filename) throws IOException { Properties properties = new Properties(); @@ -122,6 +159,7 @@ public final class ServerImpl extends Server implements Startable { return properties; } + @Override public String getURL() { return null; diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java index 81d5116b6dc..21c301b3cfe 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java @@ -19,17 +19,13 @@ */ package org.sonar.server.platform; -import com.google.common.annotations.VisibleForTesting; import org.apache.commons.configuration.Configuration; import org.sonar.api.CoreProperties; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.Settings; -import org.sonar.core.config.ConfigurationUtils; import javax.annotation.Nullable; -import javax.servlet.ServletContext; -import java.io.File; import java.util.Collections; import java.util.Map; import java.util.Properties; @@ -47,23 +43,14 @@ import java.util.Properties; */ public class ServerSettings extends Settings { - public static final String DEPLOY_DIR = "sonar.web.deployDir"; - + private final Properties properties; private Configuration deprecatedConfiguration; - private File deployDir; - private File sonarHome; - - public ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, ServletContext servletContext) { - this(definitions, deprecatedConfiguration, getDeployDir(servletContext), SonarHome.getHome()); - } - @VisibleForTesting - ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, File deployDir, File sonarHome) { + public ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, Properties properties) { super(definitions); this.deprecatedConfiguration = deprecatedConfiguration; - this.deployDir = deployDir; - this.sonarHome = sonarHome; - load(Collections. emptyMap()); + this.properties = properties; + load(Collections.emptyMap()); // Secret key is loaded from conf/sonar.properties getEncryption().setPathToSecretKey(getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); } @@ -74,43 +61,14 @@ public class ServerSettings extends Settings { private ServerSettings load(Map databaseSettings) { clear(); - setProperty(CoreProperties.SONAR_HOME, sonarHome.getAbsolutePath()); - setProperty(DEPLOY_DIR, deployDir.getAbsolutePath()); // order is important : the last override the first addProperties(databaseSettings); - loadPropertiesFile(sonarHome); - addEnvironmentVariables(); - addSystemProperties(); + addProperties(properties); return this; } - private void loadPropertiesFile(File sonarHome) { - File propertiesFile = new File(sonarHome, "conf/sonar.properties"); - if (!propertiesFile.isFile() || !propertiesFile.exists()) { - throw new IllegalStateException("Properties file does not exist: " + propertiesFile); - } - try { - Properties p = ConfigurationUtils.openProperties(propertiesFile); - addProperties(ConfigurationUtils.interpolateEnvVariables(p)); - } catch (Exception e) { - throw new IllegalStateException("Fail to load configuration file: " + propertiesFile, e); - } - } - - static File getDeployDir(ServletContext servletContext) { - String dirname = servletContext.getRealPath("/deploy/"); - if (dirname == null) { - throw new IllegalArgumentException("Web app directory not found : /deploy/"); - } - File dir = new File(dirname); - if (!dir.exists()) { - throw new IllegalArgumentException("Web app directory does not exist: " + dir); - } - return dir; - } - @Override protected void doOnSetProperty(String key, @Nullable String value) { deprecatedConfiguration.setProperty(key, value); diff --git a/sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java b/sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java index 26cf45ed572..2f1b7bcfafd 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java @@ -22,6 +22,7 @@ package org.sonar.server.platform; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import org.apache.commons.lang.StringUtils; +import org.sonar.api.CoreProperties; import java.io.File; @@ -33,6 +34,8 @@ import java.io.File; * * * @since 2.12 + * + * TODO Delete it as it's now useless (SONAR_HOME is set by Tomcat) */ final class SonarHome { @@ -40,12 +43,10 @@ final class SonarHome { // only static methods } - static final String SONAR_HOME = "SONAR_HOME"; - static Supplier homeSupplier = Suppliers.memoize(new Supplier() { public File get() { File home = locate(); - System.setProperty(SONAR_HOME, home.getAbsolutePath()); + System.setProperty(CoreProperties.SONAR_HOME, home.getAbsolutePath()); return home; } }); @@ -55,19 +56,19 @@ final class SonarHome { } static File locate() { - String value = System.getProperty(SONAR_HOME); + String value = System.getProperty(CoreProperties.SONAR_HOME); if (StringUtils.isBlank(value)) { - value = System.getenv(SONAR_HOME); + value = System.getenv(CoreProperties.SONAR_HOME); } if (StringUtils.isBlank(value)) { - throw new IllegalStateException("The system property or env variable " + SONAR_HOME + " is not set"); + throw new IllegalStateException("The system property or env variable " + CoreProperties.SONAR_HOME + " is not set"); } File dir = new File(value); if (!dir.isDirectory() || !dir.exists()) { - throw new IllegalStateException(SONAR_HOME + " is not valid: " + value + ". Please fix the env variable/system " + - "property " + SONAR_HOME); + throw new IllegalStateException(CoreProperties.SONAR_HOME + " is not valid: " + value + ". Please fix the env variable/system " + + "property " + CoreProperties.SONAR_HOME); } return dir; } diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java b/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java index bcb7546ed08..f8daf5ae57e 100644 --- a/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java +++ b/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java @@ -23,7 +23,6 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.server.startup.GenerateBootstrapIndex; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -33,7 +32,6 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.PrintWriter; /** * This servlet allows to load libraries from directory "WEB-INF/lib" in order to provide them for batch-bootstrapper. @@ -48,17 +46,7 @@ public class BatchResourcesServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = filename(request); if (StringUtils.isBlank(filename)) { - PrintWriter writer = null; - try { - response.setContentType("text/plain"); - writer = response.getWriter(); - writer.print(StringUtils.join(GenerateBootstrapIndex.getLibs(getServletContext()), ',')); - } catch (IOException e) { - LOG.error("Unable to provide list of batch resources", e); - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } finally { - IOUtils.closeQuietly(writer); - } + throw new IllegalArgumentException("Filename is missing."); } else { InputStream in = null; OutputStream out = null; diff --git a/sonar-server/src/main/java/org/sonar/server/source/CodeColorizers.java b/sonar-server/src/main/java/org/sonar/server/source/CodeColorizers.java index 16509e8b9da..67803e8a6e5 100644 --- a/sonar-server/src/main/java/org/sonar/server/source/CodeColorizers.java +++ b/sonar-server/src/main/java/org/sonar/server/source/CodeColorizers.java @@ -19,6 +19,7 @@ */ package org.sonar.server.source; +import com.google.common.collect.Lists; import org.apache.commons.lang.StringUtils; import org.sonar.api.ServerExtension; import org.sonar.api.utils.Logs; @@ -49,6 +50,13 @@ public class CodeColorizers implements ServerExtension { Logs.INFO.info("Code colorizer, supported languages: " + StringUtils.join(byLang.keySet(), ",")); } + /** + * Used when no plugin is defining some CodeColorizerFormat + */ + public CodeColorizers() { + this(Lists.newArrayList()); + } + public String toHtml(String code, String language) { CodeColorizerFormat format = byLang.get(language); List tokenizers; diff --git a/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java b/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java index 70def7e35b0..4b71498785a 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java @@ -19,22 +19,23 @@ */ package org.sonar.server.startup; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.HiddenFileFilter; import org.apache.commons.lang.CharUtils; import org.apache.commons.lang.StringUtils; +import org.sonar.api.platform.Server; import org.sonar.home.cache.FileHashes; import org.sonar.server.platform.DefaultServerFileSystem; -import javax.servlet.ServletContext; - import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStream; +import java.util.Collection; import java.util.List; -import java.util.Set; /** * @since 3.5 @@ -45,11 +46,13 @@ public final class GenerateBootstrapIndex { private static final String[] IGNORE = {"jtds", "mysql", "postgresql", "jruby", "jfreechart", "eastwood", "elasticsearch", "lucene"}; - private final ServletContext servletContext; + private static final String LIB_DIR = "/web/WEB-INF/lib"; + + private final Server server; private final DefaultServerFileSystem fileSystem; - public GenerateBootstrapIndex(DefaultServerFileSystem fileSystem, ServletContext servletContext) { - this.servletContext = servletContext; + public GenerateBootstrapIndex(DefaultServerFileSystem fileSystem, Server server) { + this.server = server; this.fileSystem = fileSystem; } @@ -61,25 +64,32 @@ public final class GenerateBootstrapIndex { FileUtils.forceMkdir(indexFile.getParentFile()); FileWriter writer = new FileWriter(indexFile, false); try { - for (String path : getLibs(servletContext)) { - writer.append(path); - InputStream is = servletContext.getResourceAsStream("/WEB-INF/lib/" + path); - writer.append("|").append(new FileHashes().of(is)); - writer.append(CharUtils.LF); + File libDir = new File(server.getRootDir(), LIB_DIR); + // TODO hack for Medium tests + if (libDir.exists()) { + for (String path : getLibs(libDir)) { + writer.append(path); + File is = new File(libDir, path); + writer.append("|").append(new FileHashes().of(is)); + writer.append(CharUtils.LF); + } + writer.flush(); } - writer.flush(); } finally { IOUtils.closeQuietly(writer); } } - public static List getLibs(ServletContext servletContext) { + @VisibleForTesting + static List getLibs(File libDir) { List libs = Lists.newArrayList(); - Set paths = servletContext.getResourcePaths("/WEB-INF/lib/"); - for (String path : paths) { + + Collection files = FileUtils.listFiles(libDir, HiddenFileFilter.VISIBLE, FileFilterUtils.directoryFileFilter()); + for (File file : files) { + String path = file.getPath(); if (StringUtils.endsWith(path, ".jar")) { - String filename = StringUtils.removeStart(path, "/WEB-INF/lib/"); + String filename = StringUtils.removeStart(path, libDir.getAbsolutePath() + "/"); if (!isIgnored(filename)) { libs.add(filename); } diff --git a/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java b/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java index 8980988255b..a69b50a758c 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java @@ -19,17 +19,18 @@ */ package org.sonar.server.startup; +import com.google.common.annotations.VisibleForTesting; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.config.Settings; +import org.sonar.api.platform.Server; import org.sonar.api.utils.Logs; import org.sonar.api.utils.SonarException; import org.sonar.api.utils.TimeProfiler; import org.sonar.api.utils.ZipUtils; import org.sonar.api.web.GwtExtension; -import org.sonar.server.platform.ServerSettings; import java.io.File; import java.io.IOException; @@ -41,15 +42,23 @@ import java.util.zip.ZipEntry; public class GwtPublisher { private static final Logger LOG = LoggerFactory.getLogger(GwtPublisher.class); - private Settings settings; + private Server server; private GwtExtension[] extensions = null; private File outputDir = null; - public GwtPublisher(GwtExtension[] extensions, Settings settings) { + public GwtPublisher(GwtExtension[] extensions, Settings settings, Server server) { this.extensions = extensions; - this.settings = settings; + this.server = server; } + /** + * Used when no plugin is defining some GwtExtension + */ + public GwtPublisher(Settings settings, Server server) { + this(new GwtExtension[]{}, settings, server); + } + + @VisibleForTesting GwtPublisher(GwtExtension[] extensions, File outputDir) { this.extensions = extensions; this.outputDir = outputDir; @@ -62,7 +71,7 @@ public class GwtPublisher { TimeProfiler profiler = new TimeProfiler().start("Deploy GWT plugins"); try { cleanDirectory(); - this.outputDir = new File(settings.getString(ServerSettings.DEPLOY_DIR), "gwt"); + this.outputDir = new File(server.getDeployDir(), "gwt"); LoggerFactory.getLogger(GwtPublisher.class).debug("Deploy {} GWT extensions to {}", extensions.length, outputDir); publish(); diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterDashboards.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterDashboards.java index 11f85d0e53d..317e08d9a47 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterDashboards.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterDashboards.java @@ -57,6 +57,13 @@ public class RegisterDashboards implements Startable { this.loadedTemplateDao = loadedTemplateDao; } + /** + * Used when no plugin is defining some DashboardTemplate + */ + public RegisterDashboards(DashboardDao dashboardDao, ActiveDashboardDao activeDashboardDao, LoadedTemplateDao loadedTemplateDao) { + this(new DashboardTemplate[]{}, dashboardDao, activeDashboardDao, loadedTemplateDao); + } + @Override public void start() { TimeProfiler profiler = new TimeProfiler(LOG).start("Register dashboards"); diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java index 689348d9ca0..5e5b6cfc582 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java @@ -51,6 +51,13 @@ public class RegisterMetrics { this.conditionDao = conditionDao; } + /** + * Used when no plugin is defining Metrics + */ + public RegisterMetrics(MeasuresDao measuresDao, QualityGateConditionDao conditionDao) { + this(measuresDao, conditionDao, new Metrics[]{}); + } + public void start() { TimeProfiler profiler = new TimeProfiler().start("Load metrics"); measuresDao.disableAutomaticMetrics(); diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewMeasureFilters.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewMeasureFilters.java index e2c8574b838..755a1eed6a6 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewMeasureFilters.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewMeasureFilters.java @@ -54,6 +54,13 @@ public final class RegisterNewMeasureFilters { this.loadedTemplateDao = loadedTemplateDao; } + /** + * Used when no plugin is defining some FilterTemplate + */ + public RegisterNewMeasureFilters(MeasureFilterDao filterDao, LoadedTemplateDao loadedTemplateDao) { + this(new FilterTemplate[]{}, filterDao, loadedTemplateDao); + } + public void start() { TimeProfiler profiler = new TimeProfiler(LOG).start("Register measure filters"); diff --git a/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java b/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java index 0f8c60ac335..0971feae8a0 100644 --- a/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java +++ b/sonar-server/src/main/java/org/sonar/server/text/MacroInterpreter.java @@ -22,17 +22,17 @@ package org.sonar.server.text; import com.google.common.collect.ImmutableList; import org.sonar.api.ServerComponent; +import org.sonar.api.platform.Server; -import javax.servlet.ServletContext; import java.util.List; public class MacroInterpreter implements ServerComponent { private final List macros; - public MacroInterpreter(ServletContext servletContext) { + public MacroInterpreter(Server server) { this.macros = ImmutableList.of( - new RuleMacro(servletContext.getContextPath()) + new RuleMacro(server.getContextPath()) ); } diff --git a/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java b/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java index cc6f008d474..3612c104526 100644 --- a/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java @@ -28,9 +28,9 @@ import org.sonar.api.config.PropertyDefinitions; import org.sonar.core.properties.PropertiesDao; import org.sonar.core.properties.PropertyDto; -import java.io.File; import java.net.URISyntaxException; import java.util.Arrays; +import java.util.Properties; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.argThat; @@ -44,11 +44,11 @@ public class PersistentSettingsTest { @Before public void init() throws URISyntaxException { dao = mock(PropertiesDao.class); + settings = new ServerSettings( new PropertyDefinitions(), new PropertiesConfiguration(), - new File("."), - new File(PersistentSettingsTest.class.getResource("/org/sonar/server/platform/PersistentSettingsTest/").toURI())); + new Properties()); } @Test diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java index 2101db16a78..44954c85fb6 100644 --- a/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java +++ b/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java @@ -20,22 +20,41 @@ package org.sonar.server.platform; import org.hamcrest.core.Is; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; +import java.io.File; + import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assert.assertThat; public class ServerImplTest { + @Rule public ExpectedException exception = ExpectedException.none(); + @Rule + public TemporaryFolder sonarHome = new TemporaryFolder(); + + Settings settings; + + ServerImpl server; + + @Before + public void setUp() throws Exception { + settings = new Settings().setProperty(CoreProperties.SONAR_HOME, sonarHome.getRoot().getAbsolutePath()); + new File(sonarHome.getRoot(), "web/deploy").mkdirs(); + + server = new ServerImpl(settings, "/org/sonar/server/platform/ServerImplTest/build.properties", "/org/sonar/server/platform/ServerImplTest/version.txt"); + } + @Test - public void alwaysReturnTheSameValues() { - ServerImpl server = new ServerImpl(new Settings(), "", "/org/sonar/server/platform/ServerImplTest/pom-with-version.properties"); + public void always_return_the_same_values() { server.start(); assertThat(server.getId()).isNotNull(); @@ -49,52 +68,48 @@ public class ServerImplTest { } @Test - public void getVersionFromFile() { - ServerImpl server = new ServerImpl(new Settings(), "", "/org/sonar/server/platform/ServerImplTest/pom-with-version.properties"); + public void read_version_from_file() { server.start(); assertThat(server.getVersion()).isEqualTo("1.0"); } @Test - public void getImplementationBuildFromManifest() { - ServerImpl server = new ServerImpl(new Settings(), - "/org/sonar/server/platform/ServerImplTest/build.properties", - "/org/sonar/server/platform/ServerImplTest/pom-with-version.properties"); + public void read_implementation_build_from_manifest() { server.start(); assertThat(server.getImplementationBuild()).isEqualTo("0b9545a8b74aca473cb776275be4dc93a327c363"); } @Test - public void testFileWithNoVersion() { + public void read_file_with_no_version() { exception.expect(IllegalStateException.class); exception.expectMessage("Unknown SonarQube version"); - ServerImpl server = new ServerImpl(new Settings(), "", "/org/sonar/server/platform/ServerImplTest/pom-without-version.properties"); + ServerImpl server = new ServerImpl(settings, "", "/org/sonar/server/platform/ServerImplTest/empty-version.txt"); server.start(); } @Test - public void testFileWithEmptyVersionParameter() { + public void read_file_with_empty_version() { exception.expect(IllegalStateException.class); exception.expectMessage("Unknown SonarQube version"); - ServerImpl server = new ServerImpl(new Settings(), "", "/org/sonar/server/platform/ServerImplTest/pom-with-empty-version.properties"); + ServerImpl server = new ServerImpl(settings, "", "/org/sonar/server/platform/ServerImplTest/empty-version.txt"); server.start(); } @Test - public void shouldFailIfFileNotFound() { + public void fail_if_version_file_not_found() { exception.expect(IllegalStateException.class); exception.expectMessage("Unknown SonarQube version"); - ServerImpl server = new ServerImpl(new Settings(), "", "/org/sonar/server/platform/ServerImplTest/unknown-file.properties"); + ServerImpl server = new ServerImpl(settings, "", "/org/sonar/server/platform/ServerImplTest/unknown-file.properties"); server.start(); } @Test - public void shouldLoadServerIdFromDatabase() { + public void load_server_id_from_database() { Settings settings = new Settings(); settings.setProperty(CoreProperties.PERMANENT_SERVER_ID, "abcde"); @@ -102,4 +117,18 @@ public class ServerImplTest { assertThat(server.getPermanentServerId(), Is.is("abcde")); } + + @Test + public void use_default_context_path() { + server.start(); + assertThat(server.getContextPath()).isEqualTo("/"); + } + + @Test + public void get_context_path_from_settings() { + settings.setProperty("sonar.web.context", "/my_path"); + server.start(); + assertThat(server.getContextPath()).isEqualTo("/my_path"); + } + } diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java index 4acb5baf2ce..8907b3e6d5d 100644 --- a/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java +++ b/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java @@ -21,10 +21,11 @@ package org.sonar.server.platform; import org.junit.Before; import org.junit.Test; +import org.sonar.api.platform.Server; import org.sonar.api.platform.ServerStartHandler; import org.sonar.api.platform.ServerStopHandler; -import org.sonar.api.platform.Server; +import java.io.File; import java.util.Date; import static org.mockito.Mockito.*; @@ -99,6 +100,21 @@ class FakeServer extends Server { return null; } + @Override + public File getRootDir() { + return null; + } + + @Override + public File getDeployDir() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + @Override public String getURL() { return null; diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java index 4b7ef9b0edf..af0cc558e8f 100644 --- a/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java @@ -21,44 +21,37 @@ package org.sonar.server.platform; import com.google.common.collect.ImmutableMap; import org.apache.commons.configuration.BaseConfiguration; +import org.junit.Before; import org.junit.Test; import org.sonar.api.config.PropertyDefinitions; -import java.io.File; -import java.net.URISyntaxException; import java.util.Map; +import java.util.Properties; import static org.fest.assertions.Assertions.assertThat; public class ServerSettingsTest { - private static File home = getHome(); + Properties properties; - @Test - public void load_properties_file() { - ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home); + ServerSettings settings; - assertThat(settings.getString("hello")).isEqualTo("world"); + @Before + public void before() throws Exception { + properties = new Properties(); + properties.put("hello", "world"); + properties.put("in_file", "true"); + properties.put("ServerSettingsTestEnv", "in_file"); + settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), properties); } @Test - public void systemPropertiesShouldOverridePropertiesFile() { - System.setProperty("ServerSettingsTestEnv", "in_env"); - ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home); - - assertThat(settings.getString("ServerSettingsTestEnv")).isEqualTo("in_env"); - } - - @Test(expected = IllegalStateException.class) - public void fail_if_properties_file_is_not_found() { - File sonarHome = new File("unknown/path"); - new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), sonarHome); + public void load_properties_file() { + assertThat(settings.getString("hello")).isEqualTo("world"); } @Test - public void activateDatabaseSettings() { - ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home); - + public void activate_database_settings() { Map databaseProperties = ImmutableMap.of("in_db", "true"); settings.activateDatabaseSettings(databaseProperties); @@ -67,7 +60,6 @@ public class ServerSettingsTest { @Test public void file_settings_override_db_settings() { - ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home); assertThat(settings.getString("in_file")).isEqualTo("true"); Map databaseProperties = ImmutableMap.of("in_file", "false"); @@ -79,7 +71,7 @@ public class ServerSettingsTest { @Test public void synchronize_deprecated_commons_configuration() { BaseConfiguration deprecated = new BaseConfiguration(); - ServerSettings settings = new ServerSettings(new PropertyDefinitions(), deprecated, new File("."), home); + ServerSettings settings = new ServerSettings(new PropertyDefinitions(), deprecated, properties); assertThat(settings.getString("in_file")).isEqualTo("true"); assertThat(deprecated.getString("in_file")).isEqualTo("true"); @@ -90,12 +82,4 @@ public class ServerSettingsTest { settings.removeProperty("foo"); assertThat(deprecated.getString("foo")).isNull(); } - - private static File getHome() { - try { - return new File(ServerSettingsTest.class.getResource("/org/sonar/server/platform/ServerSettingsTest/").toURI()); - } catch (URISyntaxException e) { - throw new IllegalStateException(e); - } - } } diff --git a/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java b/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java index caf2b8f7acc..fc0ef01ada4 100644 --- a/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java +++ b/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java @@ -50,7 +50,7 @@ public class ServerPluginJarsInstallerTest { public TemporaryFolder temp = new TemporaryFolder(); DefaultServerFileSystem fileSystem; - File homeDir, deployDir, pluginsDir, downloadsDir, bundledDir, trashDir, coreDir; + File homeDir, pluginsDir, downloadsDir, bundledDir, trashDir, coreDir; ServerPluginJarInstaller jarInstaller; ServerPluginJarsInstaller jarsInstaller; Server server = mock(Server.class); @@ -67,8 +67,7 @@ public class ServerPluginJarsInstallerTest { bundledDir = new File(homeDir, "lib/bundled-plugins"); coreDir = new File(homeDir, "lib/core-plugins"); FileUtils.forceMkdir(bundledDir); - deployDir = temp.newFolder("deploy"); - fileSystem = new DefaultServerFileSystem(mock(Database.class), homeDir, deployDir); + fileSystem = new DefaultServerFileSystem(mock(Database.class), homeDir, server); jarInstaller = new ServerPluginJarInstaller(); jarsInstaller = new ServerPluginJarsInstaller(server, upgradeStatus, fileSystem, jarInstaller); } diff --git a/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java b/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java index 3b4686a461c..ca6f7c74e0e 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java @@ -19,40 +19,41 @@ */ package org.sonar.server.startup; -import com.google.common.collect.Sets; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; -import javax.servlet.ServletContext; - -import java.util.Set; +import java.io.File; +import java.io.IOException; import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class GenerateBootstrapIndexTest { + @Rule + public TemporaryFolder rootDir = new TemporaryFolder(); + @Before public void setUp() throws Exception { } @Test - public void shouldDetermineListOfResources() { - ServletContext servletContext = mock(ServletContext.class); - Set libs = Sets.newHashSet(); - libs.add("/WEB-INF/lib/sonar-core-2.6.jar"); - libs.add("/WEB-INF/lib/treemap.rb"); - libs.add("/WEB-INF/lib/directory/"); - when(servletContext.getResourcePaths(anyString())).thenReturn(libs); + public void determine_list_of_resources() throws IOException { + new File(rootDir.getRoot(), "/web/WEB-INF/lib").mkdirs(); + File webInf = new File(rootDir.getRoot(), "/web/WEB-INF"); + File lib = new File(rootDir.getRoot(), "/web/WEB-INF/lib"); + new File(webInf, "directory").mkdir(); + new File(lib, "sonar-core-2.6.jar").createNewFile(); + new File(lib, "treemap.rbr").createNewFile(); + new File(lib, "sonar-core-2.6.jar").createNewFile(); - assertThat(GenerateBootstrapIndex.getLibs(servletContext)).hasSize(1); - assertThat(GenerateBootstrapIndex.getLibs(servletContext).get(0)).isEqualTo("sonar-core-2.6.jar"); + assertThat(GenerateBootstrapIndex.getLibs(lib)).hasSize(1); + assertThat(GenerateBootstrapIndex.getLibs(lib).get(0)).isEqualTo("sonar-core-2.6.jar"); } @Test - public void shouldIgnore() { + public void ignore_some_jars() { assertThat(GenerateBootstrapIndex.isIgnored("sonar-batch-2.6-SNAPSHOT.jar")).isFalse(); assertThat(GenerateBootstrapIndex.isIgnored("mysql-connector-java-5.1.13.jar")).isTrue(); assertThat(GenerateBootstrapIndex.isIgnored("postgresql-9.0-801.jdbc3.jar")).isTrue(); diff --git a/sonar-server/src/test/java/org/sonar/server/startup/GwtPublisherTest.java b/sonar-server/src/test/java/org/sonar/server/startup/GwtPublisherTest.java index fc6ffdc3945..8e900809fc4 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/GwtPublisherTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/GwtPublisherTest.java @@ -45,7 +45,6 @@ public class GwtPublisherTest { outputDir = new File("./target/test-tmp/org/sonar/server/startup/GwtPublisherTest/output"); if (outputDir.exists()) { FileUtils.forceDelete(outputDir); - } } diff --git a/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java b/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java index ef9ad6775ae..b993dbfd058 100644 --- a/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java +++ b/sonar-server/src/test/java/org/sonar/server/text/MacroInterpreterTest.java @@ -22,8 +22,7 @@ package org.sonar.server.text; import org.junit.Before; import org.junit.Test; - -import javax.servlet.ServletContext; +import org.sonar.api.platform.Server; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -36,9 +35,9 @@ public class MacroInterpreterTest { @Before public void setUp() { - ServletContext servletContext = mock(ServletContext.class); - when(servletContext.getContextPath()).thenReturn(path); - interpreter = new MacroInterpreter(servletContext); + Server server = mock(Server.class); + when(server.getContextPath()).thenReturn(path); + interpreter = new MacroInterpreter(server); } @Test diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/PersistentSettingsTest/conf/sonar.properties b/sonar-server/src/test/resources/org/sonar/server/platform/PersistentSettingsTest/conf/sonar.properties deleted file mode 100644 index b4a8077471c..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/platform/PersistentSettingsTest/conf/sonar.properties +++ /dev/null @@ -1 +0,0 @@ -in_file: true \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/empty-version.txt b/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/empty-version.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-with-empty-version.properties b/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-with-empty-version.properties deleted file mode 100644 index 287ce487033..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-with-empty-version.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Fri Nov 23 14:23:53 CET 2007 -groupId=org.codehaus.sonar -artifactId=sonar-core -version= \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-with-version.properties b/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-with-version.properties deleted file mode 100644 index 6fff0c5f4d1..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-with-version.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Fri Nov 23 14:23:53 CET 2007 -version=1.0 -groupId=org.codehaus.sonar -artifactId=sonar-core diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-without-version.properties b/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-without-version.properties deleted file mode 100644 index 8d70c2289f8..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/pom-without-version.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Generated by Maven -#Fri Nov 23 14:23:53 CET 2007 -groupId=org.codehaus.sonar -artifactId=sonar-core diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/version.txt b/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/version.txt new file mode 100644 index 00000000000..d3827e75a5c --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/platform/ServerImplTest/version.txt @@ -0,0 +1 @@ +1.0 diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/conf/sonar.properties b/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/conf/sonar.properties deleted file mode 100644 index 020777dad4f..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/conf/sonar.properties +++ /dev/null @@ -1,3 +0,0 @@ -hello: world -in_file: true -ServerSettingsTestEnv: in_file \ No newline at end of file