aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java91
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java8
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java39
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java62
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java94
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java14
-rw-r--r--sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java9
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml3
8 files changed, 304 insertions, 16 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java
new file mode 100644
index 00000000000..c4202a5e40b
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java
@@ -0,0 +1,91 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch;
+
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.platform.Server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class RemoteServerMetadata implements BatchComponent {
+
+ public static final int CONNECT_TIMEOUT_MILLISECONDS = 30000;
+ public static final int READ_TIMEOUT_MILLISECONDS = 60000;
+
+ private String serverUrl;
+
+ public RemoteServerMetadata(Server server) {
+ serverUrl = server.getURL();
+ if (serverUrl.endsWith("/")) {
+ serverUrl = StringUtils.chop(serverUrl);
+ }
+ }
+
+ public String getServerId() throws IOException {
+ String remoteServerInfo = remoteContent("/api/server");
+ // don't use JSON utilities to extract ID from such a small string
+ String id = extractId(remoteServerInfo);
+ return id;
+ }
+
+ protected String extractId(String remoteServerInfo) {
+ String partialId = StringUtils.substringAfter(remoteServerInfo, "\"id\":\"");
+ String id = StringUtils.substringBefore(partialId, "\"");
+ return id;
+ }
+
+ protected String getUrlFor(String path) {
+ String fullUrl = serverUrl + path;
+ return fullUrl;
+ }
+
+ protected String remoteContent(String path) throws IOException {
+ String fullUrl = getUrlFor(path);
+ HttpURLConnection conn = getConnection(fullUrl, "GET");
+ InputStream input = (InputStream) conn.getContent();
+ try {
+ int statusCode = conn.getResponseCode();
+ if (statusCode != HttpURLConnection.HTTP_OK) {
+ throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
+ }
+ return IOUtil.toString(input);
+
+ } finally {
+ IOUtil.close(input);
+ conn.disconnect();
+ }
+ }
+
+ static HttpURLConnection getConnection(String url, String method) throws IOException {
+ URL page = new URL(url);
+ HttpURLConnection conn = (HttpURLConnection) page.openConnection();
+ conn.setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS);
+ conn.setReadTimeout(READ_TIMEOUT_MILLISECONDS);
+ conn.setRequestMethod(method);
+ conn.connect();
+ return conn;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java
index ced7e8a4d34..c987c4d09c0 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java
@@ -24,15 +24,16 @@ import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.utils.HttpDownloader;
import org.sonar.batch.FakeMavenPluginExecutor;
import org.sonar.batch.MavenPluginExecutor;
+import org.sonar.batch.RemoteServerMetadata;
import org.sonar.batch.ServerMetadata;
-import org.sonar.batch.config.BatchSettings;
import org.sonar.batch.config.BatchDatabaseSettingsLoader;
+import org.sonar.batch.config.BatchSettings;
+import org.sonar.core.persistence.DaoUtils;
import org.sonar.core.persistence.DatabaseVersion;
+import org.sonar.core.persistence.MyBatis;
import org.sonar.jpa.session.DatabaseSessionProvider;
import org.sonar.jpa.session.DefaultDatabaseConnector;
import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
-import org.sonar.core.persistence.DaoUtils;
-import org.sonar.core.persistence.MyBatis;
import java.net.URLClassLoader;
@@ -65,6 +66,7 @@ public class BootstrapModule extends Module {
// set as the current context classloader for hibernate, else it does not find the JDBC driver.
Thread.currentThread().setContextClassLoader(bootstrapClassLoader);
+ addCoreSingleton(RemoteServerMetadata.class);
// mybatis
addCoreSingleton(BatchDatabase.class);
addCoreSingleton(MyBatis.class);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java
index 683bcda5d1d..21a149589aa 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java
@@ -20,10 +20,16 @@
package org.sonar.batch.bootstrap;
import org.sonar.api.BatchComponent;
+import org.sonar.api.config.Settings;
+import org.sonar.api.database.DatabaseProperties;
import org.sonar.api.platform.Server;
+import org.sonar.api.utils.SonarException;
+import org.sonar.batch.RemoteServerMetadata;
import org.sonar.core.persistence.BadDatabaseVersion;
import org.sonar.core.persistence.DatabaseVersion;
+import java.io.IOException;
+
/**
* Detects if database is not up-to-date with the version required by the batch.
*/
@@ -31,13 +37,44 @@ public class DatabaseBatchCompatibility implements BatchComponent {
private DatabaseVersion version;
private Server server;
+ private Settings settings;
+ private RemoteServerMetadata remoteServer;
- public DatabaseBatchCompatibility(DatabaseVersion version, Server server) {
+ public DatabaseBatchCompatibility(DatabaseVersion version, Server server, RemoteServerMetadata remoteServer, Settings settings) {
this.version = version;
this.server = server;
+ this.settings = settings;
+ this.remoteServer = remoteServer;
}
public void start() {
+ checkCorrectServerId();
+ checkDatabaseStatus();
+ }
+
+ private void checkCorrectServerId() {
+ String remoteServerId = null;
+ try {
+ remoteServerId = remoteServer.getServerId();
+ } catch (IOException e) {
+ throw new SonarException("Impossible to get the ID of the remote server: " + server.getURL(), e);
+ }
+
+ if (!version.getSonarCoreId().equals(remoteServerId)) {
+ StringBuilder message = new StringBuilder("The current batch process and the configured remote server do not share the same DB configuration.\n");
+ message.append("\t- Batch side: ");
+ message.append(settings.getString(DatabaseProperties.PROP_URL));
+ message.append(" (");
+ String userName = settings.getString(DatabaseProperties.PROP_USER);
+ message.append(userName == null ? "sonar" : userName);
+ message.append(" / *****)\n\t- Server side: check the configuration at ");
+ message.append(server.getURL());
+ message.append("/system\n");
+ throw new BadDatabaseVersion(message.toString());
+ }
+ }
+
+ private void checkDatabaseStatus() {
DatabaseVersion.Status status = version.getStatus();
if (status == DatabaseVersion.Status.REQUIRES_DOWNGRADE) {
throw new BadDatabaseVersion("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)");
diff --git a/sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java b/sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java
new file mode 100644
index 00000000000..5a99dbf5ce1
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java
@@ -0,0 +1,62 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.platform.Server;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RemoteServerMetadataTest {
+
+ private RemoteServerMetadata remoteServerMetadata;
+
+ @Before
+ public void init() throws Exception {
+ Server server = mock(Server.class);
+ when(server.getURL()).thenReturn("http://localhost:8080");
+
+ remoteServerMetadata = new RemoteServerMetadata(server);
+ }
+
+ @Test
+ public void shouldExtractId() throws Exception {
+ assertThat(remoteServerMetadata.extractId("{\"id\":\"123456\",\"version\":\"3.1\",\"status\":\"UP\"}"), is("123456"));
+ }
+
+ @Test
+ public void shouldGiveUrlForPath() throws Exception {
+ assertThat(remoteServerMetadata.getUrlFor("/api/server"), is("http://localhost:8080/api/server"));
+ }
+
+ @Test
+ public void handleLastSlash() throws Exception {
+ Server server = mock(Server.class);
+ when(server.getURL()).thenReturn("http://localhost:8080/");
+
+ remoteServerMetadata = new RemoteServerMetadata(server);
+ assertThat(remoteServerMetadata.getUrlFor("/api/server"), is("http://localhost:8080/api/server"));
+ }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java
index 2059313776a..4c023921487 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java
@@ -19,39 +19,109 @@
*/
package org.sonar.batch.bootstrap;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings;
+import org.sonar.api.database.DatabaseProperties;
import org.sonar.api.platform.Server;
-import org.sonar.batch.ServerMetadata;
+import org.sonar.api.utils.SonarException;
+import org.sonar.batch.RemoteServerMetadata;
import org.sonar.core.persistence.BadDatabaseVersion;
import org.sonar.core.persistence.DatabaseVersion;
+import java.io.IOException;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class DatabaseBatchCompatibilityTest {
- private Server server = new ServerMetadata(new Settings());
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private DatabaseVersion databaseVersion;
+ private Server server;
+ private Settings settings;
+ private RemoteServerMetadata remoteServerMetadata;
+
+ @Before
+ public void init() throws Exception {
+ databaseVersion = mock(DatabaseVersion.class);
+ when(databaseVersion.getSonarCoreId()).thenReturn("123456");
+
+ server = mock(Server.class);
+ when(server.getURL()).thenReturn("http://localhost:9000");
- @Test(expected = BadDatabaseVersion.class)
+ settings = new Settings();
+ settings.setProperty(DatabaseProperties.PROP_URL, "jdbc:postgresql://localhost/foo");
+ settings.setProperty(DatabaseProperties.PROP_USER, "bar");
+
+ remoteServerMetadata = mock(RemoteServerMetadata.class);
+ when(remoteServerMetadata.getServerId()).thenReturn("123456");
+ }
+
+ @Test
public void shouldFailIfRequiresDowngrade() {
- DatabaseVersion version = mock(DatabaseVersion.class);
- when(version.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE);
- new DatabaseBatchCompatibility(version, server).start();
+ when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE);
+
+ thrown.expect(BadDatabaseVersion.class);
+ thrown.expectMessage("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)");
+
+ new DatabaseBatchCompatibility(databaseVersion, server, remoteServerMetadata, settings).start();
}
- @Test(expected = BadDatabaseVersion.class)
+ @Test
public void shouldFailIfRequiresUpgrade() {
+ when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
+
+ thrown.expect(BadDatabaseVersion.class);
+ thrown.expectMessage("Database must be upgraded.");
+
+ new DatabaseBatchCompatibility(databaseVersion, server, remoteServerMetadata, settings).start();
+ }
+
+ @Test
+ public void shouldFailIfNotSameServerId() throws Exception {
DatabaseVersion version = mock(DatabaseVersion.class);
- when(version.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
- new DatabaseBatchCompatibility(version, server).start();
+ when(version.getSonarCoreId()).thenReturn("1111111");
+
+ thrown.expect(BadDatabaseVersion.class);
+ thrown.expectMessage("The current batch process and the configured remote server do not share the same DB configuration.");
+ thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (bar / *****)");
+ thrown.expectMessage("- Server side: check the configuration at http://localhost:9000/system");
+
+ new DatabaseBatchCompatibility(version, server, remoteServerMetadata, settings).start();
}
@Test
- public void shouldDoNothingIfUpToDate() {
+ public void shouldUseDefaultUserNameWhenFaillingIfNotSameServerIdAndNoUserNameFound() throws Exception {
DatabaseVersion version = mock(DatabaseVersion.class);
- when(version.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
- new DatabaseBatchCompatibility(version, server).start();
+ when(version.getSonarCoreId()).thenReturn("1111111");
+
+ settings.removeProperty(DatabaseProperties.PROP_USER);
+
+ thrown.expect(BadDatabaseVersion.class);
+ thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (sonar / *****)");
+
+ new DatabaseBatchCompatibility(version, server, remoteServerMetadata, settings).start();
+ }
+
+ @Test
+ public void shouldFailIfCantGetServerId() throws Exception {
+ when(remoteServerMetadata.getServerId()).thenThrow(IOException.class);
+
+ thrown.expect(SonarException.class);
+ thrown.expectMessage("Impossible to get the ID of the remote server: http://localhost:9000");
+
+ new DatabaseBatchCompatibility(mock(DatabaseVersion.class), server, remoteServerMetadata, settings).start();
+ }
+
+ @Test
+ public void shouldDoNothingIfUpToDate() {
+ when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
+ new DatabaseBatchCompatibility(databaseVersion, server, remoteServerMetadata, settings).start();
// no error
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
index 43476f3f6cf..fc6290e80a4 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
@@ -22,7 +22,10 @@ package org.sonar.core.persistence;
import com.google.common.annotations.VisibleForTesting;
import org.apache.ibatis.session.SqlSession;
import org.sonar.api.BatchComponent;
+import org.sonar.api.CoreProperties;
import org.sonar.api.ServerComponent;
+import org.sonar.core.properties.PropertiesMapper;
+import org.sonar.core.properties.PropertyDto;
import java.util.Collections;
import java.util.List;
@@ -63,6 +66,17 @@ public class DatabaseVersion implements BatchComponent, ServerComponent {
}
}
+ public String getSonarCoreId() {
+ SqlSession session = mybatis.openSession();
+ try {
+ PropertyDto serverIdProperty = session.getMapper(PropertiesMapper.class).selectByKey(new PropertyDto().setKey(CoreProperties.SERVER_ID));
+ // this property can't be NULL
+ return serverIdProperty.getValue();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
public Status getStatus() {
return getStatus(getVersion(), LAST_VERSION);
}
diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java
index 9dbee6dbe21..1ec1e6b84aa 100644
--- a/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseVersionTest.java
@@ -46,6 +46,15 @@ public class DatabaseVersionTest extends DaoTestCase {
}
@Test
+ public void getSonarCoreId() {
+ setupData("getSonarCoreId");
+
+ String sonarCoreId = new DatabaseVersion(getMyBatis()).getSonarCoreId();
+
+ assertThat(sonarCoreId, is("123456"));
+ }
+
+ @Test
public void getStatus() {
assertThat(DatabaseVersion.getStatus(null, 150), is(DatabaseVersion.Status.FRESH_INSTALL));
assertThat(DatabaseVersion.getStatus(123, 150), is(DatabaseVersion.Status.REQUIRES_UPGRADE));
diff --git a/sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml b/sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml
new file mode 100644
index 00000000000..44b1e8eb5be
--- /dev/null
+++ b/sonar-core/src/test/resources/org/sonar/core/persistence/DatabaseVersionTest/getSonarCoreId.xml
@@ -0,0 +1,3 @@
+<dataset>
+ <properties id="1" prop_key="sonar.core.id" resource_id="[null]" text_value="123456" user_id="[null]"/>
+</dataset>