diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-08-28 13:24:15 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-09-13 15:50:48 +0200 |
commit | d42dbb96cbcefb6f631fc9ddb52ec8755e26f19e (patch) | |
tree | 28b33a5ef3cf44fae7a99a200d95640c31c4692d | |
parent | c7697d5366690c86f4a772c74fc621ee5d7b3edb (diff) | |
download | sonarqube-d42dbb96cbcefb6f631fc9ddb52ec8755e26f19e.tar.gz sonarqube-d42dbb96cbcefb6f631fc9ddb52ec8755e26f19e.zip |
SONAR-9739 improve integration tests of api/system/status
7 files changed, 299 insertions, 49 deletions
diff --git a/tests/plugins/server-plugin/src/main/java/ServerPlugin.java b/tests/plugins/server-plugin/src/main/java/ServerPlugin.java index 9ab0dd987de..c7f4c560a25 100644 --- a/tests/plugins/server-plugin/src/main/java/ServerPlugin.java +++ b/tests/plugins/server-plugin/src/main/java/ServerPlugin.java @@ -88,6 +88,6 @@ import static org.sonar.api.PropertyType.USER_LOGIN; public class ServerPlugin extends SonarPlugin { public List getExtensions() { return Arrays.asList( - StartupCrash.class, TempFolderExtension.class, PauseMetric.class, CePauseStep.class); + StartupCrash.class, ServerStartupLock.class, TempFolderExtension.class, PauseMetric.class, CePauseStep.class); } } diff --git a/tests/plugins/server-plugin/src/main/java/ServerStartupLock.java b/tests/plugins/server-plugin/src/main/java/ServerStartupLock.java new file mode 100644 index 00000000000..85aaef2213d --- /dev/null +++ b/tests/plugins/server-plugin/src/main/java/ServerStartupLock.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import java.io.File; +import java.util.Optional; +import org.sonar.api.Startable; +import org.sonar.api.config.Configuration; +import org.sonar.api.server.ServerSide; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; + +@ServerSide +public class ServerStartupLock implements Startable { + + private final Configuration configuration; + private static final Logger LOGGER = Loggers.get(ServerStartupLock.class); + + public ServerStartupLock(Configuration configuration) { + this.configuration = configuration; + } + + @Override + public void start() { + Optional<String> path = configuration.get("sonar.test.serverStartupLock.path"); + if (path.isPresent()) { + File lock = new File(path.get()); + try { + while (lock.exists()) { + LOGGER.info("ServerStartupLock - Waiting for file to be deleted: " + lock.getAbsolutePath()); + Thread.sleep(100L); + } + LOGGER.info("ServerStartupLock - File deleted. Resuming startup."); + } catch (InterruptedException e) { + LOGGER.info("ServerStartupLock - interrupted"); + Thread.currentThread().interrupt(); + } + } + } + + @Override + public void stop() { + // nothing to do + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/Category4Suite.java b/tests/src/test/java/org/sonarqube/tests/Category4Suite.java index 84d96dca189..26e5a65c75f 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category4Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category4Suite.java @@ -42,6 +42,7 @@ import org.sonarqube.tests.serverSystem.HttpHeadersTest; import org.sonarqube.tests.serverSystem.LogsTest; import org.sonarqube.tests.serverSystem.PingTest; import org.sonarqube.tests.serverSystem.ServerSystemTest; +import org.sonarqube.tests.serverSystem.SystemInfoTest; import org.sonarqube.tests.ui.SourceViewerTest; import org.sonarqube.tests.ui.UiExtensionsTest; import org.sonarqube.tests.ui.UiTest; @@ -63,6 +64,7 @@ import static util.ItUtils.xooPlugin; RootUserTest.class, // server system ServerSystemTest.class, + SystemInfoTest.class, PingTest.class, // user MyAccountPageTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java index 9ef6a74a20f..298d51dcabe 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java @@ -30,6 +30,7 @@ import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest import org.sonarqube.tests.rule.RuleEsResilienceTest; import org.sonarqube.tests.serverSystem.RestartTest; import org.sonarqube.tests.serverSystem.ServerSystemRestartingOrchestrator; +import org.sonarqube.tests.serverSystem.SystemStateTest; import org.sonarqube.tests.settings.ElasticsearchSettingsTest; import org.sonarqube.tests.settings.LicensesPageTest; import org.sonarqube.tests.settings.SettingsTestRestartingOrchestrator; @@ -52,6 +53,7 @@ import org.sonarqube.tests.user.UserEsResilienceTest; ServerSystemRestartingOrchestrator.class, RestartTest.class, SettingsTestRestartingOrchestrator.class, + SystemStateTest.class, LicensesPageTest.class, // update center UpdateCenterTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/serverSystem/ServerSystemTest.java b/tests/src/test/java/org/sonarqube/tests/serverSystem/ServerSystemTest.java index ed7784b3db9..5be7753116e 100644 --- a/tests/src/test/java/org/sonarqube/tests/serverSystem/ServerSystemTest.java +++ b/tests/src/test/java/org/sonarqube/tests/serverSystem/ServerSystemTest.java @@ -21,11 +21,9 @@ package org.sonarqube.tests.serverSystem; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; -import java.io.File; import java.io.IOException; import java.util.Map; import okhttp3.Response; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.json.simple.JSONValue; import org.junit.Before; @@ -67,18 +65,12 @@ public class ServerSystemTest { Map<String, Object> json = callStatus(); String version = (String) json.get("version"); - if (!startsWithAny(version, new String[] {"6."})) { + if (!startsWithAny(version, new String[]{"6."})) { fail("Bad version: " + version); } } @Test - public void get_server_status() { - Map<String, Object> json = callStatus(); - assertThat(json.get("status")).isEqualTo("UP"); - } - - @Test public void generate_server_id() throws IOException { Navigation nav = tester.openBrowser().openHome().logIn().submitCredentials(ADMIN_USER_LOGIN); String validIpAddress = getValidIpAddress(); @@ -109,44 +101,6 @@ public class ServerSystemTest { return ItUtils.jsonToMap(statusResponse.content()); } - @Test - public void display_system_info() { - tester.runHtmlTests("/serverSystem/ServerSystemTest/system_info.html"); - } - - @Test - public void download_system_info() throws Exception { - waitForComputeEngineToBeUp(orchestrator); - - WsResponse response = tester.wsClient().wsConnector().call( - new GetRequest("api/system/info")); - - assertThat(response.code()).isEqualTo(200); - - assertThat(response.content()).contains( - // SONAR-7436 monitor ES and CE - "\"Compute Engine Database Connection\":", "\"Compute Engine State\":", "\"Compute Engine Tasks\":", - "\"Elasticsearch\":", "\"State\":\"GREEN\"", - - // SONAR-7271 get settings - "\"Settings\":", "\"sonar.jdbc.url\":", "\"sonar.path.data\":"); - } - - private static void waitForComputeEngineToBeUp(Orchestrator orchestrator) throws IOException { - for (int i = 0; i < 10_000; i++) { - File logs = orchestrator.getServer().getCeLogs(); - if (FileUtils.readFileToString(logs).contains("Compute Engine is operational")) { - return; - } - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // ignored - } - } - throw new IllegalStateException("Compute Engine is not operational"); - } - /** * See http://jira.codehaus.org/browse/SONAR-2727 */ @@ -163,7 +117,7 @@ public class ServerSystemTest { */ @Test public void hide_jdbc_settings_to_non_admin() { - tester.runHtmlTests( "/serverSystem/ServerSystemTest/hide-jdbc-settings.html"); + tester.runHtmlTests("/serverSystem/ServerSystemTest/hide-jdbc-settings.html"); } @Test diff --git a/tests/src/test/java/org/sonarqube/tests/serverSystem/SystemInfoTest.java b/tests/src/test/java/org/sonarqube/tests/serverSystem/SystemInfoTest.java new file mode 100644 index 00000000000..62098db3749 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/serverSystem/SystemInfoTest.java @@ -0,0 +1,91 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarqube.tests.serverSystem; + +import com.sonar.orchestrator.Orchestrator; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import org.apache.commons.io.FileUtils; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.tests.Category4Suite; +import org.sonarqube.tests.Tester; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsResponse; +import util.ItUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SystemInfoTest { + + private static final String ADMIN_USER_LOGIN = "admin-user"; + + @ClassRule + public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator).disableOrganizations(); + + @Test + public void test_system_info_page() { + tester.users().generateAdministrator(u -> u.setLogin(ADMIN_USER_LOGIN).setPassword(ADMIN_USER_LOGIN)); + tester.runHtmlTests("/serverSystem/ServerSystemTest/system_info.html"); + } + + @Test + public void test_system_info_web_service() throws Exception { + waitForComputeEngineToBeUp(orchestrator); + + WsResponse response = tester.wsClient().wsConnector().call( + new GetRequest("api/system/info")); + + assertThat(response.code()).isEqualTo(200); + Map<String, Object> json = ItUtils.jsonToMap(response.content()); + + // SONAR-7436 monitor ES and CE + assertThat((Map)json.get("Compute Engine Database Connection")).isNotEmpty(); + assertThat((Map)json.get("Compute Engine State")).isNotEmpty(); + assertThat((Map)json.get("Compute Engine Tasks")).isNotEmpty(); + Map<String,Object> esJson = (Map) json.get("Elasticsearch"); + assertThat(esJson.get("State")).isEqualTo("GREEN"); + + // SONAR-7271 get settings + Map<String,Object> settingsJson = (Map) json.get("Settings"); + assertThat(settingsJson.get("sonar.jdbc.url")).isNotNull(); + assertThat(settingsJson.get("sonar.path.data")).isNotNull(); + } + + private static void waitForComputeEngineToBeUp(Orchestrator orchestrator) throws IOException { + for (int i = 0; i < 10_000; i++) { + File logs = orchestrator.getServer().getCeLogs(); + if (FileUtils.readFileToString(logs).contains("Compute Engine is operational")) { + return; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // ignored + } + } + throw new IllegalStateException("Compute Engine is not operational"); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/serverSystem/SystemStateTest.java b/tests/src/test/java/org/sonarqube/tests/serverSystem/SystemStateTest.java new file mode 100644 index 00000000000..b0ac4666913 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/serverSystem/SystemStateTest.java @@ -0,0 +1,140 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarqube.tests.serverSystem; + +import com.sonar.orchestrator.Orchestrator; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import org.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsClient; +import org.sonarqube.ws.client.WsResponse; +import util.ItUtils; + +import static com.google.common.base.Preconditions.checkState; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.newWsClient; +import static util.ItUtils.pluginArtifact; + +/** + * Test system status and health + */ +public class SystemStateTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); + + @Test + public void system_status_becomes_UP_when_web_server_is_started() throws Exception { + try (Commander commander = new Commander()) { + commander.startAsync(); + + commander.waitFor(() -> commander.webLogsContain("ServerStartupLock - Waiting for file to be deleted")); + assertThat(commander.status()).hasValue("STARTING"); + + commander.unlock(); + commander.waitFor(() -> "UP".equals(commander.status().orElse(null))); + } + } + + private class Commander implements AutoCloseable { + private final File lock = temp.newFile(); + private final Orchestrator orchestrator = Orchestrator.builderEnv() + .addPlugin(pluginArtifact("server-plugin")) + .setServerProperty("sonar.test.serverStartupLock.path", lock.getCanonicalPath()) + .build(); + private Thread starter; + + Commander() throws Exception { + + } + + void startAsync() { + checkState(starter == null); + starter = new Thread(orchestrator::start); + starter.start(); + while (orchestrator.getServer() == null) { + sleep(100L); + } + } + + void unlock() throws IOException { + FileUtils.forceDelete(lock); + } + + boolean webLogsContain(String message) { + try { + return FileUtils.readFileToString(orchestrator.getServer().getWebLogs()).contains(message); + } catch (IOException e) { + return false; + } + } + + void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + void waitFor(Supplier<Boolean> predicate) { + while (!predicate.get()) { + sleep(100L); + } + } + + Optional<String> status() { + if (orchestrator.getServer() != null) { + WsClient wsClient = newWsClient(orchestrator); + try { + WsResponse statusResponse = wsClient.wsConnector().call(new GetRequest("api/system/status")); + if (statusResponse.isSuccessful()) { + Map<String, Object> json = ItUtils.jsonToMap(statusResponse.content()); + return Optional.ofNullable((String) json.get("status")); + } + } catch (Exception e) { + // server does not accept connections + } + } + return Optional.empty(); + } + + @Override + public void close() { + if (starter != null) { + starter.interrupt(); + orchestrator.stop(); + } + } + } +} |