Repository: dropwizard/dropwizard
Issue: DropwizardTestSupport should clean system properties (config overrides) on service startup failure

We had a few test classes using both `DropwizardAppRule` and `DropwizardClientRule` (`DropwizardClientRule` around `DropwizardAppRule`). The service started by the `DropwizardAppRule` would fail on startup because of some environment problem. The _config override_ properties would stick around for the following tests causing unexpected behavior.

The problem seems to be that in the `before` method, overrides are set as system properties but are not cleaned/reset in case the service fails to start.

```java
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.Application;
import io.dropwizard.Configuration;
import io.dropwizard.setup.Environment;
import io.dropwizard.testing.ConfigOverride;
import io.dropwizard.testing.DropwizardTestSupport;
import io.dropwizard.testing.ResourceHelpers;
import org.junit.Test;
import org.junit.runners.model.Statement;

import static junit.framework.TestCase.assertNull;

public class IntTestReproduce {

    @Test
    public void dropwizardTestSupportShouldCleanSystemPropertiesOnServiceStartupFailure() {
        assertNull(System.getProperty("dw.dummyProperty"));

        final DropwizardTestSupport<TestConfiguration> testSupport = new DropwizardTestSupport<>(TestService.class,
                        ResourceHelpers.resourceFilePath("config.yml"),
                        ConfigOverride.config("dummyProperty", "dummy"));

        try {
            testSupport.before();
        } catch (Exception e) {
            // expected since the service will throw on startup
        }

        // Since ExternalResource will not call `after()` on exception, maybe DropwizardTestSupport should
        // clean system properties. Otherwise the properties stick around and might affect the following tests.
        assertNull(String.format("System property is not null. The value is [%s]",
                System.getProperty("dw.dummyProperty")),
                System.getProperty("dw.dummyProperty"));
    }

    public static class TestService extends Application<TestConfiguration> {

        @Override
        public void run(TestConfiguration testConfiguration, Environment environment) throws Exception {
            throw new RuntimeException("fail");
        }

    }
    public static class TestConfiguration extends Configuration {

        private String dummyProperty;
        @JsonProperty("dummyProperty")
        public String getDummyProperty() {
            return dummyProperty;
        }

        public void setDummyProperty(String dummyProperty) {
            this.dummyProperty = dummyProperty;
        }

    }

    private static final Statement TEST_STATEMENT = new Statement() {
        @Override
        public void evaluate() {

        }
    };
}
```


Changed files:
dropwizard-testing/src/main/java/io/dropwizard/testing/DropwizardTestSupport.java
dropwizard-e2e/src/test/java/com/example/badlog/BadLogTest.java

diff --git a/dropwizard-e2e/src/test/java/com/example/badlog/BadLogTest.java b/dropwizard-e2e/src/test/java/com/example/badlog/BadLogTest.java
index 03dd9abf9..147ce4337 100644
--- a/dropwizard-e2e/src/test/java/com/example/badlog/BadLogTest.java
+++ b/dropwizard-e2e/src/test/java/com/example/badlog/BadLogTest.java
@@ -66,11 +66,17 @@ public class BadLogTest {
         // Clear out the log file
         Files.write(logFile, new byte[]{});
 
+        final ConfigOverride logOverride = ConfigOverride.config("logging.appenders[0].currentLogFilename", logFile.toString());
         final String configPath = ResourceHelpers.resourceFilePath("badlog/config.yaml");
-        final DropwizardTestSupport<Configuration> app = new DropwizardTestSupport<>(BadLogApp.class, configPath,
-            ConfigOverride.config("logging.appenders[0].currentLogFilename", logFile.toString()));
+        final DropwizardTestSupport<Configuration> app = new DropwizardTestSupport<>(BadLogApp.class, configPath, logOverride);
         assertThatThrownBy(app::before).hasMessage("I'm a bad app");
 
+        // Dropwizard test support resets configuration overrides if `before` throws an exception
+        // which is fine, as that would normally signal the end of the test, but since we're
+        // testing logging behavior that is setup in the application `run` method, we need
+        // to ensure our log override is still present (it's removed again in `after`)
+        logOverride.addToSystemProperties();
+
         // Explicitly run the command so that the fatal error function runs
         app.getApplication().run("server", configPath);
         app.after();
@@ -109,10 +115,12 @@ public class BadLogTest {
         // Clear out the log file
         Files.write(logFile, new byte[]{});
 
-        final DropwizardTestSupport<Configuration> app3 = new DropwizardTestSupport<>(BadLogApp.class, configPath,
-            ConfigOverride.config("logging.appenders[0].currentLogFilename", logFile.toString()));
+        final DropwizardTestSupport<Configuration> app3 = new DropwizardTestSupport<>(BadLogApp.class, configPath, logOverride);
         assertThatThrownBy(app3::before).hasMessage("I'm a bad app");
 
+        // See comment above about manually adding config to system properties
+        logOverride.addToSystemProperties();
+
         // Explicitly run the command so that the fatal error function runs
         app3.getApplication().run("server", configPath);
         app3.after();
diff --git a/dropwizard-testing/src/main/java/io/dropwizard/testing/DropwizardTestSupport.java b/dropwizard-testing/src/main/java/io/dropwizard/testing/DropwizardTestSupport.java
index c1942ead6..0d8cefa63 100644
--- a/dropwizard-testing/src/main/java/io/dropwizard/testing/DropwizardTestSupport.java
+++ b/dropwizard-testing/src/main/java/io/dropwizard/testing/DropwizardTestSupport.java
@@ -147,7 +147,16 @@ public class DropwizardTestSupport<C extends Configuration> {
 
     public void before() {
         applyConfigOverrides();
-        startIfRequired();
+        try {
+            startIfRequired();
+        } catch (Exception e) {
+
+            // If there's an exception when setting up the server / application,
+            // manually call after as junit does not call the after method if
+            // the `before` method throws.
+            after();
+            throw e;
+        }
     }
 
     public void after() {