aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-ws-client
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-10-15 09:50:37 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2013-10-15 09:51:19 +0200
commit74d69a407524f52b5194264918654fcf68f3e34e (patch)
tree13afa374630c90719ccd2a498514d653ea017ea8 /sonar-ws-client
parent7b463fa85d8a00bd1dfed220634258a67658ef8f (diff)
downloadsonarqube-74d69a407524f52b5194264918654fcf68f3e34e.tar.gz
sonarqube-74d69a407524f52b5194264918654fcf68f3e34e.zip
SONAR-4777 Asynchronous web service to upgrade database
Diffstat (limited to 'sonar-ws-client')
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java6
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/system/Migration.java43
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/system/SystemClient.java36
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultMigration.java38
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultSystemClient.java76
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/package-info.java22
-rw-r--r--sonar-ws-client/src/main/java/org/sonar/wsclient/system/package-info.java22
-rw-r--r--sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java2
-rw-r--r--sonar-ws-client/src/test/java/org/sonar/wsclient/system/internal/DefaultSystemClientTest.java98
9 files changed, 343 insertions, 0 deletions
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java
index 04d4c1b7964..aefd3e382b1 100644
--- a/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java
@@ -28,6 +28,8 @@ import org.sonar.wsclient.permissions.PermissionClient;
import org.sonar.wsclient.permissions.internal.DefaultPermissionClient;
import org.sonar.wsclient.project.ProjectClient;
import org.sonar.wsclient.project.internal.DefaultProjectClient;
+import org.sonar.wsclient.system.SystemClient;
+import org.sonar.wsclient.system.internal.DefaultSystemClient;
import org.sonar.wsclient.user.UserClient;
import org.sonar.wsclient.user.internal.DefaultUserClient;
@@ -101,6 +103,10 @@ public class SonarClient {
return new DefaultProjectClient(requestFactory);
}
+ public SystemClient systemClient() {
+ return new DefaultSystemClient(requestFactory);
+ }
+
/**
* Create a builder of {@link SonarClient}s.
*/
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/system/Migration.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/Migration.java
new file mode 100644
index 00000000000..8891d96f939
--- /dev/null
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/Migration.java
@@ -0,0 +1,43 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.wsclient.system;
+
+import javax.annotation.Nullable;
+import java.util.Date;
+
+/**
+ * @since 4.0
+ */
+public interface Migration {
+ enum Status {
+ MIGRATION_NEEDED, MIGRATION_RUNNING, MIGRATION_FAILED,
+ MIGRATION_SUCCEEDED, NO_MIGRATION
+ }
+
+ boolean operationalWebapp();
+
+ Status status();
+
+ @Nullable
+ String message();
+
+ @Nullable
+ Date startedAt();
+}
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/system/SystemClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/SystemClient.java
new file mode 100644
index 00000000000..d14377d3f32
--- /dev/null
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/SystemClient.java
@@ -0,0 +1,36 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.wsclient.system;
+
+/**
+ * @since 4.0
+ */
+public interface SystemClient {
+ /**
+ * Asynchronously start a database migration. No effect if executed
+ * several times.
+ */
+ Migration migrate();
+
+ /**
+ * Synchronously start a database migration.
+ */
+ Migration migrate(long timeoutInSeconds, long rateInSeconds);
+}
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultMigration.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultMigration.java
new file mode 100644
index 00000000000..2aa90de9b94
--- /dev/null
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultMigration.java
@@ -0,0 +1,38 @@
+package org.sonar.wsclient.system.internal;
+
+import org.sonar.wsclient.system.Migration;
+import org.sonar.wsclient.unmarshallers.JsonUtils;
+
+import javax.annotation.Nullable;
+import java.util.Date;
+import java.util.Map;
+
+public class DefaultMigration implements Migration {
+
+ private final Map json;
+
+ public DefaultMigration(Map json) {
+ this.json = json;
+ }
+
+ @Override
+ public boolean operationalWebapp() {
+ return JsonUtils.getBoolean(json, "operational");
+ }
+
+ @Override
+ public Status status() {
+ return Status.valueOf(JsonUtils.getString(json, "state"));
+ }
+
+ @Override
+ public String message() {
+ return JsonUtils.getString(json, "message");
+ }
+
+ @Override
+ @Nullable
+ public Date startedAt() {
+ return JsonUtils.getDateTime(json, "startedAt");
+ }
+}
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultSystemClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultSystemClient.java
new file mode 100644
index 00000000000..86781a7cdfd
--- /dev/null
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/DefaultSystemClient.java
@@ -0,0 +1,76 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.wsclient.system.internal;
+
+import org.json.simple.JSONValue;
+import org.sonar.wsclient.internal.HttpRequestFactory;
+import org.sonar.wsclient.system.Migration;
+import org.sonar.wsclient.system.SystemClient;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DefaultSystemClient implements SystemClient {
+
+ private final HttpRequestFactory requestFactory;
+
+ public DefaultSystemClient(HttpRequestFactory requestFactory) {
+ this.requestFactory = requestFactory;
+ }
+
+ @Override
+ public Migration migrate() {
+ String json = requestFactory.post("/api/server/setup", new HashMap<String, Object>());
+ return jsonToMigration(json);
+ }
+
+ @Override
+ public Migration migrate(long timeoutInMs, long rateInMs) {
+ if (rateInMs >= timeoutInMs) {
+ throw new IllegalArgumentException("Timeout must be greater than rate");
+ }
+ Migration migration = null;
+ boolean running = true;
+ long endAt = System.currentTimeMillis() + timeoutInMs;
+ while (running && System.currentTimeMillis() < endAt) {
+ migration = migrate();
+ if (migration.status() == Migration.Status.MIGRATION_NEEDED ||
+ migration.status() == Migration.Status.MIGRATION_RUNNING) {
+ sleepQuietly(rateInMs);
+ } else {
+ running = false;
+ }
+ }
+ return migration;
+ }
+
+ private void sleepQuietly(long rateInMs) {
+ try {
+ Thread.sleep(rateInMs);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException("Fail to sleep!", e);
+ }
+ }
+
+ private Migration jsonToMigration(String json) {
+ Map jsonRoot = (Map) JSONValue.parse(json);
+ return new DefaultMigration(jsonRoot);
+ }
+}
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/package-info.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/package-info.java
new file mode 100644
index 00000000000..3cb9011d7f8
--- /dev/null
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/internal/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.wsclient.system.internal;
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/system/package-info.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/package-info.java
new file mode 100644
index 00000000000..433b6d9424b
--- /dev/null
+++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/system/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.wsclient.system;
diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java
index cb1516a9db9..92741d41d26 100644
--- a/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java
+++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java
@@ -24,6 +24,7 @@ import org.sonar.wsclient.issue.internal.DefaultActionPlanClient;
import org.sonar.wsclient.issue.internal.DefaultIssueClient;
import org.sonar.wsclient.permissions.internal.DefaultPermissionClient;
import org.sonar.wsclient.project.internal.DefaultProjectClient;
+import org.sonar.wsclient.system.internal.DefaultSystemClient;
import org.sonar.wsclient.user.internal.DefaultUserClient;
import static org.fest.assertions.Assertions.assertThat;
@@ -38,6 +39,7 @@ public class SonarClientTest {
assertThat(client.userClient()).isNotNull().isInstanceOf(DefaultUserClient.class);
assertThat(client.permissionClient()).isNotNull().isInstanceOf(DefaultPermissionClient.class);
assertThat(client.projectClient()).isNotNull().isInstanceOf(DefaultProjectClient.class);
+ assertThat(client.systemClient()).isNotNull().isInstanceOf(DefaultSystemClient.class);
}
@Test
diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/system/internal/DefaultSystemClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/system/internal/DefaultSystemClientTest.java
new file mode 100644
index 00000000000..fffc6c83a88
--- /dev/null
+++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/system/internal/DefaultSystemClientTest.java
@@ -0,0 +1,98 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.wsclient.system.internal;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.wsclient.MockHttpServerInterceptor;
+import org.sonar.wsclient.internal.HttpRequestFactory;
+import org.sonar.wsclient.system.Migration;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DefaultSystemClientTest {
+
+ static final String RUNNING_JSON = "{\"status\": \"KO\", \"state\": \"MIGRATION_RUNNING\", " +
+ "\"operational\": false, \"startedAt\": \"2013-12-20T12:34:56+0100\"}";
+
+ static final String DONE_JSON = "{\"status\": \"OK\", \"state\": \"MIGRATION_SUCCEEDED\", " +
+ "\"operational\": true, \"message\": \"done\"}";
+
+ @Rule
+ public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor();
+
+ @Test
+ public void start_migration_asynchronously() {
+ HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url());
+ httpServer.stubResponseBody(RUNNING_JSON);
+
+ DefaultSystemClient client = new DefaultSystemClient(requestFactory);
+ Migration migration = client.migrate();
+
+ assertThat(httpServer.requestedPath()).isEqualTo("/api/server/setup");
+ assertThat(migration.status()).isEqualTo(Migration.Status.MIGRATION_RUNNING);
+ assertThat(migration.operationalWebapp()).isFalse();
+ assertThat(migration.startedAt().getYear()).isEqualTo(113);//2013 = nb of years since 1900
+ }
+
+ @Test
+ public void fail_if_rate_is_greater_than_timeout() throws Exception {
+ try {
+ DefaultSystemClient client = new DefaultSystemClient(mock(HttpRequestFactory.class));
+ client.migrate(5L, 50L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).isEqualTo("Timeout must be greater than rate");
+ }
+ }
+
+ @Test
+ public void stop_synchronous_migration_on_timeout() {
+ HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url());
+ httpServer.stubResponseBody(RUNNING_JSON);
+
+ DefaultSystemClient client = new DefaultSystemClient(requestFactory);
+ Migration migration = client.migrate(50L, 5L);
+
+ assertThat(migration.status()).isEqualTo(Migration.Status.MIGRATION_RUNNING);
+ assertThat(migration.operationalWebapp()).isFalse();
+ }
+
+ @Test
+ public void return_result_before_timeout_of_synchronous_migration() {
+ HttpRequestFactory requestFactory = mock(HttpRequestFactory.class);
+ when(requestFactory.post(eq("/api/server/setup"), anyMap())).thenReturn(
+ RUNNING_JSON, DONE_JSON
+ );
+
+ DefaultSystemClient client = new DefaultSystemClient(requestFactory);
+ Migration migration = client.migrate(50L, 5L);
+
+ assertThat(migration.status()).isEqualTo(Migration.Status.MIGRATION_SUCCEEDED);
+ assertThat(migration.operationalWebapp()).isTrue();
+ assertThat(migration.message()).isEqualTo("done");
+ assertThat(migration.startedAt()).isNull();
+ }
+}