From f9d6d236fe015483086c06993c16826375e78b9e Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Tue, 15 Jun 2021 15:53:40 -0500 Subject: [PATCH] Improve test coverage --- server/sonar-ce/build.gradle | 1 + .../org/sonar/ce/app/CeSecurityManager.java | 51 +++++++++ .../main/java/org/sonar/ce/app/CeServer.java | 18 +-- .../sonar/ce/app/CeSecurityManagerTest.java | 61 ++++++++++ .../java/org/sonar/ce/app/CeServerTest.java | 108 +++++++++++------- .../sonar/process/PluginSecurityManager.java | 14 +-- .../process/PluginSecurityManagerTest.java | 10 ++ .../sonar/server/app/WebSecurityManager.java | 49 ++++++++ .../java/org/sonar/server/app/WebServer.java | 9 +- .../server/app/WebSecurityManagerTest.java | 60 ++++++++++ .../org/sonar/server/app/WebServerTest.java | 37 ++++++ 11 files changed, 347 insertions(+), 71 deletions(-) create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/app/CeSecurityManager.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/app/CeSecurityManagerTest.java create mode 100644 server/sonar-webserver/src/main/java/org/sonar/server/app/WebSecurityManager.java create mode 100644 server/sonar-webserver/src/test/java/org/sonar/server/app/WebSecurityManagerTest.java create mode 100644 server/sonar-webserver/src/test/java/org/sonar/server/app/WebServerTest.java diff --git a/server/sonar-ce/build.gradle b/server/sonar-ce/build.gradle index 7590ef78620..8a3a736e2d5 100644 --- a/server/sonar-ce/build.gradle +++ b/server/sonar-ce/build.gradle @@ -32,6 +32,7 @@ dependencies { testCompile 'com.tngtech.java:junit-dataprovider' testCompile 'junit:junit' testCompile 'org.assertj:assertj-core' + testCompile 'org.awaitility:awaitility' testCompile 'org.mockito:mockito-core' testCompile 'org.slf4j:slf4j-api' diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/app/CeSecurityManager.java b/server/sonar-ce/src/main/java/org/sonar/ce/app/CeSecurityManager.java new file mode 100644 index 00000000000..0543fd5c438 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/app/CeSecurityManager.java @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.sonar.ce.app; + +import org.sonar.ce.security.PluginCeRule; +import org.sonar.process.PluginFileWriteRule; +import org.sonar.process.PluginSecurityManager; +import org.sonar.process.ProcessProperties; +import org.sonar.process.Props; + +public class CeSecurityManager { + private final PluginSecurityManager pluginSecurityManager; + private final Props props; + + private boolean applied; + + public CeSecurityManager(PluginSecurityManager pluginSecurityManager, Props props) { + this.pluginSecurityManager = pluginSecurityManager; + this.props = props; + } + + public void apply() { + if (applied) { + throw new IllegalStateException("can't apply twice"); + } + applied = true; + + PluginFileWriteRule writeRule = new PluginFileWriteRule( + props.nonNullValueAsFile(ProcessProperties.Property.PATH_HOME.getKey()).toPath(), + props.nonNullValueAsFile(ProcessProperties.Property.PATH_TEMP.getKey()).toPath()); + PluginCeRule ceRule = new PluginCeRule(); + pluginSecurityManager.restrictPlugins(writeRule, ceRule); + } +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/app/CeServer.java b/server/sonar-ce/src/main/java/org/sonar/ce/app/CeServer.java index c26f2857dbd..bb2c9145c49 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/app/CeServer.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/app/CeServer.java @@ -29,13 +29,10 @@ import org.sonar.ce.ComputeEngine; import org.sonar.ce.ComputeEngineImpl; import org.sonar.ce.container.ComputeEngineContainerImpl; import org.sonar.ce.logging.CeProcessLogging; -import org.sonar.ce.security.PluginCeRule; import org.sonar.process.MinimumViableSystem; import org.sonar.process.Monitored; -import org.sonar.process.PluginFileWriteRule; import org.sonar.process.PluginSecurityManager; import org.sonar.process.ProcessEntryPoint; -import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static com.google.common.base.Preconditions.checkState; @@ -52,14 +49,14 @@ public class CeServer implements Monitored { private static final String CE_MAIN_THREAD_NAME = "ce-main"; - private CountDownLatch awaitStop = new CountDownLatch(1); - + private final CountDownLatch awaitStop = new CountDownLatch(1); private final ComputeEngine computeEngine; @Nullable private CeMainThread ceMainThread = null; @VisibleForTesting - protected CeServer(ComputeEngine computeEngine, MinimumViableSystem mvs) { + protected CeServer(ComputeEngine computeEngine, MinimumViableSystem mvs, CeSecurityManager securityManager) { + securityManager.apply(); this.computeEngine = computeEngine; mvs .checkWritableTempDir() @@ -121,15 +118,10 @@ public class CeServer implements Monitored { Props props = entryPoint.getProps(); new CeProcessLogging().configure(props); - PluginFileWriteRule writeRule = new PluginFileWriteRule( - props.nonNullValueAsFile(ProcessProperties.Property.PATH_HOME.getKey()).toPath(), - props.nonNullValueAsFile(ProcessProperties.Property.PATH_TEMP.getKey()).toPath()); - PluginCeRule ceRule = new PluginCeRule(); - PluginSecurityManager.restrictPlugins(writeRule, ceRule); - CeServer server = new CeServer( new ComputeEngineImpl(props, new ComputeEngineContainerImpl()), - new MinimumViableSystem()); + new MinimumViableSystem(), + new CeSecurityManager(new PluginSecurityManager(), props)); entryPoint.launch(server); } diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/app/CeSecurityManagerTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/app/CeSecurityManagerTest.java new file mode 100644 index 00000000000..b96ab585c21 --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/app/CeSecurityManagerTest.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.sonar.ce.app; + +import java.util.Properties; +import org.junit.Test; +import org.sonar.ce.security.PluginCeRule; +import org.sonar.process.PluginFileWriteRule; +import org.sonar.process.PluginSecurityManager; +import org.sonar.process.Props; + +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.sonar.process.ProcessProperties.Property.PATH_HOME; +import static org.sonar.process.ProcessProperties.Property.PATH_TEMP; + +public class CeSecurityManagerTest { + private final PluginSecurityManager pluginSecurityManager = mock(PluginSecurityManager.class); + + @Test + public void apply_calls_PluginSecurityManager() { + Properties properties = new Properties(); + properties.setProperty(PATH_HOME.getKey(), "home"); + properties.setProperty(PATH_TEMP.getKey(), "temp"); + Props props = new Props(properties); + CeSecurityManager ceSecurityManager = new CeSecurityManager(pluginSecurityManager, props); + ceSecurityManager.apply(); + + verify(pluginSecurityManager).restrictPlugins(any(PluginFileWriteRule.class), any(PluginCeRule.class)); + } + + @Test + public void fail_if_runs_twice() { + Properties properties = new Properties(); + properties.setProperty(PATH_HOME.getKey(), "home"); + properties.setProperty(PATH_TEMP.getKey(), "temp"); + Props props = new Props(properties); + CeSecurityManager ceSecurityManager = new CeSecurityManager(pluginSecurityManager, props); + ceSecurityManager.apply(); + assertThrows(IllegalStateException.class, ceSecurityManager::apply); + } +} diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/app/CeServerTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/app/CeServerTest.java index 073ebe748db..a30c17c4f4a 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/app/CeServerTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/app/CeServerTest.java @@ -19,7 +19,11 @@ */ package org.sonar.ce.app; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.junit.After; @@ -29,16 +33,21 @@ import org.junit.rules.DisableOnDebug; import org.junit.rules.ExpectedException; import org.junit.rules.TestRule; import org.junit.rules.Timeout; +import org.junit.runner.RunWith; import org.mockito.Mockito; import org.sonar.ce.ComputeEngine; +import org.sonar.process.MessageException; import org.sonar.process.MinimumViableSystem; import org.sonar.process.Monitored; import static com.google.common.base.Preconditions.checkState; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +@RunWith(DataProviderRunner.class) public class CeServerTest { @Rule public TestRule safeguardTimeout = new DisableOnDebug(Timeout.seconds(60)); @@ -48,6 +57,7 @@ public class CeServerTest { private CeServer underTest = null; private Thread waitingThread = null; private MinimumViableSystem minimumViableSystem = mock(MinimumViableSystem.class, Mockito.RETURNS_MOCKS); + private CeSecurityManager ceSecurityManager = mock(CeSecurityManager.class); @After public void tearDown() throws Exception { @@ -64,12 +74,16 @@ public class CeServerTest { @Test public void constructor_does_not_start_a_new_Thread() { int activeCount = Thread.activeCount(); - newCeServer(); - assertThat(Thread.activeCount()).isSameAs(activeCount); } + @Test + public void constructor_calls_ceSecurityManager() { + newCeServer(); + verify(ceSecurityManager).apply(); + } + @Test public void awaitStop_throws_ISE_if_called_before_start() { CeServer ceServer = newCeServer(); @@ -89,6 +103,31 @@ public class CeServerTest { assertThat(Thread.activeCount()).isSameAs(activeCount + 1); } + @Test + public void stop_stops_Thread() { + CeServer ceServer = newCeServer(); + assertThat(ceThreadExists()).isFalse(); + ceServer.start(); + assertThat(ceThreadExists()).isTrue(); + ceServer.stop(); + await().atMost(5, TimeUnit.SECONDS).until(() -> !ceThreadExists()); + } + + @Test + public void stop_dontDoAnythingIfThreadDoesntExist() { + CeServer ceServer = newCeServer(); + assertThat(ceThreadExists()).isFalse(); + + ceServer.stop(); + + //expect no exception and thread still doesn't exist + assertThat(ceThreadExists()).isFalse(); + } + + private static boolean ceThreadExists() { + return Thread.getAllStackTraces().keySet().stream().anyMatch(t -> t.getName().equals("ce-main")); + } + @Test public void start_throws_ISE_when_called_twice() { CeServer ceServer = newCeServer(); @@ -123,17 +162,13 @@ public class CeServerTest { // release ComputeEngine startup method computeEngine.releaseStartup(); - while (ceServer.getStatus() == Monitored.Status.DOWN) { - // wait for isReady to change to true, otherwise test will fail with timeout - } - assertThat(ceServer.getStatus()).isEqualTo(Monitored.Status.OPERATIONAL); + await().atMost(5, TimeUnit.SECONDS).until(() -> ceServer.getStatus() == Monitored.Status.OPERATIONAL); } @Test - public void getStatus_returns_OPERATIONAL_when_ComputeEngine_startup_throws_any_Exception_or_Error() { - Throwable startupException = new Throwable("Faking failing ComputeEngine#startup()"); - - BlockingStartupComputeEngine computeEngine = new BlockingStartupComputeEngine(startupException); + @UseDataProvider("exceptions") + public void getStatus_returns_FAILED_when_ComputeEngine_startup_throws_any_Exception_or_Error(RuntimeException exception) { + BlockingStartupComputeEngine computeEngine = new BlockingStartupComputeEngine(exception); CeServer ceServer = newCeServer(computeEngine); ceServer.start(); @@ -143,10 +178,12 @@ public class CeServerTest { // release ComputeEngine startup method which will throw startupException computeEngine.releaseStartup(); - while (ceServer.getStatus() == Monitored.Status.DOWN) { - // wait for isReady to change to not DOWN, otherwise test will fail with timeout - } - assertThat(ceServer.getStatus()).isEqualTo(Monitored.Status.OPERATIONAL); + await().atMost(5, TimeUnit.SECONDS).until(() -> ceServer.getStatus() == Monitored.Status.FAILED); + } + + @DataProvider + public static Object[] exceptions() { + return new Object[] {new MessageException("exception"), new IllegalStateException("Faking failing ComputeEngine#startup()")}; } @Test @@ -194,6 +231,15 @@ public class CeServerTest { ceServer.awaitStop(); } + @Test + public void staticMain_withoutAnyArguments_expectException() { + String[] emptyArray = {}; + + expectedException.expectMessage("Only a single command-line argument is accepted (absolute path to configuration file)"); + + CeServer.main(emptyArray); + } + @Test public void stop_releases_thread_in_awaitStop_even_when_ComputeEngine_shutdown_fails() throws InterruptedException { final CeServer ceServer = newCeServer(new ComputeEngine() { @@ -223,13 +269,12 @@ public class CeServerTest { } private CeServer newCeServer() { - return newCeServer(DoNothingComputeEngine.INSTANCE); + return newCeServer(mock(ComputeEngine.class)); } private CeServer newCeServer(ComputeEngine computeEngine) { checkState(this.underTest == null, "Only one CeServer can be created per test method"); - this.underTest = new CeServer( - computeEngine, minimumViableSystem); + this.underTest = new CeServer(computeEngine, minimumViableSystem, ceSecurityManager); return underTest; } @@ -243,9 +288,9 @@ public class CeServerTest { private static class BlockingStartupComputeEngine implements ComputeEngine { private final CountDownLatch latch = new CountDownLatch(1); @CheckForNull - private final Throwable throwable; + private final RuntimeException throwable; - public BlockingStartupComputeEngine(@Nullable Throwable throwable) { + public BlockingStartupComputeEngine(@Nullable RuntimeException throwable) { this.throwable = throwable; } @@ -257,11 +302,7 @@ public class CeServerTest { throw new RuntimeException("await failed", e); } if (throwable != null) { - if (throwable instanceof Error) { - throw (Error) throwable; - } else if (throwable instanceof RuntimeException) { - throw (RuntimeException) throwable; - } + throw throwable; } } @@ -279,23 +320,4 @@ public class CeServerTest { this.latch.countDown(); } } - - private enum DoNothingComputeEngine implements ComputeEngine { - INSTANCE; - - @Override - public void startup() { - // do nothing - } - - @Override - public void stopProcessing() { - // do nothing - } - - @Override - public void shutdown() { - // do nothing - } - } } diff --git a/server/sonar-process/src/main/java/org/sonar/process/PluginSecurityManager.java b/server/sonar-process/src/main/java/org/sonar/process/PluginSecurityManager.java index 412cb42fb52..675b5035e42 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/PluginSecurityManager.java +++ b/server/sonar-process/src/main/java/org/sonar/process/PluginSecurityManager.java @@ -26,19 +26,19 @@ import java.security.Permissions; import java.security.Policy; import java.security.ProtectionDomain; import java.security.Security; -import java.util.Arrays; import java.util.List; public class PluginSecurityManager { private static final String CACHE_TTL_KEY = "networkaddress.cache.ttl"; + private boolean alreadyRan = false; - private PluginSecurityManager() { - // static only - } - - public static void restrictPlugins(PluginPolicyRule... rules) { + public void restrictPlugins(PluginPolicyRule... rules) { + if (alreadyRan) { + throw new IllegalStateException("can't run twice"); + } + alreadyRan = true; SecurityManager sm = new SecurityManager(); - Policy.setPolicy(new PluginPolicy(Arrays.asList(rules))); + Policy.setPolicy(new PluginPolicy(List.of(rules))); System.setSecurityManager(sm); // SONAR-14870 By default, with a security manager installed, the DNS cache never times out. See InetAddressCachePolicy. if (Security.getProperty(CACHE_TTL_KEY) == null) { diff --git a/server/sonar-process/src/test/java/org/sonar/process/PluginSecurityManagerTest.java b/server/sonar-process/src/test/java/org/sonar/process/PluginSecurityManagerTest.java index 34e97485733..c15f7437f90 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/PluginSecurityManagerTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/PluginSecurityManagerTest.java @@ -20,6 +20,7 @@ package org.sonar.process; import java.security.Permission; +import java.security.Policy; import java.security.ProtectionDomain; import java.util.Arrays; import javax.management.MBeanPermission; @@ -40,6 +41,15 @@ public class PluginSecurityManagerTest { private final PluginPolicyRule rule1 = mock(PluginPolicyRule.class); private final PluginPolicyRule rule2 = mock(PluginPolicyRule.class); + @Test + public void constructor_dontSetAnyPolicy() { + Policy policy = Policy.getPolicy(); + + new PluginSecurityManager(); + + assertThat(policy).isEqualTo(Policy.getPolicy()); + } + @Test public void protection_domain_can_have_no_classloader() { PluginSecurityManager.PluginPolicy policy = new PluginSecurityManager.PluginPolicy(Arrays.asList(rule1, rule2)); diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/app/WebSecurityManager.java b/server/sonar-webserver/src/main/java/org/sonar/server/app/WebSecurityManager.java new file mode 100644 index 00000000000..f17b076b9ba --- /dev/null +++ b/server/sonar-webserver/src/main/java/org/sonar/server/app/WebSecurityManager.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.sonar.server.app; + +import org.sonar.process.PluginFileWriteRule; +import org.sonar.process.PluginSecurityManager; +import org.sonar.process.ProcessProperties; +import org.sonar.process.Props; + +public class WebSecurityManager { + private final PluginSecurityManager pluginSecurityManager; + private final Props props; + + private boolean applied; + + public WebSecurityManager(PluginSecurityManager pluginSecurityManager, Props props) { + this.pluginSecurityManager = pluginSecurityManager; + this.props = props; + } + + public void apply() { + if (applied) { + throw new IllegalStateException("can't apply twice"); + } + applied = true; + + PluginFileWriteRule writeRule = new PluginFileWriteRule( + props.nonNullValueAsFile(ProcessProperties.Property.PATH_HOME.getKey()).toPath(), + props.nonNullValueAsFile(ProcessProperties.Property.PATH_TEMP.getKey()).toPath()); + pluginSecurityManager.restrictPlugins(writeRule); + } +} diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/app/WebServer.java b/server/sonar-webserver/src/main/java/org/sonar/server/app/WebServer.java index a3ddfc67900..12c959c986d 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/app/WebServer.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/app/WebServer.java @@ -24,11 +24,9 @@ import java.io.File; import org.slf4j.LoggerFactory; import org.sonar.process.MinimumViableSystem; import org.sonar.process.Monitored; -import org.sonar.process.PluginFileWriteRule; import org.sonar.process.PluginSecurityManager; import org.sonar.process.ProcessEntryPoint; import org.sonar.process.ProcessId; -import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; @@ -98,12 +96,7 @@ public class WebServer implements Monitored { ProcessEntryPoint entryPoint = ProcessEntryPoint.createForArguments(args); Props props = entryPoint.getProps(); new WebServerProcessLogging().configure(props); - - - PluginFileWriteRule writeRule = new PluginFileWriteRule( - props.nonNullValueAsFile(ProcessProperties.Property.PATH_HOME.getKey()).toPath(), - props.nonNullValueAsFile(ProcessProperties.Property.PATH_TEMP.getKey()).toPath()); - PluginSecurityManager.restrictPlugins(writeRule); + new WebSecurityManager(new PluginSecurityManager(), props).apply(); WebServer server = new WebServer(props); entryPoint.launch(server); diff --git a/server/sonar-webserver/src/test/java/org/sonar/server/app/WebSecurityManagerTest.java b/server/sonar-webserver/src/test/java/org/sonar/server/app/WebSecurityManagerTest.java new file mode 100644 index 00000000000..4d3c71eaadd --- /dev/null +++ b/server/sonar-webserver/src/test/java/org/sonar/server/app/WebSecurityManagerTest.java @@ -0,0 +1,60 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.sonar.server.app; + +import java.util.Properties; +import org.junit.Test; +import org.sonar.process.PluginFileWriteRule; +import org.sonar.process.PluginSecurityManager; +import org.sonar.process.Props; + +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.sonar.process.ProcessProperties.Property.PATH_HOME; +import static org.sonar.process.ProcessProperties.Property.PATH_TEMP; + +public class WebSecurityManagerTest { + private final PluginSecurityManager pluginSecurityManager = mock(PluginSecurityManager.class); + + @Test + public void apply_calls_PluginSecurityManager() { + Properties properties = new Properties(); + properties.setProperty(PATH_HOME.getKey(), "home"); + properties.setProperty(PATH_TEMP.getKey(), "temp"); + Props props = new Props(properties); + WebSecurityManager securityManager = new WebSecurityManager(pluginSecurityManager, props); + securityManager.apply(); + + verify(pluginSecurityManager).restrictPlugins(any(PluginFileWriteRule.class)); + } + + @Test + public void fail_if_runs_twice() { + Properties properties = new Properties(); + properties.setProperty(PATH_HOME.getKey(), "home"); + properties.setProperty(PATH_TEMP.getKey(), "temp"); + Props props = new Props(properties); + WebSecurityManager securityManager = new WebSecurityManager(pluginSecurityManager, props); + securityManager.apply(); + assertThrows(IllegalStateException.class, securityManager::apply); + } +} diff --git a/server/sonar-webserver/src/test/java/org/sonar/server/app/WebServerTest.java b/server/sonar-webserver/src/test/java/org/sonar/server/app/WebServerTest.java new file mode 100644 index 00000000000..88258837d09 --- /dev/null +++ b/server/sonar-webserver/src/test/java/org/sonar/server/app/WebServerTest.java @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.sonar.server.app; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; + +public class WebServerTest { + + @Test + public void main_givenNoArguments() { + String[] arguments = {}; + + ThrowingRunnable runnable = () -> WebServer.main(arguments); + + Assert.assertThrows("Only a single command-line argument is accepted (absolute path to configuration file)", + IllegalArgumentException.class, runnable); + } +} -- 2.39.5